regcomp.c: Make sure /di nodes ending in 's' are EXACTF
authorKarl Williamson <khw@cpan.org>
Fri, 30 Nov 2018 03:43:32 +0000 (20:43 -0700)
committerKarl Williamson <khw@cpan.org>
Sat, 8 Dec 2018 04:12:16 +0000 (21:12 -0700)
Prior to this commit only nodes that filled fully were guaranteed not to
be upgraded to EXACTFU.

EXACTF nodes are used when /d rules are to be used unless the string
being matched against is in UTF-8.  EXACTFU nodes are used when the /u
rules are to be used always.  If the node contains only characters whose
interpretation is the same under /d and /u, both node types behave
identically, and so either can be used.  EXACTFU nodes are preferred
because they are trie-able, and otherwise faster at runtime due to not
having to check the UTF-8ness of the target string.  The pattern
compilation uses an EXACTFU node when possible, over an EXACTF node.

The sequences 'ss', 'SS', 'Ss', 'sS'  are very tricky, for several
reasons.  For this commit, the trickiness lies in the fact that they are
the only sequences where both the pattern and target string aren't in
UTF-8, and what matches under /ui rules differs from what matches under
/di.  (There are various single characters that match differently, but
this is the only sequence whose individual components match the same,
but the sequence as a whole matches differently.)

The code has long taken special care for these sequences, but overlooked
two fairly obscure cases where it matters.  This commit addresses one of
those cases; the next commit, the other.

Because these  are sequences, it might be possible for it to be split
across two EXACTFish nodes, so that the first 's' or 'S' is the last
thing in the first node, and the second 's' or 'S' is the first thing in
the second.  Should these nodes get joined during optimization, they
form the sequence.  The code has long recognized this possibility if the
first node gets filled up, necessitating a split, and it doesn't make
the first node EXACTFU if it ends in 's' or 'S'.  But we don't fill
those nodes totally completely, and optimization can join two together.

Future commits in the pipeline will join nodes in more cases during
optimization, and so, we need to not create an EXACTFU for trailing 's'
or 'S' always, not just if the first node fills up.  This commit moves
the code that accomplishes this so it always gets executed at node end
of /di nodes, instead of previously only getting executed when the node
fills.

regcomp.c

index 350e730..db7876c 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -14426,14 +14426,6 @@ S_regatom(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
                 if (len == 0) {
                     len = full_len;
 
-                    /* If the node ends in an 's' we make sure it stays EXACTF,
-                     * as if it turns into an EXACTFU, it could later get
-                     * joined with another 's' that would then wrongly match
-                     * the sharp s */
-                    if (maybe_exactfu && isALPHA_FOLD_EQ(ender, 's'))
-                    {
-                        maybe_exactfu = FALSE;
-                    }
                 } else {
 
                     /* Here, the node does contain some characters that aren't
@@ -14509,6 +14501,15 @@ S_regatom(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
                 }
 
                 if (FOLD) {
+                    /* If the node ends in an 's' we make sure it stays EXACTF,
+                     * as if it turns into an EXACTFU, it could later get
+                     * joined with another 's' that would then wrongly match
+                     * the sharp s */
+                    if (maybe_exactfu && isALPHA_FOLD_EQ(ender, 's'))
+                    {
+                        maybe_exactfu = FALSE;
+                    }
+
                     /* If 'maybe_exactfu' is set, then there are no code points
                      * that match differently depending on UTF8ness of the
                      * target string (for /u), or depending on locale for /l */