package regexp
import (
)
type onePassProg struct {
Inst []onePassInst
Start int
NumCap int
}
type onePassInst struct {
syntax.Inst
Next []uint32
}
func ( *syntax.Prog) ( string, bool, uint32) {
:= &.Inst[.Start]
if .Op != syntax.InstEmptyWidth || (syntax.EmptyOp(.Arg))&syntax.EmptyBeginText == 0 {
return "", .Op == syntax.InstMatch, uint32(.Start)
}
= .Out
= &.Inst[]
for .Op == syntax.InstNop {
= .Out
= &.Inst[]
}
if iop() != syntax.InstRune || len(.Rune) != 1 {
return "", .Op == syntax.InstMatch, uint32(.Start)
}
var strings.Builder
for iop() == syntax.InstRune && len(.Rune) == 1 && syntax.Flags(.Arg)&syntax.FoldCase == 0 {
.WriteRune(.Rune[0])
, = .Out, &.Inst[.Out]
}
if .Op == syntax.InstEmptyWidth &&
syntax.EmptyOp(.Arg)&syntax.EmptyEndText != 0 &&
.Inst[.Out].Op == syntax.InstMatch {
= true
}
return .String(), ,
}
func ( *onePassInst, rune) uint32 {
:= .MatchRunePos()
if >= 0 {
return .Next[]
}
if .Op == syntax.InstAltMatch {
return .Out
}
return 0
}
func ( *syntax.Inst) syntax.InstOp {
:= .Op
switch {
case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
= syntax.InstRune
}
return
}
type queueOnePass struct {
sparse []uint32
dense []uint32
size, nextIndex uint32
}
func ( *queueOnePass) () bool {
return .nextIndex >= .size
}
func ( *queueOnePass) () ( uint32) {
= .dense[.nextIndex]
.nextIndex++
return
}
func ( *queueOnePass) () {
.size = 0
.nextIndex = 0
}
func ( *queueOnePass) ( uint32) bool {
if >= uint32(len(.sparse)) {
return false
}
return .sparse[] < .size && .dense[.sparse[]] ==
}
func ( *queueOnePass) ( uint32) {
if !.contains() {
.insertNew()
}
}
func ( *queueOnePass) ( uint32) {
if >= uint32(len(.sparse)) {
return
}
.sparse[] = .size
.dense[.size] =
.size++
}
func ( int) ( *queueOnePass) {
return &queueOnePass{
sparse: make([]uint32, ),
dense: make([]uint32, ),
}
}
const mergeFailed = uint32(0xffffffff)
var (
noRune = []rune{}
noNext = []uint32{mergeFailed}
)
func (, *[]rune, , uint32) ([]rune, []uint32) {
:= len(*)
:= len(*)
if &0x1 != 0 || &0x1 != 0 {
panic("mergeRuneSets odd length []rune")
}
var (
, int
)
:= make([]rune, 0)
:= make([]uint32, 0)
:= true
defer func() {
if ! {
= nil
= nil
}
}()
:= -1
:= func( *int, *[]rune, uint32) bool {
if > 0 && (*)[*] <= [] {
return false
}
= append(, (*)[*], (*)[*+1])
* += 2
+= 2
= append(, )
return true
}
for < || < {
switch {
case >= :
= (&, , )
case >= :
= (&, , )
case (*)[] < (*)[]:
= (&, , )
default:
= (&, , )
}
if ! {
return noRune, noNext
}
}
return ,
}
func ( *onePassProg, *syntax.Prog) {
for , := range .Inst {
switch .Op {
case syntax.InstAlt, syntax.InstAltMatch, syntax.InstRune:
case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop, syntax.InstMatch, syntax.InstFail:
.Inst[].Next = nil
case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
.Inst[].Next = nil
.Inst[] = onePassInst{Inst: }
}
}
}
func ( *syntax.Prog) *onePassProg {
:= &onePassProg{
Start: .Start,
NumCap: .NumCap,
Inst: make([]onePassInst, len(.Inst)),
}
for , := range .Inst {
.Inst[] = onePassInst{Inst: }
}
for := range .Inst {
switch .Inst[].Op {
default:
continue
case syntax.InstAlt, syntax.InstAltMatch:
:= &.Inst[].Out
:= &.Inst[].Arg
:= .Inst[*]
if !(.Op == syntax.InstAlt || .Op == syntax.InstAltMatch) {
, = ,
= .Inst[*]
if !(.Op == syntax.InstAlt || .Op == syntax.InstAltMatch) {
continue
}
}
:= .Inst[*]
if .Op == syntax.InstAlt || .Op == syntax.InstAltMatch {
continue
}
:= &.Inst[*].Out
:= &.Inst[*].Arg
:= false
if .Out == uint32() {
= true
} else if .Arg == uint32() {
= true
, = ,
}
if {
* = *
}
if * == * {
* = *
}
}
}
return
}
type runeSlice []rune
func ( runeSlice) () int { return len() }
func ( runeSlice) (, int) bool { return [] < [] }
func ( runeSlice) (, int) { [], [] = [], [] }
var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
var anyRune = []rune{0, unicode.MaxRune}
func ( *onePassProg) *onePassProg {
if len(.Inst) >= 1000 {
return nil
}
var (
= newQueue(len(.Inst))
= newQueue(len(.Inst))
func(uint32, []bool) bool
= make([][]rune, len(.Inst))
)
= func( uint32, []bool) ( bool) {
= true
:= &.Inst[]
if .contains() {
return
}
.insert()
switch .Op {
case syntax.InstAlt, syntax.InstAltMatch:
= (.Out, ) && (.Arg, )
:= [.Out]
:= [.Arg]
if && {
= false
break
}
if {
.Out, .Arg = .Arg, .Out
, = ,
}
if {
[] = true
.Op = syntax.InstAltMatch
}
[], .Next = mergeRuneSets(
&[.Out], &[.Arg], .Out, .Arg)
if len(.Next) > 0 && .Next[0] == mergeFailed {
= false
break
}
case syntax.InstCapture, syntax.InstNop:
= (.Out, )
[] = [.Out]
[] = append([]rune{}, [.Out]...)
.Next = make([]uint32, len([])/2+1)
for := range .Next {
.Next[] = .Out
}
case syntax.InstEmptyWidth:
= (.Out, )
[] = [.Out]
[] = append([]rune{}, [.Out]...)
.Next = make([]uint32, len([])/2+1)
for := range .Next {
.Next[] = .Out
}
case syntax.InstMatch, syntax.InstFail:
[] = .Op == syntax.InstMatch
case syntax.InstRune:
[] = false
if len(.Next) > 0 {
break
}
.insert(.Out)
if len(.Rune) == 0 {
[] = []rune{}
.Next = []uint32{.Out}
break
}
:= make([]rune, 0)
if len(.Rune) == 1 && syntax.Flags(.Arg)&syntax.FoldCase != 0 {
:= .Rune[0]
= append(, , )
for := unicode.SimpleFold(); != ; = unicode.SimpleFold() {
= append(, , )
}
sort.Sort(runeSlice())
} else {
= append(, .Rune...)
}
[] =
.Next = make([]uint32, len([])/2+1)
for := range .Next {
.Next[] = .Out
}
.Op = syntax.InstRune
case syntax.InstRune1:
[] = false
if len(.Next) > 0 {
break
}
.insert(.Out)
:= []rune{}
if syntax.Flags(.Arg)&syntax.FoldCase != 0 {
:= .Rune[0]
= append(, , )
for := unicode.SimpleFold(); != ; = unicode.SimpleFold() {
= append(, , )
}
sort.Sort(runeSlice())
} else {
= append(, .Rune[0], .Rune[0])
}
[] =
.Next = make([]uint32, len([])/2+1)
for := range .Next {
.Next[] = .Out
}
.Op = syntax.InstRune
case syntax.InstRuneAny:
[] = false
if len(.Next) > 0 {
break
}
.insert(.Out)
[] = append([]rune{}, anyRune...)
.Next = []uint32{.Out}
case syntax.InstRuneAnyNotNL:
[] = false
if len(.Next) > 0 {
break
}
.insert(.Out)
[] = append([]rune{}, anyRuneNotNL...)
.Next = make([]uint32, len([])/2+1)
for := range .Next {
.Next[] = .Out
}
}
return
}
.clear()
.insert(uint32(.Start))
:= make([]bool, len(.Inst))
for !.empty() {
.clear()
:= .next()
if !(, ) {
= nil
break
}
}
if != nil {
for := range .Inst {
.Inst[].Rune = []
}
}
return
}
func ( *syntax.Prog) ( *onePassProg) {
if .Start == 0 {
return nil
}
if .Inst[.Start].Op != syntax.InstEmptyWidth ||
syntax.EmptyOp(.Inst[.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText {
return nil
}
for , := range .Inst {
:= .Inst[.Out].Op
switch .Op {
default:
if == syntax.InstMatch {
return nil
}
case syntax.InstAlt, syntax.InstAltMatch:
if == syntax.InstMatch || .Inst[.Arg].Op == syntax.InstMatch {
return nil
}
case syntax.InstEmptyWidth:
if == syntax.InstMatch {
if syntax.EmptyOp(.Arg)&syntax.EmptyEndText == syntax.EmptyEndText {
continue
}
return nil
}
}
}
= onePassCopy()
= makeOnePass()
if != nil {
cleanupOnePass(, )
}
return
}