closures
This commit is contained in:
parent
1fdd522c8f
commit
1117f2c104
4 changed files with 65 additions and 36 deletions
56
callable.go
56
callable.go
|
@ -1,36 +1,44 @@
|
|||
package main
|
||||
|
||||
type Callable struct {
|
||||
arity int
|
||||
call func(*Interpreter, ...any) any
|
||||
type Callable interface {
|
||||
arity() int
|
||||
call(i *Interpreter, args ...any) (ret any)
|
||||
}
|
||||
|
||||
func newCallable(f *FunStmt) *Callable {
|
||||
return &Callable{
|
||||
arity: len(f.args),
|
||||
call: func(i *Interpreter, args ...any) (ret any) {
|
||||
type Function struct {
|
||||
definition *FunStmt
|
||||
closure *Environment
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
re, ok := err.(Return)
|
||||
func (f *Function) call(i *Interpreter, args ...any) (ret any) {
|
||||
|
||||
if !ok {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
re, ok := err.(Return)
|
||||
|
||||
ret = re.val
|
||||
}
|
||||
}()
|
||||
|
||||
env := newEnvironment(i.globals)
|
||||
|
||||
for idx, arg := range f.args {
|
||||
env.define(arg.lexeme, args[idx])
|
||||
if !ok {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
i.executeBlock(f.body, env)
|
||||
ret = re.val
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
},
|
||||
env := newEnvironment(f.closure)
|
||||
|
||||
for idx, arg := range f.definition.args {
|
||||
env.define(arg.lexeme, args[idx])
|
||||
}
|
||||
|
||||
i.executeBlock(f.definition.body, env)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Function) arity() int {
|
||||
return len(f.definition.args)
|
||||
}
|
||||
|
||||
func newFunction(fun *FunStmt, env *Environment) Callable {
|
||||
return &Function{fun, env}
|
||||
}
|
||||
|
|
18
globals.go
18
globals.go
|
@ -2,12 +2,16 @@ package main
|
|||
|
||||
import "time"
|
||||
|
||||
func defineGlobals(env *Environment) {
|
||||
type ClockFun struct{}
|
||||
|
||||
env.define("clock", &Callable{
|
||||
arity: 0,
|
||||
call: func(i *Interpreter, arg ...any) any {
|
||||
return time.Now().Unix()
|
||||
},
|
||||
})
|
||||
func (cf *ClockFun) call(i *Interpreter, args ...any) any {
|
||||
return time.Now().Unix()
|
||||
}
|
||||
|
||||
func (cf *ClockFun) arity() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func defineGlobals(env *Environment) {
|
||||
env.define("clock", &ClockFun{})
|
||||
}
|
||||
|
|
|
@ -171,18 +171,18 @@ func (i *Interpreter) visitCall(c *Call) any {
|
|||
args = append(args, i.evaluate(arg))
|
||||
}
|
||||
|
||||
callable, ok := callee.(*Callable)
|
||||
callable, ok := callee.(Callable)
|
||||
|
||||
if !ok {
|
||||
i.panic(&RuntimeError{c.paren, "Can only call function and classes."})
|
||||
}
|
||||
|
||||
if callable.arity != len(args) {
|
||||
if callable.arity() != len(args) {
|
||||
i.panic(&RuntimeError{
|
||||
c.paren,
|
||||
fmt.Sprintf(
|
||||
"Expected %d arguments but got %d",
|
||||
callable.arity,
|
||||
callable.arity(),
|
||||
len(args),
|
||||
),
|
||||
})
|
||||
|
@ -192,7 +192,7 @@ func (i *Interpreter) visitCall(c *Call) any {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -42,3 +42,20 @@ fun fib(n) {
|
|||
for (var i = 1; i <= 10; i = i + 1) {
|
||||
print fib(i);
|
||||
}
|
||||
|
||||
|
||||
fun makeCounter() {
|
||||
var i = 0;
|
||||
|
||||
fun incr() {
|
||||
i = i + 1;
|
||||
print i;
|
||||
}
|
||||
|
||||
return incr;
|
||||
}
|
||||
|
||||
var counter = makeCounter();
|
||||
|
||||
counter();
|
||||
counter();
|
Loading…
Reference in a new issue