diff --git a/internal/vm/frame.go b/internal/vm/frame.go index 6e6b57d..5a564a2 100644 --- a/internal/vm/frame.go +++ b/internal/vm/frame.go @@ -14,18 +14,30 @@ type Frame struct { func NewFrame(cl *object.Closure, basePointer int) *Frame { return &Frame{ cl: cl, - ip: -1, basePointer: basePointer, } } -// NextOp ... -func (f *Frame) NextOp() code.Opcode { - return code.Opcode(f.Instructions()[f.ip+1]) +func (f *Frame) ReadNextOp() code.Opcode { + op := code.Opcode(f.cl.Fn.Instructions[f.ip]) + f.ip++ + return op } -func (f *Frame) Reset() { - f.ip = -1 +func (f *Frame) PeekNextOp() code.Opcode { + return code.Opcode(f.cl.Fn.Instructions[f.ip]) +} + +func (f *Frame) ReadUint8() uint8 { + n := code.ReadUint8(f.cl.Fn.Instructions[f.ip:]) + f.ip++ + return n +} + +func (f *Frame) ReadUint16() uint16 { + n := code.ReadUint16(f.cl.Fn.Instructions[f.ip:]) + f.ip += 2 + return n } func (f *Frame) Instructions() code.Instructions { diff --git a/internal/vm/vm.go b/internal/vm/vm.go index 42df88b..c1b316c 100644 --- a/internal/vm/vm.go +++ b/internal/vm/vm.go @@ -12,7 +12,6 @@ import ( "monkey/internal/utils" "os" "path/filepath" - "strings" "time" "unicode" ) @@ -39,13 +38,6 @@ func isTruthy(obj object.Object) bool { } } -func nativeBoolToBooleanObject(input bool) *object.Boolean { - if input { - return True - } - return False -} - // executeModule compiles the named module and returns a *object.Module object func executeModule(name string, state *VMState) (object.Object, error) { filename := utils.FindModule(name) @@ -217,11 +209,92 @@ func (vm *VM) pop() object.Object { return o } +func (vm *VM) executeLoadBuiltin() error { + builtinIndex := vm.frame.ReadUint8() + builtin := builtins.BuiltinsIndex[builtinIndex] + return vm.push(builtin) +} + +func (vm *VM) executeConstant() error { + constIndex := vm.frame.ReadUint16() + return vm.push(vm.state.Constants[constIndex]) +} + +func (vm *VM) executeAssignGlobal() error { + globalIndex := vm.frame.ReadUint16() + vm.state.Globals[globalIndex] = vm.pop() + return vm.push(Null) +} + +func (vm *VM) executeAssignLocal() error { + localIndex := vm.frame.ReadUint8() + vm.stack[vm.frame.basePointer+int(localIndex)] = vm.pop() + return vm.push(Null) +} + +func (vm *VM) executeSetGlobal() error { + globalIndex := vm.frame.ReadUint16() + + ref := vm.pop() + if immutable, ok := ref.(object.Immutable); ok { + vm.state.Globals[globalIndex] = immutable.Clone() + } else { + vm.state.Globals[globalIndex] = ref + } + + return vm.push(Null) +} + +func (vm *VM) executeGetGlobal() error { + globalIndex := vm.frame.ReadUint16() + return vm.push(vm.state.Globals[globalIndex]) +} + +func (vm *VM) executeSetLocal() error { + localIndex := vm.frame.ReadUint8() + + ref := vm.pop() + if immutable, ok := ref.(object.Immutable); ok { + vm.stack[vm.frame.basePointer+int(localIndex)] = immutable.Clone() + } else { + vm.stack[vm.frame.basePointer+int(localIndex)] = ref + } + + return vm.push(Null) +} + +func (vm *VM) executeGetLocal() error { + localIndex := vm.frame.ReadUint8() + return vm.push(vm.stack[vm.frame.basePointer+int(localIndex)]) +} + +func (vm *VM) executeGetFree() error { + freeIndex := vm.frame.ReadUint8() + return vm.push(vm.frame.cl.Free[freeIndex]) +} + func (vm *VM) executeLoadModule() error { name := vm.pop() return vm.loadModule(name) } +func (vm *VM) executeCurrentClosure() error { + currentClosure := vm.frame.cl + return vm.push(currentClosure) +} + +func (vm *VM) executeTrue() error { + return vm.push(True) +} + +func (vm *VM) executeFalse() error { + return vm.push(False) +} + +func (vm *VM) executeNull() error { + return vm.push(Null) +} + func (vm *VM) buildHash(startIndex, endIndex int) (object.Object, error) { hashedPairs := make(map[object.HashKey]object.HashPair) @@ -242,8 +315,9 @@ func (vm *VM) buildHash(startIndex, endIndex int) (object.Object, error) { return &object.Hash{Pairs: hashedPairs}, nil } -func (vm *VM) executeMakeHash(startIndex, endIndex int) error { - hash, err := vm.buildHash(startIndex, endIndex) +func (vm *VM) executeMakeHash() error { + startIndex := vm.sp - int(vm.frame.ReadUint16()) + hash, err := vm.buildHash(startIndex, vm.sp) if err != nil { return err } @@ -261,8 +335,9 @@ func (vm *VM) buildArray(startIndex, endIndex int) (object.Object, error) { return &object.Array{Elements: elements}, nil } -func (vm *VM) executeMakeArray(startIndex, endIndex int) error { - hash, err := vm.buildArray(startIndex, endIndex) +func (vm *VM) executeMakeArray() error { + startIndex := vm.sp - int(vm.frame.ReadUint16()) + hash, err := vm.buildArray(startIndex, vm.sp) if err != nil { return err } @@ -270,6 +345,12 @@ func (vm *VM) executeMakeArray(startIndex, endIndex int) error { return vm.push(hash) } +func (vm *VM) executeClosure() error { + constIndex := vm.frame.ReadUint16() + numFree := vm.frame.ReadUint8() + return vm.pushClosure(int(constIndex), int(numFree)) +} + func (vm *VM) executeAdd() error { right := vm.pop() left := vm.pop() @@ -577,7 +658,9 @@ func (vm *VM) executeGetItem() error { ) } -func (vm *VM) executeCall(args int) error { +func (vm *VM) executeCall() error { + args := int(vm.frame.ReadUint8()) + callee := vm.stack[vm.sp-1-args] switch callee := callee.(type) { case *object.Closure: @@ -601,6 +684,25 @@ func (vm *VM) executeReturn() error { return vm.push(returnValue) } +func (vm *VM) executeJumpIfFalse() error { + pos := int(vm.frame.ReadUint16()) + if !isTruthy(vm.pop()) { + vm.frame.ip = pos + } + return nil +} + +func (vm *VM) executeJump() error { + pos := int(vm.frame.ReadUint16()) + vm.frame.ip = pos + return nil +} + +func (vm *VM) executePop() error { + vm.pop() + return nil +} + func (vm *VM) callClosure(cl *object.Closure, numArgs int) error { if numArgs != cl.Fn.NumParameters { return fmt.Errorf("wrong number of arguments: want=%d, got=%d", cl.Fn.NumParameters, numArgs) @@ -608,13 +710,13 @@ func (vm *VM) callClosure(cl *object.Closure, numArgs int) error { // Optimize tail calls and avoid a new frame if cl.Fn == vm.frame.cl.Fn { - nextOP := vm.frame.NextOp() + nextOP := vm.frame.PeekNextOp() if nextOP == code.OpReturn { for p := 0; p < numArgs; p++ { vm.stack[vm.frame.basePointer+p] = vm.stack[vm.sp-numArgs+p] } vm.sp -= numArgs + 1 - vm.frame.ip = -1 // reset IP to the beginning of the frame + vm.frame.ip = 0 // reset IP to the beginning of the frame return nil } } @@ -688,9 +790,6 @@ func (vm *VM) LastPoppedStackElem() object.Object { func (vm *VM) Run() (err error) { var n int - var ip int - var ins code.Instructions - var op code.Opcode if vm.Debug { start := time.Now() @@ -700,98 +799,59 @@ func (vm *VM) Run() (err error) { } for err == nil { - vm.frame.ip++ - - ip = vm.frame.ip - ins = vm.frame.Instructions() - op = code.Opcode(ins[ip]) + op := vm.frame.ReadNextOp() if vm.Debug { n++ log.Printf( "%-25s %-20s\n", - fmt.Sprintf( - "%04d %s", ip, - strings.Split(ins[ip:].String(), "\n")[0][4:], - ), + fmt.Sprintf("%04d %s", vm.frame.ip, op), fmt.Sprintf( "[ip=%02d fp=%02d, sp=%02d]", - ip, vm.fp-1, vm.sp, + vm.frame.ip, vm.fp-1, vm.sp, ), ) } switch op { case code.OpConstant: - constIndex := code.ReadUint16(ins[ip+1:]) - vm.frame.ip += 2 - err = vm.push(vm.state.Constants[constIndex]) + err = vm.executeConstant() case code.OpPop: - vm.pop() + err = vm.executePop() case code.OpTrue: - err = vm.push(True) + err = vm.executeTrue() case code.OpFalse: - err = vm.push(False) + err = vm.executeFalse() case code.OpJump: - pos := int(code.ReadUint16(ins[ip+1:])) - vm.frame.ip = pos - 1 + err = vm.executeJump() case code.OpJumpNotTruthy: - pos := int(code.ReadUint16(ins[ip+1:])) - vm.frame.ip += 2 - if !isTruthy(vm.pop()) { - vm.frame.ip = pos - 1 - } + err = vm.executeJumpIfFalse() case code.OpNull: - err = vm.push(Null) + err = vm.executeNull() case code.OpSetGlobal: - globalIndex := code.ReadUint16(ins[ip+1:]) - vm.frame.ip += 2 - - ref := vm.pop() - if immutable, ok := ref.(object.Immutable); ok { - vm.state.Globals[globalIndex] = immutable.Clone() - } else { - vm.state.Globals[globalIndex] = ref - } - - err = vm.push(Null) + err = vm.executeSetGlobal() case code.OpAssignGlobal: - globalIndex := code.ReadUint16(ins[ip+1:]) - vm.frame.ip += 2 - vm.state.Globals[globalIndex] = vm.pop() - - err = vm.push(Null) + err = vm.executeAssignGlobal() case code.OpAssignLocal: - localIndex := code.ReadUint8(ins[ip+1:]) - vm.frame.ip += 1 - - vm.stack[vm.frame.basePointer+int(localIndex)] = vm.pop() - - err = vm.push(Null) + err = vm.executeAssignLocal() case code.OpGetGlobal: - globalIndex := code.ReadUint16(ins[ip+1:]) - vm.frame.ip += 2 - err = vm.push(vm.state.Globals[globalIndex]) + err = vm.executeGetGlobal() case code.OpArray: - numElements := int(code.ReadUint16(ins[ip+1:])) - vm.frame.ip += 2 - err = vm.executeMakeArray(vm.sp-numElements, vm.sp) + err = vm.executeMakeArray() case code.OpHash: - numElements := int(code.ReadUint16(ins[ip+1:])) - vm.frame.ip += 2 - err = vm.executeMakeHash(vm.sp-numElements, vm.sp) + err = vm.executeMakeHash() case code.OpSetItem: err = vm.executeSetItem() @@ -800,86 +860,77 @@ func (vm *VM) Run() (err error) { err = vm.executeGetItem() case code.OpCall: - args := int(code.ReadUint8(ins[ip+1:])) - vm.frame.ip++ - err = vm.executeCall(args) + err = vm.executeCall() case code.OpReturn: err = vm.executeReturn() case code.OpSetLocal: - localIndex := code.ReadUint8(ins[ip+1:]) - vm.frame.ip += 1 - - ref := vm.pop() - if immutable, ok := ref.(object.Immutable); ok { - vm.stack[vm.frame.basePointer+int(localIndex)] = immutable.Clone() - } else { - vm.stack[vm.frame.basePointer+int(localIndex)] = ref - } - - err = vm.push(Null) + err = vm.executeSetLocal() case code.OpGetLocal: - localIndex := code.ReadUint8(ins[ip+1:]) - vm.frame.ip += 1 - err = vm.push(vm.stack[vm.frame.basePointer+int(localIndex)]) + err = vm.executeGetLocal() case code.OpGetBuiltin: - builtinIndex := code.ReadUint8(ins[ip+1:]) - vm.frame.ip++ - builtin := builtins.BuiltinsIndex[builtinIndex] - err = vm.push(builtin) + err = vm.executeLoadBuiltin() case code.OpClosure: - constIndex := code.ReadUint16(ins[ip+1:]) - numFree := code.ReadUint8(ins[ip+3:]) - vm.frame.ip += 3 - err = vm.pushClosure(int(constIndex), int(numFree)) + err = vm.executeClosure() case code.OpGetFree: - freeIndex := code.ReadUint8(ins[ip+1:]) - vm.frame.ip += 1 - err = vm.push(vm.frame.cl.Free[freeIndex]) + err = vm.executeGetFree() case code.OpCurrentClosure: - currentClosure := vm.frame.cl - err = vm.push(currentClosure) + err = vm.executeCurrentClosure() case code.OpLoadModule: err = vm.executeLoadModule() case code.OpAdd: err = vm.executeAdd() + case code.OpSub: err = vm.executeSub() + case code.OpMul: err = vm.executeMul() + case code.OpDiv: err = vm.executeDiv() + case code.OpMod: err = vm.executeMod() + case code.OpOr: err = vm.executeOr() + case code.OpAnd: err = vm.executeAnd() + case code.OpBitwiseOR: err = vm.executeBitwiseOr() + case code.OpBitwiseXOR: err = vm.executeBitwiseXor() + case code.OpBitwiseAND: err = vm.executeBitwiseAnd() + case code.OpLeftShift: err = vm.executeLeftShift() + case code.OpRightShift: err = vm.executeRightShift() case code.OpEqual: err = vm.executeEqual() + case code.OpNotEqual: err = vm.executeNotEqual() + case code.OpGreaterThan: err = vm.executeGreaterThan() + case code.OpGreaterThanEqual: err = vm.executeGreaterThanOrEqual() @@ -902,7 +953,7 @@ func (vm *VM) Run() (err error) { if vm.Debug { log.Printf( "%-25s [ip=%02d fp=%02d, sp=%02d]", - "", ip, vm.fp-1, vm.sp, + "", vm.frame.ip, vm.fp-1, vm.sp, ) } }