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
|
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) {
|
}
|
||||||
|
|
||||||
defer func() {
|
func (f *Function) call(i *Interpreter, args ...any) (ret any) {
|
||||||
if err := recover(); err != nil {
|
|
||||||
re, ok := err.(Return)
|
|
||||||
|
|
||||||
if !ok {
|
defer func() {
|
||||||
panic(err)
|
if err := recover(); err != nil {
|
||||||
}
|
re, ok := err.(Return)
|
||||||
|
|
||||||
ret = re.val
|
if !ok {
|
||||||
}
|
panic(err)
|
||||||
}()
|
|
||||||
|
|
||||||
env := newEnvironment(i.globals)
|
|
||||||
|
|
||||||
for idx, arg := range f.args {
|
|
||||||
env.define(arg.lexeme, args[idx])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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"
|
import "time"
|
||||||
|
|
||||||
func defineGlobals(env *Environment) {
|
type ClockFun struct{}
|
||||||
|
|
||||||
env.define("clock", &Callable{
|
func (cf *ClockFun) call(i *Interpreter, args ...any) any {
|
||||||
arity: 0,
|
return time.Now().Unix()
|
||||||
call: func(i *Interpreter, arg ...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))
|
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) {
|
||||||
|
|
|
@ -41,4 +41,21 @@ 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();
|
Loading…
Reference in a new issue