From 0de3a94ce34c8d0518a807ea5c2b9a25e25ae7d6 Mon Sep 17 00:00:00 2001 From: Aadhavan Srinivasan Date: Sun, 24 Nov 2024 15:04:51 -0500 Subject: [PATCH] Fixed bug with lookaheads: f(?=f) would not match anything in 'ffa', because of the 'a' at the end of the string. Fixed by checking if there are other last states when an assertion fails, rather than immediately aborting --- matching.go | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/matching.go b/matching.go index c66971e..cc47d50 100644 --- a/matching.go +++ b/matching.go @@ -173,6 +173,8 @@ func findAllMatchesHelper(start *State, str []rune, offset int) (bool, MatchInde // Take any transitions corresponding to current character numStatesMatched := 0 // The number of states which had at least 1 match for this round assertionFailed := false // Whether or not an assertion failed for this round + lastStateInList := false // Whether or not a last state was in our list of states + // lastStateLookaround := false // Whether or not a last state (that is also a lookaround) matched for _, state := range currentStates { matches, numMatches := state.matchesFor(str, i) if numMatches > 0 { @@ -184,16 +186,30 @@ func findAllMatchesHelper(start *State, str []rune, offset int) (bool, MatchInde assertionFailed = true } if state.isLast { - endIdx = i - tempIndices, _ = unique_append(tempIndices, MatchIndex{startIdx, endIdx}) + lastStateInList = true } } - if assertionFailed && numStatesMatched == 0 { // Nothing has matched and an assertion has failed - abort - if i == startingFrom { - i++ + + if assertionFailed && numStatesMatched == 0 { // Nothing has matched and an assertion has failed + // One of the states in our list was a last state. In this case, we + // don't abort upon the failure of an assertion, because we have found + // another path to a final state. + // Even if the last state _was_ an assertion, we can use the previously + // saved indices to find a match. + if lastStateInList { + break + } else { + if i == startingFrom { + i++ + } + return false, MatchIndex{}, i } - return false, MatchIndex{}, i } + if lastStateInList { // A last-state was in the list of states. add the matchIndex to our MatchIndex list + endIdx = i + tempIndices, _ = unique_append(tempIndices, MatchIndex{startIdx, endIdx}) + } + // Check if we can find a zero-length match if foundPath == false { if zeroMatchPossible(str, i, currentStates...) { @@ -250,7 +266,7 @@ func findAllMatchesHelper(start *State, str []rune, offset int) (bool, MatchInde // Only add the match if the start index is in bounds. If the state has an assertion, // make sure the assertion checks out. if state.isLast && startIdx < len(str) { - if state.assert == NONE || state.checkAssertion(str, len(str)) { + if state.assert == NONE || state.checkAssertion(str, i) { endIdx = i tempIndices, _ = unique_append(tempIndices, MatchIndex{startIdx, endIdx}) }