package regexp
import (
)
type queue struct {
sparse []uint32
dense []entry
}
type entry struct {
pc uint32
t *thread
}
type thread struct {
inst *syntax.Inst
cap []int
}
type machine struct {
re *Regexp
p *syntax.Prog
q0, q1 queue
pool []*thread
matched bool
matchcap []int
inputs inputs
}
type inputs struct {
bytes inputBytes
string inputString
reader inputReader
}
func ( *inputs) ( []byte) input {
.bytes.str =
return &.bytes
}
func ( *inputs) ( string) input {
.string.str =
return &.string
}
func ( *inputs) ( io.RuneReader) input {
.reader.r =
.reader.atEOT = false
.reader.pos = 0
return &.reader
}
func ( *inputs) () {
if .bytes.str != nil {
.bytes.str = nil
} else if .reader.r != nil {
.reader.r = nil
} else {
.string.str = ""
}
}
func ( *inputs) ( io.RuneReader, []byte, string) (input, int) {
if != nil {
return .newReader(), 0
}
if != nil {
return .newBytes(), len()
}
return .newString(), len()
}
func ( *machine) ( int) {
for , := range .pool {
.cap = .cap[:]
}
.matchcap = .matchcap[:]
}
func ( *machine) ( *syntax.Inst) *thread {
var *thread
if := len(.pool); > 0 {
= .pool[-1]
.pool = .pool[:-1]
} else {
= new(thread)
.cap = make([]int, len(.matchcap), cap(.matchcap))
}
.inst =
return
}
type lazyFlag uint64
func (, rune) lazyFlag {
return lazyFlag(uint64()<<32 | uint64(uint32()))
}
func ( lazyFlag) ( syntax.EmptyOp) bool {
if == 0 {
return true
}
:= rune( >> 32)
if &syntax.EmptyBeginLine != 0 {
if != '\n' && >= 0 {
return false
}
&^= syntax.EmptyBeginLine
}
if &syntax.EmptyBeginText != 0 {
if >= 0 {
return false
}
&^= syntax.EmptyBeginText
}
if == 0 {
return true
}
:= rune()
if &syntax.EmptyEndLine != 0 {
if != '\n' && >= 0 {
return false
}
&^= syntax.EmptyEndLine
}
if &syntax.EmptyEndText != 0 {
if >= 0 {
return false
}
&^= syntax.EmptyEndText
}
if == 0 {
return true
}
if syntax.IsWordChar() != syntax.IsWordChar() {
&^= syntax.EmptyWordBoundary
} else {
&^= syntax.EmptyNoWordBoundary
}
return == 0
}
func ( *machine) ( input, int) bool {
:= .re.cond
if == ^syntax.EmptyOp(0) {
return false
}
.matched = false
for := range .matchcap {
.matchcap[] = -1
}
, := &.q0, &.q1
, := endOfText, endOfText
, := 0, 0
, = .step()
if != endOfText {
, = .step( + )
}
var lazyFlag
if == 0 {
= newLazyFlag(-1, )
} else {
= .context()
}
for {
if len(.dense) == 0 {
if &syntax.EmptyBeginText != 0 && != 0 {
break
}
if .matched {
break
}
if len(.re.prefix) > 0 && != .re.prefixRune && .canCheckPrefix() {
:= .index(.re, )
if < 0 {
break
}
+=
, = .step()
, = .step( + )
}
}
if !.matched {
if len(.matchcap) > 0 {
.matchcap[0] =
}
.add(, uint32(.p.Start), , .matchcap, &, nil)
}
= newLazyFlag(, )
.step(, , , +, , &)
if == 0 {
break
}
if len(.matchcap) == 0 && .matched {
break
}
+=
, = ,
if != endOfText {
, = .step( + )
}
, = ,
}
.clear()
return .matched
}
func ( *machine) ( *queue) {
for , := range .dense {
if .t != nil {
.pool = append(.pool, .t)
}
}
.dense = .dense[:0]
}
func ( *machine) (, *queue, , int, rune, *lazyFlag) {
:= .re.longest
for := 0; < len(.dense); ++ {
:= &.dense[]
:= .t
if == nil {
continue
}
if && .matched && len(.cap) > 0 && .matchcap[0] < .cap[0] {
.pool = append(.pool, )
continue
}
:= .inst
:= false
switch .Op {
default:
panic("bad inst")
case syntax.InstMatch:
if len(.cap) > 0 && (! || !.matched || .matchcap[1] < ) {
.cap[1] =
copy(.matchcap, .cap)
}
if ! {
for , := range .dense[+1:] {
if .t != nil {
.pool = append(.pool, .t)
}
}
.dense = .dense[:0]
}
.matched = true
case syntax.InstRune:
= .MatchRune()
case syntax.InstRune1:
= == .Rune[0]
case syntax.InstRuneAny:
= true
case syntax.InstRuneAnyNotNL:
= != '\n'
}
if {
= .add(, .Out, , .cap, , )
}
if != nil {
.pool = append(.pool, )
}
}
.dense = .dense[:0]
}
func ( *machine) ( *queue, uint32, int, []int, *lazyFlag, *thread) *thread {
:
if == 0 {
return
}
if := .sparse[]; < uint32(len(.dense)) && .dense[].pc == {
return
}
:= len(.dense)
.dense = .dense[:+1]
:= &.dense[]
.t = nil
.pc =
.sparse[] = uint32()
:= &.p.Inst[]
switch .Op {
default:
panic("unhandled")
case syntax.InstFail:
case syntax.InstAlt, syntax.InstAltMatch:
= .(, .Out, , , , )
= .Arg
goto
case syntax.InstEmptyWidth:
if .match(syntax.EmptyOp(.Arg)) {
= .Out
goto
}
case syntax.InstNop:
= .Out
goto
case syntax.InstCapture:
if int(.Arg) < len() {
:= [.Arg]
[.Arg] =
.(, .Out, , , , nil)
[.Arg] =
} else {
= .Out
goto
}
case syntax.InstMatch, syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
if == nil {
= .alloc()
} else {
.inst =
}
if len() > 0 && &.cap[0] != &[0] {
copy(.cap, )
}
.t =
= nil
}
return
}
type onePassMachine struct {
inputs inputs
matchcap []int
}
var onePassPool sync.Pool
func () *onePassMachine {
, := onePassPool.Get().(*onePassMachine)
if ! {
= new(onePassMachine)
}
return
}
func ( *onePassMachine) {
.inputs.clear()
onePassPool.Put()
}
func ( *Regexp) ( io.RuneReader, []byte, string, , int, []int) []int {
:= .cond
if == ^syntax.EmptyOp(0) {
return nil
}
:= newOnePassMachine()
if cap(.matchcap) < {
.matchcap = make([]int, )
} else {
.matchcap = .matchcap[:]
}
:= false
for := range .matchcap {
.matchcap[] = -1
}
, := .inputs.init(, , )
, := endOfText, endOfText
, := 0, 0
, = .step()
if != endOfText {
, = .step( + )
}
var lazyFlag
if == 0 {
= newLazyFlag(-1, )
} else {
= .context()
}
:= .onepass.Start
:= .onepass.Inst[]
if == 0 && .match(syntax.EmptyOp(.Arg)) &&
len(.prefix) > 0 && .canCheckPrefix() {
if !.hasPrefix() {
goto
}
+= len(.prefix)
, = .step()
, = .step( + )
= .context()
= int(.prefixEnd)
}
for {
= .onepass.Inst[]
= int(.Out)
switch .Op {
default:
panic("bad inst")
case syntax.InstMatch:
= true
if len(.matchcap) > 0 {
.matchcap[0] = 0
.matchcap[1] =
}
goto
case syntax.InstRune:
if !.MatchRune() {
goto
}
case syntax.InstRune1:
if != .Rune[0] {
goto
}
case syntax.InstRuneAny:
case syntax.InstRuneAnyNotNL:
if == '\n' {
goto
}
case syntax.InstAlt, syntax.InstAltMatch:
= int(onePassNext(&, ))
continue
case syntax.InstFail:
goto
case syntax.InstNop:
continue
case syntax.InstEmptyWidth:
if !.match(syntax.EmptyOp(.Arg)) {
goto
}
continue
case syntax.InstCapture:
if int(.Arg) < len(.matchcap) {
.matchcap[.Arg] =
}
continue
}
if == 0 {
break
}
= newLazyFlag(, )
+=
, = ,
if != endOfText {
, = .step( + )
}
}
:
if ! {
freeOnePassMachine()
return nil
}
= append(, .matchcap...)
freeOnePassMachine()
return
}
func ( *Regexp) ( io.RuneReader, []byte, string) bool {
return .doExecute(, , , 0, 0, nil) != nil
}
func ( *Regexp) ( io.RuneReader, []byte, string, int, int, []int) []int {
if == nil {
= arrayNoInts[:0:0]
}
if == nil && len()+len() < .minInputLen {
return nil
}
if .onepass != nil {
return .doOnePass(, , , , , )
}
if == nil && len()+len() < .maxBitStateLen {
return .backtrack(, , , , )
}
:= .get()
, := .inputs.init(, , )
.init()
if !.match(, ) {
.put()
return nil
}
= append(, .matchcap...)
.put()
return
}
var arrayNoInts [0]int