Add regnode NANYOFM
authorKarl Williamson <khw@cpan.org>
Thu, 15 Nov 2018 17:57:24 +0000 (10:57 -0700)
committerKarl Williamson <khw@cpan.org>
Sat, 17 Nov 2018 17:02:11 +0000 (10:02 -0700)
This matches when the existing node ANYOFM would not match; i.e., they
are complements.

I almost didn't create this node, but it turns out to significantly
speed up various classes of matches.  For example qr/[^g]/, both /i and
not, turn into this node; and something like

    (("a" x $large_number) . "b") =~ /[^a]/

goes through the string a word at a time, instead of previously
byte-by-byte.  Benchmarks are at the end of this mesage.

This node gets generated when complementing any single ASCII character
and when complementing any ASCII case pair, like /[^Gg]/.  It never gets
generated if the class includes a character that isn't ASCII (actually
UTF-8 invariant, which matters only on EBCDIC platforms).

The details of when this node gets constructed are complicated.  It
happens when the bit patterns of the characters in the class happen to
have certain very particular characteristics, depending on the vagaries
of the character set.  [BbCc] will do so, but [AaBb] does not.  [^01]
does, but not [^12].  Precisely, look at all the bit patterns of the
characters in the set, and count the total number of differing bits,
calling it 'n'.  If and only if the number of characters is 2**n, this
node gets generated.  As an example, on both ASCII and EBCDIC, the last
4 bits of '0' are 0000; of '1' are 0001; of '2' are 0010; and of '3' are
0011.  The other 4 bits are the same for each of these 4 digits.  That
means that only 2 bits differ among the 4 characters, and 2**2==4, so
the NANYOFM node will get generated.  Similarly, 8=1000 and 0=0000
differ only in one bit so 2**1==2, and so [^08] will generate this node.

We could consider in the future, an extension where, if the input
doesn't work to generate this node, that we construct the closure of
that input to generate this node, which would have false positives that
would have to be tested for.  The speedup of this node is so significant
that that could still be faster than what we have today.

The benchmarks are for a 64-bit word.  32-bits would not be as good.
Key:
    Ir   Instruction read
    Dr   Data read
    Dw   Data write
    COND conditional branches
    IND  indirect branches

The numbers (except for the final column) represent raw counts per loop
iteration.  The higher the number in the final column, the faster.

(('a' x 1) . 'b') =~ /[^a]/

          blead   nanyof  Ratio %
       -------- -------- --------
    Ir   2782.0   2648.0    105.1
    Dr    845.0    799.0    105.8
    Dw    531.0    500.0    106.2
  COND    431.0    419.0    102.9
   IND     22.0     22.0    100.0

(('a' x 10) . 'b') =~ /[^a]/

          blead   nanyof  Ratio %
       -------- -------- --------
    Ir   3358.0   2671.0    125.7
    Dr    998.0    801.0    124.6
    Dw    630.0    500.0    126.0
  COND    503.0    424.0    118.6
   IND     22.0     22.0    100.0

(('a' x 100) . 'b') =~ /[^a]/

          blead   nanyof  Ratio %
       -------- -------- --------
    Ir   9118.0   2773.0    328.8
    Dr   2528.0    814.0    310.6
    Dw   1620.0    500.0    324.0
  COND   1223.0    450.0    271.8
   IND     22.0     22.0    100.0

(('a' x 1000) . 'b') =~ /[^a]/

          blead   nanyof  Ratio %
       -------- -------- --------
    Ir  66718.0   3650.0   1827.9
    Dr  17828.0    923.0   1931.5
    Dw  11520.0    500.0   2304.0
  COND   8423.0    668.0   1260.9
   IND     22.0     22.0    100.0

(('a' x 10000) . 'b') =~ /[^a]/

          blead   nanyof  Ratio %
       -------- -------- --------
    Ir 642718.0  12650.0   5080.8
    Dr 170828.0   2048.0   8341.2
    Dw 110520.0    500.0  22104.0
  COND  80423.0   2918.0   2756.1
   IND     22.0     22.0    100.0

(('a' x 100000) . 'b') =~ /[^a]/

          blead   nanyof  Ratio %
       -------- -------- --------
    Ir      Inf 102654.8   6237.1
    Dr      Inf  13299.3  12788.9
    Dw      Inf    500.9 219708.7
  COND 800424.1  25419.1   3148.9
   IND     22.0     22.0    100.0

pod/perldebguts.pod
pod/perldelta.pod
regcomp.c
regcomp.sym
regexec.c
regnodes.h
t/re/anyof.t

index 080daac..8930e11 100644 (file)
@@ -613,6 +613,7 @@ will be lost.
                   posixl
  ANYOFM           byte 1     Like ANYOF, but matches an invariant byte
                              as determined by the mask and arg
+ NANYOFM          byte 1     complement of ANYOFM
 
  # POSIX Character Classes:
  POSIXD           none       Some [[:class:]] under /d; the FLAGS field
index f17d64c..b91ec62 100644 (file)
@@ -94,7 +94,12 @@ There may well be none in a stable release.
 
 =item *
 
