diff options
| author | Bobby <[email protected]> | 2024-03-29 19:53:00 +0000 |
|---|---|---|
| committer | Bobby <[email protected]> | 2024-03-29 19:53:00 +0000 |
| commit | c6a3c37f268ba3189a4902b852121e979c70817f (patch) | |
| tree | d81011b7f0831f7df6d07bb49b363ebc15bd6a3b /evaluator | |
| parent | 87b188bae2c8a2a9f81e872805d072be7ec910b2 (diff) | |
| download | mana-c6a3c37f268ba3189a4902b852121e979c70817f.tar.xz mana-c6a3c37f268ba3189a4902b852121e979c70817f.zip | |
functions and closures
Diffstat (limited to 'evaluator')
| -rw-r--r-- | evaluator/evaluator.go | 32 | ||||
| -rw-r--r-- | evaluator/evaluator_test.go | 13 |
2 files changed, 45 insertions, 0 deletions
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index f765d02..87bfc48 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -75,6 +75,8 @@ func Eval(node ast.Node, env *object.Environment) object.Object { return args[0] } + return applyFunction(function, args) + case *ast.FunctionLiteral: params := node.Parameters body := node.Body @@ -92,6 +94,36 @@ func Eval(node ast.Node, env *object.Environment) object.Object { return nil } +func applyFunction(fn object.Object, args []object.Object) object.Object { + function, ok := fn.(*object.Function) + + if !ok { + return newError("not a function: %s", fn.Type()) + } + + extendedEnv := extendFunctionEnv(function, args) + evaulated := Eval(function.Body, extendedEnv) + return unwrapReturnValue(evaulated) +} + +func extendFunctionEnv(fn *object.Function, args []object.Object) *object.Environment { + env := object.NewEnclosedEnvironment(fn.Env) + + for paramIdx, param := range fn.Parameters { + env.Set(param.Value, args[paramIdx]) + } + + return env +} + +func unwrapReturnValue(obj object.Object) object.Object { + if returnValue, ok := obj.(*object.ReturnValue); ok { + return returnValue.Value + } + + return obj +} + func evalProgram(program *ast.Program, env *object.Environment) object.Object { var result object.Object diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index f83cf7f..75480dc 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -258,6 +258,19 @@ func TestFunctionApplication(t *testing.T) { } } +func TestClosures(t *testing.T) { + input := ` + let newAdder = fn(x) { + fn(y) { x + y }; + }; + + let addTwo = newAdder(2); + addTwo(2); + ` + + testIntegerObject(t, testEval(input), 4) +} + func testEval(input string) object.Object { l := lexer.New(input) p := parser.New(l) |
