mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +00:00
op: implement StackOp in terms of general save/load of state
Push/Pop only allows saving and restoring operation state in a stack-like manner. We're going to need restoring arbitrary state for implementing deferred operations. Generalize state save/restore and implement Push and Pop on top of that. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+16
-11
@@ -61,6 +61,7 @@ type renderer struct {
|
|||||||
type drawOps struct {
|
type drawOps struct {
|
||||||
profile bool
|
profile bool
|
||||||
reader ops.Reader
|
reader ops.Reader
|
||||||
|
states []drawState
|
||||||
cache *resourceCache
|
cache *resourceCache
|
||||||
vertCache []byte
|
vertCache []byte
|
||||||
viewport image.Point
|
viewport image.Point
|
||||||
@@ -87,7 +88,6 @@ type drawState struct {
|
|||||||
t f32.Affine2D
|
t f32.Affine2D
|
||||||
cpath *pathOp
|
cpath *pathOp
|
||||||
rect bool
|
rect bool
|
||||||
z int
|
|
||||||
|
|
||||||
matType materialType
|
matType materialType
|
||||||
// Current paint.ImageOp
|
// Current paint.ImageOp
|
||||||
@@ -869,11 +869,12 @@ func splitTransform(t f32.Affine2D) (srs f32.Affine2D, offset f32.Point) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *drawOps) collectOps(r *ops.Reader, state drawState) int {
|
func (d *drawOps) collectOps(r *ops.Reader, state drawState) {
|
||||||
var (
|
var (
|
||||||
quads quadsOp
|
quads quadsOp
|
||||||
stroke clip.StrokeStyle
|
stroke clip.StrokeStyle
|
||||||
dashes dashOp
|
dashes dashOp
|
||||||
|
z int
|
||||||
)
|
)
|
||||||
loop:
|
loop:
|
||||||
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
|
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
|
||||||
@@ -995,19 +996,19 @@ loop:
|
|||||||
d.allImageOps = d.allImageOps[:0]
|
d.allImageOps = d.allImageOps[:0]
|
||||||
d.zimageOps = d.zimageOps[:0]
|
d.zimageOps = d.zimageOps[:0]
|
||||||
d.imageOps = d.imageOps[:0]
|
d.imageOps = d.imageOps[:0]
|
||||||
state.z = 0
|
z = 0
|
||||||
d.clearColor = mat.color.Opaque()
|
d.clearColor = mat.color.Opaque()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
state.z++
|
z++
|
||||||
if state.z != int(uint16(state.z)) {
|
if z != int(uint16(z)) {
|
||||||
// TODO(eliasnaur) gioui.org/issue/127.
|
// TODO(eliasnaur) gioui.org/issue/127.
|
||||||
panic("more than 65k paint objects not supported")
|
panic("more than 65k paint objects not supported")
|
||||||
}
|
}
|
||||||
// Assume 16-bit depth buffer.
|
// Assume 16-bit depth buffer.
|
||||||
const zdepth = 1 << 16
|
const zdepth = 1 << 16
|
||||||
// Convert z to window-space, assuming depth range [0;1].
|
// Convert z to window-space, assuming depth range [0;1].
|
||||||
zf := float32(state.z)*2/zdepth - 1.0
|
zf := float32(z)*2/zdepth - 1.0
|
||||||
img := imageOp{
|
img := imageOp{
|
||||||
z: zf,
|
z: zf,
|
||||||
path: state.cpath,
|
path: state.cpath,
|
||||||
@@ -1026,13 +1027,17 @@ loop:
|
|||||||
state.cpath = state.cpath.parent
|
state.cpath = state.cpath.parent
|
||||||
state.rect = wasrect
|
state.rect = wasrect
|
||||||
}
|
}
|
||||||
case opconst.TypePush:
|
case opconst.TypeSave:
|
||||||
state.z = d.collectOps(r, state)
|
id := ops.DecodeSave(encOp.Data)
|
||||||
case opconst.TypePop:
|
if extra := id - len(d.states) + 1; extra > 0 {
|
||||||
break loop
|
d.states = append(d.states, make([]drawState, extra)...)
|
||||||
|
}
|
||||||
|
d.states[id] = state
|
||||||
|
case opconst.TypeLoad:
|
||||||
|
id := ops.DecodeLoad(encOp.Data)
|
||||||
|
state = d.states[id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state.z
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandPathOp(p *pathOp, clip image.Rectangle) {
|
func expandPathOp(p *pathOp, clip image.Rectangle) {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ const (
|
|||||||
TypeKeyInput
|
TypeKeyInput
|
||||||
TypeKeyFocus
|
TypeKeyFocus
|
||||||
TypeKeySoftKeyboard
|
TypeKeySoftKeyboard
|
||||||
TypePush
|
TypeSave
|
||||||
TypePop
|
TypeLoad
|
||||||
TypeAux
|
TypeAux
|
||||||
TypeClip
|
TypeClip
|
||||||
TypeProfile
|
TypeProfile
|
||||||
@@ -54,8 +54,8 @@ const (
|
|||||||
TypeKeyInputLen = 1
|
TypeKeyInputLen = 1
|
||||||
TypeKeyFocusLen = 1 + 1
|
TypeKeyFocusLen = 1 + 1
|
||||||
TypeKeySoftKeyboardLen = 1 + 1
|
TypeKeySoftKeyboardLen = 1 + 1
|
||||||
TypePushLen = 1
|
TypeSaveLen = 1 + 4
|
||||||
TypePopLen = 1
|
TypeLoadLen = 1 + 4
|
||||||
TypeAuxLen = 1
|
TypeAuxLen = 1
|
||||||
TypeClipLen = 1 + 4*4 + 1
|
TypeClipLen = 1 + 4*4 + 1
|
||||||
TypeProfileLen = 1
|
TypeProfileLen = 1
|
||||||
@@ -84,8 +84,8 @@ func (t OpType) Size() int {
|
|||||||
TypeKeyInputLen,
|
TypeKeyInputLen,
|
||||||
TypeKeyFocusLen,
|
TypeKeyFocusLen,
|
||||||
TypeKeySoftKeyboardLen,
|
TypeKeySoftKeyboardLen,
|
||||||
TypePushLen,
|
TypeSaveLen,
|
||||||
TypePopLen,
|
TypeLoadLen,
|
||||||
TypeAuxLen,
|
TypeAuxLen,
|
||||||
TypeClipLen,
|
TypeClipLen,
|
||||||
TypeProfileLen,
|
TypeProfileLen,
|
||||||
|
|||||||
@@ -62,3 +62,21 @@ func DecodeTransform(data []byte) (t f32.Affine2D) {
|
|||||||
f := math.Float32frombits(bo.Uint32(data[4*5:]))
|
f := math.Float32frombits(bo.Uint32(data[4*5:]))
|
||||||
return f32.NewAffine2D(a, b, c, d, e, f)
|
return f32.NewAffine2D(a, b, c, d, e, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeSave decodes the state id of a save op.
|
||||||
|
func DecodeSave(data []byte) int {
|
||||||
|
if opconst.OpType(data[0]) != opconst.TypeSave {
|
||||||
|
panic("invalid op")
|
||||||
|
}
|
||||||
|
bo := binary.LittleEndian
|
||||||
|
return int(bo.Uint32(data[1:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeLoad decodes the state id of a restore op.
|
||||||
|
func DecodeLoad(data []byte) int {
|
||||||
|
if opconst.OpType(data[0]) != opconst.TypeLoad {
|
||||||
|
panic("invalid op")
|
||||||
|
}
|
||||||
|
bo := binary.LittleEndian
|
||||||
|
return int(bo.Uint32(data[1:]))
|
||||||
|
}
|
||||||
|
|||||||
+42
-27
@@ -17,6 +17,14 @@ type keyQueue struct {
|
|||||||
handlers map[event.Tag]*keyHandler
|
handlers map[event.Tag]*keyHandler
|
||||||
reader ops.Reader
|
reader ops.Reader
|
||||||
state TextInputState
|
state TextInputState
|
||||||
|
// states store states during resolveFocus
|
||||||
|
states []resolveState
|
||||||
|
}
|
||||||
|
|
||||||
|
type resolveState struct {
|
||||||
|
tag event.Tag
|
||||||
|
pri listenerPriority
|
||||||
|
keyboard TextInputState
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyHandler struct {
|
type keyHandler struct {
|
||||||
@@ -56,9 +64,9 @@ func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) {
|
|||||||
}
|
}
|
||||||
q.reader.Reset(root)
|
q.reader.Reset(root)
|
||||||
|
|
||||||
focus, pri, keyboard := q.resolveFocus(events)
|
state := q.resolveFocus(events)
|
||||||
if pri == priNone {
|
if state.pri == priNone {
|
||||||
focus = nil
|
state.tag = nil
|
||||||
}
|
}
|
||||||
for k, h := range q.handlers {
|
for k, h := range q.handlers {
|
||||||
if !h.visible {
|
if !h.visible {
|
||||||
@@ -66,26 +74,26 @@ func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) {
|
|||||||
if q.focus == k {
|
if q.focus == k {
|
||||||
// Remove the focus from the handler that is no longer visible.
|
// Remove the focus from the handler that is no longer visible.
|
||||||
q.focus = nil
|
q.focus = nil
|
||||||
keyboard = TextInputClose
|
state.keyboard = TextInputClose
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h.new && k != focus {
|
if h.new && k != state.tag {
|
||||||
// Reset the handler on (each) first appearance.
|
// Reset the handler on (each) first appearance.
|
||||||
events.Add(k, key.FocusEvent{Focus: false})
|
events.Add(k, key.FocusEvent{Focus: false})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if focus != q.focus {
|
if state.tag != q.focus {
|
||||||
if q.focus != nil {
|
if q.focus != nil {
|
||||||
events.Add(q.focus, key.FocusEvent{Focus: false})
|
events.Add(q.focus, key.FocusEvent{Focus: false})
|
||||||
}
|
}
|
||||||
q.focus = focus
|
q.focus = state.tag
|
||||||
if q.focus != nil {
|
if q.focus != nil {
|
||||||
events.Add(q.focus, key.FocusEvent{Focus: true})
|
events.Add(q.focus, key.FocusEvent{Focus: true})
|
||||||
} else {
|
} else {
|
||||||
keyboard = TextInputClose
|
state.keyboard = TextInputClose
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q.state = keyboard
|
q.state = state.keyboard
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
|
func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
|
||||||
@@ -94,28 +102,28 @@ func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *keyQueue) resolveFocus(events *handlerEvents) (tag event.Tag, pri listenerPriority, keyboard TextInputState) {
|
func (q *keyQueue) resolveFocus(events *handlerEvents) resolveState {
|
||||||
loop:
|
var state resolveState
|
||||||
for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
|
for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
|
||||||
switch opconst.OpType(encOp.Data[0]) {
|
switch opconst.OpType(encOp.Data[0]) {
|
||||||
case opconst.TypeKeyFocus:
|
case opconst.TypeKeyFocus:
|
||||||
op := decodeFocusOp(encOp.Data, encOp.Refs)
|
op := decodeFocusOp(encOp.Data, encOp.Refs)
|
||||||
if op.Focus {
|
if op.Focus {
|
||||||
pri = priNewFocus
|
state.pri = priNewFocus
|
||||||
} else {
|
} else {
|
||||||
pri, keyboard = priNone, TextInputClose
|
state.pri, state.keyboard = priNone, TextInputClose
|
||||||
}
|
}
|
||||||
case opconst.TypeKeySoftKeyboard:
|
case opconst.TypeKeySoftKeyboard:
|
||||||
op := decodeSoftKeyboardOp(encOp.Data, encOp.Refs)
|
op := decodeSoftKeyboardOp(encOp.Data, encOp.Refs)
|
||||||
if op.Show {
|
if op.Show {
|
||||||
keyboard = TextInputOpen
|
state.keyboard = TextInputOpen
|
||||||
} else {
|
} else {
|
||||||
keyboard = TextInputClose
|
state.keyboard = TextInputClose
|
||||||
}
|
}
|
||||||
case opconst.TypeKeyInput:
|
case opconst.TypeKeyInput:
|
||||||
op := decodeKeyInputOp(encOp.Data, encOp.Refs)
|
op := decodeKeyInputOp(encOp.Data, encOp.Refs)
|
||||||
if op.Tag == q.focus && pri < priCurrentFocus {
|
if op.Tag == q.focus && state.pri < priCurrentFocus {
|
||||||
pri = priCurrentFocus
|
state.pri = priCurrentFocus
|
||||||
}
|
}
|
||||||
h, ok := q.handlers[op.Tag]
|
h, ok := q.handlers[op.Tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -123,20 +131,27 @@ loop:
|
|||||||
q.handlers[op.Tag] = h
|
q.handlers[op.Tag] = h
|
||||||
}
|
}
|
||||||
h.visible = true
|
h.visible = true
|
||||||
tag = op.Tag
|
state.tag = op.Tag
|
||||||
case opconst.TypePush:
|
case opconst.TypeSave:
|
||||||
newK, newPri, newKeyboard := q.resolveFocus(events)
|
id := ops.DecodeSave(encOp.Data)
|
||||||
if newKeyboard > keyboard {
|
if extra := id - len(q.states) + 1; extra > 0 {
|
||||||
keyboard = newKeyboard
|
q.states = append(q.states, make([]resolveState, extra)...)
|
||||||
}
|
}
|
||||||
if newPri.replaces(pri) {
|
q.states[id] = state
|
||||||
tag, pri = newK, newPri
|
state = resolveState{}
|
||||||
|
case opconst.TypeLoad:
|
||||||
|
id := ops.DecodeLoad(encOp.Data)
|
||||||
|
restored := q.states[id]
|
||||||
|
if state.keyboard > restored.keyboard {
|
||||||
|
restored.keyboard = state.keyboard
|
||||||
}
|
}
|
||||||
case opconst.TypePop:
|
if state.pri.replaces(restored.pri) {
|
||||||
break loop
|
restored.tag, restored.pri = state.tag, state.pri
|
||||||
|
}
|
||||||
|
state = restored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tag, pri, keyboard
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p listenerPriority) replaces(p2 listenerPriority) bool {
|
func (p listenerPriority) replaces(p2 listenerPriority) bool {
|
||||||
|
|||||||
+38
-19
@@ -23,6 +23,8 @@ type pointerQueue struct {
|
|||||||
pointers []pointerInfo
|
pointers []pointerInfo
|
||||||
reader ops.Reader
|
reader ops.Reader
|
||||||
|
|
||||||
|
// states holds the storage for save/restore ops.
|
||||||
|
states []collectState
|
||||||
scratch []event.Tag
|
scratch []event.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,34 +72,51 @@ type areaNode struct {
|
|||||||
|
|
||||||
type areaKind uint8
|
type areaKind uint8
|
||||||
|
|
||||||
|
// collectState represents the state for collectHandlers
|
||||||
|
type collectState struct {
|
||||||
|
t f32.Affine2D
|
||||||
|
area int
|
||||||
|
node int
|
||||||
|
pass bool
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
areaRect areaKind = iota
|
areaRect areaKind = iota
|
||||||
areaEllipse
|
areaEllipse
|
||||||
)
|
)
|
||||||
|
|
||||||
func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t f32.Affine2D, area, node int, pass bool) {
|
func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
|
||||||
|
state := collectState{
|
||||||
|
area: -1,
|
||||||
|
node: -1,
|
||||||
|
}
|
||||||
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
|
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
|
||||||
switch opconst.OpType(encOp.Data[0]) {
|
switch opconst.OpType(encOp.Data[0]) {
|
||||||
case opconst.TypePush:
|
case opconst.TypeSave:
|
||||||
q.collectHandlers(r, events, t, area, node, pass)
|
id := ops.DecodeSave(encOp.Data)
|
||||||
case opconst.TypePop:
|
if extra := id - len(q.states) + 1; extra > 0 {
|
||||||
return
|
q.states = append(q.states, make([]collectState, extra)...)
|
||||||
|
}
|
||||||
|
q.states[id] = state
|
||||||
|
case opconst.TypeLoad:
|
||||||
|
id := ops.DecodeLoad(encOp.Data)
|
||||||
|
state = q.states[id]
|
||||||
case opconst.TypePass:
|
case opconst.TypePass:
|
||||||
pass = encOp.Data[1] != 0
|
state.pass = encOp.Data[1] != 0
|
||||||
case opconst.TypeArea:
|
case opconst.TypeArea:
|
||||||
var op areaOp
|
var op areaOp
|
||||||
op.Decode(encOp.Data)
|
op.Decode(encOp.Data)
|
||||||
q.areas = append(q.areas, areaNode{trans: t, next: area, area: op})
|
q.areas = append(q.areas, areaNode{trans: state.t, next: state.area, area: op})
|
||||||
area = len(q.areas) - 1
|
state.area = len(q.areas) - 1
|
||||||
q.hitTree = append(q.hitTree, hitNode{
|
q.hitTree = append(q.hitTree, hitNode{
|
||||||
next: node,
|
next: state.node,
|
||||||
area: area,
|
area: state.area,
|
||||||
pass: pass,
|
pass: state.pass,
|
||||||
})
|
})
|
||||||
node = len(q.hitTree) - 1
|
state.node = len(q.hitTree) - 1
|
||||||
case opconst.TypeTransform:
|
case opconst.TypeTransform:
|
||||||
dop := ops.DecodeTransform(encOp.Data)
|
dop := ops.DecodeTransform(encOp.Data)
|
||||||
t = t.Mul(dop)
|
state.t = state.t.Mul(dop)
|
||||||
case opconst.TypePointerInput:
|
case opconst.TypePointerInput:
|
||||||
op := pointer.InputOp{
|
op := pointer.InputOp{
|
||||||
Tag: encOp.Refs[0].(event.Tag),
|
Tag: encOp.Refs[0].(event.Tag),
|
||||||
@@ -105,12 +124,12 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t f
|
|||||||
Types: pointer.Type(encOp.Data[2]),
|
Types: pointer.Type(encOp.Data[2]),
|
||||||
}
|
}
|
||||||
q.hitTree = append(q.hitTree, hitNode{
|
q.hitTree = append(q.hitTree, hitNode{
|
||||||
next: node,
|
next: state.node,
|
||||||
area: area,
|
area: state.area,
|
||||||
pass: pass,
|
pass: state.pass,
|
||||||
tag: op.Tag,
|
tag: op.Tag,
|
||||||
})
|
})
|
||||||
node = len(q.hitTree) - 1
|
state.node = len(q.hitTree) - 1
|
||||||
h, ok := q.handlers[op.Tag]
|
h, ok := q.handlers[op.Tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
h = new(pointerHandler)
|
h = new(pointerHandler)
|
||||||
@@ -118,7 +137,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t f
|
|||||||
events.Add(op.Tag, pointer.Event{Type: pointer.Cancel})
|
events.Add(op.Tag, pointer.Event{Type: pointer.Cancel})
|
||||||
}
|
}
|
||||||
h.active = true
|
h.active = true
|
||||||
h.area = area
|
h.area = state.area
|
||||||
h.wantsGrab = h.wantsGrab || op.Grab
|
h.wantsGrab = h.wantsGrab || op.Grab
|
||||||
h.types = h.types | op.Types
|
h.types = h.types | op.Types
|
||||||
case opconst.TypeCursor:
|
case opconst.TypeCursor:
|
||||||
@@ -192,7 +211,7 @@ func (q *pointerQueue) Frame(root *op.Ops, events *handlerEvents) {
|
|||||||
q.areas = q.areas[:0]
|
q.areas = q.areas[:0]
|
||||||
q.cursors = q.cursors[:0]
|
q.cursors = q.cursors[:0]
|
||||||
q.reader.Reset(root)
|
q.reader.Reset(root)
|
||||||
q.collectHandlers(&q.reader, events, f32.Affine2D{}, -1, -1, false)
|
q.collectHandlers(&q.reader, events)
|
||||||
for k, h := range q.handlers {
|
for k, h := range q.handlers {
|
||||||
if !h.active {
|
if !h.active {
|
||||||
q.dropHandlers(events, k)
|
q.dropHandlers(events, k)
|
||||||
|
|||||||
@@ -82,8 +82,11 @@ type Ops struct {
|
|||||||
version int
|
version int
|
||||||
// data contains the serialized operations.
|
// data contains the serialized operations.
|
||||||
data []byte
|
data []byte
|
||||||
// External references for operations.
|
// refs hold external references for operations.
|
||||||
refs []interface{}
|
refs []interface{}
|
||||||
|
// nextStateID is the id allocated for the next
|
||||||
|
// StackOp.
|
||||||
|
nextStateID int
|
||||||
|
|
||||||
stackStack stack
|
stackStack stack
|
||||||
macroStack stack
|
macroStack stack
|
||||||
@@ -92,7 +95,8 @@ type Ops struct {
|
|||||||
// StackOp saves and restores the operation state
|
// StackOp saves and restores the operation state
|
||||||
// in a stack-like manner.
|
// in a stack-like manner.
|
||||||
type StackOp struct {
|
type StackOp struct {
|
||||||
id stackID
|
id int
|
||||||
|
stackID stackID
|
||||||
macroID int
|
macroID int
|
||||||
ops *Ops
|
ops *Ops
|
||||||
}
|
}
|
||||||
@@ -142,13 +146,17 @@ type pc struct {
|
|||||||
|
|
||||||
// Push (save) the current operations state.
|
// Push (save) the current operations state.
|
||||||
func Push(o *Ops) StackOp {
|
func Push(o *Ops) StackOp {
|
||||||
|
o.nextStateID++
|
||||||
s := StackOp{
|
s := StackOp{
|
||||||
ops: o,
|
ops: o,
|
||||||
id: o.stackStack.push(),
|
id: o.nextStateID,
|
||||||
|
stackID: o.stackStack.push(),
|
||||||
macroID: o.macroStack.currentID,
|
macroID: o.macroStack.currentID,
|
||||||
}
|
}
|
||||||
data := o.Write(opconst.TypePushLen)
|
bo := binary.LittleEndian
|
||||||
data[0] = byte(opconst.TypePush)
|
data := o.Write(opconst.TypeSaveLen)
|
||||||
|
data[0] = byte(opconst.TypeSave)
|
||||||
|
bo.PutUint32(data[1:], uint32(s.id))
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,9 +165,11 @@ func (s StackOp) Pop() {
|
|||||||
if s.ops.macroStack.currentID != s.macroID {
|
if s.ops.macroStack.currentID != s.macroID {
|
||||||
panic("pop in a different macro than push")
|
panic("pop in a different macro than push")
|
||||||
}
|
}
|
||||||
s.ops.stackStack.pop(s.id)
|
s.ops.stackStack.pop(s.stackID)
|
||||||
data := s.ops.Write(opconst.TypePopLen)
|
bo := binary.LittleEndian
|
||||||
data[0] = byte(opconst.TypePop)
|
data := s.ops.Write(opconst.TypeLoadLen)
|
||||||
|
data[0] = byte(opconst.TypeLoad)
|
||||||
|
bo.PutUint32(data[1:], uint32(s.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the Ops, preparing it for re-use. Reset invalidates
|
// Reset the Ops, preparing it for re-use. Reset invalidates
|
||||||
@@ -173,6 +183,7 @@ func (o *Ops) Reset() {
|
|||||||
}
|
}
|
||||||
o.data = o.data[:0]
|
o.data = o.data[:0]
|
||||||
o.refs = o.refs[:0]
|
o.refs = o.refs[:0]
|
||||||
|
o.nextStateID = 0
|
||||||
o.version++
|
o.version++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user