diff options
Diffstat (limited to 'evaluator/evaluator_test.go')
| -rw-r--r-- | evaluator/evaluator_test.go | 176 |
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) } |
