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