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