// See https://swtch.com/~rsc/regexp/regexp1.html for inspiration.
//
// These aren't really pointers: they're integers, so we can reinterpret them
-// this way without using package unsafe. A value l denotes
-// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
-// l == 0 denotes the empty list, okay because we start every program
+// this way without using package unsafe. A value l.head denotes
+// p.inst[l.head>>1].Out (l.head&1==0) or .Arg (l.head&1==1).
+// head == 0 denotes the empty list, okay because we start every program
// with a fail instruction, so we'll never want to point at its output link.
-type patchList uint32
+type patchList struct {
+ head, tail uint32
+}
-func (l patchList) next(p *Prog) patchList {
- i := &p.Inst[l>>1]
- if l&1 == 0 {
- return patchList(i.Out)
- }
- return patchList(i.Arg)
+func makePatchList(n uint32) patchList {
+ return patchList{n, n}
}
func (l patchList) patch(p *Prog, val uint32) {
- for l != 0 {
- i := &p.Inst[l>>1]
- if l&1 == 0 {
- l = patchList(i.Out)
+ head := l.head
+ for head != 0 {
+ i := &p.Inst[head>>1]
+ if head&1 == 0 {
+ head = i.Out
i.Out = val
} else {
- l = patchList(i.Arg)
+ head = i.Arg
i.Arg = val
}
}
}
func (l1 patchList) append(p *Prog, l2 patchList) patchList {
- if l1 == 0 {
+ if l1.head == 0 {
return l2
}
- if l2 == 0 {
+ if l2.head == 0 {
return l1
}
- last := l1
- for {
- next := last.next(p)
- if next == 0 {
- break
- }
- last = next
- }
-
- i := &p.Inst[last>>1]
- if last&1 == 0 {
- i.Out = uint32(l2)
+ i := &p.Inst[l1.tail>>1]
+ if l1.tail&1 == 0 {
+ i.Out = l2.head
} else {
- i.Arg = uint32(l2)
+ i.Arg = l2.head
}
- return l1
+ return patchList{l1.head, l2.tail}
}
// A frag represents a compiled program fragment.
func (c *compiler) nop() frag {
f := c.inst(InstNop)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
return f
}
func (c *compiler) cap(arg uint32) frag {
f := c.inst(InstCapture)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
c.p.Inst[f.i].Arg = arg
if c.p.NumCap < int(arg)+1 {
i := &c.p.Inst[f.i]
if nongreedy {
i.Arg = f1.i
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
} else {
i.Out = f1.i
- f.out = patchList(f.i<<1 | 1)
+ f.out = makePatchList(f.i<<1 | 1)
}
f.out = f.out.append(c.p, f1.out)
return f
i := &c.p.Inst[f.i]
if nongreedy {
i.Arg = f1.i
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
} else {
i.Out = f1.i
- f.out = patchList(f.i<<1 | 1)
+ f.out = makePatchList(f.i<<1 | 1)
}
f1.out.patch(c.p, f.i)
return f
func (c *compiler) empty(op EmptyOp) frag {
f := c.inst(InstEmptyWidth)
c.p.Inst[f.i].Arg = uint32(op)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
return f
}
flags &^= FoldCase
}
i.Arg = uint32(flags)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
// Special cases for exec machine.
switch {