You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
package interpreter
|
|
|
|
import "golox/ast"
|
|
|
|
// callable is an interface for callables like functions and methods.
|
|
type callable interface {
|
|
arity() int
|
|
call(i *Interpreter, arguments []any) any
|
|
}
|
|
|
|
// nativeCallable is a struct that implements the callable interface.
|
|
type nativeCallable struct {
|
|
arityFn func() int
|
|
callFn func(interpreter *Interpreter, args []any) any
|
|
}
|
|
|
|
// newNativeCallable creates a new nativeCallable.
|
|
func newNativeCallable(arityFn func() int, callFn func(interpreter *Interpreter, args []any) any) *nativeCallable {
|
|
return &nativeCallable{
|
|
arityFn: arityFn,
|
|
callFn: callFn,
|
|
}
|
|
}
|
|
|
|
// arity returns the number of arguments the callable expects.
|
|
func (n *nativeCallable) arity() int {
|
|
return n.arityFn()
|
|
}
|
|
|
|
// call calls the callable with the given arguments.
|
|
func (n *nativeCallable) call(i *Interpreter, arguments []any) any {
|
|
return n.callFn(i, arguments)
|
|
}
|
|
|
|
// String returns a string representation of the callable.
|
|
func (n *nativeCallable) String() string {
|
|
return "<native fn>"
|
|
}
|
|
|
|
// function is a struct that implements the callable interface.
|
|
type function struct {
|
|
declaration *ast.FunctionStmt
|
|
closure *environment
|
|
}
|
|
|
|
// newFunction creates a new function.
|
|
func newFunction(declaration *ast.FunctionStmt, closure *environment) *function {
|
|
return &function{
|
|
declaration: declaration,
|
|
closure: closure,
|
|
}
|
|
}
|
|
|
|
// arity returns the number of arguments the function expects.
|
|
func (f *function) arity() int {
|
|
return len(f.declaration.Params)
|
|
}
|
|
|
|
// call calls the function with the given arguments.
|
|
func (f *function) call(i *Interpreter, arguments []any) (result any) {
|
|
env := newEnvironment(f.closure)
|
|
|
|
for i, param := range f.declaration.Params {
|
|
env.define(param.Lexeme, arguments[i])
|
|
}
|
|
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if e, ok := r.(ReturnValue); ok {
|
|
result = e.Value
|
|
} else {
|
|
panic(r)
|
|
}
|
|
}
|
|
}()
|
|
|
|
i.executeBlock(f.declaration.Body, env)
|
|
|
|
return nil
|
|
}
|
|
|
|
// String returns a string representation of the function.
|
|
func (f *function) String() string {
|
|
return "<fn " + f.declaration.Name.Lexeme + ">"
|
|
}
|