aboutsummaryrefslogtreecommitdiff
path: root/evaluator
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-03-29 19:53:00 +0000
committerBobby <[email protected]>2024-03-29 19:53:00 +0000
commitc6a3c37f268ba3189a4902b852121e979c70817f (patch)
treed81011b7f0831f7df6d07bb49b363ebc15bd6a3b /evaluator
parent87b188bae2c8a2a9f81e872805d072be7ec910b2 (diff)
downloadmana-c6a3c37f268ba3189a4902b852121e979c70817f.tar.xz
mana-c6a3c37f268ba3189a4902b852121e979c70817f.zip
functions and closures
Diffstat (limited to 'evaluator')
-rw-r--r--evaluator/evaluator.go32
-rw-r--r--evaluator/evaluator_test.go13
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)