1
A Monkey interpreter, in Go[github]
1
2
Interpreter for the Monkey programming language, built in Go
3
following 'Writing An Interpreter In Go' by Thorsten Ball.
4
5
Features a lexer, parser, AST representation, and tree-walking
6
evaluator supporting let/return statements, closures, integers,
7
booleans, strings, arrays, and hash maps.
8
9
10
12
13
func Repl() {
14
in := os.Stdin
15
out := os.Stdout
16
scanner := bufio.NewScanner(in)
17
18
scope := object.NewGlobalScope()
19
fmt.Println("Hello bro! This is the Monkey programming language!")
20
fmt.Println("Feel free to type in commands:")
21
for {
22
fmt.Fprint(out, PROMPT)
23
scanned := scanner.Scan()
24
if !scanned {
25
return
26
}
27
28
line := scanner.Text()
29
if line == "q" || line == "quit" {
30
fmt.Printf("Bye bye!")
31
os.Exit(0)
32
}
33
l := lexer.New(line)
34
p := parser.New(l)
35
program := p.ParseProgram()
36
37
38
func Repl() {
in := os.Stdin
out := os.Stdout
scanner := bufio.NewScanner(in)
scope := object.NewGlobalScope()
fmt.Println("Hello bro! This is the Monkey programming language!")
fmt.Println("Feel free to type in commands:")
for {
fmt.Fprint(out, PROMPT)
scanned := scanner.Scan()
if !scanned {
return
}
line := scanner.Text()
if line == "q" || line == "quit" {
fmt.Printf("Bye bye!")
os.Exit(0)
}
l := lexer.New(line)
p := parser.New(l)
program := p.ParseProgram()
func (this *Lexer) readString() string {
openingQuote := this.currentChar
acc := ""
// go over to first string byte
this.nextChar()
for this.currentChar != openingQuote && this.currentChar != 0 {
if !this.isEscapeChar() {
acc += string(this.currentChar)
this.nextChar()
} else {
this.nextChar()
acc += string(this.currentChar)
this.nextChar()
}
}
// go over last quote
this.nextChar()
return acc
}
func (p *Parser) parseInfixExpression(left ast.Expression) (ast.Expression, error) {
defer untrace(trace(fmt.Sprintf("parseInfixExpression, left is %s", left.String())))
res := &ast.InfixExpression{Token: p.currentToken, Left: left, Operator: p.currentToken.Literal}
precedence := p.currPrecedence()
// Assignment is right-associative: x = y = 5 should parse as x = (y = 5)
if p.currentToken.Type == token.ASSIGN {
precedence = precedence - 1
}
p.nextToken()
exrp, err := p.parseExpression(precedence)
if err != nil {
return nil, fmt.Errorf("could not parse infix expression: %s", err)
}
res.Right = exrp
return res, nil
}
func (me *Scope) Get(identifier string) (Object, bool) {
res, has := me.s[identifier]
if has {
return res, true
}
if me.parent != nil {
return me.parent.Get(identifier)
}
return NULL_OBJECT, false
}
func (me *Scope) Add(identifier string, val Object) {
me.s[identifier] = val
}
func (me *Scope) Set(identifier string, val Object) bool {
_, has := me.s[identifier]
if has {
me.s[identifier] = val
return true
}
if me.parent != nil {
return me.parent.Set(identifier, val)
}
return false
}