If statements

This commit is contained in:
Chuck Smith
2024-01-19 15:46:10 -05:00
parent ea1ae5cfb0
commit e6d5567681
2 changed files with 68 additions and 0 deletions

View File

@@ -21,18 +21,28 @@ func Eval(node ast.Node) object.Object {
case *ast.ExpressionStatement: case *ast.ExpressionStatement:
return Eval(node.Expression) return Eval(node.Expression)
case *ast.BlockStatement:
return evalStatements(node.Statements)
case *ast.IfExpression:
return evalIfExpression(node)
// Expressions // Expressions
case *ast.IntegerLiteral: case *ast.IntegerLiteral:
return &object.Integer{Value: node.Value} return &object.Integer{Value: node.Value}
case *ast.Boolean: case *ast.Boolean:
return nativeBoolToBooleanObject(node.Value) return nativeBoolToBooleanObject(node.Value)
case *ast.PrefixExpression: case *ast.PrefixExpression:
right := Eval(node.Right) right := Eval(node.Right)
return evalPrefixExpression(node.Operator, right) return evalPrefixExpression(node.Operator, right)
case *ast.InfixExpression: case *ast.InfixExpression:
left := Eval(node.Left) left := Eval(node.Left)
right := Eval(node.Right) right := Eval(node.Right)
return evalInfixExpression(node.Operator, left, right) return evalInfixExpression(node.Operator, left, right)
} }
return nil return nil
@@ -126,3 +136,28 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje
return NULL 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
}
}

View File

@@ -86,6 +86,31 @@ func TestBangOperator(t *testing.T) {
} }
} }
func TestIfElseExpression(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 testEval(input string) object.Object { func testEval(input string) object.Object {
l := lexer.New(input) l := lexer.New(input)
p := parser.New(l) p := parser.New(l)
@@ -121,3 +146,11 @@ func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
return true return true
} }
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
}