diff options
Diffstat (limited to 'evaluator/evaluator.go')
| -rw-r--r-- | evaluator/evaluator.go | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index b9b8bb9..9cead89 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -13,17 +13,27 @@ var ( ) // Eval evaluates the given ast.Node and returns an object.Object. -func Eval(node ast.Node) object.Object { +func Eval(node ast.Node, env *object.Environment) object.Object { switch node := node.(type) { // Statements case *ast.Program: - return evalProgram(node) + return evalProgram(node, env) case *ast.ExpressionStatement: - return Eval(node.Expression) + return Eval(node.Expression, env) case *ast.BlockStatement: - return evalBlockStatement(node) + return evalBlockStatement(node, env) + + case *ast.LetStatement: + val := Eval(node.Value, env) + if isError(val) { + return val + } + env.Set(node.Name.Value, val) + + case *ast.Identifier: + return evalIdentifier(node, env) // Expressions case *ast.IntegerLiteral: @@ -33,28 +43,28 @@ func Eval(node ast.Node) object.Object { return nativeBoolToBooleanObject(node.Value) case *ast.PrefixExpression: - right := Eval(node.Right) + right := Eval(node.Right, env) if isError(right) { return right } return evalPrefixExpression(node.Operator, right) case *ast.InfixExpression: - left := Eval(node.Left) + left := Eval(node.Left, env) if isError(left) { return left } - right := Eval(node.Right) + right := Eval(node.Right, env) if isError(right) { return right } return evalInfixExpression(node.Operator, left, right) case *ast.IfExpression: - return evalIfExpression(node) + return evalIfExpression(node, env) case *ast.ReturnStatement: - val := Eval(node.ReturnValue) + val := Eval(node.ReturnValue, env) if isError(val) { return val } @@ -64,11 +74,11 @@ func Eval(node ast.Node) object.Object { return nil } -func evalProgram(program *ast.Program) object.Object { +func evalProgram(program *ast.Program, env *object.Environment) object.Object { var result object.Object for _, statement := range program.Statements { - result = Eval(statement) + result = Eval(statement, env) switch result := result.(type) { case *object.ReturnValue: @@ -81,11 +91,12 @@ func evalProgram(program *ast.Program) object.Object { return result } -func evalBlockStatement(block *ast.BlockStatement) object.Object { + +func evalBlockStatement(block *ast.BlockStatement, env *object.Environment) object.Object { var result object.Object for _, statement := range block.Statements { - result = Eval(statement) + result = Eval(statement, env) if result != nil { rt := result.Type() @@ -182,20 +193,28 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje } } -func evalIfExpression(ie *ast.IfExpression) object.Object { - condition := Eval(ie.Condition) +func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Object { + condition := Eval(ie.Condition, env) if isError(condition) { return condition } if isTruthy(condition) { - return Eval(ie.Consequence) + return Eval(ie.Consequence, env) } else if ie.Alternative != nil { - return Eval(ie.Alternative) + return Eval(ie.Alternative, env) } else { return NULL } } +func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object { + val, ok := env.Get(node.Value) + if !ok { + return newError("identifier not found: " + node.Value) + } + return val +} + func isTruthy(obj object.Object) bool { switch obj { case NULL: |
