This document describes the technical architecture of the BanglaCode programming language interpreter.
- Overview
- High-Level Architecture
- Component Details
- Data Flow
- Design Decisions
- Performance Considerations
- Extending the Language
BanglaCode is a tree-walking interpreter written in Go. It follows the classic interpreter pipeline:
Source Code → Lexer → Parser → AST → Evaluator → Result
| Aspect | Implementation |
|---|---|
| Type System | Dynamically typed |
| Evaluation | Tree-walking interpreter |
| Memory Management | Go's garbage collector |
| Concurrency | Go goroutines (for HTTP server) |
| Module System | File-based imports |
- Language: Go 1.20+
- Dependencies: Standard library only (no external dependencies for core)
- Build: Native Go toolchain
- Testing: Go testing framework
┌─────────────────────────────────────────────────────────────────────┐
│ BanglaCode │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │
│ │ main │───▶│ REPL │───▶│ Lexer │───▶│ Parser │ │
│ │ .go │ │ │ │ │ │ │ │
│ └─────────┘ └─────────┘ └────┬────┘ └────────┬────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ AST │ │
│ │ (Abstract Syntax Tree) │ │
│ └─────────────┬───────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Evaluator │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │Expressions│ │Statements│ │ Classes │ │ Modules │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Builtins │ │ Errors │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Object │ │
│ │ System │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
The entry point handles:
- Command-line argument parsing
- File reading and execution
- REPL initialization
- Version and help display
// Simplified main flow
func main() {
if len(os.Args) == 1 {
repl.Start() // Interactive mode
} else {
runFile(os.Args[1]) // Execute file
}
}The lexer (tokenizer) converts source code into a stream of tokens.
lexer.go— Main lexer implementationtoken.go— Token type definitions and keyword mapping
const (
// Literals
IDENT = "IDENT"
INT = "INT"
FLOAT = "FLOAT"
STRING = "STRING"
// Operators
ASSIGN = "="
PLUS = "+"
MINUS = "-"
// ...
// Keywords (Bengali)
DHORO = "DHORO" // let/var
JODI = "JODI" // if
NAHOLE = "NAHOLE" // else
JOTOKKHON = "JOTOKKHON" // while
GHURIYE = "GHURIYE" // for
KAJ = "KAJ" // function
FERAO = "FERAO" // return
// ...
)var keywords = map[string]TokenType{
"dhoro": DHORO,
"jodi": JODI,
"nahole": NAHOLE,
"jotokkhon": JOTOKKHON,
"ghuriye": GHURIYE,
"kaj": KAJ,
"ferao": FERAO,
"sreni": SRENI,
"shuru": SHURU,
"notun": NOTUN,
"ei": EI,
"sotti": SOTTI,
"mittha": MITTHA,
"khali": KHALI,
"ebong": EBONG,
"ba": BA,
"na": NA,
// ...
}Input: "dhoro x = 5;"
Output Tokens:
┌─────────┬───────┬──────┬────────┐
│ Type │ Value │ Line │ Column │
├─────────┼───────┼──────┼────────┤
│ DHORO │ dhoro │ 1 │ 1 │
│ IDENT │ x │ 1 │ 7 │
│ ASSIGN │ = │ 1 │ 9 │
│ INT │ 5 │ 1 │ 11 │
│ SEMI │ ; │ 1 │ 12 │
│ EOF │ │ 1 │ 13 │
└─────────┴───────┴──────┴────────┘
The parser constructs an Abstract Syntax Tree (AST) from tokens using recursive descent parsing with operator precedence climbing.
parser.go— Main parser and entry pointexpressions.go— Expression parsingstatements.go— Statement parsingprecedence.go— Operator precedence definitions
const (
_ int = iota
LOWEST
EQUALS // ==
LESSGREATER // > or <
SUM // +
PRODUCT // *
PREFIX // -X or !X
CALL // myFunction(X)
INDEX // array[index]
)The parser uses Pratt parsing (top-down operator precedence) for expressions:
func (p *Parser) parseExpression(precedence int) ast.Expression {
prefix := p.prefixParseFns[p.curToken.Type]
leftExp := prefix()
for precedence < p.peekPrecedence() {
infix := p.infixParseFns[p.peekToken.Type]
leftExp = infix(leftExp)
}
return leftExp
}The Abstract Syntax Tree represents the program structure.
ast.go— Base node interfacesexpressions.go— Expression nodesstatements.go— Statement nodesliterals.go— Literal value nodes
Node (interface)
├── Statement (interface)
│ ├── LetStatement // dhoro x = 5;
│ ├── ReturnStatement // ferao x;
│ ├── ExpressionStatement // x + 5;
│ ├── BlockStatement // { ... }
│ ├── IfStatement // jodi ... nahole
│ ├── WhileStatement // jotokkhon
│ ├── ForStatement // ghuriye
│ ├── ClassStatement // sreni
│ ├── TryStatement // chesta ... dhoro_bhul
│ ├── ThrowStatement // felo
│ ├── ImportStatement // ano
│ └── ExportStatement // pathao
│
└── Expression (interface)
├── Identifier
├── IntegerLiteral
├── FloatLiteral
├── StringLiteral
├── BooleanLiteral
├── NullLiteral
├── ArrayLiteral
├── MapLiteral
├── PrefixExpression // -x, !x, na x
├── InfixExpression // x + y, x ebong y
├── IfExpression
├── FunctionLiteral // kaj(x) { ... }
├── CallExpression // fn(x)
├── IndexExpression // arr[0]
├── MemberExpression // obj.prop
├── AssignExpression // x = 5
└── NewExpression // notun Class()
For dhoro x = 5 + 3;:
Program
└── LetStatement
├── Name: Identifier("x")
└── Value: InfixExpression
├── Operator: "+"
├── Left: IntegerLiteral(5)
└── Right: IntegerLiteral(3)
The object system represents runtime values.
object.go— Object types and interfacesenvironment.go— Variable scope management
type ObjectType string
const (
INTEGER_OBJ = "INTEGER"
FLOAT_OBJ = "FLOAT"
STRING_OBJ = "STRING"
BOOLEAN_OBJ = "BOOLEAN"
NULL_OBJ = "NULL"
ARRAY_OBJ = "ARRAY"
MAP_OBJ = "MAP"
FUNCTION_OBJ = "FUNCTION"
BUILTIN_OBJ = "BUILTIN"
CLASS_OBJ = "CLASS"
INSTANCE_OBJ = "INSTANCE"
ERROR_OBJ = "ERROR"
RETURN_VALUE_OBJ = "RETURN_VALUE"
BREAK_OBJ = "BREAK"
CONTINUE_OBJ = "CONTINUE"
MODULE_OBJ = "MODULE"
)type Environment struct {
store map[string]Object
outer *Environment // Parent scope for closures
}
func (e *Environment) Get(name string) (Object, bool) {
obj, ok := e.store[name]
if !ok && e.outer != nil {
obj, ok = e.outer.Get(name) // Check parent scope
}
return obj, ok
}The evaluator walks the AST and executes the program.
evaluator.go— Main evaluation loopexpressions.go— Expression evaluationstatements.go— Statement evaluationbuiltins.go— Built-in functions (40+)classes.go— OOP supportmodules.go— Import/export handlingerrors.go— Error creation and handlinghelpers.go— Utility functions
func Eval(node ast.Node, env *object.Environment) object.Object {
switch node := node.(type) {
case *ast.Program:
return evalProgram(node, env)
case *ast.LetStatement:
val := Eval(node.Value, env)
env.Set(node.Name.Value, val)
case *ast.IfStatement:
return evalIfStatement(node, env)
case *ast.InfixExpression:
left := Eval(node.Left, env)
right := Eval(node.Right, env)
return evalInfixExpression(node.Operator, left, right)
// ... more cases
}
}var builtins = map[string]*object.Builtin{
"dekho": {
Fn: func(args ...object.Object) object.Object {
// Print implementation
},
},
"dorghyo": {
Fn: func(args ...object.Object) object.Object {
// Length implementation
},
},
// ... 40+ more functions
}The Read-Eval-Print Loop for interactive usage.
- Multi-line input support
- Command history
- Built-in help system
- Clear screen command
- Graceful exit handling
func Start(in io.Reader, out io.Writer) {
scanner := bufio.NewScanner(in)
env := object.NewEnvironment()
for {
fmt.Print(">> ")
if !scanner.Scan() {
return
}
line := scanner.Text()
l := lexer.New(line)
p := parser.New(l)
program := p.ParseProgram()
result := evaluator.Eval(program, env)
if result != nil {
io.WriteString(out, result.Inspect())
}
}
}┌──────────────────────────────────────────────────────────────────┐
│ Source Code │
│ "dhoro x = 5 + 3;" │
└─────────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Lexer │
│ Converts source text into tokens │
│ [DHORO, IDENT(x), ASSIGN, INT(5), PLUS, INT(3), SEMICOLON] │
└─────────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Parser │
│ Builds Abstract Syntax Tree from tokens │
│ LetStatement { Name: "x", Value: InfixExpr(5, +, 3) } │
└─────────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Evaluator │
│ Walks AST and executes nodes │
│ 1. Evaluate InfixExpr(5, +, 3) → 8 │
│ 2. Bind "x" → 8 in environment │
└─────────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Environment │
│ { "x": Integer(8) } │
└──────────────────────────────────────────────────────────────────┘
| Reason | Benefit |
|---|---|
| Performance | Native compilation, efficient execution |
| Simplicity | Clean syntax, easy to understand |
| Standard Library | Rich stdlib reduces dependencies |
| Concurrency | Goroutines for HTTP server |
| Cross-platform | Easy cross-compilation |
| Memory Safety | Garbage collection, no manual memory management |
| Advantage | Trade-off |
|---|---|
| Simplicity | Slower than bytecode compilation |
| Debuggability | Higher memory usage |
| Rapid development | No optimization passes |
| Educational value | Suitable for scripting, not systems programming |
| Reason | Benefit |
|---|---|
| Accessibility | Familiar to Bengali speakers |
| ASCII compatibility | Works on all keyboards |
| C-like syntax | Familiar structure for programming students |
| Searchability | Easy to type and search |
- Teaches discipline and attention to detail
- Matches C/Java syntax students will encounter
- Simpler parser (no automatic semicolon insertion)
- Clear statement boundaries
- Efficient Token Lookup — HashMap for keyword identification
- Environment Chain — Fast variable lookup with scope chain
- Object Pooling — Reuse common objects (NULL, TRUE, FALSE)
- Lazy Evaluation — Short-circuit evaluation for
ebong/ba
- Bytecode Compilation — Compile AST to bytecode for faster execution
- JIT Compilation — Just-in-time compilation for hot paths
- Constant Folding — Pre-compute constant expressions
- Tail Call Optimization — Optimize recursive functions
- Inline Caching — Cache property lookups
- Go's garbage collector handles memory
- Environments are garbage collected when no longer referenced
- Large strings and arrays are heap-allocated
- Define the function in
src/evaluator/builtins.go:
"myFunc": {
Fn: func(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments")
}
// Implementation
return &object.String{Value: result}
},
},- Update documentation in README.md and SYNTAX.md
- Add examples in
examples/directory
- Add token in
src/lexer/token.go:
const MYKEYWORD = "MYKEYWORD"
var keywords = map[string]TokenType{
"mykeyword": MYKEYWORD,
}- Add AST node in
src/ast/:
type MyStatement struct {
Token token.Token
// Fields
}- Update parser in
src/parser/:
case token.MYKEYWORD:
return p.parseMyStatement()- Update evaluator in
src/evaluator/:
case *ast.MyStatement:
return evalMyStatement(node, env)- Define object type in
src/object/object.go:
const MYTYPE_OBJ = "MYTYPE"
type MyType struct {
Value interface{}
}
func (m *MyType) Type() ObjectType { return MYTYPE_OBJ }
func (m *MyType) Inspect() string { return fmt.Sprintf("%v", m.Value) }- Handle in evaluator — Add cases for operations with the new type
- Add conversion functions — Built-in functions to create/convert
BanglaCode/
├── main.go # Entry point (CLI handling)
├── go.mod # Go module definition
├── src/
│ ├── lexer/
│ │ ├── lexer.go # Tokenization logic
│ │ └── token.go # Token definitions
│ ├── parser/
│ │ ├── parser.go # Main parser
│ │ ├── expressions.go # Expression parsing
│ │ ├── statements.go # Statement parsing
│ │ └── precedence.go # Operator precedence
│ ├── ast/
│ │ ├── ast.go # AST interfaces
│ │ ├── expressions.go # Expression nodes
│ │ ├── statements.go # Statement nodes
│ │ └── literals.go # Literal nodes
│ ├── object/
│ │ ├── object.go # Runtime types
│ │ └── environment.go # Scope management
│ ├── evaluator/
│ │ ├── evaluator.go # Main evaluation
│ │ ├── builtins.go # Built-in functions
│ │ ├── expressions.go # Expression evaluation
│ │ ├── statements.go # Statement evaluation
│ │ ├── classes.go # OOP support
│ │ ├── modules.go # Module system
│ │ ├── errors.go # Error handling
│ │ └── helpers.go # Utilities
│ └── repl/
│ └── repl.go # Interactive shell
├── examples/ # Example programs
├── Extension/ # VSCode extension
└── Documentation/ # Docs website
- Writing An Interpreter In Go — Thorsten Ball
- Crafting Interpreters — Robert Nystrom
- Go Programming Language
Last Updated: 2024 Architecture Version: 3.x