Skip to content

Commit

Permalink
3.5 Evaluate Expression (basic)
Browse files Browse the repository at this point in the history
  • Loading branch information
cedrickchee committed Mar 29, 2020
1 parent bd039e1 commit b9d8599
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 0 deletions.
46 changes: 46 additions & 0 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package evaluator

// Package evaluator implements the evaluator -- a tree-walker implementation
// that recursively walks the parsed AST (Abstract Syntax Tree) and evaluates
// the nodes according to their semantic meaning.

import (
"github.com/cedrickchee/hou/ast"
"github.com/cedrickchee/hou/object"
)

// Eval evaluates the node and returns an object.
func Eval(node ast.Node) object.Object {
// Traverse the AST by starting at the top of the tree, receiving an
// *ast.Program, and then traverse every node in it.

switch node := node.(type) {

// Statements
case *ast.Program:
// Traverse the tree and evaluate every statement of the *ast.Program.
return evalStatements(node.Statements)

case *ast.ExpressionStatement:
// If the statement is an *ast.ExpressionStatement we evaluate its
// expression. An expression statement (not a return statement and not
// a let statement).
return Eval(node.Expression)

// Expressions
case *ast.IntegerLiteral:
return &object.Integer{Value: node.Value}
}

return nil
}

func evalStatements(stmts []ast.Statement) object.Object {
var result object.Object

for _, statement := range stmts {
result = Eval(statement)
}

return result
}
47 changes: 47 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package evaluator

import (
"testing"

"github.com/cedrickchee/hou/lexer"
"github.com/cedrickchee/hou/object"
"github.com/cedrickchee/hou/parser"
)

func TestEvalIntegerExpression(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"5", 5},
{"10", 10},
}

for _, tt := range tests {
evaluated := testEval(tt.input)
testIntegerObject(t, evaluated, tt.expected)
}
}

func testEval(input string) object.Object {
l := lexer.New(input)
p := parser.New(l)
program := p.ParseProgram()

// The heart of the test is the call to Eval.
return Eval(program)
}

func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
result, ok := obj.(*object.Integer)
if !ok {
t.Errorf("object is not Integer. got=%T (%+v)", obj, obj)
return false
}
if result.Value != expected {
t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
return false
}

return true
}

0 comments on commit b9d8599

Please sign in to comment.