github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/internal/ops/reader.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package ops 4 5 import ( 6 "encoding/binary" 7 8 "github.com/gop9/olt/gio/internal/opconst" 9 "github.com/gop9/olt/gio/op" 10 ) 11 12 // Reader parses an ops list. 13 type Reader struct { 14 pc pc 15 stack []macro 16 ops *op.Ops 17 } 18 19 // EncodedOp represents an encoded op returned by 20 // Reader. 21 type EncodedOp struct { 22 Key Key 23 Data []byte 24 Refs []interface{} 25 } 26 27 // Key is a unique key for a given op. 28 type Key struct { 29 ops *op.Ops 30 pc int 31 version int 32 } 33 34 // Shadow of op.MacroOp. 35 type macroOp struct { 36 pc pc 37 } 38 39 // Shadow of op.CallOp. 40 type callOp struct { 41 ops *op.Ops 42 } 43 44 type pc struct { 45 data int 46 refs int 47 } 48 49 type macro struct { 50 ops *op.Ops 51 retPC pc 52 endPC pc 53 } 54 55 type opMacroDef struct { 56 endpc pc 57 } 58 59 // Reset start reading from the op list. 60 func (r *Reader) Reset(ops *op.Ops) { 61 r.stack = r.stack[:0] 62 r.pc = pc{} 63 r.ops = ops 64 } 65 66 func (r *Reader) Decode() (EncodedOp, bool) { 67 if r.ops == nil { 68 return EncodedOp{}, false 69 } 70 for { 71 if len(r.stack) > 0 { 72 b := r.stack[len(r.stack)-1] 73 if r.pc == b.endPC { 74 r.ops = b.ops 75 r.pc = b.retPC 76 r.stack = r.stack[:len(r.stack)-1] 77 continue 78 } 79 } 80 data := r.ops.Data() 81 data = data[r.pc.data:] 82 if len(data) == 0 { 83 return EncodedOp{}, false 84 } 85 key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.Version()} 86 t := opconst.OpType(data[0]) 87 n := t.Size() 88 nrefs := t.NumRefs() 89 data = data[:n] 90 refs := r.ops.Refs() 91 refs = refs[r.pc.refs:] 92 refs = refs[:nrefs] 93 switch t { 94 case opconst.TypeAux: 95 // An Aux operations is always wrapped in a macro, and 96 // its length is the remaining space. 97 block := r.stack[len(r.stack)-1] 98 n += block.endPC.data - r.pc.data - opconst.TypeAuxLen 99 data = data[:n] 100 case opconst.TypeCall: 101 var op callOp 102 op.decode(data, refs) 103 endPC := pc{ 104 data: len(op.ops.Data()), 105 refs: len(op.ops.Refs()), 106 } 107 retPC := r.pc 108 retPC.data += n 109 retPC.refs += nrefs 110 r.stack = append(r.stack, macro{ 111 ops: r.ops, 112 retPC: retPC, 113 endPC: endPC, 114 }) 115 r.pc = pc{} 116 r.ops = op.ops 117 continue 118 case opconst.TypeMacro: 119 var op macroOp 120 op.decode(data) 121 macroData := r.ops.Data()[op.pc.data:] 122 if opconst.OpType(macroData[0]) != opconst.TypeMacroDef { 123 panic("invalid macro reference") 124 } 125 var opDef opMacroDef 126 opDef.decode(macroData[:opconst.TypeMacroDef.Size()]) 127 retPC := r.pc 128 retPC.data += n 129 retPC.refs += nrefs 130 r.stack = append(r.stack, macro{ 131 ops: r.ops, 132 retPC: retPC, 133 endPC: opDef.endpc, 134 }) 135 r.pc = op.pc 136 r.pc.data += opconst.TypeMacroDef.Size() 137 r.pc.refs += opconst.TypeMacroDef.NumRefs() 138 continue 139 case opconst.TypeMacroDef: 140 var op opMacroDef 141 op.decode(data) 142 r.pc = op.endpc 143 continue 144 } 145 r.pc.data += n 146 r.pc.refs += nrefs 147 return EncodedOp{Key: key, Data: data, Refs: refs}, true 148 } 149 } 150 151 func (op *opMacroDef) decode(data []byte) { 152 if opconst.OpType(data[0]) != opconst.TypeMacroDef { 153 panic("invalid op") 154 } 155 bo := binary.LittleEndian 156 dataIdx := int(int32(bo.Uint32(data[1:]))) 157 refsIdx := int(int32(bo.Uint32(data[5:]))) 158 *op = opMacroDef{ 159 endpc: pc{ 160 data: dataIdx, 161 refs: refsIdx, 162 }, 163 } 164 } 165 166 func (m *callOp) decode(data []byte, refs []interface{}) { 167 if opconst.OpType(data[0]) != opconst.TypeCall { 168 panic("invalid op") 169 } 170 *m = callOp{ 171 ops: refs[0].(*op.Ops), 172 } 173 } 174 175 func (m *macroOp) decode(data []byte) { 176 if opconst.OpType(data[0]) != opconst.TypeMacro { 177 panic("invalid op") 178 } 179 bo := binary.LittleEndian 180 dataIdx := int(int32(bo.Uint32(data[1:]))) 181 refsIdx := int(int32(bo.Uint32(data[5:]))) 182 *m = macroOp{ 183 pc: pc{ 184 data: dataIdx, 185 refs: refsIdx, 186 }, 187 } 188 }