From 9645d499c017db67655b8f1bc5aa4d5c74786b61 Mon Sep 17 00:00:00 2001 From: nibral Date: Wed, 23 Jan 2019 21:10:47 +0900 Subject: [PATCH] 3.6: Evaluate if statements --- evaluator/evaluator.go | 29 +++++++++++++++++++++++++++++ evaluator/evaluator_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 994680e..eb2750d 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -19,6 +19,8 @@ func Eval(node ast.Node) object.Object { return evalStatements(node.Statements) case *ast.ExpressionStatement: return Eval(node.Expression) + case *ast.BlockStatement: + return evalStatements(node.Statements) // expressions case *ast.IntegerLiteral: @@ -32,6 +34,8 @@ func Eval(node ast.Node) object.Object { left := Eval(node.Left) right := Eval(node.Right) return evalInfixExpression(node.Operator, left, right) + case *ast.IfExpression: + return evalIfExpression(node) } @@ -126,3 +130,28 @@ func nativeBoolToBooleanObject(input bool) *object.Boolean { } return FALSE } + +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/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 31bb465..4ecf4b3 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -122,3 +122,36 @@ func TestBangOperator(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) { 10 }", nil}, + {"if (1) { 10 }", 10}, + {"if (1 < 2) { 10 }", 10}, + {"if (1 > 2) { 10 }", nil}, + {"if (1 > 2) { 10 } else { 20 }", 20}, + {"if (1 < 2) { 10 } else { 20 }", 10}, + } + + 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("object is not NULL. got=%T (%+v)", obj, obj) + return false + } + return true +}