commit 4469a343e5eb7af7b7ec8fb3a348630b159b60fc
parent 7b8cd20ca0804b40f3621fea353739f8214c8055
Author: bsandro <email@bsandro.tech>
Date:   Thu, 23 Jun 2022 23:49:10 +0300
eval ! and - prefix operators
Diffstat:
2 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/eval/eval.go b/eval/eval.go
@@ -11,6 +11,14 @@ var (
 	NULL  = &object.Null{}
 )
 
+func boolToObject(value bool) *object.Boolean {
+	if value {
+		return TRUE
+	} else {
+		return FALSE
+	}
+}
+
 func Eval(node ast.Node) object.Object {
 	switch node := node.(type) {
 	case *ast.Program:
@@ -20,7 +28,10 @@ func Eval(node ast.Node) object.Object {
 	case *ast.IntegerLiteral:
 		return &object.Integer{Value: node.Value}
 	case *ast.Boolean:
-		return nativeBoolToBooleanObject(node.Value)
+		return boolToObject(node.Value)
+	case *ast.PrefixExpression:
+		right := Eval(node.Right)
+		return evalPrefixExpression(node.Operator, right)
 	}
 	return nil
 }
@@ -33,10 +44,34 @@ func evalStatements(statements []ast.Statement) object.Object {
 	return result
 }
 
-func nativeBoolToBooleanObject(input bool) *object.Boolean {
-	if input {
+func evalPrefixExpression(operator string, right object.Object) object.Object {
+	switch operator {
+	case "!":
+		return evalShriekOperatorExpression(right)
+	case "-":
+		return evalMinusPrefixOperatorExpression(right)
+	default:
+		return NULL
+	}
+}
+
+func evalShriekOperatorExpression(right object.Object) object.Object {
+	switch right {
+	case TRUE:
+		return FALSE
+	case FALSE:
 		return TRUE
-	} else {
+	case NULL:
+		return TRUE
+	default:
 		return FALSE
 	}
 }
+
+func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
+	if right.Type() != object.INTEGER_OBJ {
+		return NULL
+	}
+	value := right.(*object.Integer).Value
+	return &object.Integer{Value: -value}
+}
diff --git a/eval/eval_test.go b/eval/eval_test.go
@@ -13,7 +13,9 @@ func TestEvalIntegerExpression(t *testing.T) {
 		expected int64
 	}{
 		{"6", 6},
+		{"-8", -8},
 		{"10", 10},
+		{"-256", -256},
 	}
 	for _, tt := range tests {
 		evaluated := testEval(tt.input)
@@ -67,3 +69,21 @@ func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
 	}
 	return true
 }
+
+func TestShriekOperator(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected bool
+	}{
+		{"!true", false},
+		{"!false", true},
+		{"!5", false},
+		{"!!true", true},
+		{"!!!false", true},
+		{"!!8", true},
+	}
+	for _, tt := range tests {
+		evaluated := testEval(tt.input)
+		testBooleanObject(t, evaluated, tt.expected)
+	}
+}