commit ed5362ca03dff4a3b9d7b3c0958a450b9a46db7d
parent d068fe3b1d66c3d0500299e2c3ae1388b4d0cf0a
Author: bsandro <email@bsandro.tech>
Date: Fri, 24 Jun 2022 00:44:54 +0300
if-else eval
Diffstat:
2 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/eval/eval.go b/eval/eval.go
@@ -36,6 +36,10 @@ func Eval(node ast.Node) object.Object {
left := Eval(node.Left)
right := Eval(node.Right)
return evalInfixExpression(node.Operator, left, right)
+ case *ast.BlockStatement:
+ return evalStatements(node.Statements)
+ case *ast.IfExpression:
+ return evalIfExpression(node)
}
return nil
}
@@ -117,3 +121,27 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje
return NULL
}
}
+
+func evalIfExpression(ie *ast.IfExpression) object.Object {
+ condition := Eval(ie.Condition)
+ if isTruthy(condition) {
+ return Eval(ie.Consequence)
+ } else if ie.Alternative != nil {
+ return Eval(ie.Alternative)
+ } else {
+ return NULL
+ }
+}
+
+func isTruthy(obj object.Object) bool {
+ switch obj {
+ case NULL:
+ return false
+ case TRUE:
+ return true
+ case FALSE:
+ return false
+ default:
+ return true
+ }
+}
diff --git a/eval/eval_test.go b/eval/eval_test.go
@@ -99,3 +99,35 @@ func TestShriekOperator(t *testing.T) {
testBooleanObject(t, evaluated, tt.expected)
}
}
+
+func TestIfElseExpressions(t *testing.T) {
+ tests := []struct {
+ input string
+ expected interface{}
+ }{
+ {"if (true) { 10 }", 10},
+ {"if (false) { 20 }", nil},
+ {"if (1) { 30 }", 30},
+ {"if (1<2) { 40 }", 40},
+ {"if (1>2) { 11 }", nil},
+ {"if (1>2) { 50 } else { 60 }", 60},
+ {"if (1<2) { 50 } else { 60 }", 50},
+ }
+ for _, tt := range tests {
+ evaluated := testEval(tt.input)
+ integer, ok := tt.expected.(int)
+ if ok {
+ testIntegerObject(t, evaluated, int64(integer))
+ } else {
+ testNullObject(t, evaluated)
+ }
+ }
+}
+
+func testNullObject(t *testing.T, obj object.Object) bool {
+ if obj != NULL {
+ t.Errorf("obj is not NULL but %T (%+v)", obj, obj)
+ return false
+ }
+ return true
+}