| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- package evaluator
- import (
- "fmt"
- "github/runnignwater/monkey/ast"
- "github/runnignwater/monkey/object"
- )
- var (
- NULL = &object.Null{}
- TRUE = &object.Boolean{Value: true}
- FALSE = &object.Boolean{Value: false}
- )
- func Eval(node ast.Node, env *object.Environment) object.Object {
- switch node := node.(type) {
- // Statements
- case *ast.Program:
- return evalProgram(node, env)
- case *ast.ExpressionStatement:
- return Eval(node.Expression, env)
- // Expression
- case *ast.IntegerLiteral:
- return &object.Integer{Value: node.Value}
- case *ast.Boolean:
- return nativeBooleanObject(node.Value)
- case *ast.PrefixExpression:
- right := Eval(node.Right, env)
- if isError(right) {
- return right
- }
- return evalPrefixExpression(node.Operator, right)
- case *ast.InfixExpression:
- left := Eval(node.Left, env)
- if isError(left) {
- return left
- }
- right := Eval(node.Right, env)
- if isError(right) {
- return right
- }
- return evalInfixExpression(node.Operator, left, right)
- case *ast.BlockStatement:
- return evalBlockStatements(node, env)
- case *ast.IfExpression:
- return evalIfExpression(node, env)
- case *ast.ReturnStatement:
- val := Eval(node.ReturnValue, env)
- if isError(val) {
- return val
- }
- return &object.ReturnValue{Value: val}
- case *ast.Identifier:
- return evalIdentifier(node, env)
- case *ast.LetStatement:
- val := Eval(node.Value, env)
- if isError(val) {
- return val
- }
- env.Set(node.Name.Value, val)
- case *ast.FunctionLiteral:
- params := node.Parameters
- body := node.Body
- return &object.Function{Parameters: params, Body: body, Env: env}
- case *ast.CallExpression:
- function := Eval(node.Function, env)
- if isError(function) {
- return function
- }
- args := evalExpressions(node.Arguments, env)
- if len(args) == 1 && isError(args[0]) {
- return args[0]
- }
- return applyFunction(function, args)
- case *ast.StringLiteral:
- return &object.String{Value: node.Value}
- case *ast.ArrayLiteral:
- elements := evalExpressions(node.Element, env)
- if len(elements) == 1 && isError(elements[0]) {
- // return object.Error
- return elements[0]
- }
- return &object.Array{Elements: elements}
- case *ast.IndexExpression:
- left := Eval(node.Left, env)
- if isError(left) {
- return left
- }
- index := Eval(node.Index, env)
- if isError(index) {
- return index
- }
- return evalIndexExpression(left, index)
- case *ast.HashLiteral:
- return evalHashLiteral(node, env)
- }
- return nil
- }
- func applyFunction(fn object.Object, args []object.Object) object.Object {
- switch fn := fn.(type) {
- case *object.Function:
- extendEnv := extendFunctionEnv(fn, args)
- evaluated := Eval(fn.Body, extendEnv)
- return unwrapReturnValue(evaluated)
- case *object.Builtin:
- return fn.Fn(args...)
- default:
- return newError("not a function: %s", fn.Type())
- }
- }
- func extendFunctionEnv(fn *object.Function, args []object.Object) *object.Environment {
- env := object.NewEnclosedEnvironment(fn.Env)
- for paramIdx, param := range fn.Parameters {
- env.Set(param.Value, args[paramIdx])
- }
- return env
- }
- func unwrapReturnValue(obj object.Object) object.Object {
- if returnValue, ok := obj.(*object.ReturnValue); ok {
- return returnValue.Value
- }
- return obj
- }
- func newError(format string, a ...interface{}) *object.Error {
- return &object.Error{Msg: fmt.Sprintf(format, a...)}
- }
- func evalProgram(node *ast.Program, env *object.Environment) object.Object {
- var result object.Object
- for _, stmt := range node.Statements {
- result = Eval(stmt, env)
- // skip return 后面的语句
- switch result := result.(type) {
- case *object.ReturnValue:
- return result.Value
- case *object.Error:
- return result
- }
- }
- return result
- }
- func nativeBooleanObject(input bool) *object.Boolean {
- if input {
- return TRUE
- } else {
- return FALSE
- }
- }
- func evalPrefixExpression(operator string, right object.Object) object.Object {
- switch operator {
- case "!":
- return evalBangOperatorExpression(right)
- case "-":
- return evalMinusPreOperatorExpression(right)
- default:
- return newError("unknown operator: %s%s", operator, right.Type())
- }
- }
- func evalInfixExpression(operator string, left object.Object, right object.Object) object.Object {
- switch {
- case left.Type() == object.IntegerObj && right.Type() == object.IntegerObj:
- return evalIntegerInfixExpression(operator, left, right)
- case left.Type() == object.StringObj && right.Type() == object.StringObj:
- return evalStringInfixExpression(operator, left, right)
- case operator == "==":
- 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 newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
- }
- }
- func evalIfExpression(node *ast.IfExpression, env *object.Environment) object.Object {
- condition := Eval(node.Condition, env)
- if isError(condition) {
- return condition
- }
- if isTruthy(condition) {
- return Eval(node.Consequence, env)
- } else if node.Alternative != nil {
- return Eval(node.Alternative, env)
- } else {
- return NULL
- }
- }
- func evalBlockStatements(block *ast.BlockStatement, env *object.Environment) object.Object {
- var result object.Object
- for _, stmt := range block.Statements {
- result = Eval(stmt, env)
- if result != nil {
- rt := result.Type()
- if rt == object.ReturnValueObj || rt == object.ErrorObj {
- return result
- }
- }
- }
- return result
- }
- func evalIntegerInfixExpression(operator string,
- left object.Object, right object.Object) object.Object {
- leftVal := left.(*object.Integer).Value
- rightVal := right.(*object.Integer).Value
- switch operator {
- case "+":
- return &object.Integer{Value: leftVal + rightVal}
- case "-":
- return &object.Integer{Value: leftVal - rightVal}
- case "*":
- return &object.Integer{Value: leftVal * rightVal}
- case "/":
- return &object.Integer{Value: leftVal / rightVal}
- case "<":
- return nativeBooleanObject(leftVal < rightVal)
- case ">":
- return nativeBooleanObject(leftVal > rightVal)
- case "==":
- return nativeBooleanObject(leftVal == rightVal)
- case "!=":
- return nativeBooleanObject(leftVal != rightVal)
- default:
- return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
- }
- }
- func evalStringInfixExpression(operator string,
- left object.Object, right object.Object) object.Object {
- // Only identifier + is valid
- if operator != "+" {
- return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
- }
- leftVal := left.(*object.String).Value
- rightVal := right.(*object.String).Value
- return &object.String{Value: leftVal + rightVal}
- }
- func evalMinusPreOperatorExpression(right object.Object) object.Object {
- if right.Type() != object.IntegerObj {
- return newError("unknown operator: -%s", right.Type())
- }
- value := right.(*object.Integer).Value
- return &object.Integer{Value: -value}
- }
- func evalBangOperatorExpression(right object.Object) object.Object {
- switch right {
- case TRUE:
- return FALSE
- case FALSE:
- return TRUE
- default:
- return FALSE
- }
- }
- func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
- if val, ok := env.Get(node.Value); ok {
- return val
- }
- if builtin, ok := builtins[node.Value]; ok {
- return builtin
- }
- return newError("identifier not found: " + node.Value)
- }
- func evalExpressions(exps []ast.Expression, env *object.Environment) []object.Object {
- var result []object.Object
- for _, e := range exps {
- evaluated := Eval(e, env)
- if isError(evaluated) {
- return []object.Object{evaluated}
- }
- result = append(result, evaluated)
- }
- return result
- }
- func evalIndexExpression(left, index object.Object) object.Object {
- switch {
- case left.Type() == object.ArrayObj && index.Type() == object.IntegerObj:
- return evalArrayIndexExpression(left, index)
- case left.Type() == object.HashObj:
- return evalHashIndexExpression(left, index)
- default:
- return newError("index operator not supported: %s", left.Type())
- }
- }
- func evalArrayIndexExpression(array, index object.Object) object.Object {
- arrayObj := array.(*object.Array)
- idx := index.(*object.Integer).Value
- max := int64(len(arrayObj.Elements) - 1)
- if idx < 0 || idx > max {
- return NULL
- }
- return arrayObj.Elements[idx]
- }
- func evalHashIndexExpression(hash, index object.Object) object.Object {
- hashObj := hash.(*object.Hash)
- key, ok := index.(object.Hashtable)
- if !ok {
- return newError("unusable as hash key: %s", index.Type())
- }
- pair, ok := hashObj.Pairs[key.HashKey()]
- if !ok {
- return NULL
- }
- return pair.Value
- }
- func evalHashLiteral(node *ast.HashLiteral, env *object.Environment) object.Object {
- pairs := make(map[object.HashKey]object.HashPair)
- for keyNode, valueNode := range node.Pairs {
- key := Eval(keyNode, env)
- if isError(key) {
- return key
- }
- hashKey, ok := key.(object.Hashtable)
- if !ok {
- return newError("unusable as hash key: %s", key.Type())
- }
- value := Eval(valueNode, env)
- if isError(value) {
- return value
- }
- hashed := hashKey.HashKey()
- pairs[hashed] = object.HashPair{Key: key, Value: value}
- }
- return &object.Hash{Pairs: pairs}
- }
- func isTruthy(obj object.Object) bool {
- switch obj {
- case NULL:
- return false
- case TRUE:
- return true
- case FALSE:
- return false
- default:
- return true
- }
- }
- func isError(obj object.Object) bool {
- if obj != nil {
- return obj.Type() == object.ErrorObj
- }
- return false
- }
|