Refactor VM and next instruction and argument reading
Some checks failed
Build / build (push) Failing after 6m1s
Publish Image / publish (push) Failing after 38s
Test / build (push) Failing after 6m23s

This commit is contained in:
Chuck Smith
2024-03-31 09:09:04 -04:00
parent c8de195ac8
commit 7a32cce8a1
2 changed files with 173 additions and 110 deletions

View File

@@ -14,18 +14,30 @@ type Frame struct {
func NewFrame(cl *object.Closure, basePointer int) *Frame { func NewFrame(cl *object.Closure, basePointer int) *Frame {
return &Frame{ return &Frame{
cl: cl, cl: cl,
ip: -1,
basePointer: basePointer, basePointer: basePointer,
} }
} }
// NextOp ... func (f *Frame) ReadNextOp() code.Opcode {
func (f *Frame) NextOp() code.Opcode { op := code.Opcode(f.cl.Fn.Instructions[f.ip])
return code.Opcode(f.Instructions()[f.ip+1]) f.ip++
return op
} }
func (f *Frame) Reset() { func (f *Frame) PeekNextOp() code.Opcode {
f.ip = -1 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 { func (f *Frame) Instructions() code.Instructions {

View File

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