-XXX
+Regular expression pattern matching of things like C<qr/[^I<a>]/> is
+significantly sped up, where I<a> is any ASCII character.  Which classes
+will get this speed up is complicated and depends on the underlying bit
+patterns of those characters, so differs between ASCII and EBCDIC
+platforms, but all case pairs, like C<qr/[Gg]/> are included, as is
+C<[^01]>.
 
 =back
 
index e16d91f..7ffba08 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -5630,21 +5630,16 @@ Perl_re_printf( aTHX_  "LHS=%" UVuf " RHS=%" UVuf "\n",
                                                           (regnode_charclass *) scan);
                    break;
 
+                case NANYOFM:
                 case ANYOFM:
                   {
                     SV* cp_list = get_ANYOFM_contents(scan);
 
                     if (flags & SCF_DO_STCLASS_OR) {
-                        ssc_union(data->start_class,
-                                  cp_list,
-                                  FALSE /* don't invert */
-                                  );
+                        ssc_union(data->start_class, cp_list, invert);
                     }
                     else if (flags & SCF_DO_STCLASS_AND) {
-                        ssc_intersection(data->start_class,
-                                         cp_list,
-                                         FALSE /* don't invert */
-                                         );
+                        ssc_intersection(data->start_class, cp_list, invert);
                     }
 
                     SvREFCNT_dec_NN(cp_list);
@@ -18280,26 +18275,30 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                  * usage, is optimizable into ANYOFM, and can benefit from the
                  * speed up.  We can only do this on UTF-8 invariant bytes,
                  * because the variance would throw this off.  */
-                if (   op == END
-                    && invlist_highest(cp_list) <=
+                if (op == END) {
+                    PERL_UINT_FAST8_T inverted = 0;
 #ifdef EBCDIC
-                                                   0xFF
+                    const PERL_UINT_FAST8_T max_permissible = 0xFF;
 #else
-                                                   0x7F
+                    const PERL_UINT_FAST8_T max_permissible = 0x7F;
 #endif
-                ) {
+                    if (invlist_highest(cp_list) > max_permissible) {
+                        _invlist_invert(cp_list);
+                        inverted = 1;
+                    }
+
+                    if (invlist_highest(cp_list) <= max_permissible) {
                     Size_t cp_count = 0;
                     bool first_time = TRUE;
                     unsigned int lowest_cp = 0xFF;
                     U8 bits_differing = 0;
 
-                    /* Only needed on EBCDIC, as there, variants and non- are
-                     * mixed together.  Could #ifdef it out on ASCII, but
-                     * probably the compiler will optimize it out */
+                    /* Only needed on EBCDIC, as there, variants and non- are mixed
+                     * together.  Could #ifdef it out on ASCII, but probably the
+                     * compiler will optimize it out */
                     bool has_variant = FALSE;
 
-                    /* Go through the bytes and find the bit positions that
-                     * differ */
+                    /* Go through the bytes and find the bit positions that differ */
                     invlist_iterinit(cp_list);
                     while (invlist_iternext(cp_list, &start, &end)) {
                         unsigned int i = start;
@@ -18350,8 +18349,8 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                     if ( ! has_variant
                         && cp_count == 1U << PL_bitcount[bits_differing])
                     {
-                        assert(cp_count > 1);
-                        op = ANYOFM;
+                        assert(inverted || cp_count > 1);
+                        op = ANYOFM + inverted;;
 
                         /* We need to make the bits that differ be 0's */
                         ANYOFM_mask = ~ bits_differing; /* This goes into FLAGS
@@ -18362,6 +18361,10 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                         *flagp |= HASWIDTH|SIMPLE;
                     }
                 }
+                if (inverted) {
+                    _invlist_invert(cp_list);
+                }
+            }
             }
         }
 
@@ -19275,8 +19278,8 @@ S_regtail_study(pTHX_ RExC_state_t *pRExC_state, regnode_offset p,
 STATIC SV*
 S_get_ANYOFM_contents(pTHX_ const regnode * n) {
 
-    /* Returns an inversion list of all the code points matched by the ANYOFM
-     * node 'n' */
+    /* Returns an inversion list of all the code points matched by the
+     * ANYOFM/NANYOFM node 'n' */
 
     SV * cp_list = _new_invlist(-1);
     const U8 lowest = (U8) ARG(n);
@@ -19299,6 +19302,9 @@ S_get_ANYOFM_contents(pTHX_ const regnode * n) {
         }
     }
 
+    if (OP(n) == NANYOFM) {
+        _invlist_invert(cp_list);
+    }
     return cp_list;
 }
 
@@ -19832,6 +19838,10 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
         SV * cp_list = get_ANYOFM_contents(o);
 
        Perl_sv_catpvf(aTHX_ sv, "[%s", PL_colors[0]);
+        if (OP(o) == NANYOFM) {
+            _invlist_invert(cp_list);
+        }
+
         put_charclass_bitmap_innards(sv, NULL, cp_list, NULL, NULL, TRUE);
        Perl_sv_catpvf(aTHX_ sv, "%s]", PL_colors[1]);
 
index 6305bfb..02bd998 100644 (file)
@@ -63,6 +63,7 @@ ANYOFD      ANYOF,      sv charclass S    ; Like ANYOF, but /d is in effect
 ANYOFL      ANYOF,      sv charclass S    ; Like ANYOF, but /l is in effect
 ANYOFPOSIXL ANYOF,      sv charclass_posixl S    ; Like ANYOFL, but matches [[:posix:]] classes
 ANYOFM      ANYOFM      byte 1 S  ; Like ANYOF, but matches an invariant byte as determined by the mask and arg
+NANYOFM     ANYOFM      byte 1 S  ; complement of ANYOFM
 
 #* POSIX Character Classes:
 # Order of the below is important.  See ordering comment above.
index 3345369..be1f5ae 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -2265,6 +2265,12 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                                    (U8) ARG(c), FLAGS(c)));
         break;
 
+    case NANYOFM:
+        REXEC_FBC_FIND_NEXT_SCAN(0,
+         (char *) find_span_end_mask((U8 *) s, (U8 *) strend,
+                                   (U8) ARG(c), FLAGS(c)));
+        break;
+
     case EXACTFAA_NO_TRIE: /* This node only generated for non-utf8 patterns */
         assert(! is_utf8_pat);
        /* FALLTHROUGH */
@@ -6743,6 +6749,13 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
             locinput++;
             break;
 
+        case NANYOFM:
+            if (NEXTCHR_IS_EOS || (UCHARAT(locinput) & FLAGS(scan)) == ARG(scan)) {
+                sayNO;
+            }
+            goto increment_locinput;
+            break;
+
         case ASCII:
             if (NEXTCHR_IS_EOS || ! isASCII(UCHARAT(locinput))) {
                 sayNO;
@@ -9397,6 +9410,21 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
         scan = (char *) find_span_end_mask((U8 *) scan, (U8 *) loceol, (U8) ARG(p), FLAGS(p));
         break;
 
+    case NANYOFM:
+       if (utf8_target) {
+           while (     hardcount < max
+                   &&   scan < loceol
+                  &&  (*scan & FLAGS(p)) != ARG(p))
+           {
+               scan += UTF8SKIP(scan);
+               hardcount++;
+           }
+       }
+        else {
+            scan = (char *) find_next_masked((U8 *) scan, (U8 *) loceol, (U8) ARG(p), FLAGS(p));
+       }
+        break;
+
     case ASCII:
         if (utf8_target && loceol - scan > max) {
             loceol = scan + max;
index f94b16b..4023f90 100644 (file)
@@ -6,8 +6,8 @@
 
 /* Regops and State definitions */
 
-#define REGNODE_MAX            98
-#define REGMATCH_STATE_MAX     138
+#define REGNODE_MAX            99
+#define REGMATCH_STATE_MAX     139
 
 #define        END                     0       /* 0000 End of program. */
 #define        SUCCEED                 1       /* 0x01 Return from a subroutine, basically. */
 #define        ANYOFL                  20      /* 0x14 Like ANYOF, but /l is in effect */
 #define        ANYOFPOSIXL             21      /* 0x15 Like ANYOFL, but matches [[:posix:]] classes */
 #define        ANYOFM                  22      /* 0x16 Like ANYOF, but matches an invariant byte as determined by the mask and arg */
-#define        POSIXD                  23      /* 0x17 Some [[:class:]] under /d; the FLAGS field gives which one */
-#define        POSIXL                  24      /* 0x18 Some [[:class:]] under /l; the FLAGS field gives which one */
-#define        POSIXU                  25      /* 0x19 Some [[:class:]] under /u; the FLAGS field gives which one */
-#define        POSIXA                  26      /* 0x1a Some [[:class:]] under /a; the FLAGS field gives which one */
-#define        NPOSIXD                 27      /* 0x1b complement of POSIXD, [[:^class:]] */
-#define        NPOSIXL                 28      /* 0x1c complement of POSIXL, [[:^class:]] */
-#define        NPOSIXU                 29      /* 0x1d complement of POSIXU, [[:^class:]] */
-#define        NPOSIXA                 30      /* 0x1e complement of POSIXA, [[:^class:]] */
-#define        ASCII                   31      /* 0x1f [[:ascii:]] */
-#define        NASCII                  32      /* 0x20 [[:^ascii:]] */
-#define        CLUMP                   33      /* 0x21 Match any extended grapheme cluster sequence */
-#define        BRANCH                  34      /* 0x22 Match this alternative, or the next... */
-#define        EXACT                   35      /* 0x23 Match this string (preceded by length). */
-#define        EXACTL                  36      /* 0x24 Like EXACT, but /l is in effect (used so locale-related warnings can be checked for). */
-#define        EXACTF                  37      /* 0x25 Match this non-UTF-8 string (not guaranteed to be folded) using /id rules (w/len). */
-#define        EXACTFL                 38      /* 0x26 Match this string (not guaranteed to be folded) using /il rules (w/len). */
-#define        EXACTFU                 39      /* 0x27 Match this string (folded iff in UTF-8, length in folding doesn't change if not in UTF-8) using /iu rules (w/len). */
-#define        EXACTFAA                40      /* 0x28 Match this string (not guaranteed to be folded) using /iaa rules (w/len). */
-#define        EXACTFU_SS              41      /* 0x29 Match this string (folded iff in UTF-8, length in folding may change even if not in UTF-8) using /iu rules (w/len). */
-#define        EXACTFLU8               42      /* 0x2a Rare circumstances: like EXACTFU, but is under /l, UTF-8, folded, and everything in it is above 255. */
-#define        EXACTFAA_NO_TRIE        43      /* 0x2b Match this string (which is not trie-able; not guaranteed to be folded) using /iaa rules (w/len). */
-#define        NOTHING                 44      /* 0x2c Match empty string. */
-#define        TAIL                    45      /* 0x2d Match empty string. Can jump here from outside. */
-#define        STAR                    46      /* 0x2e Match this (simple) thing 0 or more times. */
-#define        PLUS                    47      /* 0x2f Match this (simple) thing 1 or more times. */
-#define        CURLY                   48      /* 0x30 Match this simple thing {n,m} times. */
-#define        CURLYN                  49      /* 0x31 Capture next-after-this simple thing */
-#define        CURLYM                  50      /* 0x32 Capture this medium-complex thing {n,m} times. */
-#define        CURLYX                  51      /* 0x33 Match this complex thing {n,m} times. */
-#define        WHILEM                  52      /* 0x34 Do curly processing and see if rest matches. */
-#define        OPEN                    53      /* 0x35 Mark this point in input as start of #n. */
-#define        CLOSE                   54      /* 0x36 Close corresponding OPEN of #n. */
-#define        SROPEN                  55      /* 0x37 Same as OPEN, but for script run */
-#define        SRCLOSE                 56      /* 0x38 Close preceding SROPEN */
-#define        REF                     57      /* 0x39 Match some already matched string */
-#define        REFF                    58      /* 0x3a Match already matched string, folded using native charset rules for non-utf8 */
-#define        REFFL                   59      /* 0x3b Match already matched string, folded in loc. */
-#define        REFFU                   60      /* 0x3c Match already matched string, folded using unicode rules for non-utf8 */
-#define        REFFA                   61      /* 0x3d Match already matched string, folded using unicode rules for non-utf8, no mixing ASCII, non-ASCII */
-#define        NREF                    62      /* 0x3e Match some already matched string */
-#define        NREFF                   63      /* 0x3f Match already matched string, folded using native charset rules for non-utf8 */
-#define        NREFFL                  64      /* 0x40 Match already matched string, folded in loc. */
-#define        NREFFU                  65      /* 0x41 Match already matched string, folded using unicode rules for non-utf8 */
-#define        NREFFA                  66      /* 0x42 Match already matched string, folded using unicode rules for non-utf8, no mixing ASCII, non-ASCII */
-#define        LONGJMP                 67      /* 0x43 Jump far away. */
-#define        BRANCHJ                 68      /* 0x44 BRANCH with long offset. */
-#define        IFMATCH                 69      /* 0x45 Succeeds if the following matches. */
-#define        UNLESSM                 70      /* 0x46 Fails if the following matches. */
-#define        SUSPEND                 71      /* 0x47 "Independent" sub-RE. */
-#define        IFTHEN                  72      /* 0x48 Switch, should be preceded by switcher. */
-#define        GROUPP                  73      /* 0x49 Whether the group matched. */
-#define        EVAL                    74      /* 0x4a Execute some Perl code. */
-#define        MINMOD                  75      /* 0x4b Next operator is not greedy. */
-#define        LOGICAL                 76      /* 0x4c Next opcode should set the flag only. */
-#define        RENUM                   77      /* 0x4d Group with independently numbered parens. */
-#define        TRIE                    78      /* 0x4e Match many EXACT(F[ALU]?)? at once. flags==type */
-#define        TRIEC                   79      /* 0x4f Same as TRIE, but with embedded charclass data */
-#define        AHOCORASICK             80      /* 0x50 Aho Corasick stclass. flags==type */
-#define        AHOCORASICKC            81      /* 0x51 Same as AHOCORASICK, but with embedded charclass data */
-#define        GOSUB                   82      /* 0x52 recurse to paren arg1 at (signed) ofs arg2 */
-#define        NGROUPP                 83      /* 0x53 Whether the group matched. */
-#define        INSUBP                  84      /* 0x54 Whether we are in a specific recurse. */
-#define        DEFINEP                 85      /* 0x55 Never execute directly. */
-#define        ENDLIKE                 86      /* 0x56 Used only for the type field of verbs */
-#define        OPFAIL                  87      /* 0x57 Same as (?!), but with verb arg */
-#define        ACCEPT                  88      /* 0x58 Accepts the current matched string, with verbar */
-#define        VERB                    89      /* 0x59 Used only for the type field of verbs */
-#define        PRUNE                   90      /* 0x5a Pattern fails at this startpoint if no-backtracking through this */
-#define        MARKPOINT               91      /* 0x5b Push the current location for rollback by cut. */
-#define        SKIP                    92      /* 0x5c On failure skip forward (to the mark) before retrying */
-#define        COMMIT                  93      /* 0x5d Pattern fails outright if backtracking through this */
-#define        CUTGROUP                94      /* 0x5e On failure go to the next alternation in the group */
-#define        KEEPS                   95      /* 0x5f $& begins here. */
-#define        LNBREAK                 96      /* 0x60 generic newline pattern */
-#define        OPTIMIZED               97      /* 0x61 Placeholder for dump. */
-#define        PSEUDO                  98      /* 0x62 Pseudo opcode for internal use. */
+#define        NANYOFM                 23      /* 0x17 complement of ANYOFM */
+#define        POSIXD                  24      /* 0x18 Some [[:class:]] under /d; the FLAGS field gives which one */
+#define        POSIXL                  25      /* 0x19 Some [[:class:]] under /l; the FLAGS field gives which one */
+#define        POSIXU                  26      /* 0x1a Some [[:class:]] under /u; the FLAGS field gives which one */
+#define        POSIXA                  27      /* 0x1b Some [[:class:]] under /a; the FLAGS field gives which one */
+#define        NPOSIXD                 28      /* 0x1c complement of POSIXD, [[:^class:]] */
+#define        NPOSIXL                 29      /* 0x1d complement of POSIXL, [[:^class:]] */
+#define        NPOSIXU                 30      /* 0x1e complement of POSIXU, [[:^class:]] */
+#define        NPOSIXA                 31      /* 0x1f complement of POSIXA, [[:^class:]] */
+#define        ASCII                   32      /* 0x20 [[:ascii:]] */
+#define        NASCII                  33      /* 0x21 [[:^ascii:]] */
+#define        CLUMP                   34      /* 0x22 Match any extended grapheme cluster sequence */
+#define        BRANCH                  35      /* 0x23 Match this alternative, or the next... */
+#define        EXACT                   36      /* 0x24 Match this string (preceded by length). */
+#define        EXACTL                  37      /* 0x25 Like EXACT, but /l is in effect (used so locale-related warnings can be checked for). */
+#define        EXACTF                  38      /* 0x26 Match this non-UTF-8 string (not guaranteed to be folded) using /id rules (w/len). */
+#define        EXACTFL                 39      /* 0x27 Match this string (not guaranteed to be folded) using /il rules (w/len). */
+#define        EXACTFU                 40      /* 0x28 Match this string (folded iff in UTF-8, length in folding doesn't change if not in UTF-8) using /iu rules (w/len). */
+#define        EXACTFAA                41      /* 0x29 Match this string (not guaranteed to be folded) using /iaa rules (w/len). */
+#define        EXACTFU_SS              42      /* 0x2a Match this string (folded iff in UTF-8, length in folding may change even if not in UTF-8) using /iu rules (w/len). */
+#define        EXACTFLU8               43      /* 0x2b Rare circumstances: like EXACTFU, but is under /l, UTF-8, folded, and everything in it is above 255. */
+#define        EXACTFAA_NO_TRIE        44      /* 0x2c Match this string (which is not trie-able; not guaranteed to be folded) using /iaa rules (w/len). */
+#define        NOTHING                 45      /* 0x2d Match empty string. */
+#define        TAIL                    46      /* 0x2e Match empty string. Can jump here from outside. */
+#define        STAR                    47      /* 0x2f Match this (simple) thing 0 or more times. */
+#define        PLUS                    48      /* 0x30 Match this (simple) thing 1 or more times. */
+#define        CURLY                   49      /* 0x31 Match this simple thing {n,m} times. */
+#define        CURLYN                  50      /* 0x32 Capture next-after-this simple thing */
+#define        CURLYM                  51      /* 0x33 Capture this medium-complex thing {n,m} times. */
+#define        CURLYX                  52      /* 0x34 Match this complex thing {n,m} times. */
+#define        WHILEM                  53      /* 0x35 Do curly processing and see if rest matches. */
+#define        OPEN                    54      /* 0x36 Mark this point in input as start of #n. */
+#define        CLOSE                   55      /* 0x37 Close corresponding OPEN of #n. */
+#define        SROPEN                  56      /* 0x38 Same as OPEN, but for script run */
+#define        SRCLOSE                 57      /* 0x39 Close preceding SROPEN */
+#define        REF                     58      /* 0x3a Match some already matched string */
+#define        REFF                    59      /* 0x3b Match already matched string, folded using native charset rules for non-utf8 */
+#define        REFFL                   60      /* 0x3c Match already matched string, folded in loc. */
+#define        REFFU                   61      /* 0x3d Match already matched string, folded using unicode rules for non-utf8 */
+#define        REFFA                   62      /* 0x3e Match already matched string, folded using unicode rules for non-utf8, no mixing ASCII, non-ASCII */
+#define        NREF                    63      /* 0x3f Match some already matched string */
+#define        NREFF                   64      /* 0x40 Match already matched string, folded using native charset rules for non-utf8 */
+#define        NREFFL                  65      /* 0x41 Match already matched string, folded in loc. */
+#define        NREFFU                  66      /* 0x42 Match already matched string, folded using unicode rules for non-utf8 */
+#define        NREFFA                  67      /* 0x43 Match already matched string, folded using unicode rules for non-utf8, no mixing ASCII, non-ASCII */
+#define        LONGJMP                 68      /* 0x44 Jump far away. */
+#define        BRANCHJ                 69      /* 0x45 BRANCH with long offset. */
+#define        IFMATCH                 70      /* 0x46 Succeeds if the following matches. */
+#define        UNLESSM                 71      /* 0x47 Fails if the following matches. */
+#define        SUSPEND                 72      /* 0x48 "Independent" sub-RE. */
+#define        IFTHEN                  73      /* 0x49 Switch, should be preceded by switcher. */
+#define        GROUPP                  74      /* 0x4a Whether the group matched. */
+#define        EVAL                    75      /* 0x4b Execute some Perl code. */
+#define        MINMOD                  76      /* 0x4c Next operator is not greedy. */
+#define        LOGICAL                 77      /* 0x4d Next opcode should set the flag only. */
+#define        RENUM                   78      /* 0x4e Group with independently numbered parens. */
+#define        TRIE                    79      /* 0x4f Match many EXACT(F[ALU]?)? at once. flags==type */
+#define        TRIEC                   80      /* 0x50 Same as TRIE, but with embedded charclass data */
+#define        AHOCORASICK             81      /* 0x51 Aho Corasick stclass. flags==type */
+#define        AHOCORASICKC            82      /* 0x52 Same as AHOCORASICK, but with embedded charclass data */
+#define        GOSUB                   83      /* 0x53 recurse to paren arg1 at (signed) ofs arg2 */
+#define        NGROUPP                 84      /* 0x54 Whether the group matched. */
+#define        INSUBP                  85      /* 0x55 Whether we are in a specific recurse. */
+#define        DEFINEP                 86      /* 0x56 Never execute directly. */
+#define        ENDLIKE                 87      /* 0x57 Used only for the type field of verbs */
+#define        OPFAIL                  88      /* 0x58 Same as (?!), but with verb arg */
+#define        ACCEPT                  89      /* 0x59 Accepts the current matched string, with verbar */
+#define        VERB                    90      /* 0x5a Used only for the type field of verbs */
+#define        PRUNE                   91      /* 0x5b Pattern fails at this startpoint if no-backtracking through this */
+#define        MARKPOINT               92      /* 0x5c Push the current location for rollback by cut. */
+#define        SKIP                    93      /* 0x5d On failure skip forward (to the mark) before retrying */
+#define        COMMIT                  94      /* 0x5e Pattern fails outright if backtracking through this */
+#define        CUTGROUP                95      /* 0x5f On failure go to the next alternation in the group */
+#define        KEEPS                   96      /* 0x60 $& begins here. */
+#define        LNBREAK                 97      /* 0x61 generic newline pattern */
+#define        OPTIMIZED               98      /* 0x62 Placeholder for dump. */
+#define        PSEUDO                  99      /* 0x63 Pseudo opcode for internal use. */
        /* ------------ States ------------- */
 #define        TRIE_next               (REGNODE_MAX + 1)       /* state for TRIE */
 #define        TRIE_next_fail          (REGNODE_MAX + 2)       /* state for TRIE */
@@ -181,6 +182,7 @@ EXTCONST U8 PL_regkind[] = {
        ANYOF,          /* ANYOFL                 */
        ANYOF,          /* ANYOFPOSIXL            */
        ANYOFM,         /* ANYOFM                 */
+       ANYOFM,         /* NANYOFM                */
        POSIXD,         /* POSIXD                 */
        POSIXD,         /* POSIXL                 */
        POSIXD,         /* POSIXU                 */
@@ -329,6 +331,7 @@ static const U8 regarglen[] = {
        EXTRA_SIZE(struct regnode_charclass),   /* ANYOFL       */
        EXTRA_SIZE(struct regnode_charclass_posixl),    /* ANYOFPOSIXL  */
        EXTRA_SIZE(struct regnode_1),           /* ANYOFM       */
+       EXTRA_SIZE(struct regnode_1),           /* NANYOFM      */
        0,                                      /* POSIXD       */
        0,                                      /* POSIXL       */
        0,                                      /* POSIXU       */
@@ -433,6 +436,7 @@ static const char reg_off_by_arg[] = {
        0,      /* ANYOFL       */
        0,      /* ANYOFPOSIXL  */
        0,      /* ANYOFM       */
+       0,      /* NANYOFM      */
        0,      /* POSIXD       */
        0,      /* POSIXL       */
        0,      /* POSIXU       */
@@ -543,82 +547,83 @@ EXTCONST char * const PL_reg_name[] = {
        "ANYOFL",                       /* 0x14 */
        "ANYOFPOSIXL",                  /* 0x15 */
        "ANYOFM",                       /* 0x16 */
-       "POSIXD",                       /* 0x17 */
-       "POSIXL",                       /* 0x18 */
-       "POSIXU",                       /* 0x19 */
-       "POSIXA",                       /* 0x1a */
-       "NPOSIXD",                      /* 0x1b */
-       "NPOSIXL",                      /* 0x1c */
-       "NPOSIXU",                      /* 0x1d */
-       "NPOSIXA",                      /* 0x1e */
-       "ASCII",                        /* 0x1f */
-       "NASCII",                       /* 0x20 */
-       "CLUMP",                        /* 0x21 */
-       "BRANCH",                       /* 0x22 */
-       "EXACT",                        /* 0x23 */
-       "EXACTL",                       /* 0x24 */
-       "EXACTF",                       /* 0x25 */
-       "EXACTFL",                      /* 0x26 */
-       "EXACTFU",                      /* 0x27 */
-       "EXACTFAA",                     /* 0x28 */
-       "EXACTFU_SS",                   /* 0x29 */
-       "EXACTFLU8",                    /* 0x2a */
-       "EXACTFAA_NO_TRIE",             /* 0x2b */
-       "NOTHING",                      /* 0x2c */
-       "TAIL",                         /* 0x2d */
-       "STAR",                         /* 0x2e */
-       "PLUS",                         /* 0x2f */
-       "CURLY",                        /* 0x30 */
-       "CURLYN",                       /* 0x31 */
-       "CURLYM",                       /* 0x32 */
-       "CURLYX",                       /* 0x33 */
-       "WHILEM",                       /* 0x34 */
-       "OPEN",                         /* 0x35 */
-       "CLOSE",                        /* 0x36 */
-       "SROPEN",                       /* 0x37 */
-       "SRCLOSE",                      /* 0x38 */
-       "REF",                          /* 0x39 */
-       "REFF",                         /* 0x3a */
-       "REFFL",                        /* 0x3b */
-       "REFFU",                        /* 0x3c */
-       "REFFA",                        /* 0x3d */
-       "NREF",                         /* 0x3e */
-       "NREFF",                        /* 0x3f */
-       "NREFFL",                       /* 0x40 */
-       "NREFFU",                       /* 0x41 */
-       "NREFFA",                       /* 0x42 */
-       "LONGJMP",                      /* 0x43 */
-       "BRANCHJ",                      /* 0x44 */
-       "IFMATCH",                      /* 0x45 */
-       "UNLESSM",                      /* 0x46 */
-       "SUSPEND",                      /* 0x47 */
-       "IFTHEN",                       /* 0x48 */
-       "GROUPP",                       /* 0x49 */
-       "EVAL",                         /* 0x4a */
-       "MINMOD",                       /* 0x4b */
-       "LOGICAL",                      /* 0x4c */
-       "RENUM",                        /* 0x4d */
-       "TRIE",                         /* 0x4e */
-       "TRIEC",                        /* 0x4f */
-       "AHOCORASICK",                  /* 0x50 */
-       "AHOCORASICKC",                 /* 0x51 */
-       "GOSUB",                        /* 0x52 */
-       "NGROUPP",                      /* 0x53 */
-       "INSUBP",                       /* 0x54 */
-       "DEFINEP",                      /* 0x55 */
-       "ENDLIKE",                      /* 0x56 */
-       "OPFAIL",                       /* 0x57 */
-       "ACCEPT",                       /* 0x58 */
-       "VERB",                         /* 0x59 */
-       "PRUNE",                        /* 0x5a */
-       "MARKPOINT",                    /* 0x5b */
-       "SKIP",                         /* 0x5c */
-       "COMMIT",                       /* 0x5d */
-       "CUTGROUP",                     /* 0x5e */
-       "KEEPS",                        /* 0x5f */
-       "LNBREAK",                      /* 0x60 */
-       "OPTIMIZED",                    /* 0x61 */
-       "PSEUDO",                       /* 0x62 */
+       "NANYOFM",                      /* 0x17 */
+       "POSIXD",                       /* 0x18 */
+       "POSIXL",                       /* 0x19 */
+       "POSIXU",                       /* 0x1a */
+       "POSIXA",                       /* 0x1b */
+       "NPOSIXD",                      /* 0x1c */
+       "NPOSIXL",                      /* 0x1d */
+       "NPOSIXU",                      /* 0x1e */
+       "NPOSIXA",                      /* 0x1f */
+       "ASCII",                        /* 0x20 */
+       "NASCII",                       /* 0x21 */
+       "CLUMP",                        /* 0x22 */
+       "BRANCH",                       /* 0x23 */
+       "EXACT",                        /* 0x24 */
+       "EXACTL",                       /* 0x25 */
+       "EXACTF",                       /* 0x26 */
+       "EXACTFL",                      /* 0x27 */
+       "EXACTFU",                      /* 0x28 */
+       "EXACTFAA",                     /* 0x29 */
+       "EXACTFU_SS",                   /* 0x2a */
+       "EXACTFLU8",                    /* 0x2b */
+       "EXACTFAA_NO_TRIE",             /* 0x2c */
+       "NOTHING",                      /* 0x2d */
+       "TAIL",                         /* 0x2e */
+       "STAR",                         /* 0x2f */
+       "PLUS",                         /* 0x30 */
+       "CURLY",                        /* 0x31 */
+       "CURLYN",                       /* 0x32 */
+       "CURLYM",                       /* 0x33 */
+       "CURLYX",                       /* 0x34 */
+       "WHILEM",                       /* 0x35 */
+       "OPEN",                         /* 0x36 */
+       "CLOSE",                        /* 0x37 */
+       "SROPEN",                       /* 0x38 */
+       "SRCLOSE",                      /* 0x39 */
+       "REF",                          /* 0x3a */
+       "REFF",                         /* 0x3b */
+       "REFFL",                        /* 0x3c */
+       "REFFU",                        /* 0x3d */
+       "REFFA",                        /* 0x3e */
+       "NREF",                         /* 0x3f */
+       "NREFF",                        /* 0x40 */
+       "NREFFL",                       /* 0x41 */
+       "NREFFU",                       /* 0x42 */
+       "NREFFA",                       /* 0x43 */
+       "LONGJMP",                      /* 0x44 */
+       "BRANCHJ",                      /* 0x45 */
+       "IFMATCH",                      /* 0x46 */
+       "UNLESSM",                      /* 0x47 */
+       "SUSPEND",                      /* 0x48 */
+       "IFTHEN",                       /* 0x49 */
+       "GROUPP",                       /* 0x4a */
+       "EVAL",                         /* 0x4b */
+       "MINMOD",                       /* 0x4c */
+       "LOGICAL",                      /* 0x4d */
+       "RENUM",                        /* 0x4e */
+       "TRIE",                         /* 0x4f */
+       "TRIEC",                        /* 0x50 */
+       "AHOCORASICK",                  /* 0x51 */
+       "AHOCORASICKC",                 /* 0x52 */
+       "GOSUB",                        /* 0x53 */
+       "NGROUPP",                      /* 0x54 */
+       "INSUBP",                       /* 0x55 */
+       "DEFINEP",                      /* 0x56 */
+       "ENDLIKE",                      /* 0x57 */
+       "OPFAIL",                       /* 0x58 */
+       "ACCEPT",                       /* 0x59 */
+       "VERB",                         /* 0x5a */
+       "PRUNE",                        /* 0x5b */
+       "MARKPOINT",                    /* 0x5c */
+       "SKIP",                         /* 0x5d */
+       "COMMIT",                       /* 0x5e */
+       "CUTGROUP",                     /* 0x5f */
+       "KEEPS",                        /* 0x60 */
+       "LNBREAK",                      /* 0x61 */
+       "OPTIMIZED",                    /* 0x62 */
+       "PSEUDO",                       /* 0x63 */
        /* ------------ States ------------- */
        "TRIE_next",                    /* REGNODE_MAX +0x01 */
        "TRIE_next_fail",               /* REGNODE_MAX +0x02 */
@@ -753,7 +758,7 @@ EXTCONST U8 PL_varies[] __attribute__deprecated__ = {
 EXTCONST U8 PL_varies_bitmask[];
 #else
 EXTCONST U8 PL_varies_bitmask[] = {
-    0x00, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x1F, 0xFE, 0x97, 0x01, 0x00, 0x00, 0x00
+    0x00, 0x00, 0x00, 0x00, 0x0C, 0x80, 0x3F, 0xFC, 0x2F, 0x03, 0x00, 0x00, 0x00
 };
 #endif /* DOINIT */
 
@@ -765,9 +770,9 @@ EXTCONST U8 PL_varies_bitmask[] = {
 EXTCONST U8 PL_simple[] __attribute__deprecated__;
 #else
 EXTCONST U8 PL_simple[] __attribute__deprecated__ = {
-    REG_ANY, SANY, ANYOF, ANYOFD, ANYOFL, ANYOFPOSIXL, ANYOFM, POSIXD,
-    POSIXL, POSIXU, POSIXA, NPOSIXD, NPOSIXL, NPOSIXU, NPOSIXA, ASCII,
-    NASCII,
+    REG_ANY, SANY, ANYOF, ANYOFD, ANYOFL, ANYOFPOSIXL, ANYOFM, NANYOFM,
+    POSIXD, POSIXL, POSIXU, POSIXA, NPOSIXD, NPOSIXL, NPOSIXU, NPOSIXA,
+    ASCII, NASCII,
     0
 };
 #endif /* DOINIT */
@@ -776,7 +781,7 @@ EXTCONST U8 PL_simple[] __attribute__deprecated__ = {
 EXTCONST U8 PL_simple_bitmask[];
 #else
 EXTCONST U8 PL_simple_bitmask[] = {
-    0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 #endif /* DOINIT */
 
index b452243..7576a77 100644 (file)
@@ -52,7 +52,7 @@ my @tests = (
     '(?l:[\x{212A}])' => 'ANYOFL[212A]',
     '(?l:[\s\x{212A}])' => 'ANYOFPOSIXL[\s][1680 2000-200A 2028-2029 202F 205F 212A 3000]',
     '(?l:[^\S\x{202F}])' => 'ANYOFPOSIXL[^\\S][1680 2000-200A 2028-2029 205F 3000]',
-    '(?i:[^:])' => 'ANYOF[^:][0100-INFINITY]',
+    '(?i:[^:])' => 'NANYOFM[:]',
     '[\p{Any}]' => 'ANYOF[\x00-\xFF][0100-10FFFF]',
     '[\p{IsMyRuntimeProperty}]' => 'ANYOF[+utf8::IsMyRuntimeProperty]',
     '[^\p{IsMyRuntimeProperty}]' => 'ANYOF[^{+utf8::IsMyRuntimeProperty}]',