Skip to content

Commit

Permalink
👷 Evaluate ADD, SUB, MUL, DIV infix expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
ChmielewskiKamil committed Oct 4, 2024
1 parent 2ac4449 commit 794b2e2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
63 changes: 55 additions & 8 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func Eval(node ast.Node) object.Object {
switch node := node.(type) {
default:
return retEvalErrorObj(fmt.Sprintf("Unhandled ast node: %T", node))

// File

case *ast.File:
Expand Down Expand Up @@ -48,6 +49,10 @@ func Eval(node ast.Node) object.Object {
case *ast.PrefixExpression:
right := Eval(node.Right)
return evalPrefixExpression(node.Operator, right)
case *ast.InfixExpression:
left := Eval(node.Left)
right := Eval(node.Right)
return evalInfixExpression(node.Operator, left, right)
}
}

Expand All @@ -71,14 +76,6 @@ func evalStatements(stmts []ast.Statement) object.Object {
return result
}

func nativeBoolToBooleanObject(nodeVal bool) *object.Boolean {
if nodeVal {
return TRUE
}

return FALSE
}

func evalPrefixExpression(operator token.Token, right object.Object) object.Object {
switch operator.Type {
default:
Expand All @@ -94,6 +91,7 @@ func evalPrefixExpression(operator token.Token, right object.Object) object.Obje
func evalNotPrefixOperatorExpression(right object.Object) object.Object {
switch right {
default:
// TODO: Why do we return true in the default case?
return FALSE
case TRUE:
return FALSE
Expand All @@ -114,6 +112,55 @@ func evalSubPrefixOperatorExpression(right object.Object) object.Object {
return &object.Integer{Value: *new(big.Int).Neg(&value)}
}

func evalInfixExpression(
operator token.Token,
left object.Object,
right object.Object) object.Object {

switch {
default:
return retEvalErrorObj("Incorrect object types for infix expression.")
case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
return evalIntegerInfixExpression(operator, left, right)
}
}

func evalIntegerInfixExpression(
operator token.Token,
left object.Object,
right object.Object) object.Object {

leftVal := left.(*object.Integer).Value
rightVal := right.(*object.Integer).Value

switch operator.Type {
default:
return retEvalErrorObj(
fmt.Sprintf("Unhandled: %s operator when evaluating infix expression.",
operator.String()))
case token.ADD:
result := new(big.Int).Add(&leftVal, &rightVal)
return &object.Integer{Value: *result}
case token.SUB:
result := new(big.Int).Sub(&leftVal, &rightVal)
return &object.Integer{Value: *result}
case token.MUL:
result := new(big.Int).Mul(&leftVal, &rightVal)
return &object.Integer{Value: *result}
case token.DIV:
result := new(big.Int).Div(&leftVal, &rightVal)
return &object.Integer{Value: *result}
}
}

func nativeBoolToBooleanObject(nodeVal bool) *object.Boolean {
if nodeVal {
return TRUE
}

return FALSE
}

// retEvalErrorObj is an error handling helper. Since evaluation functions
// expect some kind of object to be returned and we don't have nil, we
// just return EvalError object. The caller can decide what to do with it.
Expand Down
4 changes: 4 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ func Test_EvalIntegerExpression(t *testing.T) {
{"50", big.NewInt(50)},
{"-1", big.NewInt(-1)},
{"-50", big.NewInt(-50)},
{"-2 + -2 + 4", big.NewInt(0)},
{"-10 + 10 - 10", big.NewInt(-10)},
{"10 + 5 * 2 - 10 / 2", big.NewInt(15)},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", big.NewInt(50)},
}

for _, tt := range tests {
Expand Down

0 comments on commit 794b2e2

Please sign in to comment.