aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--evaluator/evaluator.go42
-rw-r--r--evaluator/evaluator_test.go51
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
+}