aboutsummaryrefslogtreecommitdiff
path: root/evaluator/evaluator_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'evaluator/evaluator_test.go')
-rw-r--r--evaluator/evaluator_test.go176
1 files changed, 110 insertions, 66 deletions
diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go
index 38fed91..f83cf7f 100644
--- a/evaluator/evaluator_test.go
+++ b/evaluator/evaluator_test.go
@@ -5,7 +5,7 @@ import (
"mana/object"
"mana/parser"
- "testing"
+ "testing"
)
func TestEvalIntegerExpression(t *testing.T) {
@@ -138,36 +138,36 @@ func TestReturnStatements(t *testing.T) {
}
func TestErrorhandling(t *testing.T) {
- tests := [] struct {
- input string
- expectedMessage string
- } {
- {
- "5 + true;",
- "type mismatch: INTEGER + BOOLEAN",
- },
- {
- "5 + true; 5;",
- "type mismatch: INTEGER + BOOLEAN",
- },
- {
- "-true",
- "unknown operator: -BOOLEAN",
- },
- {
- "true + false;",
- "unknown operator: BOOLEAN + BOOLEAN",
- },
- {
- "5; true + false; 5",
- "unknown operator: BOOLEAN + BOOLEAN",
- },
- {
- "if (10 > 1) { true + false; }",
- "unknown operator: BOOLEAN + BOOLEAN",
- },
- {
- `
+ tests := []struct {
+ input string
+ expectedMessage string
+ }{
+ {
+ "5 + true;",
+ "type mismatch: INTEGER + BOOLEAN",
+ },
+ {
+ "5 + true; 5;",
+ "type mismatch: INTEGER + BOOLEAN",
+ },
+ {
+ "-true",
+ "unknown operator: -BOOLEAN",
+ },
+ {
+ "true + false;",
+ "unknown operator: BOOLEAN + BOOLEAN",
+ },
+ {
+ "5; true + false; 5",
+ "unknown operator: BOOLEAN + BOOLEAN",
+ },
+ {
+ "if (10 > 1) { true + false; }",
+ "unknown operator: BOOLEAN + BOOLEAN",
+ },
+ {
+ `
if (10 > 1) {
if (10 > 1) {
return true + false;
@@ -175,50 +175,94 @@ func TestErrorhandling(t *testing.T) {
return 1;
}
`,
- "unknown operator: BOOLEAN + BOOLEAN",
- },
- {
- "foobar",
- "identifier not found: foobar",
- },
- }
-
- for _, tt := range tests {
- evaluated := testEval(tt.input)
-
- errObj, ok := evaluated.(*object.Error)
- if !ok {
- t.Errorf("no error object returned. got=%T(%+v)", evaluated, evaluated)
- continue
- }
-
- if errObj.Message != tt.expectedMessage {
- t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMessage, errObj.Message)
- }
- }
+ "unknown operator: BOOLEAN + BOOLEAN",
+ },
+ {
+ "foobar",
+ "identifier not found: foobar",
+ },
+ }
+
+ for _, tt := range tests {
+ evaluated := testEval(tt.input)
+
+ errObj, ok := evaluated.(*object.Error)
+ if !ok {
+ t.Errorf("no error object returned. got=%T(%+v)", evaluated, evaluated)
+ continue
+ }
+
+ if errObj.Message != tt.expectedMessage {
+ t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMessage, errObj.Message)
+ }
+ }
}
func TestLetStatements(t *testing.T) {
- tests := []struct {
- input string
- expected int64
- } {
- {"let a = 5; a;", 5},
- {"let a = 5 * 5; a;", 25},
- {"let a = 5; let b = a; b;", 5},
- {"let a = 5; let b = a; let c = a + b + 5; c;", 15},
- }
-
- for _, tt := range tests {
- testIntegerObject(t, testEval(tt.input), tt.expected)
- }
+ tests := []struct {
+ input string
+ expected int64
+ }{
+ {"let a = 5; a;", 5},
+ {"let a = 5 * 5; a;", 25},
+ {"let a = 5; let b = a; b;", 5},
+ {"let a = 5; let b = a; let c = a + b + 5; c;", 15},
+ }
+
+ for _, tt := range tests {
+ testIntegerObject(t, testEval(tt.input), tt.expected)
+ }
+}
+
+func TestFunctionObject(t *testing.T) {
+ input := "fn(x) { x + 2; };"
+
+ evaluated := testEval(input)
+
+ fn, ok := evaluated.(*object.Function)
+
+ if !ok {
+ t.Fatalf("object is not Function. got=%T (%+v)", evaluated, evaluated)
+ }
+
+ if len(fn.Parameters) != 1 {
+ t.Fatalf("function has wrong parameters. Parameters=%+v", fn.Parameters)
+ }
+
+ if fn.Parameters[0].String() != "x" {
+ t.Fatalf("parameter is not 'x'. got=%q", fn.Parameters[0])
+ }
+
+ expectedBody := "(x + 2)"
+
+ if fn.Body.String() != expectedBody {
+ t.Fatalf("body is not %q. got=%q", expectedBody, fn.Body.String())
+ }
+}
+
+func TestFunctionApplication(t *testing.T) {
+ tests := []struct {
+ input string
+ expected int64
+ }{
+ {"let identity = fn(x) { x; }; identity(5);", 5},
+ {"let identity = fn(x) { return x; }; identity(5);", 5},
+ {"let double = fn(x) { x * 2; }; double(5);", 10},
+ {"let add = fn(x, y) { x + y; }; add(5, 5);", 10},
+ {"let add = fn(x, y) { x + y; }; add(5 + 5, add(5, 5));", 20},
+ {"fn(x) { x; }(5)", 5},
+ }
+
+ for _, tt := range tests {
+ testIntegerObject(t, testEval(tt.input), tt.expected)
+ }
}
func testEval(input string) object.Object {
l := lexer.New(input)
p := parser.New(l)
program := p.ParseProgram()
- env := object.NewEnvironment()
+ env := object.NewEnvironment()
return Eval(program, env)
}