diff options
Diffstat (limited to 'vendor/github.com/d5/tengo/runtime/vm.go')
-rw-r--r-- | vendor/github.com/d5/tengo/runtime/vm.go | 673 |
1 files changed, 194 insertions, 479 deletions
diff --git a/vendor/github.com/d5/tengo/runtime/vm.go b/vendor/github.com/d5/tengo/runtime/vm.go index 2708fde7..9066bfea 100644 --- a/vendor/github.com/d5/tengo/runtime/vm.go +++ b/vendor/github.com/d5/tengo/runtime/vm.go @@ -8,7 +8,6 @@ import ( "github.com/d5/tengo/compiler/source" "github.com/d5/tengo/compiler/token" "github.com/d5/tengo/objects" - "github.com/d5/tengo/stdlib" ) const ( @@ -26,7 +25,6 @@ var ( truePtr = &objects.TrueValue falsePtr = &objects.FalseValue undefinedPtr = &objects.UndefinedValue - builtinFuncs []objects.Object ) // VM is a virtual machine that executes the bytecode compiled by Compiler. @@ -43,17 +41,30 @@ type VM struct { curIPLimit int ip int aborting int64 + builtinFuncs []objects.Object builtinModules map[string]*objects.Object + err error + errOffset int } // NewVM creates a VM. -func NewVM(bytecode *compiler.Bytecode, globals []*objects.Object, builtinModules map[string]*objects.Object) *VM { +func NewVM(bytecode *compiler.Bytecode, globals []*objects.Object, builtinFuncs []objects.Object, builtinModules map[string]*objects.Object) *VM { if globals == nil { globals = make([]*objects.Object, GlobalsSize) } if builtinModules == nil { - builtinModules = stdlib.Modules + builtinModules = make(map[string]*objects.Object) + } + + if builtinFuncs == nil { + builtinFuncs = make([]objects.Object, len(objects.Builtins)) + for idx, fn := range objects.Builtins { + builtinFuncs[idx] = &objects.BuiltinFunction{ + Name: fn.Name, + Value: fn.Value, + } + } } frames := make([]Frame, MaxFrames) @@ -74,6 +85,7 @@ func NewVM(bytecode *compiler.Bytecode, globals []*objects.Object, builtinModule curInsts: frames[0].fn.Instructions, curIPLimit: len(frames[0].fn.Instructions) - 1, ip: -1, + builtinFuncs: builtinFuncs, builtinModules: builtinModules, } } @@ -94,8 +106,31 @@ func (v *VM) Run() (err error) { v.ip = -1 atomic.StoreInt64(&v.aborting, 0) - var filePos source.FilePos + v.run() + + err = v.err + if err != nil { + filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-v.errOffset]) + err = fmt.Errorf("Runtime Error: %s\n\tat %s", err.Error(), filePos) + for v.framesIndex > 1 { + v.framesIndex-- + v.curFrame = &v.frames[v.framesIndex-1] + + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.curFrame.ip-1]) + err = fmt.Errorf("%s\n\tat %s", err.Error(), filePos) + } + return err + } + + // check if stack still has some objects left + if v.sp > 0 && atomic.LoadInt64(&v.aborting) == 0 { + panic(fmt.Errorf("non empty stack after execution: %d", v.sp)) + } + + return nil +} +func (v *VM) run() { mainloop: for v.ip < v.curIPLimit && (atomic.LoadInt64(&v.aborting) == 0) { v.ip++ @@ -106,8 +141,8 @@ mainloop: v.ip += 2 if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &v.constants[cidx] @@ -115,298 +150,45 @@ mainloop: case compiler.OpNull: if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = undefinedPtr v.sp++ case compiler.OpAdd: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Add, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s + %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Add) case compiler.OpSub: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Sub, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s - %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Sub) case compiler.OpMul: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Mul, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s * %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Mul) case compiler.OpDiv: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Quo, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s / %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Quo) case compiler.OpRem: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Rem, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s %% %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Rem) case compiler.OpBAnd: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.And, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s & %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.And) case compiler.OpBOr: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Or, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s | %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Or) case compiler.OpBXor: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Xor, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s ^ %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Xor) case compiler.OpBAndNot: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.AndNot, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s &^ %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.AndNot) case compiler.OpBShiftLeft: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Shl, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s << %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Shl) case compiler.OpBShiftRight: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Shr, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s >> %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Shr) case compiler.OpEqual: right := v.stack[v.sp-1] @@ -414,8 +196,8 @@ mainloop: v.sp -= 2 if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } if (*left).Equals(*right) { @@ -431,8 +213,8 @@ mainloop: v.sp -= 2 if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } if (*left).Equals(*right) { @@ -443,64 +225,18 @@ mainloop: v.sp++ case compiler.OpGreaterThan: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.Greater, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s > %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.Greater) case compiler.OpGreaterThanEqual: - right := v.stack[v.sp-1] - left := v.stack[v.sp-2] - v.sp -= 2 - - res, e := (*left).BinaryOp(token.GreaterEq, *right) - if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - if e == objects.ErrInvalidOperator { - err = fmt.Errorf("invalid operation: %s >= %s", - (*left).TypeName(), (*right).TypeName()) - break mainloop - } - - err = e - break mainloop - } - - if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop - } - - v.stack[v.sp] = &res - v.sp++ + v.binaryOp(token.GreaterEq) case compiler.OpPop: v.sp-- case compiler.OpTrue: if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = truePtr @@ -508,8 +244,8 @@ mainloop: case compiler.OpFalse: if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = falsePtr @@ -520,8 +256,8 @@ mainloop: v.sp-- if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } if (*operand).IsFalsy() { @@ -538,8 +274,8 @@ mainloop: switch x := (*operand).(type) { case *objects.Int: if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var res objects.Object = &objects.Int{Value: ^x.Value} @@ -547,9 +283,8 @@ mainloop: v.stack[v.sp] = &res v.sp++ default: - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid operation: ^%s", (*operand).TypeName()) - break mainloop + v.err = fmt.Errorf("invalid operation: ^%s", (*operand).TypeName()) + return } case compiler.OpMinus: @@ -559,8 +294,8 @@ mainloop: switch x := (*operand).(type) { case *objects.Int: if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var res objects.Object = &objects.Int{Value: -x.Value} @@ -569,8 +304,8 @@ mainloop: v.sp++ case *objects.Float: if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var res objects.Object = &objects.Float{Value: -x.Value} @@ -578,9 +313,8 @@ mainloop: v.stack[v.sp] = &res v.sp++ default: - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid operation: -%s", (*operand).TypeName()) - break mainloop + v.err = fmt.Errorf("invalid operation: -%s", (*operand).TypeName()) + return } case compiler.OpJumpFalsy: @@ -639,9 +373,9 @@ mainloop: v.sp -= numSelectors + 1 if e := indexAssign(v.globals[globalIndex], val, selectors); e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) - err = e - break mainloop + v.errOffset = 3 + v.err = e + return } case compiler.OpGetGlobal: @@ -651,8 +385,8 @@ mainloop: val := v.globals[globalIndex] if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = val @@ -671,8 +405,8 @@ mainloop: var arr objects.Object = &objects.Array{Value: elements} if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &arr @@ -693,8 +427,8 @@ mainloop: var m objects.Object = &objects.Map{Value: kv} if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &m @@ -734,23 +468,22 @@ mainloop: case objects.Indexable: val, e := left.IndexGet(*index) if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidIndexType { - err = fmt.Errorf("invalid index type: %s", (*index).TypeName()) - break mainloop + v.err = fmt.Errorf("invalid index type: %s", (*index).TypeName()) + return } - err = e - break mainloop + v.err = e + return } if val == nil { val = objects.UndefinedValue } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &val @@ -759,23 +492,21 @@ mainloop: case *objects.Error: // e.value key, ok := (*index).(*objects.String) if !ok || key.Value != "value" { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid index on error") - break mainloop + v.err = fmt.Errorf("invalid index on error") + return } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &left.Value v.sp++ default: - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("not indexable: %s", left.TypeName()) - break mainloop + v.err = fmt.Errorf("not indexable: %s", left.TypeName()) + return } case compiler.OpSliceIndex: @@ -789,9 +520,8 @@ mainloop: if low, ok := (*low).(*objects.Int); ok { lowIdx = low.Value } else { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index type: %s", low.TypeName()) - break mainloop + v.err = fmt.Errorf("invalid slice index type: %s", low.TypeName()) + return } } @@ -804,15 +534,13 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) - break mainloop + v.err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) + return } if lowIdx > highIdx { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) - break mainloop + v.err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) + return } if lowIdx < 0 { @@ -828,8 +556,8 @@ mainloop: } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var val objects.Object = &objects.Array{Value: left.Value[lowIdx:highIdx]} @@ -844,15 +572,13 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) - break mainloop + v.err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) + return } if lowIdx > highIdx { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) - break mainloop + v.err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) + return } if lowIdx < 0 { @@ -868,8 +594,8 @@ mainloop: } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var val objects.Object = &objects.Array{Value: left.Value[lowIdx:highIdx]} @@ -885,15 +611,13 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) - break mainloop + v.err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) + return } if lowIdx > highIdx { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) - break mainloop + v.err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) + return } if lowIdx < 0 { @@ -909,8 +633,8 @@ mainloop: } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var val objects.Object = &objects.String{Value: left.Value[lowIdx:highIdx]} @@ -926,15 +650,13 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) - break mainloop + v.err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) + return } if lowIdx > highIdx { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) - break mainloop + v.err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) + return } if lowIdx < 0 { @@ -950,8 +672,8 @@ mainloop: } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var val objects.Object = &objects.Bytes{Value: left.Value[lowIdx:highIdx]} @@ -969,10 +691,10 @@ mainloop: switch callee := value.(type) { case *objects.Closure: if numArgs != callee.Fn.NumParameters { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) - err = fmt.Errorf("wrong number of arguments: want=%d, got=%d", + v.errOffset = 1 + v.err = fmt.Errorf("wrong number of arguments: want=%d, got=%d", callee.Fn.NumParameters, numArgs) - break mainloop + return } // test if it's tail-call @@ -1003,10 +725,10 @@ mainloop: case *objects.CompiledFunction: if numArgs != callee.NumParameters { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) - err = fmt.Errorf("wrong number of arguments: want=%d, got=%d", + v.errOffset = 1 + v.err = fmt.Errorf("wrong number of arguments: want=%d, got=%d", callee.NumParameters, numArgs) - break mainloop + return } // test if it's tail-call @@ -1046,22 +768,22 @@ mainloop: // runtime error if e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) + v.errOffset = 1 if e == objects.ErrWrongNumArguments { - err = fmt.Errorf("wrong number of arguments in call to '%s'", + v.err = fmt.Errorf("wrong number of arguments in call to '%s'", value.TypeName()) - break mainloop + return } if e, ok := e.(objects.ErrInvalidArgumentType); ok { - err = fmt.Errorf("invalid type for argument '%s' in call to '%s': expected %s, found %s", + v.err = fmt.Errorf("invalid type for argument '%s' in call to '%s': expected %s, found %s", e.Name, value.TypeName(), e.Expected, e.Found) - break mainloop + return } - err = e - break mainloop + v.err = e + return } // nil return -> undefined @@ -1070,17 +792,17 @@ mainloop: } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &ret v.sp++ default: - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) - err = fmt.Errorf("not callable: %s", callee.TypeName()) - break mainloop + v.errOffset = 1 + v.err = fmt.Errorf("not callable: %s", callee.TypeName()) + return } case compiler.OpReturnValue: @@ -1155,9 +877,9 @@ mainloop: sp := v.curFrame.basePointer + localIndex if e := indexAssign(v.stack[sp], val, selectors); e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-2]) - err = e - break mainloop + v.errOffset = 2 + v.err = e + return } case compiler.OpGetLocal: @@ -1167,8 +889,8 @@ mainloop: val := v.stack[v.curFrame.basePointer+localIndex] if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = val @@ -1179,11 +901,11 @@ mainloop: v.ip++ if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } - v.stack[v.sp] = &builtinFuncs[builtinIndex] + v.stack[v.sp] = &v.builtinFuncs[builtinIndex] v.sp++ case compiler.OpGetBuiltinModule: @@ -1194,14 +916,14 @@ mainloop: module, ok := v.builtinModules[moduleName] if !ok { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) - err = fmt.Errorf("module '%s' not found", moduleName) - break mainloop + v.errOffset = 3 + v.err = fmt.Errorf("module '%s' not found", moduleName) + return } if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = module @@ -1214,9 +936,9 @@ mainloop: fn, ok := v.constants[constIndex].(*objects.CompiledFunction) if !ok { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) - err = fmt.Errorf("not function: %s", fn.TypeName()) - break mainloop + v.errOffset = 3 + v.err = fmt.Errorf("not function: %s", fn.TypeName()) + return } free := make([]*objects.Object, numFree) @@ -1226,8 +948,8 @@ mainloop: v.sp -= numFree if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } var cl objects.Object = &objects.Closure{ @@ -1245,8 +967,8 @@ mainloop: val := v.curFrame.freeVars[freeIndex] if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = val @@ -1263,9 +985,9 @@ mainloop: v.sp -= numSelectors + 1 if e := indexAssign(v.curFrame.freeVars[freeIndex], val, selectors); e != nil { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-2]) - err = e - break mainloop + v.errOffset = 2 + v.err = e + return } case compiler.OpSetFree: @@ -1285,16 +1007,15 @@ mainloop: iterable, ok := (*dst).(objects.Iterable) if !ok { - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("not iterable: %s", (*dst).TypeName()) - break mainloop + v.err = fmt.Errorf("not iterable: %s", (*dst).TypeName()) + return } iterator = iterable.Iterate() if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &iterator @@ -1307,8 +1028,8 @@ mainloop: hasMore := (*iterator).(objects.Iterator).Next() if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } if hasMore { @@ -1325,8 +1046,8 @@ mainloop: val := (*iterator).(objects.Iterator).Key() if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &val @@ -1339,8 +1060,8 @@ mainloop: val := (*iterator).(objects.Iterator).Value() if v.sp >= StackSize { - err = ErrStackOverflow - break mainloop + v.err = ErrStackOverflow + return } v.stack[v.sp] = &val @@ -1350,25 +1071,6 @@ mainloop: panic(fmt.Errorf("unknown opcode: %d", v.curInsts[v.ip])) } } - - if err != nil { - err = fmt.Errorf("Runtime Error: %s\n\tat %s", err.Error(), filePos) - for v.framesIndex > 1 { - v.framesIndex-- - v.curFrame = &v.frames[v.framesIndex-1] - - filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.curFrame.ip-1]) - err = fmt.Errorf("%s\n\tat %s", err.Error(), filePos) - } - return err - } - - // check if stack still has some objects left - if v.sp > 0 && atomic.LoadInt64(&v.aborting) == 0 { - panic(fmt.Errorf("non empty stack after execution: %d", v.sp)) - } - - return nil } // Globals returns the global variables. @@ -1413,12 +1115,25 @@ func indexAssign(dst, src *objects.Object, selectors []*objects.Object) error { return nil } -func init() { - builtinFuncs = make([]objects.Object, len(objects.Builtins)) - for i, b := range objects.Builtins { - builtinFuncs[i] = &objects.BuiltinFunction{ - Name: b.Name, - Value: b.Func, +func (v *VM) binaryOp(tok token.Token) { + right := v.stack[v.sp-1] + left := v.stack[v.sp-2] + + res, e := (*left).BinaryOp(tok, *right) + if e != nil { + v.sp -= 2 + atomic.StoreInt64(&v.aborting, 1) + + if e == objects.ErrInvalidOperator { + v.err = fmt.Errorf("invalid operation: %s + %s", + (*left).TypeName(), (*right).TypeName()) + return } + + v.err = e + return } + + v.stack[v.sp-2] = &res + v.sp-- } |