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  }