package vm import ( "fmt" "jinx/pkg/lang/vm/code" ) type VM struct { code *code.Code pc int stack CallStack } func New(code *code.Code) *VM { return &VM{ code: code, pc: 0, stack: NewCallStack(), } } func (vm *VM) Run() { for vm.pc < vm.code.Len() { op, advance := vm.code.GetOp(vm.pc) vm.pc += advance vm.step(op) } } type stepDecision int const ( stepDecisionContinue stepDecision = iota stepDecisionHalt ) func (vm *VM) step(op code.Op) stepDecision { switch op { case code.OpNop: // do nothing case code.OpHalt: return stepDecisionHalt case code.OpPushInt: x, advance := vm.code.GetInt(vm.pc) vm.pc += advance vm.execPushInt(x) case code.OpPushFloat: x, advance := vm.code.GetFloat(vm.pc) vm.pc += advance vm.execPushFloat(x) case code.OpPushString: str, advance := vm.code.GetString(vm.pc) vm.pc += advance vm.execPushString(str) case code.OpPushNull: vm.execPushNull() case code.OpPushTrue: vm.execPushBool(true) case code.OpPushFalse: vm.execPushBool(false) case code.OpPushArray: vm.execPushArray() case code.OpPushFunction: panic("not implemented") case code.OpPushObject: panic("not implemented") case code.OpGetGlobal: panic("not implemented") case code.OpGetLocal: offset, advance := vm.code.GetInt(vm.pc) vm.pc += advance vm.execGetLocal(int(offset)) case code.OpGetMember: panic("not implemented") case code.OpGetArg: vm.execGetArg() case code.OpGetEnv: panic("not implemented") case code.OpAdd: vm.execAdd() case code.OpSub: vm.execSub() case code.OpIndex: vm.execIndex() case code.OpCall: panic("not implemented") case code.OpJmp: pc, _ := vm.code.GetUint(vm.pc) vm.pc = int(pc) case code.OpJez: panic("not implemented") case code.OpRet: panic("not implemented") default: panic(fmt.Errorf("unimplemented op: %v", op)) } return stepDecisionContinue }