Compare commits
3 Commits
22ead83625
...
f15a5cae34
| Author | SHA1 | Date | |
|---|---|---|---|
| f15a5cae34 | |||
| 62ca1a872a | |||
| 99230b49de |
@@ -816,7 +816,7 @@ func thompson(re []postfixNode) (Reg, error) {
|
|||||||
// In these cases, we will return an NFA with 1 state, with an assertion that is always true.
|
// In these cases, we will return an NFA with 1 state, with an assertion that is always true.
|
||||||
if len(re) == 0 {
|
if len(re) == 0 {
|
||||||
start := zeroLengthMatchState()
|
start := zeroLengthMatchState()
|
||||||
nfa = append(nfa, &start)
|
nfa = append(nfa, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range re {
|
for _, c := range re {
|
||||||
@@ -1068,14 +1068,14 @@ func thompson(re []postfixNode) (Reg, error) {
|
|||||||
nfa = append(nfa, s2)
|
nfa = append(nfa, s2)
|
||||||
}
|
}
|
||||||
tmp := zeroLengthMatchState()
|
tmp := zeroLengthMatchState()
|
||||||
s2 = &tmp
|
s2 = tmp
|
||||||
}
|
}
|
||||||
if err1 != nil || (s1.groupBegin && s1.numTransitions() == 0) { // Doesn't exist, or its just an LPAREN
|
if err1 != nil || (s1.groupBegin && s1.numTransitions() == 0) { // Doesn't exist, or its just an LPAREN
|
||||||
if err1 == nil { // See above for explanation
|
if err1 == nil { // See above for explanation
|
||||||
nfa = append(nfa, s1)
|
nfa = append(nfa, s1)
|
||||||
}
|
}
|
||||||
tmp := zeroLengthMatchState()
|
tmp := zeroLengthMatchState()
|
||||||
s1 = &tmp
|
s1 = tmp
|
||||||
}
|
}
|
||||||
s3 := alternate(s1, s2)
|
s3 := alternate(s1, s2)
|
||||||
nfa = append(nfa, s3)
|
nfa = append(nfa, s3)
|
||||||
|
|||||||
@@ -251,38 +251,40 @@ func (regex Reg) FindAllSubmatch(str string) []Match {
|
|||||||
return indices
|
return indices
|
||||||
}
|
}
|
||||||
|
|
||||||
func addStateToList(str []rune, idx int, list []nfaState, state nfaState, threadGroups []Group) []nfaState {
|
func addStateToList(str []rune, idx int, list []nfaState, state nfaState, threadGroups []Group, visited []nfaState) []nfaState {
|
||||||
if stateExists(list, state) {
|
if stateExists(list, state) || stateExists(visited, state) {
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
visited = append(visited, state)
|
||||||
|
|
||||||
if state.isKleene || state.isQuestion {
|
if state.isKleene || state.isQuestion {
|
||||||
copyThread(state.splitState, state)
|
copyThread(state.splitState, state)
|
||||||
list = addStateToList(str, idx, list, *state.splitState, threadGroups)
|
list = addStateToList(str, idx, list, *state.splitState, threadGroups, visited)
|
||||||
copyThread(state.next, state)
|
copyThread(state.next, state)
|
||||||
list = addStateToList(str, idx, list, *state.next, threadGroups)
|
list = addStateToList(str, idx, list, *state.next, threadGroups, visited)
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
if state.isAlternation {
|
if state.isAlternation {
|
||||||
copyThread(state.next, state)
|
copyThread(state.next, state)
|
||||||
list = addStateToList(str, idx, list, *state.next, threadGroups)
|
list = addStateToList(str, idx, list, *state.next, threadGroups, visited)
|
||||||
copyThread(state.splitState, state)
|
copyThread(state.splitState, state)
|
||||||
list = addStateToList(str, idx, list, *state.splitState, threadGroups)
|
list = addStateToList(str, idx, list, *state.splitState, threadGroups, visited)
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
state.threadGroups = append([]Group{}, threadGroups...)
|
state.threadGroups = append([]Group{}, threadGroups...)
|
||||||
if state.assert != noneAssert {
|
if state.assert != noneAssert {
|
||||||
if state.checkAssertion(str, idx) {
|
if state.checkAssertion(str, idx) {
|
||||||
copyThread(state.next, state)
|
copyThread(state.next, state)
|
||||||
return append(list, addStateToList(str, idx, list, *state.next, state.threadGroups)...)
|
return addStateToList(str, idx, list, *state.next, state.threadGroups, visited)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if state.groupBegin {
|
if state.groupBegin {
|
||||||
state.threadGroups[state.groupNum].StartIdx = idx
|
state.threadGroups[state.groupNum].StartIdx = idx
|
||||||
return append(list, addStateToList(str, idx, list, *state.next, state.threadGroups)...)
|
return addStateToList(str, idx, list, *state.next, state.threadGroups, visited)
|
||||||
}
|
}
|
||||||
if state.groupEnd {
|
if state.groupEnd {
|
||||||
state.threadGroups[state.groupNum].EndIdx = idx
|
state.threadGroups[state.groupNum].EndIdx = idx
|
||||||
return append(list, addStateToList(str, idx, list, *state.next, state.threadGroups)...)
|
return addStateToList(str, idx, list, *state.next, state.threadGroups, visited)
|
||||||
}
|
}
|
||||||
return append(list, state)
|
return append(list, state)
|
||||||
|
|
||||||
@@ -344,7 +346,7 @@ func findAllSubmatchHelper(start *nfaState, str []rune, offset int, numGroups in
|
|||||||
|
|
||||||
start.threadGroups = newMatch(numGroups + 1)
|
start.threadGroups = newMatch(numGroups + 1)
|
||||||
start.threadGroups[0].StartIdx = i
|
start.threadGroups[0].StartIdx = i
|
||||||
currentStates = addStateToList(str, i, currentStates, *start, start.threadGroups)
|
currentStates = addStateToList(str, i, currentStates, *start, start.threadGroups, nil)
|
||||||
var match Match = nil
|
var match Match = nil
|
||||||
// var isEmptyAndNoAssertion bool
|
// var isEmptyAndNoAssertion bool
|
||||||
// Main loop
|
// Main loop
|
||||||
@@ -366,7 +368,7 @@ func findAllSubmatchHelper(start *nfaState, str []rune, offset int, numGroups in
|
|||||||
break
|
break
|
||||||
} else if !currentState.isAlternation && !currentState.isKleene && !currentState.isQuestion && !currentState.groupBegin && !currentState.groupEnd { // Normal character or assertion
|
} else if !currentState.isAlternation && !currentState.isKleene && !currentState.isQuestion && !currentState.groupBegin && !currentState.groupEnd { // Normal character or assertion
|
||||||
if currentState.contentContains(str, idx) {
|
if currentState.contentContains(str, idx) {
|
||||||
nextStates = addStateToList(str, idx+1, nextStates, *currentState.next, currentState.threadGroups)
|
nextStates = addStateToList(str, idx+1, nextStates, *currentState.next, currentState.threadGroups, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -402,19 +402,20 @@ func newState() nfaState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates and returns a state that _always_ has a zero-length match.
|
// Creates and returns a state that _always_ has a zero-length match.
|
||||||
func zeroLengthMatchState() nfaState {
|
func zeroLengthMatchState() *nfaState {
|
||||||
start := newState()
|
start := &nfaState{}
|
||||||
start.content = newContents(epsilon)
|
start.content = newContents(epsilon)
|
||||||
start.isEmpty = true
|
start.isEmpty = true
|
||||||
start.assert = alwaysTrueAssert
|
start.assert = alwaysTrueAssert
|
||||||
|
start.output = append([]*nfaState{}, start)
|
||||||
return start
|
return start
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s nfaState) equals(other nfaState) bool {
|
func (s nfaState) equals(other nfaState) bool {
|
||||||
return slices.Equal(s.content, other.content) &&
|
return s.isEmpty == other.isEmpty &&
|
||||||
s.isEmpty == other.isEmpty &&
|
|
||||||
s.isLast == other.isLast &&
|
s.isLast == other.isLast &&
|
||||||
slices.Equal(s.output, other.output) &&
|
slices.Equal(s.output, other.output) &&
|
||||||
|
slices.Equal(s.content, other.content) &&
|
||||||
s.next == other.next &&
|
s.next == other.next &&
|
||||||
s.isKleene == other.isKleene &&
|
s.isKleene == other.isKleene &&
|
||||||
s.isQuestion == other.isQuestion &&
|
s.isQuestion == other.isQuestion &&
|
||||||
|
|||||||
Reference in New Issue
Block a user