3 Commits

3 changed files with 21 additions and 18 deletions

View File

@@ -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.
if len(re) == 0 {
start := zeroLengthMatchState()
nfa = append(nfa, &start)
nfa = append(nfa, start)
}
for _, c := range re {
@@ -1068,14 +1068,14 @@ func thompson(re []postfixNode) (Reg, error) {
nfa = append(nfa, s2)
}
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 { // See above for explanation
nfa = append(nfa, s1)
}
tmp := zeroLengthMatchState()
s1 = &tmp
s1 = tmp
}
s3 := alternate(s1, s2)
nfa = append(nfa, s3)

View File

@@ -251,38 +251,40 @@ func (regex Reg) FindAllSubmatch(str string) []Match {
return indices
}
func addStateToList(str []rune, idx int, list []nfaState, state nfaState, threadGroups []Group) []nfaState {
if stateExists(list, state) {
func addStateToList(str []rune, idx int, list []nfaState, state nfaState, threadGroups []Group, visited []nfaState) []nfaState {
if stateExists(list, state) || stateExists(visited, state) {
return list
}
visited = append(visited, state)
if state.isKleene || state.isQuestion {
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)
list = addStateToList(str, idx, list, *state.next, threadGroups)
list = addStateToList(str, idx, list, *state.next, threadGroups, visited)
return list
}
if state.isAlternation {
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)
list = addStateToList(str, idx, list, *state.splitState, threadGroups)
list = addStateToList(str, idx, list, *state.splitState, threadGroups, visited)
return list
}
state.threadGroups = append([]Group{}, threadGroups...)
if state.assert != noneAssert {
if state.checkAssertion(str, idx) {
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 {
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 {
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)
@@ -344,7 +346,7 @@ func findAllSubmatchHelper(start *nfaState, str []rune, offset int, numGroups in
start.threadGroups = newMatch(numGroups + 1)
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 isEmptyAndNoAssertion bool
// Main loop
@@ -366,7 +368,7 @@ func findAllSubmatchHelper(start *nfaState, str []rune, offset int, numGroups in
break
} else if !currentState.isAlternation && !currentState.isKleene && !currentState.isQuestion && !currentState.groupBegin && !currentState.groupEnd { // Normal character or assertion
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)
}
}

View File

@@ -402,19 +402,20 @@ func newState() nfaState {
}
// Creates and returns a state that _always_ has a zero-length match.
func zeroLengthMatchState() nfaState {
start := newState()
func zeroLengthMatchState() *nfaState {
start := &nfaState{}
start.content = newContents(epsilon)
start.isEmpty = true
start.assert = alwaysTrueAssert
start.output = append([]*nfaState{}, start)
return start
}
func (s nfaState) equals(other nfaState) bool {
return slices.Equal(s.content, other.content) &&
s.isEmpty == other.isEmpty &&
return s.isEmpty == other.isEmpty &&
s.isLast == other.isLast &&
slices.Equal(s.output, other.output) &&
slices.Equal(s.content, other.content) &&
s.next == other.next &&
s.isKleene == other.isKleene &&
s.isQuestion == other.isQuestion &&