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