From 17755252c68ae4a16b768e89237c66d9a0feee46 Mon Sep 17 00:00:00 2001 From: Kamil Chmielewski <45183584+ChmielewskiKamil@users.noreply.github.com> Date: Mon, 9 Sep 2024 00:25:52 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=20Evaluate=20number=20literals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evaluator/evaluator.go | 55 +++++++++++++++++++++++++++++++++++++ evaluator/evaluator_test.go | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 evaluator/evaluator.go create mode 100644 evaluator/evaluator_test.go diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go new file mode 100644 index 0000000..0fcf133 --- /dev/null +++ b/evaluator/evaluator.go @@ -0,0 +1,55 @@ +package evaluator + +import ( + "solbot/ast" + "solbot/object" +) + +func Eval(node ast.Node) object.Object { + switch node := node.(type) { + // File + + case *ast.File: + return evalDeclarations(node.Declarations) + + // Declarations + + case *ast.FunctionDeclaration: + // TODO: Hacky way to eval other parts in tests, fix later. + return Eval(node.Body) + + // Statements + + case *ast.ExpressionStatement: + return Eval(node.Expression) + case *ast.BlockStatement: + return evalStatements(node.Statements) + + // Expressions + + case *ast.NumberLiteral: + return &object.Integer{Value: node.Value} + } + + return nil +} + +func evalDeclarations(decls []ast.Declaration) object.Object { + var result object.Object + + for _, decl := range decls { + result = Eval(decl) + } + + return result +} + +func evalStatements(stmts []ast.Statement) object.Object { + var result object.Object + + for _, stmt := range stmts { + result = Eval(stmt) + } + + return result +} diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go new file mode 100644 index 0000000..f5a82c3 --- /dev/null +++ b/evaluator/evaluator_test.go @@ -0,0 +1,54 @@ +package evaluator + +import ( + "math/big" + "solbot/object" + "solbot/parser" + "solbot/token" + "testing" +) + +func TestEvalIntegerExpression(t *testing.T) { + tests := []struct { + input string + expected *big.Int + }{ + {"1", big.NewInt(1)}, + {"50", big.NewInt(50)}, + } + + for _, tt := range tests { + evaluated := testEval(tt.input, true) + testIntegerObject(t, evaluated, tt.expected) + } +} + +func testEval(input string, boilerplate bool) object.Object { + p := parser.Parser{} + + if boilerplate { + input = "function test() { " + input + " }" + } + + handle := token.NewFile("test.sol", input) + p.Init(handle) + + file := p.ParseFile() + + return Eval(file) +} + +func testIntegerObject(t *testing.T, obj object.Object, expected *big.Int) bool { + result, ok := obj.(*object.Integer) + if !ok { + t.Errorf("Expected object.Integer, got %T (%+v)", obj, obj) + return false + } + + if result.Value.Cmp(expected) != 0 { + t.Errorf("Expected %s, got %s", expected.String(), result.Value.String()) + return false + } + + return true +}