Skip to content

Commit bc8d3aa

Browse files
committed
add support for resolving and binding
1 parent 079c735 commit bc8d3aa

File tree

10 files changed

+335
-102
lines changed

10 files changed

+335
-102
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ https://craftinginterpreters.com/
1010
- [x] Evaluating Expressions
1111
- [x] Statements and State
1212
- [x] Control Flow
13-
- [x] Functions
13+
- [x] Functions
14+
- [x] Resolving and Binding

main.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import (
66
"log"
77
"os"
88

9-
"golox/pkg/ast"
109
"golox/pkg/interpreter"
10+
"golox/pkg/parser"
11+
"golox/pkg/resolver"
1112
"golox/pkg/scanner"
1213
)
1314

@@ -32,43 +33,53 @@ func runFile(path string) {
3233
os.Exit(65)
3334
}
3435

35-
interpreter := interpreter.NewInterpreter()
36-
err = interpreter.Interpret(stmts)
36+
i := interpreter.NewInterpreter()
37+
r := resolver.NewResolver(i)
38+
err = r.Resolve(stmts)
39+
if err != nil {
40+
os.Exit(65)
41+
}
42+
43+
err = i.Interpret(stmts)
3744
if err != nil {
3845
os.Exit(70)
3946
}
4047
}
4148

