diff --git a/glox/ast/ast.go b/glox/ast/ast.go index dcc1d80..6ce625e 100644 --- a/glox/ast/ast.go +++ b/glox/ast/ast.go @@ -263,7 +263,7 @@ func parenthesize(name ExpType, value string) string { out.WriteString("(" + string(name) + " ") out.WriteString(value) - out.WriteString(" )") + out.WriteString(")") return out.String() } diff --git a/glox/interpreter/interpreter.go b/glox/interpreter/interpreter.go index d6e391a..f944957 100644 --- a/glox/interpreter/interpreter.go +++ b/glox/interpreter/interpreter.go @@ -5,6 +5,7 @@ import ( "glox/ast" "glox/env" "glox/exception" + "glox/object" "glox/token" "io" "math" @@ -319,6 +320,41 @@ func (i *Interpreter) VisitWhile(exp *ast.WhileStmt) any { return nil } +func (i *Interpreter) VisitCall(expr *ast.Call) any { + calle := i.evaluate(expr.Callee) + err, isErr := calle.(error) + if !isErr { + args := []any{} + for _, arg := range expr.Args { + val := i.evaluate(arg) + if err, isErr = val.(error); isErr { + break + } + args = append(args, val) + } + if err != nil { + return err + } + function, isOk := calle.(object.Callable[*Interpreter]) + if !isOk { + return exception.Runtime(expr.Paren, fmt.Sprintf("'%v' cannot be called.", expr.Callee.String())) + } else if function.Arity() != len(args) { + want, got := function.Arity(), len(args) + var msg string + if got > want { + msg = fmt.Sprintf("too many arguments passed. expected %d but got %d.", want, got) + } else { + msg = fmt.Sprintf("not enough arguments passed. expected %d but got %d.", want, got) + } + return exception.Runtime(expr.Paren, msg) + } + return function.Call(i, args) + } + + return err + +} + func (i *Interpreter) execLoop(loop *ast.WhileStmt) (res any, err error) { //FIXME: The `continue` statement doesn't seem to work as expected. defer func() { diff --git a/glox/object/object.go b/glox/object/object.go new file mode 100644 index 0000000..7eb6ce7 --- /dev/null +++ b/glox/object/object.go @@ -0,0 +1,6 @@ +package object + +type Callable[T any] interface { + Call(i T, arguments []any) any + Arity() int +}