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) GetResult() (string, error) { res, err := vm.stack.Top().Pop() if err != nil { return "", err } return fmt.Sprintf("%v", res.Data()), nil } func (vm *VM) Run() error { for vm.pc < vm.code.Len() { op, advance := vm.code.GetOp(vm.pc) vm.pc += advance if decision, err := vm.step(op); err != nil { return err } else if decision == stepDecisionHalt { return nil } } return nil } type stepDecision int const ( stepDecisionContinue stepDecision = iota stepDecisionHalt ) func (vm *VM) step(op code.Op) (stepDecision, error) { var err error switch op { case code.OpNop: // do nothing case code.OpHalt: return stepDecisionHalt, nil 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 err = vm.execGetLocal(int(offset)) case code.OpGetMember: panic("not implemented") case code.OpGetArg: vm.execGetArg() case code.OpGetEnv: panic("not implemented") case code.OpAdd: err = vm.execAdd() case code.OpSub: err = vm.execSub() case code.OpIndex: err = 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: err = ErrInvalidOp{Op: uint8(op)} } return stepDecisionContinue, err }