func (e *Emitter) addInstr(fn *bytecode.Fn, op bytecode.Opcode, flg bytecode.Flag, ix uint64) { if e.err != nil { return } switch op { case bytecode.OP_PUSH: e.stackSz[fn] += 1 case bytecode.OP_NEW: e.stackSz[fn] += (1 - (2 * int64(ix))) case bytecode.OP_POP, bytecode.OP_RET, bytecode.OP_UNM, bytecode.OP_NOT, bytecode.OP_TEST, bytecode.OP_LT, bytecode.OP_LTE, bytecode.OP_GT, bytecode.OP_GTE, bytecode.OP_EQ, bytecode.OP_ADD, bytecode.OP_SUB, bytecode.OP_MUL, bytecode.OP_DIV, bytecode.OP_MOD, bytecode.OP_GFLD, bytecode.OP_NEQ: e.stackSz[fn] -= 1 case bytecode.OP_SFLD: e.stackSz[fn] -= 3 case bytecode.OP_CALL: e.stackSz[fn] -= (int64(ix) + 1) case bytecode.OP_CFLD: e.stackSz[fn] -= (int64(ix) + 2) } if e.stackSz[fn] > fn.Header.StackSz { fn.Header.StackSz = e.stackSz[fn] } fn.Is = append(fn.Is, bytecode.NewInstr(op, flg, ix)) }
func (a *Asm) readIs(fn *bytecode.Fn) { var l string var ok bool // While a new F section is not reached for l, ok = a.getLine(false); ok && l != "[f]"; l, ok = a.getLine(false) { // Split in three parts parts := strings.SplitN(l, " ", 3) if a.assertIParts(parts) { var ix uint64 o := bytecode.NewOpcode(parts[0]) f := bytecode.NewFlag(parts[1]) ix, a.err = strconv.ParseUint(parts[2], 10, 64) fn.Is = append(fn.Is, bytecode.NewInstr(o, f, ix)) } } if ok { a.readFn() } }
exp: &bytecode.File{ Fns: []*bytecode.Fn{ &bytecode.Fn{ // := emits Second before First, so literal is K0 Ks: []*bytecode.K{ &bytecode.K{ Type: bytecode.KtInteger, Val: int64(5), }, &bytecode.K{ Type: bytecode.KtString, Val: "a", }, }, Is: []bytecode.Instr{ bytecode.NewInstr(bytecode.OP_PUSH, bytecode.FLG_K, 0), bytecode.NewInstr(bytecode.OP_POP, bytecode.FLG_V, 1), }, }, }, }, }, 1: { // return nil src: []*parser.Symbol{ &parser.Symbol{Id: "return", Ar: parser.ArStatement, First: &parser.Symbol{Id: "nil", Ar: parser.ArName, Val: nil}}, }, exp: &bytecode.File{ Fns: []*bytecode.Fn{ &bytecode.Fn{ Is: []bytecode.Instr{
func (e *Emitter) updateJumpfInstr(fn *bytecode.Fn, ix int) { fn.Is[ix] = bytecode.NewInstr(bytecode.OP_JMP, bytecode.FLG_Jf, uint64(len(fn.Is)-ix-1)) }
func (e *Emitter) updateTestInstr(fn *bytecode.Fn, ix int) { fn.Is[ix] = bytecode.NewInstr(bytecode.OP_TEST, bytecode.FLG_Jf, uint64(len(fn.Is)-ix-1)) }
i5 [l] [i] PUSH K 1 // Push constant value 5 on the stack POP V 0 // Pop the value from the stack into variable identified by constant 0 (a) PUSH V 0 // Push value of variable identified by constant 0 on the stack (a) DUMP S 1 RET _ 0 `, exp: AppendAny(SigVer(bytecode.Version()), Int64ToByteSlice(4), 't', 'e', 's', 't', // StackSz - ExpArgs - ParentFnIx - LineStart - LineEnd Int64ToByteSlice(1), ExpZeroInt64, ExpZeroInt64, ExpZeroInt64, Int64ToByteSlice(2), // Ks - Ls - Is Int64ToByteSlice(2), 's', Int64ToByteSlice(1), 'a', 'i', Int64ToByteSlice(5), ExpZeroInt64, Int64ToByteSlice(5), // 5 ops UInt64ToByteSlice(uint64(bytecode.NewInstr(bytecode.NewOpcode("PUSH"), bytecode.NewFlag("K"), 1))), UInt64ToByteSlice(uint64(bytecode.NewInstr(bytecode.NewOpcode("POP"), bytecode.NewFlag("V"), 0))), UInt64ToByteSlice(uint64(bytecode.NewInstr(bytecode.NewOpcode("PUSH"), bytecode.NewFlag("V"), 0))), UInt64ToByteSlice(uint64(bytecode.NewInstr(bytecode.NewOpcode("DUMP"), bytecode.NewFlag("S"), 1))), UInt64ToByteSlice(uint64(bytecode.NewInstr(bytecode.NewOpcode("RET"), bytecode.NewFlag("_"), 0))), ), }, 3: { // Unknown opcode id: "test", src: ` [f] test 1 0 0