umx_compiler

UMX virtual machine "Monkey" interpreter / bytecode compiler
git clone git://bsandro.tech/umx_compiler
Log | Files | Refs | README | LICENSE

eval.go (9709B)


      1 package eval
      2 
      3 import (
      4 	"fmt"
      5 	"umx_compiler/ast"
      6 	"umx_compiler/object"
      7 )
      8 
      9 var (
     10 	TRUE  = &object.Boolean{Value: true}
     11 	FALSE = &object.Boolean{Value: false}
     12 	NULL  = &object.Null{}
     13 )
     14 
     15 func boolToObject(value bool) *object.Boolean {
     16 	if value {
     17 		return TRUE
     18 	} else {
     19 		return FALSE
     20 	}
     21 }
     22 
     23 func newError(format string, a ...interface{}) *object.Error {
     24 	return &object.Error{Message: fmt.Sprintf(format, a...)}
     25 }
     26 
     27 func isError(obj object.Object) bool {
     28 	if obj != nil {
     29 		return obj.Type() == object.ERROR_OBJ
     30 	}
     31 	return false
     32 }
     33 
     34 func Eval(node ast.Node, ctx *object.Context) object.Object {
     35 	switch node := node.(type) {
     36 	case *ast.Program:
     37 		return evalProgram(node, ctx)
     38 	case *ast.ExpressionStatement:
     39 		return Eval(node.Expression, ctx)
     40 	case *ast.IntegerLiteral:
     41 		return &object.Integer{Value: node.Value}
     42 	case *ast.Boolean:
     43 		return boolToObject(node.Value)
     44 	case *ast.PrefixExpression:
     45 		right := Eval(node.Right, ctx)
     46 		if isError(right) {
     47 			return right
     48 		}
     49 		return evalPrefixExpression(node.Operator, right, ctx)
     50 	case *ast.InfixExpression:
     51 		left := Eval(node.Left, ctx)
     52 		if isError(left) {
     53 			return left
     54 		}
     55 		right := Eval(node.Right, ctx)
     56 		if isError(right) {
     57 			return right
     58 		}
     59 		return evalInfixExpression(node.Operator, left, right, ctx)
     60 	case *ast.BlockStatement:
     61 		return evalBlockStatement(node, ctx)
     62 	case *ast.IfExpression:
     63 		return evalIfExpression(node, ctx)
     64 	case *ast.ReturnStatement:
     65 		value := Eval(node.ReturnValue, ctx)
     66 		if isError(value) {
     67 			return value
     68 		}
     69 		return &object.ReturnValue{Value: value}
     70 	case *ast.LetStatement:
     71 		value := Eval(node.Value, ctx)
     72 		if isError(value) {
     73 			return value
     74 		}
     75 		ctx.Set(node.Name.Value, value)
     76 	case *ast.Identifier:
     77 		return evalIdentifier(node, ctx)
     78 	case *ast.FunctionLiteral:
     79 		params := node.Parameters
     80 		body := node.Body
     81 		return &object.Function{Parameters: params, Ctx: ctx, Body: body}
     82 	case *ast.CallExpression:
     83 		fn := Eval(node.Function, ctx)
     84 		if isError(fn) {
     85 			return fn
     86 		}
     87 		args := evalExpressions(node.Arguments, ctx)
     88 		if len(args) == 1 && isError(args[0]) {
     89 			return args[0]
     90 		}
     91 		return applyFunction(fn, args)
     92 	case *ast.StringLiteral:
     93 		return &object.String{Value: node.Value}
     94 	case *ast.ArrayLiteral:
     95 		elements := evalExpressions(node.Elements, ctx)
     96 		if len(elements) == 1 && isError(elements[0]) {
     97 			return elements[0]
     98 		}
     99 		return &object.Array{Elements: elements}
    100 	case *ast.IndexExpression:
    101 		left := Eval(node.Left, ctx)
    102 		if isError(left) {
    103 			return left
    104 		}
    105 		index := Eval(node.Index, ctx)
    106 		if isError(index) {
    107 			return index
    108 		}
    109 		return evalIndexExpression(left, index)
    110 	case *ast.HashLiteral:
    111 		return evalHashLiteral(node, ctx)
    112 	}
    113 	return nil
    114 }
    115 
    116 func evalStatements(statements []ast.Statement, ctx *object.Context) object.Object {
    117 	var result object.Object
    118 	for _, statement := range statements {
    119 		result = Eval(statement, ctx)
    120 		if returnValue, ok := result.(*object.ReturnValue); ok {
    121 			return returnValue.Value
    122 		}
    123 	}
    124 	return result
    125 }
    126 
    127 func evalPrefixExpression(operator string, right object.Object, ctx *object.Context) object.Object {
    128 	switch operator {
    129 	case "!":
    130 		return evalShriekOperatorExpression(right, ctx)
    131 	case "-":
    132 		return evalMinusPrefixOperatorExpression(right, ctx)
    133 	default:
    134 		return newError("unknown operator: %s%s", operator, right.Type())
    135 	}
    136 }
    137 
    138 func evalShriekOperatorExpression(right object.Object, ctx *object.Context) object.Object {
    139 	switch right {
    140 	case TRUE:
    141 		return FALSE
    142 	case FALSE:
    143 		return TRUE
    144 	case NULL:
    145 		return TRUE
    146 	default:
    147 		return FALSE
    148 	}
    149 }
    150 
    151 func evalMinusPrefixOperatorExpression(right object.Object, ctx *object.Context) object.Object {
    152 	if right.Type() != object.INTEGER_OBJ {
    153 		return newError("unknown operator: -%s", right.Type())
    154 	}
    155 	value := right.(*object.Integer).Value
    156 	return &object.Integer{Value: -value}
    157 }
    158 
    159 func evalInfixExpression(operator string, left, right object.Object, ctx *object.Context) object.Object {
    160 	switch {
    161 	case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
    162 		return evalIntegerInfixExpression(operator, left, right, ctx)
    163 	case left.Type() == object.STRING_OBJ && right.Type() == object.STRING_OBJ:
    164 		return evalStringInfixExpression(operator, left, right, ctx)
    165 	case operator == "==":
    166 		return boolToObject(left == right)
    167 	case operator == "!=":
    168 		return boolToObject(left != right)
    169 	case left.Type() != right.Type():
    170 		return newError("type mismatch: %s %s %s", left.Type(), operator, right.Type())
    171 	default:
    172 		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    173 	}
    174 }
    175 
    176 func evalIntegerInfixExpression(operator string, left, right object.Object, ctx *object.Context) object.Object {
    177 	leftValue := left.(*object.Integer).Value
    178 	rightValue := right.(*object.Integer).Value
    179 	switch operator {
    180 	case "+":
    181 		return &object.Integer{Value: leftValue + rightValue}
    182 	case "-":
    183 		return &object.Integer{Value: leftValue - rightValue}
    184 	case "*":
    185 		return &object.Integer{Value: leftValue * rightValue}
    186 	case "/":
    187 		return &object.Integer{Value: leftValue / rightValue}
    188 	case "<":
    189 		return boolToObject(leftValue < rightValue)
    190 	case ">":
    191 		return boolToObject(leftValue > rightValue)
    192 	case "==":
    193 		return boolToObject(leftValue == rightValue)
    194 	case "!=":
    195 		return boolToObject(leftValue != rightValue)
    196 	default:
    197 		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    198 	}
    199 }
    200 
    201 func evalIfExpression(ie *ast.IfExpression, ctx *object.Context) object.Object {
    202 	condition := Eval(ie.Condition, ctx)
    203 	if isError(condition) {
    204 		return condition
    205 	} else if isTruthy(condition) {
    206 		return Eval(ie.Consequence, ctx)
    207 	} else if ie.Alternative != nil {
    208 		return Eval(ie.Alternative, ctx)
    209 	} else {
    210 		return NULL
    211 	}
    212 }
    213 
    214 func isTruthy(obj object.Object) bool {
    215 	switch obj {
    216 	case NULL:
    217 		return false
    218 	case TRUE:
    219 		return true
    220 	case FALSE:
    221 		return false
    222 	default:
    223 		return true
    224 	}
    225 }
    226 
    227 func evalProgram(program *ast.Program, ctx *object.Context) object.Object {
    228 	var result object.Object
    229 	for _, statement := range program.Statements {
    230 		result = Eval(statement, ctx)
    231 		switch result := result.(type) {
    232 		case *object.ReturnValue:
    233 			return result.Value
    234 		case *object.Error:
    235 			return result
    236 		}
    237 	}
    238 	return result
    239 }
    240 
    241 func evalBlockStatement(block *ast.BlockStatement, ctx *object.Context) object.Object {
    242 	var result object.Object
    243 	for _, statement := range block.Statements {
    244 		result = Eval(statement, ctx)
    245 		if result != nil {
    246 			rt := result.Type()
    247 			if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ {
    248 				return result
    249 			}
    250 		}
    251 	}
    252 	return result
    253 }
    254 
    255 func evalIdentifier(node *ast.Identifier, ctx *object.Context) object.Object {
    256 	if value, ok := ctx.Get(node.Value); ok {
    257 		return value
    258 	}
    259 
    260 	if builtin, ok := builtins[node.Value]; ok {
    261 		return builtin
    262 	}
    263 
    264 	return newError("identifier not found: " + node.Value)
    265 }
    266 
    267 func evalExpressions(expressions []ast.Expression, ctx *object.Context) []object.Object {
    268 	var result []object.Object
    269 	for _, e := range expressions {
    270 		evaluated := Eval(e, ctx)
    271 		if isError(evaluated) {
    272 			return []object.Object{evaluated}
    273 		}
    274 		result = append(result, evaluated)
    275 	}
    276 	return result
    277 }
    278 
    279 func applyFunction(fn object.Object, args []object.Object) object.Object {
    280 	switch function := fn.(type) {
    281 	case *object.Function:
    282 		childCtx := childFunctionContext(function, args)
    283 		evaluated := Eval(function.Body, childCtx)
    284 		return unwrapReturnValue(evaluated)
    285 
    286 	case *object.Builtin:
    287 		return function.Fn(args...)
    288 
    289 	default:
    290 		return newError("not a function: %s", fn.Type())
    291 	}
    292 }
    293 
    294 func childFunctionContext(fn *object.Function, args []object.Object) *object.Context {
    295 	ctx := object.NewChildContext(fn.Ctx)
    296 	for paramIdx, param := range fn.Parameters {
    297 		ctx.Set(param.Value, args[paramIdx])
    298 	}
    299 	return ctx
    300 }
    301 
    302 func unwrapReturnValue(obj object.Object) object.Object {
    303 	if returnValue, ok := obj.(*object.ReturnValue); ok {
    304 		return returnValue.Value
    305 	}
    306 	return obj
    307 }
    308 
    309 func evalStringInfixExpression(operator string, left, right object.Object, ctx *object.Context) object.Object {
    310 	if operator != "+" {
    311 		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
    312 	}
    313 	leftVal := left.(*object.String).Value
    314 	rightVal := right.(*object.String).Value
    315 	return &object.String{Value: leftVal + rightVal}
    316 }
    317 
    318 func evalIndexExpression(left, index object.Object) object.Object {
    319 	switch {
    320 	case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
    321 		return evalArrayIndexExpression(left, index)
    322 	case left.Type() == object.HASH_OBJ:
    323 		return evalHashIndexExpression(left, index)
    324 	default:
    325 		return newError("index operator not supported: %s", left.Type())
    326 	}
    327 }
    328 
    329 func evalArrayIndexExpression(array, index object.Object) object.Object {
    330 	arrayObject := array.(*object.Array)
    331 	idx := index.(*object.Integer).Value
    332 	max := int64(len(arrayObject.Elements) - 1)
    333 	if idx < 0 || idx > max {
    334 		return NULL
    335 	}
    336 	return arrayObject.Elements[idx]
    337 }
    338 
    339 func evalHashLiteral(node *ast.HashLiteral, ctx *object.Context) object.Object {
    340 	pairs := make(map[object.HashKey]object.HashPair)
    341 	for knode, vnode := range node.Pairs {
    342 		k := Eval(knode, ctx)
    343 		if isError(k) {
    344 			return k
    345 		}
    346 		hashKey, ok := k.(object.Hashable)
    347 		if !ok {
    348 			return newError("unusable as hash key: %s", k.Type())
    349 		}
    350 		v := Eval(vnode, ctx)
    351 		if isError(v) {
    352 			return v
    353 		}
    354 		hashed := hashKey.HashKey()
    355 		pairs[hashed] = object.HashPair{Key: k, Value: v}
    356 	}
    357 	return &object.Hash{Pairs: pairs}
    358 }
    359 
    360 func evalHashIndexExpression(hash, index object.Object) object.Object {
    361 	hashObj := hash.(*object.Hash)
    362 	key, ok := index.(object.Hashable)
    363 	if !ok {
    364 		return newError("unusable as hash key: %s", index.Type())
    365 	}
    366 	pair, ok := hashObj.Pairs[key.HashKey()]
    367 	if !ok {
    368 		return NULL
    369 	}
    370 	return pair.Value
    371 }