You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
5.7 KiB
Go
223 lines
5.7 KiB
Go
package ac
|
|
|
|
type automaton interface {
|
|
Repr() *iRepr
|
|
MatchKind() *matchKind
|
|
Anchored() bool
|
|
Prefilter() prefilter
|
|
StartState() stateID
|
|
IsValid(stateID) bool
|
|
IsMatchState(stateID) bool
|
|
IsMatchOrDeadState(stateID) bool
|
|
GetMatch(stateID, int, int) *Match
|
|
MatchCount(stateID) int
|
|
NextState(stateID, byte) stateID
|
|
NextStateNoFail(stateID, byte) stateID
|
|
StandardFindAt(*prefilterState, []byte, int, *stateID) *Match
|
|
StandardFindAtImp(*prefilterState, prefilter, []byte, int, *stateID) *Match
|
|
LeftmostFindAt(*prefilterState, []byte, int, *stateID) *Match
|
|
LeftmostFindAtImp(*prefilterState, prefilter, []byte, int, *stateID) *Match
|
|
LeftmostFindAtNoState(*prefilterState, []byte, int) *Match
|
|
LeftmostFindAtNoStateImp(*prefilterState, prefilter, []byte, int) *Match
|
|
OverlappingFindAt(*prefilterState, []byte, int, *stateID, *int) *Match
|
|
EarliestFindAt(*prefilterState, []byte, int, *stateID) *Match
|
|
FindAt(*prefilterState, []byte, int, *stateID) *Match
|
|
FindAtNoState(*prefilterState, []byte, int) *Match
|
|
}
|
|
|
|
func isMatchOrDeadState(a automaton, si stateID) bool {
|
|
return si == deadStateID || a.IsMatchState(si)
|
|
}
|
|
|
|
func standardFindAt(a automaton, prestate *prefilterState, haystack []byte, at int, sID *stateID) *Match {
|
|
pre := a.Prefilter()
|
|
return a.StandardFindAtImp(prestate, pre, haystack, at, sID)
|
|
}
|
|
|
|
func standardFindAtImp(a automaton, prestate *prefilterState, prefilter prefilter, haystack []byte, at int, sID *stateID) *Match {
|
|
for at < len(haystack) {
|
|
if prefilter != nil {
|
|
startState := a.StartState()
|
|
if prestate.IsEffective(at) && sID == &startState {
|
|
c, typ := nextPrefilter(prestate, prefilter, haystack, at)
|
|
switch typ {
|
|
case noneCandidate:
|
|
return nil
|
|
case possibleStartOfMatchCandidate:
|
|
i := c.(int)
|
|
at = i
|
|
}
|
|
}
|
|
}
|
|
*sID = a.NextStateNoFail(*sID, haystack[at])
|
|
at += 1
|
|
|
|
if a.IsMatchOrDeadState(*sID) {
|
|
if *sID == deadStateID {
|
|
return nil
|
|
} else {
|
|
return a.GetMatch(*sID, 0, at)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func leftmostFindAt(a automaton, prestate *prefilterState, haystack []byte, at int, sID *stateID) *Match {
|
|
prefilter := a.Prefilter()
|
|
return a.LeftmostFindAtImp(prestate, prefilter, haystack, at, sID)
|
|
}
|
|
|
|
func leftmostFindAtImp(a automaton, prestate *prefilterState, prefilter prefilter, haystack []byte, at int, sID *stateID) *Match {
|
|
if a.Anchored() && at > 0 && *sID == a.StartState() {
|
|
return nil
|
|
}
|
|
lastMatch := a.GetMatch(*sID, 0, at)
|
|
|
|
for at < len(haystack) {
|
|
if prefilter != nil {
|
|
startState := a.StartState()
|
|
if prestate.IsEffective(at) && sID == &startState {
|
|
c, typ := nextPrefilter(prestate, prefilter, haystack, at)
|
|
switch typ {
|
|
case noneCandidate:
|
|
return nil
|
|
case possibleStartOfMatchCandidate:
|
|
i := c.(int)
|
|
at = i
|
|
}
|
|
}
|
|
}
|
|
|
|
*sID = a.NextStateNoFail(*sID, haystack[at])
|
|
at += 1
|
|
|
|
if a.IsMatchOrDeadState(*sID) {
|
|
if *sID == deadStateID {
|
|
return lastMatch
|
|
} else {
|
|
a.GetMatch(*sID, 0, at)
|
|
}
|
|
}
|
|
}
|
|
|
|
return lastMatch
|
|
}
|
|
|
|
func leftmostFindAtNoState(a automaton, prestate *prefilterState, haystack []byte, at int) *Match {
|
|
return leftmostFindAtNoStateImp(a, prestate, a.Prefilter(), haystack, at)
|
|
}
|
|
|
|
func leftmostFindAtNoStateImp(a automaton, prestate *prefilterState, prefilter prefilter, haystack []byte, at int) *Match {
|
|
if a.Anchored() && at > 0 {
|
|
return nil
|
|
}
|
|
if prefilter != nil && !prefilter.ReportsFalsePositives() {
|
|
c, typ := prefilter.NextCandidate(prestate, haystack, at)
|
|
switch typ {
|
|
case noneCandidate:
|
|
return nil
|
|
case matchCandidate:
|
|
m := c.(*Match)
|
|
return m
|
|
}
|
|
}
|
|
|
|
stateID := a.StartState()
|
|
lastMatch := a.GetMatch(stateID, 0, at)
|
|
|
|
for at < len(haystack) {
|
|
if prefilter != nil && prestate.IsEffective(at) && stateID == a.StartState() {
|
|
c, typ := prefilter.NextCandidate(prestate, haystack, at)
|
|
switch typ {
|
|
case noneCandidate:
|
|
return nil
|
|
case matchCandidate:
|
|
m := c.(*Match)
|
|
return m
|
|
case possibleStartOfMatchCandidate:
|
|
i := c.(int)
|
|
at = i
|
|
}
|
|
}
|
|
|
|
stateID = a.NextStateNoFail(stateID, haystack[at])
|
|
at += 1
|
|
|
|
if a.IsMatchOrDeadState(stateID) {
|
|
if stateID == deadStateID {
|
|
return lastMatch
|
|
}
|
|
lastMatch = a.GetMatch(stateID, 0, at)
|
|
}
|
|
}
|
|
|
|
return lastMatch
|
|
}
|
|
|
|
func overlappingFindAt(a automaton, prestate *prefilterState, haystack []byte, at int, id *stateID, matchIndex *int) *Match {
|
|
if a.Anchored() && at > 0 && *id == a.StartState() {
|
|
return nil
|
|
}
|
|
|
|
matchCount := a.MatchCount(*id)
|
|
|
|
if *matchIndex < matchCount {
|
|
result := a.GetMatch(*id, *matchIndex, at)
|
|
*matchIndex += 1
|
|
return result
|
|
}
|
|
|
|
*matchIndex = 0
|
|
match := a.StandardFindAt(prestate, haystack, at, id)
|
|
|
|
if match == nil {
|
|
return nil
|
|
}
|
|
|
|
*matchIndex = 1
|
|
return match
|
|
}
|
|
|
|
func earliestFindAt(a automaton, prestate *prefilterState, haystack []byte, at int, id *stateID) *Match {
|
|
if *id == a.StartState() {
|
|
if a.Anchored() && at > 0 {
|
|
return nil
|
|
}
|
|
match := a.GetMatch(*id, 0, at)
|
|
if match != nil {
|
|
return match
|
|
}
|
|
}
|
|
return a.StandardFindAt(prestate, haystack, at, id)
|
|
}
|
|
|
|
func findAt(a automaton, prestate *prefilterState, haystack []byte, at int, id *stateID) *Match {
|
|
kind := a.MatchKind()
|
|
if kind == nil {
|
|
return nil
|
|
}
|
|
switch *kind {
|
|
case StandardMatch:
|
|
return a.EarliestFindAt(prestate, haystack, at, id)
|
|
case LeftMostFirstMatch, LeftMostLongestMatch:
|
|
return a.LeftmostFindAt(prestate, haystack, at, id)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func findAtNoState(a automaton, prestate *prefilterState, haystack []byte, at int) *Match {
|
|
kind := a.MatchKind()
|
|
if kind == nil {
|
|
return nil
|
|
}
|
|
switch *kind {
|
|
case StandardMatch:
|
|
state := a.StartState()
|
|
return a.EarliestFindAt(prestate, haystack, at, &state)
|
|
case LeftMostFirstMatch, LeftMostLongestMatch:
|
|
return a.LeftmostFindAtNoState(prestate, haystack, at)
|
|
}
|
|
return nil
|
|
}
|