diff options
| -rw-r--r-- | evaluator/evaluator.go | 42 | ||||
| -rw-r--r-- | evaluator/evaluator_test.go | 51 |
2 files changed, 91 insertions, 2 deletions
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 8d1b26d..0cc003f 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -5,6 +5,12 @@ import ( "mana/object" ) +var ( + NULL = &object.Null{} + TRUE = &object.Boolean{Value: true} + FALSE = &object.Boolean{Value: false} +) + // Eval evaluates the given ast.Node and returns an object.Object. func Eval(node ast.Node) object.Object { switch node := node.(type) { @@ -18,6 +24,13 @@ func Eval(node ast.Node) object.Object { // Expressions case *ast.IntegerLiteral: return &object.Integer{Value: node.Value} + + case *ast.Boolean: + return nativeBoolToBooleanObject(node.Value) + + case *ast.PrefixExpression: + right := Eval(node.Right) + return evalPrefixExpression(node.Operator, right) } return nil @@ -32,3 +45,32 @@ func evalStatements(stmts []ast.Statement) object.Object { return result } + +func nativeBoolToBooleanObject(input bool) *object.Boolean { + if input { + return TRUE + } + return FALSE +} + +func evalPrefixExpression(operator string, right object.Object) object.Object { + switch operator { + case "!": + return evalBangOperatorExpression(right) + default: + return NULL + } +} + +func evalBangOperatorExpression(right object.Object) object.Object { + switch right { + case TRUE: + return FALSE + case FALSE: + return TRUE + case NULL: + return TRUE + default: + return FALSE + } +} diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index cd1edb1..aa1833a 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -18,8 +18,42 @@ func TestEvalIntegerExpression(t *testing.T) { } for _, tt := range tests { - evalated := testEval(tt.input) - testIntegerObject(t, evalated, tt.expected) + evaluated := testEval(tt.input) + testIntegerObject(t, evaluated, tt.expected) + } +} + +func TestEvalBooleanExpression(t *testing.T) { + tests := []struct { + input string + expected bool + }{ + {"true", true}, + {"false", false}, + } + + for _, tt := range tests { + evaluated := testEval(tt.input) + testBooleanObject(t, evaluated, tt.expected) + } +} + +func TestBangOperator(t *testing.T) { + tests := []struct { + input string + expected bool + }{ + {"!true", false}, + {"!false", true}, + {"!5", false}, + {"!!true", true}, + {"!!false", false}, + {"!!5", true}, + } + + for _, tt := range tests { + evaluated := testEval(tt.input) + testBooleanObject(t, evaluated, tt.expected) } } @@ -42,3 +76,16 @@ func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool { } return true } + +func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool { + result, ok := obj.(*object.Boolean) + if !ok { + t.Errorf("object is not Boolean. got=%T (%+v)", obj, obj) + return false + } + if result.Value != expected { + t.Errorf("object has wrong value. got=%t, want=%t", result.Value, expected) + return false + } + return true +} |
