interpreter-in-go/pkg/evaluator/evaluator.go
jmug cf8b0033c9 Introduced the evaluator (and integrated it with the REPL)
It supports integer and boolean literals, prefix expressions and infix
expressions with integer operands.

Signed-off-by: jmug <u.g.a.mariano@gmail.com>
2025-01-06 18:24:23 -08:00

104 lines
2.3 KiB
Go

package evaluator
import (
"code.jmug.me/jmug/interpreter-in-go/pkg/ast"
"code.jmug.me/jmug/interpreter-in-go/pkg/object"
)
var (
_NULL = &object.Null{}
_TRUE = &object.Boolean{Value: true}
_FALSE = &object.Boolean{Value: false}
)
func Eval(node ast.Node) object.Object {
switch node := node.(type) {
// Statements.
case *ast.Program:
return evalStatements(node.Statements)
case *ast.ExpressionStatement:
return Eval(node.Expression)
// Expressions.
case *ast.IntegerLiteral:
return &object.Integer{Value: node.Value}
case *ast.Boolean:
return nativeBoolToBooleanObject(node.Value)
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)
}
return nil
}
func evalStatements(stmts []ast.Statement) object.Object {
var res object.Object
for _, stmt := range stmts {
res = Eval(stmt)
}
return res
}
func evalPrefixExpression(op string, right object.Object) object.Object {
switch op {
case "!":
return evalBangOperatorExpression(right)
case "-":
return evalMinusPrefixOperatorExpression(right)
}
return _NULL
}
func evalBangOperatorExpression(obj object.Object) object.Object {
switch obj {
case _TRUE:
return _FALSE
case _FALSE:
return _TRUE
case _NULL:
return _TRUE
default:
return _FALSE
}
}
func evalMinusPrefixOperatorExpression(obj object.Object) object.Object {
if obj.Type() != object.INTEGER_OBJ {
return _NULL
}
val := obj.(*object.Integer).Value
return &object.Integer{Value: -val}
}
func evalInfixExpression(op string, left, right object.Object) object.Object {
if left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ {
return evalIntegerInfixExpression(op, left, right)
}
return _NULL
}
func evalIntegerInfixExpression(op string, left, right object.Object) object.Object {
l := left.(*object.Integer).Value
r := right.(*object.Integer).Value
switch op {
case "+":
return &object.Integer{Value: l + r}
case "-":
return &object.Integer{Value: l - r}
case "*":
return &object.Integer{Value: l * r}
case "/":
return &object.Integer{Value: l / r}
}
return _NULL
}
func nativeBoolToBooleanObject(b bool) object.Object {
if b {
return _TRUE
}
return _FALSE
}