|
|
@@ -14,6 +14,7 @@ import (
|
|
|
|
|
|
const StackSize = 2048
|
|
|
const GlobalSize = 65535
|
|
|
+const MaxFrames = 1024
|
|
|
|
|
|
var True = &object.Boolean{Value: true}
|
|
|
var False = &object.Boolean{Value: false}
|
|
|
@@ -27,9 +28,18 @@ type VM struct {
|
|
|
sp int // Always points to the next value. Top of stack is stack[sp-1]
|
|
|
|
|
|
globals []object.Object
|
|
|
+
|
|
|
+ frames []*Frame
|
|
|
+ framesIndex int
|
|
|
}
|
|
|
|
|
|
func New(byteCode *compiler.ByteCode) *VM {
|
|
|
+ mainFn := &object.CompileFunction{Instructions: byteCode.Instructions}
|
|
|
+ mainFrame := NewFrame(mainFn)
|
|
|
+
|
|
|
+ frames := make([]*Frame, MaxFrames)
|
|
|
+ frames[0] = mainFrame
|
|
|
+
|
|
|
return &VM{
|
|
|
instructions: byteCode.Instructions,
|
|
|
constants: byteCode.Constants,
|
|
|
@@ -38,6 +48,9 @@ func New(byteCode *compiler.ByteCode) *VM {
|
|
|
sp: 0,
|
|
|
|
|
|
globals: make([]object.Object, GlobalSize),
|
|
|
+
|
|
|
+ frames: frames,
|
|
|
+ framesIndex: 1,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -55,13 +68,21 @@ func NewWithGlobalsStore(byteCode *compiler.ByteCode, s []object.Object) *VM {
|
|
|
// }
|
|
|
|
|
|
func (vm *VM) Run() error {
|
|
|
- for ip := 0; ip < len(vm.instructions); ip++ {
|
|
|
- op := code.Opcode(vm.instructions[ip])
|
|
|
+ var ip int
|
|
|
+ var ins code.Instructions
|
|
|
+ var op code.Opcode
|
|
|
+
|
|
|
+ for vm.currentFrame().ip < len(vm.currentFrame().Instructions())-1 {
|
|
|
+ vm.currentFrame().ip++
|
|
|
+
|
|
|
+ ip = vm.currentFrame().ip
|
|
|
+ ins = vm.currentFrame().Instructions()
|
|
|
+ op = code.Opcode(ins[ip])
|
|
|
|
|
|
switch op {
|
|
|
case code.OpConstant:
|
|
|
- constIndex := code.ReadUint16(vm.instructions[ip+1:])
|
|
|
- ip += 2
|
|
|
+ constIndex := code.ReadUint16(ins[ip+1:])
|
|
|
+ vm.currentFrame().ip += 2
|
|
|
|
|
|
// 执行
|
|
|
err := vm.push(vm.constants[constIndex])
|
|
|
@@ -101,15 +122,15 @@ func (vm *VM) Run() error {
|
|
|
case code.OpPop:
|
|
|
vm.pop()
|
|
|
case code.OpJump:
|
|
|
- pos := int(code.ReadUint16(vm.instructions[ip+1:]))
|
|
|
- ip = pos - 1
|
|
|
+ pos := int(code.ReadUint16(ins[ip+1:]))
|
|
|
+ vm.currentFrame().ip = pos - 1
|
|
|
case code.OpJumpNotTruthy:
|
|
|
- pos := int(code.ReadUint16(vm.instructions[ip+1:]))
|
|
|
- ip += 2
|
|
|
+ pos := int(code.ReadUint16(ins[ip+1:]))
|
|
|
+ vm.currentFrame().ip += 2
|
|
|
|
|
|
condition := vm.pop()
|
|
|
if !isTruthy(condition) {
|
|
|
- ip = pos - 1
|
|
|
+ vm.currentFrame().ip = pos - 1
|
|
|
}
|
|
|
case code.OpNull:
|
|
|
err := vm.push(Null)
|
|
|
@@ -117,13 +138,13 @@ func (vm *VM) Run() error {
|
|
|
return err
|
|
|
}
|
|
|
case code.OpSetGlobal:
|
|
|
- globalIndex := code.ReadUint16(vm.instructions[ip+1:])
|
|
|
- ip += 2
|
|
|
+ globalIndex := code.ReadUint16(ins[ip+1:])
|
|
|
+ vm.currentFrame().ip += 2
|
|
|
|
|
|
vm.globals[globalIndex] = vm.pop()
|
|
|
case code.OpGetGlobal:
|
|
|
- globalIndex := code.ReadUint16(vm.instructions[ip+1:])
|
|
|
- ip += 2
|
|
|
+ globalIndex := code.ReadUint16(ins[ip+1:])
|
|
|
+ vm.currentFrame().ip += 2
|
|
|
|
|
|
err := vm.push(vm.globals[globalIndex])
|
|
|
if err != nil {
|
|
|
@@ -131,8 +152,8 @@ func (vm *VM) Run() error {
|
|
|
}
|
|
|
|
|
|
case code.OpArray:
|
|
|
- numElements := int(code.ReadUint16(vm.instructions[ip+1:]))
|
|
|
- ip += 2
|
|
|
+ numElements := int(code.ReadUint16(ins[ip+1:]))
|
|
|
+ vm.currentFrame().ip += 2
|
|
|
|
|
|
array := vm.buildArray(vm.sp-numElements, vm.sp)
|
|
|
vm.sp -= numElements
|
|
|
@@ -142,8 +163,8 @@ func (vm *VM) Run() error {
|
|
|
return err
|
|
|
}
|
|
|
case code.OpHash:
|
|
|
- numElements := int(code.ReadUint16(vm.instructions[ip+1:]))
|
|
|
- ip += 2
|
|
|
+ numElements := int(code.ReadUint16(ins[ip+1:]))
|
|
|
+ vm.currentFrame().ip += 2
|
|
|
|
|
|
hash, err := vm.buildHash(vm.sp-numElements, vm.sp)
|
|
|
if err != nil {
|
|
|
@@ -163,6 +184,31 @@ func (vm *VM) Run() error {
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
+ case code.OpCall:
|
|
|
+ fn, ok := vm.stack[vm.sp-1].(*object.CompileFunction)
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("calling non-function")
|
|
|
+ }
|
|
|
+ frame := NewFrame(fn)
|
|
|
+ vm.pushFrame(frame)
|
|
|
+ case code.OpReturnValue:
|
|
|
+ returnValue := vm.pop()
|
|
|
+
|
|
|
+ vm.popFrame()
|
|
|
+ vm.pop()
|
|
|
+
|
|
|
+ err := vm.push(returnValue)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ case code.OpReturn:
|
|
|
+ vm.popFrame()
|
|
|
+ vm.pop()
|
|
|
+
|
|
|
+ err := vm.push(Null)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -179,6 +225,21 @@ func isTruthy(obj object.Object) bool {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func (vm *VM) currentFrame() *Frame {
|
|
|
+ return vm.frames[vm.framesIndex-1]
|
|
|
+}
|
|
|
+
|
|
|
+func (vm *VM) pushFrame(f *Frame) {
|
|
|
+ vm.frames[vm.framesIndex] = f
|
|
|
+ vm.framesIndex++
|
|
|
+}
|
|
|
+
|
|
|
+func (vm *VM) popFrame() *Frame {
|
|
|
+ vm.framesIndex--
|
|
|
+ return vm.frames[vm.framesIndex]
|
|
|
+}
|
|
|
+
|
|
|
func (vm *VM) push(o object.Object) error {
|
|
|
if vm.sp >= StackSize {
|
|
|
return fmt.Errorf("stack overflow")
|