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 }