@@ -1022,20 +1022,41 @@ module SuffixConstruction {
10221022 * Holds if there likely exists a suffix starting from `s` that leads to the regular expression being rejected.
10231023 * This predicate might find impossible suffixes when searching for suffixes of length > 1, which can cause FPs.
10241024 */
1025+ pragma [ nomagic]
10251026 private predicate isLikelyRejectable ( StateInPumpableRegexp s ) {
10261027 // exists a reject edge with some char.
1027- hasRejectEdge ( s , _ )
1028+ hasRejectEdge ( s )
10281029 or
1030+ hasEdgeToLikelyRejectable ( s )
1031+ or
1032+ // stopping here is rejection
1033+ isRejectState ( s )
1034+ }
1035+
1036+ /**
1037+ * Holds if `s` is not an accept state, and there is no epsilon transition to an accept state.
1038+ */
1039+ predicate isRejectState ( StateInPumpableRegexp s ) { not epsilonSucc * ( s ) = Accept ( _) }
1040+
1041+ /**
1042+ * Holds if there is likely a non-empty suffix leading to rejection starting in `s`.
1043+ */
1044+ predicate hasEdgeToLikelyRejectable ( StateInPumpableRegexp s ) {
10291045 // all edges (at least one) with some char leads to another state that is rejectable.
10301046 // the `next` states might not share a common suffix, which can cause FPs.
10311047 exists ( string char | char = relevant ( ) |
1032- forex ( State next | deltaClosed ( s , getAnInputSymbolMatching ( char ) , next ) |
1033- isLikelyRejectable ( next )
1034- )
1048+ forex ( State next | deltaClosedChar ( s , char , next ) | isLikelyRejectable ( next ) )
10351049 )
1036- or
1037- // stopping here is rejection
1038- not epsilonSucc * ( s ) = Accept ( _)
1050+ }
1051+
1052+ /**
1053+ * Holds if there is a state `next` that can be reached from `prev`
1054+ * along epsilon edges, such that there is a transition from
1055+ * `prev` to `next` that the character symbol `char`.
1056+ */
1057+ predicate deltaClosedChar ( StateInPumpableRegexp prev , string char , StateInPumpableRegexp next ) {
1058+ char = relevant ( ) and
1059+ deltaClosed ( prev , getAnInputSymbolMatching ( char ) , next )
10391060 }
10401061
10411062 /**
@@ -1047,9 +1068,8 @@ module SuffixConstruction {
10471068 * Holds if there is no edge from `s` labeled `char` in our NFA.
10481069 * The NFA does not model reject states, so the above is the same as saying there is a reject edge.
10491070 */
1050- private predicate hasRejectEdge ( StateInPumpableRegexp s , string char ) {
1051- char = relevant ( ) and
1052- not deltaClosed ( s , getAnInputSymbolMatching ( char ) , _)
1071+ private predicate hasRejectEdge ( State s ) {
1072+ exists ( string char | char = relevant ( ) | not deltaClosedChar ( s , char , _) )
10531073 }
10541074
10551075 /**
0 commit comments