diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go new file mode 100644 index 0000000..dc480b9 --- /dev/null +++ b/evaluator/evaluator.go @@ -0,0 +1,32 @@ +package evaluator + +import ( + "monkey/ast" + "monkey/object" +) + +func Eval(node ast.Node) object.Object { + switch node := node.(type) { + // Statements + case *ast.Program: + return eval_statements(node.Statements) + + case *ast.ExpressionStatement: + return Eval(node.Expression) + + // Expressions + case *ast.IntegerLiteral: + return &object.Integer{Value: node.Value} + } + + return nil +} + +func eval_statements(statements []ast.Statement) object.Object { + var result object.Object + + for _, statement := range statements { + result = Eval(statement) + } + return result +} diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go new file mode 100644 index 0000000..aceb434 --- /dev/null +++ b/evaluator/evaluator_test.go @@ -0,0 +1,45 @@ +package evaluator + +import ( + "monkey/lexer" + "monkey/object" + "monkey/parser" + "testing" +) + +func TestEvalIntegerExpression(l_test *testing.T) { + tests := []struct { + input string + expected int64 + }{ + {"5", 5}, + {"10", 10}, + } + + for _, tt := range tests { + evaluated := test_eval(tt.input) + test_integer_object(l_test, evaluated, tt.expected) + } +} + +// Helpers +func test_eval(input string) object.Object { + l_lexer := lexer.New(input) + l_parser := parser.New(l_lexer) + program := l_parser.ParseProgram() + + return Eval(program) +} + +func test_integer_object(l_test *testing.T, l_object object.Object, expected int64) bool { + result, ok := l_object.(*object.Integer) + if !ok { + l_test.Errorf("object is not integer, got=%T (%+v)", l_object, l_object) + return false + } + if result.Value != expected { + l_test.Errorf("object has wrong value, got=%d, want=%d", result.Value, expected) + return false + } + return true +} diff --git a/object/object.go b/object/object.go new file mode 100644 index 0000000..e81b429 --- /dev/null +++ b/object/object.go @@ -0,0 +1,53 @@ +package object + +import "fmt" + +type ObjectType string + +const ( + INTEGER_OBJECT = "INTEGER" + BOOLEAN_OBJECT = "BOOLEAN" + NULL_OBJECT = "NULL" +) + +type Object interface { + Type() ObjectType + Inspect() string +} + +// Integer +type Integer struct { + Value int64 +} + +func (i *Integer) Type() ObjectType { + return INTEGER_OBJECT +} + +func (i *Integer) Inspect() string { + return fmt.Sprintf("%d", i.Value) +} + +// Booleans +type Boolean struct { + Value bool +} + +func (b *Boolean) Type() ObjectType { + return BOOLEAN_OBJECT +} + +func (b *Boolean) Inpect() string { + return fmt.Sprintf("%t", b.Value) +} + +// Null +type Null struct{} + +func (n *Null) Type() ObjectType { + return NULL_OBJECT +} + +func (n *Null) Inpect() string { + return "null" +}