This commit is contained in:
Greg 2024-10-12 00:09:25 +03:00
parent 1fdd522c8f
commit 1117f2c104
4 changed files with 65 additions and 36 deletions

View file

@ -1,14 +1,16 @@
package main package main
type Callable struct { type Callable interface {
arity int arity() int
call func(*Interpreter, ...any) any call(i *Interpreter, args ...any) (ret any)
} }
func newCallable(f *FunStmt) *Callable { type Function struct {
return &Callable{ definition *FunStmt
arity: len(f.args), closure *Environment
call: func(i *Interpreter, args ...any) (ret any) { }
func (f *Function) call(i *Interpreter, args ...any) (ret any) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
@ -22,15 +24,21 @@ func newCallable(f *FunStmt) *Callable {
} }
}() }()
env := newEnvironment(i.globals) env := newEnvironment(f.closure)
for idx, arg := range f.args { for idx, arg := range f.definition.args {
env.define(arg.lexeme, args[idx]) env.define(arg.lexeme, args[idx])
} }
i.executeBlock(f.body, env) i.executeBlock(f.definition.body, env)
return nil return nil
}, }
}
func (f *Function) arity() int {
return len(f.definition.args)
}
func newFunction(fun *FunStmt, env *Environment) Callable {
return &Function{fun, env}
} }

View file

@ -2,12 +2,16 @@ package main
import "time" import "time"
func defineGlobals(env *Environment) { type ClockFun struct{}
env.define("clock", &Callable{ func (cf *ClockFun) call(i *Interpreter, args ...any) any {
arity: 0,
call: func(i *Interpreter, arg ...any) any {
return time.Now().Unix() return time.Now().Unix()
}, }
})
func (cf *ClockFun) arity() int {
return 0
}
func defineGlobals(env *Environment) {
env.define("clock", &ClockFun{})
} }

View file

@ -171,18 +171,18 @@ func (i *Interpreter) visitCall(c *Call) any {
args = append(args, i.evaluate(arg)) args = append(args, i.evaluate(arg))
} }
callable, ok := callee.(*Callable) callable, ok := callee.(Callable)
if !ok { if !ok {
i.panic(&RuntimeError{c.paren, "Can only call function and classes."}) i.panic(&RuntimeError{c.paren, "Can only call function and classes."})
} }
if callable.arity != len(args) { if callable.arity() != len(args) {
i.panic(&RuntimeError{ i.panic(&RuntimeError{
c.paren, c.paren,
fmt.Sprintf( fmt.Sprintf(
"Expected %d arguments but got %d", "Expected %d arguments but got %d",
callable.arity, callable.arity(),
len(args), len(args),
), ),
}) })
@ -192,7 +192,7 @@ func (i *Interpreter) visitCall(c *Call) any {
} }
func (i *Interpreter) visitFunStmt(f *FunStmt) { func (i *Interpreter) visitFunStmt(f *FunStmt) {
i.env.define(f.name.lexeme, newCallable(f)) i.env.define(f.name.lexeme, newFunction(f, i.env))
} }
func (i *Interpreter) visitReturnStmt(r *ReturnStmt) { func (i *Interpreter) visitReturnStmt(r *ReturnStmt) {

View file

@ -42,3 +42,20 @@ fun fib(n) {
for (var i = 1; i <= 10; i = i + 1) { for (var i = 1; i <= 10; i = i + 1) {
print fib(i); print fib(i);
} }
fun makeCounter() {
var i = 0;
fun incr() {
i = i + 1;
print i;
}
return incr;
}
var counter = makeCounter();
counter();
counter();