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

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 + ">"
}