|
|
@@ -1,6 +1,7 @@
|
|
|
package evaluator
|
|
|
|
|
|
import (
|
|
|
+ "fmt"
|
|
|
"github/runnignwater/monkey/ast"
|
|
|
"github/runnignwater/monkey/object"
|
|
|
)
|
|
|
@@ -27,10 +28,19 @@ func Eval(node ast.Node) object.Object {
|
|
|
return nativeBooleanObject(node.Value)
|
|
|
case *ast.PrefixExpression:
|
|
|
right := Eval(node.Right)
|
|
|
+ if isError(right) {
|
|
|
+ return right
|
|
|
+ }
|
|
|
return evalPrefixExpression(node.Operator, right)
|
|
|
case *ast.InfixExpression:
|
|
|
left := Eval(node.Left)
|
|
|
+ if isError(left) {
|
|
|
+ return left
|
|
|
+ }
|
|
|
right := Eval(node.Right)
|
|
|
+ if isError(right) {
|
|
|
+ return right
|
|
|
+ }
|
|
|
return evalInfixExpression(node.Operator, left, right)
|
|
|
|
|
|
case *ast.BlockStatement:
|
|
|
@@ -40,20 +50,29 @@ func Eval(node ast.Node) object.Object {
|
|
|
|
|
|
case *ast.ReturnStatement:
|
|
|
val := Eval(node.ReturnValue)
|
|
|
+ if isError(val) {
|
|
|
+ return val
|
|
|
+ }
|
|
|
return &object.ReturnValue{Value: val}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+func newError(format string, a ...interface{}) *object.Error {
|
|
|
+ return &object.Error{Msg: fmt.Sprintf(format, a...)}
|
|
|
+}
|
|
|
func evalProgram(node *ast.Program) object.Object {
|
|
|
var result object.Object
|
|
|
|
|
|
for _, stmt := range node.Statements {
|
|
|
result = Eval(stmt)
|
|
|
// skip return 后面的语句
|
|
|
- if rVal, ok := result.(*object.ReturnValue); ok {
|
|
|
- return rVal.Value
|
|
|
+ switch result := result.(type) {
|
|
|
+ case *object.ReturnValue:
|
|
|
+ return result.Value
|
|
|
+ case *object.Error:
|
|
|
+ return result
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -75,7 +94,7 @@ func evalPrefixExpression(operator string, right object.Object) object.Object {
|
|
|
case "-":
|
|
|
return evalMinusPreOperatorExpression(right)
|
|
|
default:
|
|
|
- return NULL
|
|
|
+ return newError("unknown operator: %s%s", operator, right.Type())
|
|
|
}
|
|
|
}
|
|
|
func evalInfixExpression(operator string, left object.Object, right object.Object) object.Object {
|
|
|
@@ -86,12 +105,17 @@ func evalInfixExpression(operator string, left object.Object, right object.Objec
|
|
|
return nativeBooleanObject(left == right)
|
|
|
case operator == "!=":
|
|
|
return nativeBooleanObject(left != right)
|
|
|
+ case left.Type() != right.Type():
|
|
|
+ return newError("type mismatch: %s %s %s", left.Type(), operator, right.Type())
|
|
|
default:
|
|
|
- return NULL
|
|
|
+ return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
|
|
|
}
|
|
|
}
|
|
|
func evalIfExpression(node *ast.IfExpression) object.Object {
|
|
|
condition := Eval(node.Condition)
|
|
|
+ if isError(condition) {
|
|
|
+ return condition
|
|
|
+ }
|
|
|
if isTruthy(condition) {
|
|
|
return Eval(node.Consequence)
|
|
|
} else if node.Alternative != nil {
|
|
|
@@ -100,14 +124,17 @@ func evalIfExpression(node *ast.IfExpression) object.Object {
|
|
|
return NULL
|
|
|
}
|
|
|
}
|
|
|
-func evalBlockStatements(node *ast.BlockStatement) object.Object {
|
|
|
+func evalBlockStatements(block *ast.BlockStatement) object.Object {
|
|
|
var result object.Object
|
|
|
|
|
|
- for _, stmt := range node.Statements {
|
|
|
+ for _, stmt := range block.Statements {
|
|
|
result = Eval(stmt)
|
|
|
|
|
|
- if result != nil && result.Type() == object.ReturnValueObj {
|
|
|
- return result
|
|
|
+ if result != nil {
|
|
|
+ rt := result.Type()
|
|
|
+ if rt == object.ReturnValueObj || rt == object.ErrorObj {
|
|
|
+ return result
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return result
|
|
|
@@ -135,13 +162,13 @@ func evalIntegerInfixExpression(operator string,
|
|
|
case "!=":
|
|
|
return nativeBooleanObject(leftVal != rightVal)
|
|
|
default:
|
|
|
- return NULL
|
|
|
+ return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func evalMinusPreOperatorExpression(right object.Object) object.Object {
|
|
|
if right.Type() != object.IntegerObj {
|
|
|
- return NULL
|
|
|
+ return newError("unknown operator: -%s", right.Type())
|
|
|
}
|
|
|
value := right.(*object.Integer).Value
|
|
|
return &object.Integer{Value: -value}
|
|
|
@@ -170,3 +197,10 @@ func isTruthy(obj object.Object) bool {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func isError(obj object.Object) bool {
|
|
|
+ if obj != nil {
|
|
|
+ return obj.Type() == object.ErrorObj
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|