4249
func runPrompt() {
43-
scanner := bufio.NewScanner(os.Stdin)
44-
interpreter := interpreter.NewInterpreter()
50+
s := bufio.NewScanner(os.Stdin)
51+
i := interpreter.NewInterpreter()
4552
fmt.Print("> ")
46-
for scanner.Scan() {
47-
stmts, err := scanAndParse(scanner.Text())
53+
for s.Scan() {
54+
stmts, err := scanAndParse(s.Text())
4855
if err == nil {
49-
interpreter.Interpret(stmts)
56+
r := resolver.NewResolver(i)
57+
err = r.Resolve(stmts)
58+
}
59+
if err == nil {
60+
i.Interpret(stmts)
5061
}
5162
fmt.Print("> ")
5263
}
5364

54-
if err := scanner.Err(); err == nil {
65+
if err := s.Err(); err == nil {
5566
fmt.Println("bye")
5667
os.Exit(0)
5768
}
5869
}
5970

60-
func scanAndParse(source string) ([]ast.Stmt, error) {
61-
scanner := scanner.NewScanner(source)
62-
err := scanner.ScanTokens()
71+
func scanAndParse(source string) ([]parser.Stmt, error) {
72+
s := scanner.NewScanner(source)
73+
err := s.ScanTokens()
6374
if err != nil {
6475
return nil, err
6576
}
6677

67-
parser := ast.NewParser(scanner.Tokens)
68-
stmts, err := parser.Parse()
78+
p := parser.NewParser(s.Tokens)
79+
stmts, err := p.Parse()
6980
if err != nil {
7081
return nil, err
7182
}
7283

7384
return stmts, nil
74-
}
85+
}

pkg/interpreter/callable.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ import (
44
"fmt"
55
"time"
66

7-
"golox/pkg/ast"
7+
"golox/pkg/parser"
88
)
99

1010
type callable interface {
1111
arity() int
12-
call(i *interpreter, args []interface{}) interface{}
12+
call(i *Interpreter, args []interface{}) interface{}
1313
}
1414

1515
type clock struct{}
1616

1717
func (c *clock) arity() int { return 0 }
1818

19-
func (c *clock) call(i *interpreter, args []interface{}) interface{} {
19+
func (c *clock) call(i *Interpreter, args []interface{}) interface{} {
2020
return float64(time.Now().UnixMilli() / 1000)
2121
}
2222

@@ -25,20 +25,21 @@ func (c clock) String() string {
2525
}
2626

2727
type function struct {
28-
declaration *ast.FunStmt
28+
declaration *parser.FunStmt
29+
closure *environment
2930
}
3031

3132
func (f *function) arity() int { return len(f.declaration.Params) }
3233

33-
func (f *function) call(i *interpreter, args []interface{}) (value interface{}) {
34-
env := &environment{i.global, make(map[string]interface{})}
34+
func (f *function) call(i *Interpreter, args []interface{}) (value interface{}) {
35+
env := &environment{f.closure, make(map[string]interface{})}
3536
for i := 0; i < f.arity(); i++ {
3637
env.define(f.declaration.Params[i].Lexeme, args[i])
3738
}
3839

39-
prev := i.env
40+
prev := i.current
4041
defer func() {
41-
i.env = prev
42+
i.current = prev
4243
r := recover()
4344
if err, ok := r.(error); ok {
4445
panic(err)
@@ -47,7 +48,7 @@ func (f *function) call(i *interpreter, args []interface{}) (value interface{})
4748
}
4849
}()
4950

50-
i.env = env
51+
i.current = env
5152
for _, stmt := range f.declaration.Body.Statements {
5253
stmt.Accept(i)
5354
}
@@ -56,5 +57,5 @@ func (f *function) call(i *interpreter, args []interface{}) (value interface{})
5657
}
5758

5859
func (f function) String() string {
59-
return fmt.Sprintf("<function %s >", f.declaration.Name.Lexeme)
60-
}
60+
return fmt.Sprintf("<function %s>", f.declaration.Name.Lexeme)
61+
}

pkg/interpreter/environment.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ func (e *environment) get(name *scanner.Token) interface{} {
2525
panic(fault.NewFault(name.Line, message))
2626
}
2727

28+
func (e *environment) getAt(name string, dist int) interface{} {
29+
ancestor := e
30+
for i := 0; i < dist; i++ {
31+
ancestor = ancestor.enclosing
32+
}
33+
34+
return ancestor.values[name]
35+
}
36+
2837
func (e *environment) assign(name *scanner.Token, value interface{}) {
2938
if _, ok := e.values[name.Lexeme]; ok {
3039
e.values[name.Lexeme] = value
@@ -36,6 +45,15 @@ func (e *environment) assign(name *scanner.Token, value interface{}) {
3645
}
3746
}
3847

48+
func (e *environment) assignAt(name string, value interface{}, dist int) {
49+
ancestor := e
50+
for i := 0; i < dist; i++ {
51+
ancestor = ancestor.enclosing
52+
}
53+
54+
ancestor.values[name] = value
55+
}
56+
3957
func (e *environment) define(name string, value interface{}) {
4058
e.values[name] = value
4159
}

pkg/interpreter/interpreter.go

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,24 @@ import (
44
"fmt"
55
"strconv"
66

7-
"golox/pkg/ast"
87
"golox/pkg/fault"
8+
"golox/pkg/parser"
99
"golox/pkg/scanner"
1010
)
1111

12-
13-
type interpreter struct {
14-
global *environment
15-
env *environment
12+
type Interpreter struct {
13+
global *environment
14+
current *environment
15+
locals map[parser.Expr]int
1616
}
1717

18-
func NewInterpreter() *interpreter {
18+
func NewInterpreter() *Interpreter {
1919
global := &environment{nil, make(map[string]interface{})}
2020
global.define("clock", &clock{})
21-
return &interpreter{global, global}
21+
return &Interpreter{global, global, make(map[parser.Expr]int)}
2222
}
2323

24-
func (i *interpreter) Interpret(stmts []ast.Stmt) (err error) {
24+
func (i *Interpreter) Interpret(stmts []parser.Stmt) (err error) {
2525
defer func() {
2626
if r := recover(); r != nil {
2727
err = r.(error)
@@ -35,12 +35,16 @@ func (i *interpreter) Interpret(stmts []ast.Stmt) (err error) {
3535
return
3636
}
3737

38-
func (i *interpreter) VisitExprStmt(e *ast.ExprStmt) interface{} {
38+
func (i *Interpreter) Resolve(expr parser.Expr, depth int) {
39+
i.locals[expr] = depth
40+
}
41+
42+
func (i *Interpreter) VisitExprStmt(e *parser.ExprStmt) interface{} {
3943
e.Expression.Accept(i)
4044
return nil
4145
}
4246

43-
func (i *interpreter) VisitPrintStmt(p *ast.PrintStmt) interface{} {
47+
func (i *Interpreter) VisitPrintStmt(p *parser.PrintStmt) interface{} {
4448
value := p.Expression.Accept(i)
4549
switch v := value.(type) {
4650
case float64:
@@ -54,31 +58,31 @@ func (i *interpreter) VisitPrintStmt(p *ast.PrintStmt) interface{} {
5458
return nil
5559
}
5660

57-
func (i *interpreter) VisitVarStmt(v *ast.VarStmt) interface{} {
61+
func (i *Interpreter) VisitVarStmt(v *parser.VarStmt) interface{} {
5862
var value interface{}
5963
if v.Initializer != nil {
6064
value = v.Initializer.Accept(i)
6165
}
6266

63-
i.env.define(v.Name.Lexeme, value)
67+
i.current.define(v.Name.Lexeme, value)
6468
return nil
6569
}
6670

67-
func (i *interpreter) VisitBlockStmt(b *ast.BlockStmt) interface{} {
68-
prev := i.env
71+
func (i *Interpreter) VisitBlockStmt(b *parser.BlockStmt) interface{} {
72+
prev := i.current
6973
defer func() {
70-
i.env = prev
74+
i.current = prev
7175
}()
7276

73-
i.env = &environment{prev, make(map[string]interface{})}
77+
i.current = &environment{prev, make(map[string]interface{})}
7478
for _, stmt := range b.Statements {
7579
stmt.Accept(i)
7680
}
7781

7882
return nil
7983
}
8084

81-
func (i *interpreter) VisitIfStmt(i_ *ast.IfStmt) interface{} {
85+
func (i *Interpreter) VisitIfStmt(i_ *parser.IfStmt) interface{} {
8286
value := i_.Condition.Accept(i)
8387
if isTruthy(value) {
8488
i_.ThenBranch.Accept(i)
@@ -89,20 +93,20 @@ func (i *interpreter) VisitIfStmt(i_ *ast.IfStmt) interface{} {
8993
return nil
9094
}
9195

92-
func (i *interpreter) VisitWhileStmt(w *ast.WhileStmt) interface{} {
96+
func (i *Interpreter) VisitWhileStmt(w *parser.WhileStmt) interface{} {
9397
for isTruthy(w.Condition.Accept(i)) {
9498
w.Body.Accept(i)
9599
}
96100

97101
return nil
98102
}
99103

100-
func (i *interpreter) VisitFunStmt(f *ast.FunStmt) interface{} {
101-
i.env.define(f.Name.Lexeme, &function{f})
104+
func (i *Interpreter) VisitFunStmt(f *parser.FunStmt) interface{} {
105+
i.current.define(f.Name.Lexeme, &function{f, i.current})
102106
return nil
103107
}
104108

105-
func (i *interpreter) VisitReturnStmt(v *ast.ReturnStmt) interface{} {
109+
func (i *Interpreter) VisitReturnStmt(v *parser.ReturnStmt) interface{} {
106110
var value interface{}
107111
if v.Value != nil {
108112
value = v.Value.Accept(i)
@@ -111,7 +115,7 @@ func (i *interpreter) VisitReturnStmt(v *ast.ReturnStmt) interface{} {
111115
panic(value)
112116
}
113117

114-
func (i *interpreter) VisitBinaryExpr(b *ast.BinaryExpr) interface{} {
118+
func (i *Interpreter) VisitBinaryExpr(b *parser.BinaryExpr) interface{} {
115119
left := b.Left.Accept(i)
116120
right := b.Right.Accept(i)
117121

@@ -160,15 +164,15 @@ func (i *interpreter) VisitBinaryExpr(b *ast.BinaryExpr) interface{} {
160164
return nil
161165
}
162166

163-
func (i *interpreter) VisitGroupingExpr(g *ast.GroupingExpr) interface{} {
167+
func (i *Interpreter) VisitGroupingExpr(g *parser.GroupingExpr) interface{} {
164168
return g.Expression.Accept(i)
165169
}
166170

167-
func (i *interpreter) VisitLiteralExpr(l *ast.LiteralExpr) interface{} {
171+
func (i *Interpreter) VisitLiteralExpr(l *parser.LiteralExpr) interface{} {
168172
return l.Value
169173
}
170174

171-
func (i *interpreter) VisitUnaryExpr(u *ast.UnaryExpr) interface{} {
175+
func (i *Interpreter) VisitUnaryExpr(u *parser.UnaryExpr) interface{} {
172176
right := u.Right.Accept(i)
173177

174178
if u.Operator.TokenType == scanner.MINUS {
@@ -193,17 +197,27 @@ func (i *interpreter) VisitUnaryExpr(u *ast.UnaryExpr) interface{} {
193197
return nil
194198
}
195199

196-
func (i *interpreter) VisitVariableExpr(v *ast.VariableExpr) interface{} {
197-
return i.env.get(v.Name)
200+
func (i *Interpreter) VisitVariableExpr(v *parser.VariableExpr) interface{} {
201+
if dist, ok := i.locals[v]; ok {
202+
return i.current.getAt(v.Name.Lexeme, dist)
203+
}
204+
205+
return i.global.get(v.Name)
198206
}
199207

200-
func (i *interpreter) VisitAssignExpr(a *ast.AssignExpr) interface{} {
208+
func (i *Interpreter) VisitAssignExpr(a *parser.AssignExpr) interface{} {
201209
value := a.Value.Accept(i)
202-
i.env.assign(a.Name, value)
210+
211+
if dist, ok := i.locals[a]; ok {
212+
i.current.assignAt(a.Name.Lexeme, value, dist)
213+
} else {
214+
i.global.assign(a.Name, value)
215+
}
216+
203217
return value
204218
}
205219

206-
func (i *interpreter) VisitLogicalExpr(l *ast.LogicalExpr) interface{} {
220+
func (i *Interpreter) VisitLogicalExpr(l *parser.LogicalExpr) interface{} {
207221
left := l.Left.Accept(i)
208222

209223
if (l.Operator.TokenType == scanner.OR && isTruthy(left)) || !isTruthy(left) {
@@ -213,7 +227,7 @@ func (i *interpreter) VisitLogicalExpr(l *ast.LogicalExpr) interface{} {
213227
return l.Right.Accept(i)
214228
}
215229

216-
func (i *interpreter) VisitCallExpr(c *ast.CallExpr) interface{} {
230+
func (i *Interpreter) VisitCallExpr(c *parser.CallExpr) interface{} {
217231
callee := c.Callee.Accept(i)
218232
args := []interface{}{}
219233
for _, arg := range c.Arguments {
@@ -232,7 +246,7 @@ func (i *interpreter) VisitCallExpr(c *ast.CallExpr) interface{} {
232246
panic(fault.NewFault(c.Paren.Line, "can only call functions and classes"))
233247
}
234248

235-
func (i *interpreter) checkNumberOperands(operator *scanner.Token, left interface{}, right interface{}) (float64, float64) {
249+
func (i *Interpreter) checkNumberOperands(operator *scanner.Token, left interface{}, right interface{}) (float64, float64) {
236250
if leftValue, leftOk := left.(float64); leftOk {
237251
if rightValue, rightOk := right.(float64); rightOk {
238252
return leftValue, rightValue

pkg/ast/expr.go renamed to pkg/parser/expr.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
package ast
1+
package parser
22

33
import "golox/pkg/scanner"
44

5-
65
type Expr interface {
76
Accept(v ExprVisitor) interface{}
87
}

0 commit comments

Comments
 (0)