REPORT_LOCATION_ARGS(offset)); \
} STMT_END
+/* These have asserts in them because of [perl #122671] Many warnings in
+ * regcomp.c can occur twice. If they get output in pass1 and later in that
+ * pass, the pattern has to be converted to UTF-8 and the pass restarted, they
+ * would get output again. So they should be output in pass2, and these
+ * asserts make sure new warnings follow that paradigm. */
/* m is not necessarily a "literal string", in this macro */
#define reg_warn_non_literal_string(loc, m) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_warner(aTHX_ packWARN(WARN_REGEXP), "%s" REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_warner(aTHX_ packWARN(WARN_REGEXP), "%s" REPORT_LOCATION, \
m, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARNreg(loc,m) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define vWARN_dep(loc, m) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_warner(aTHX_ packWARN(WARN_DEPRECATED), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_warner(aTHX_ packWARN(WARN_DEPRECATED), m REPORT_LOCATION, \
REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARNdep(loc,m) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED), \
+ __ASSERT_(PASS2) Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED), \
m REPORT_LOCATION, \
REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARNregdep(loc,m) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner_d(aTHX_ packWARN2(WARN_DEPRECATED, WARN_REGEXP), \
+ __ASSERT_(PASS2) Perl_ck_warner_d(aTHX_ packWARN2(WARN_DEPRECATED, WARN_REGEXP), \
m REPORT_LOCATION, \
REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARN2reg_d(loc,m, a1) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner_d(aTHX_ packWARN(WARN_REGEXP), \
+ __ASSERT_(PASS2) Perl_ck_warner_d(aTHX_ packWARN(WARN_REGEXP), \
m REPORT_LOCATION, \
a1, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARN2reg(loc, m, a1) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
a1, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define vWARN3(loc, m, a1, a2) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
a1, a2, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARN3reg(loc, m, a1, a2) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
a1, a2, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define vWARN4(loc, m, a1, a2, a3) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
a1, a2, a3, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define ckWARN4reg(loc, m, a1, a2, a3) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
a1, a2, a3, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
#define vWARN5(loc, m, a1, a2, a3, a4) STMT_START { \
const IV offset = loc - RExC_precomp; \
- Perl_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
+ __ASSERT_(PASS2) Perl_warner(aTHX_ packWARN(WARN_REGEXP), m REPORT_LOCATION, \
a1, a2, a3, a4, REPORT_LOCATION_ARGS(offset)); \
} STMT_END
PerlIO_printf(Perl_debug_log,"\n"); \
});
+#ifdef DEBUGGING
+
+/* is c a control character for which we have a mnemonic? */
+#define isMNEMONIC_CNTRL(c) _IS_MNEMONIC_CNTRL_ONLY_FOR_USE_BY_REGCOMP_DOT_C(c)
+
+STATIC const char *
+S_cntrl_to_mnemonic(const U8 c)
+{
+ /* Returns the mnemonic string that represents character 'c', if one
+ * exists; NULL otherwise. The only ones that exist for the purposes of
+ * this routine are a few control characters */
+
+ switch (c) {
+ case '\a': return "\\a";
+ case '\b': return "\\b";
+ case ESC_NATIVE: return "\\e";
+ case '\f': return "\\f";
+ case '\n': return "\\n";
+ case '\r': return "\\r";
+ case '\t': return "\\t";
+ }
+
+ return NULL;
+}
+
+#endif
+
/* Mark that we cannot extend a found fixed substring at this point.
Update the longest found anchored substring and the longest found
floating substrings if needed. */
ssc->invlist = sv_2mortal(_new_invlist(2)); /* mortalize so won't leak */
_append_range_to_invlist(ssc->invlist, 0, UV_MAX);
- ANYOF_FLAGS(ssc) |= ANYOF_EMPTY_STRING; /* Plus match empty string */
+ ANYOF_FLAGS(ssc) |= SSC_MATCHES_EMPTY_STRING; /* Plus matches empty */
}
STATIC int
assert(is_ANYOF_SYNTHETIC(ssc));
- if (! (ANYOF_FLAGS(ssc) & ANYOF_EMPTY_STRING)) {
+ if (! (ANYOF_FLAGS(ssc) & SSC_MATCHES_EMPTY_STRING)) {
return FALSE;
}
Zero(ssc, 1, regnode_ssc);
set_ANYOF_SYNTHETIC(ssc);
- ARG_SET(ssc, ANYOF_NONBITMAP_EMPTY);
+ ARG_SET(ssc, ANYOF_ONLY_HAS_BITMAP);
ssc_anything(ssc);
/* If any portion of the regex is to operate under locale rules,
PERL_ARGS_ASSERT_GET_ANYOF_CP_LIST_FOR_SSC;
/* Look at the data structure created by S_set_ANYOF_arg() */
- if (n != ANYOF_NONBITMAP_EMPTY) {
+ if (n != ANYOF_ONLY_HAS_BITMAP) {
SV * const rv = MUTABLE_SV(RExC_rxi->data->data[n]);
AV * const av = MUTABLE_AV(SvRV(rv));
SV **const ary = AvARRAY(av);
/* If this can match all upper Latin1 code points, have to add them
* as well */
- if (ANYOF_FLAGS(node) & ANYOF_NON_UTF8_NON_ASCII_ALL) {
+ if (ANYOF_FLAGS(node) & ANYOF_MATCHES_ALL_NON_UTF8_NON_ASCII) {
_invlist_union(invlist, PL_UpperLatin1, &invlist);
}
/* Similarly for these */
- if (ANYOF_FLAGS(node) & ANYOF_ABOVE_LATIN1_ALL) {
- invlist = _add_range_to_invlist(invlist, 256, UV_MAX);
+ if (ANYOF_FLAGS(node) & ANYOF_MATCHES_ALL_ABOVE_BITMAP) {
+ _invlist_union_complement_2nd(invlist, PL_InBitmap, &invlist);
}
if (ANYOF_FLAGS(node) & ANYOF_INVERT) {
#define ssc_match_all_cp(ssc) ssc_add_range(ssc, 0, UV_MAX)
/* 'AND' a given class with another one. Can create false positives. 'ssc'
- * should not be inverted. 'and_with->flags & ANYOF_POSIXL' should be 0 if
- * 'and_with' is a regnode_charclass instead of a regnode_ssc. */
+ * should not be inverted. 'and_with->flags & ANYOF_MATCHES_POSIXL' should be
+ * 0 if 'and_with' is a regnode_charclass instead of a regnode_ssc. */
STATIC void
S_ssc_and(pTHX_ const RExC_state_t *pRExC_state, regnode_ssc *ssc,
/* If either P1 or P2 is empty, the intersection will be also; can skip
* the loop */
- if (! (ANYOF_FLAGS(and_with) & ANYOF_POSIXL)) {
+ if (! (ANYOF_FLAGS(and_with) & ANYOF_MATCHES_POSIXL)) {
ANYOF_POSIXL_ZERO(ssc);
}
else if (ANYOF_POSIXL_SSC_TEST_ANY_SET(ssc)) {
else {
ssc->invlist = anded_cp_list;
ANYOF_POSIXL_ZERO(ssc);
- if (ANYOF_FLAGS(and_with) & ANYOF_POSIXL) {
+ if (ANYOF_FLAGS(and_with) & ANYOF_MATCHES_POSIXL) {
ANYOF_POSIXL_OR((regnode_charclass_posixl*) and_with, ssc);
}
}
}
else if (ANYOF_POSIXL_SSC_TEST_ANY_SET(ssc)
- || (ANYOF_FLAGS(and_with) & ANYOF_POSIXL))
+ || (ANYOF_FLAGS(and_with) & ANYOF_MATCHES_POSIXL))
{
/* One or the other of P1, P2 is non-empty. */
- if (ANYOF_FLAGS(and_with) & ANYOF_POSIXL) {
+ if (ANYOF_FLAGS(and_with) & ANYOF_MATCHES_POSIXL) {
ANYOF_POSIXL_AND((regnode_charclass_posixl*) and_with, ssc);
}
ssc_union(ssc, anded_cp_list, FALSE);
{
/* We ignore P2, leaving P1 going forward */
} /* else Not inverted */
- else if (ANYOF_FLAGS(or_with) & ANYOF_POSIXL) {
+ else if (ANYOF_FLAGS(or_with) & ANYOF_MATCHES_POSIXL) {
ANYOF_POSIXL_OR((regnode_charclass_posixl*)or_with, ssc);
if (ANYOF_POSIXL_SSC_TEST_ANY_SET(ssc)) {
unsigned int i;
assert(is_ANYOF_SYNTHETIC(ssc));
/* The code in this file assumes that all but these flags aren't relevant
- * to the SSC, except ANYOF_EMPTY_STRING, which should be cleared by the
- * time we reach here */
+ * to the SSC, except SSC_MATCHES_EMPTY_STRING, which should be cleared
+ * by the time we reach here */
assert(! (ANYOF_FLAGS(ssc) & ~ANYOF_COMMON_FLAGS));
populate_ANYOF_from_invlist( (regnode *) ssc, &invlist);
ssc->invlist = NULL;
if (ANYOF_POSIXL_SSC_TEST_ANY_SET(ssc)) {
- ANYOF_FLAGS(ssc) |= ANYOF_POSIXL;
+ ANYOF_FLAGS(ssc) |= ANYOF_MATCHES_POSIXL;
}
assert(! (ANYOF_FLAGS(ssc) & ANYOF_LOCALE_FLAGS) || RExC_contains_locale);
* can't match null string */
if (flags & SCF_DO_STCLASS_AND) {
ssc_cp_and(data->start_class, uc);
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class) &= ~SSC_MATCHES_EMPTY_STRING;
ssc_clear_locale(data->start_class);
}
else if (flags & SCF_DO_STCLASS_OR) {
ssc_and(pRExC_state, data->start_class, (regnode_charclass *) and_withp);
/* See commit msg 749e076fceedeb708a624933726e7989f2302f6a */
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class) &= ~SSC_MATCHES_EMPTY_STRING;
}
flags &= ~SCF_DO_STCLASS;
}
}
}
if (flags & SCF_DO_STCLASS_AND) {
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class) &= ~SSC_MATCHES_EMPTY_STRING;
ANYOF_POSIXL_ZERO(data->start_class);
ssc_intersection(data->start_class, EXACTF_invlist, FALSE);
}
ssc_and(pRExC_state, data->start_class, (regnode_charclass *) and_withp);
/* See commit msg 749e076fceedeb708a624933726e7989f2302f6a */
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class) &= ~SSC_MATCHES_EMPTY_STRING;
}
flags &= ~SCF_DO_STCLASS;
SvREFCNT_dec(EXACTF_invlist);
flags &= ~SCF_DO_STCLASS_AND;
StructCopy(&this_class, data->start_class, regnode_ssc);
flags |= SCF_DO_STCLASS_OR;
- ANYOF_FLAGS(data->start_class) |= ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class)
+ |= SSC_MATCHES_EMPTY_STRING;
}
} else { /* Non-zero len */
if (flags & SCF_DO_STCLASS_OR) {
ssc_intersection(data->start_class,
PL_XPosix_ptrs[_CC_VERTSPACE], FALSE);
ssc_clear_locale(data->start_class);
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class)
+ &= ~SSC_MATCHES_EMPTY_STRING;
}
else if (flags & SCF_DO_STCLASS_OR) {
ssc_union(data->start_class,
/* See commit msg for
* 749e076fceedeb708a624933726e7989f2302f6a */
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class)
+ &= ~SSC_MATCHES_EMPTY_STRING;
}
flags &= ~SCF_DO_STCLASS;
}
U8 namedclass;
/* See commit msg 749e076fceedeb708a624933726e7989f2302f6a */
- ANYOF_FLAGS(data->start_class) &= ~ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class) &= ~SSC_MATCHES_EMPTY_STRING;
/* Some of the logic below assumes that switching
locale on will only add false positives. */
* assertions are zero-length, so can match an EMPTY
* string */
ssc_and(pRExC_state, data->start_class, (regnode_charclass *) &intrnl);
- ANYOF_FLAGS(data->start_class) |= ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class)
+ |= SSC_MATCHES_EMPTY_STRING;
}
}
}
if (f & SCF_DO_STCLASS_AND) {
ssc_and(pRExC_state, data->start_class, (regnode_charclass *) &intrnl);
- ANYOF_FLAGS(data->start_class) |= ANYOF_EMPTY_STRING;
+ ANYOF_FLAGS(data->start_class) |= SSC_MATCHES_EMPTY_STRING;
}
if (data) {
if (data_fake.flags & (SF_HAS_PAR|SF_IN_PAR))
char **pat_p, STRLEN *plen_p, int num_code_blocks)
{
U8 *const src = (U8*)*pat_p;
- U8 *dst;
+ U8 *dst, *d;
int n=0;
- STRLEN s = 0, d = 0;
+ STRLEN s = 0;
bool do_end = 0;
GET_RE_DEBUG_FLAGS_DECL;
"UTF8 mismatch! Converting to utf8 for resizing and compile\n"));
Newx(dst, *plen_p * 2 + 1, U8);
+ d = dst;
while (s < *plen_p) {
- if (NATIVE_BYTE_IS_INVARIANT(src[s]))
- dst[d] = src[s];
- else {
- dst[d++] = UTF8_EIGHT_BIT_HI(src[s]);
- dst[d] = UTF8_EIGHT_BIT_LO(src[s]);
- }
+ append_utf8_from_native_byte(src[s], &d);
if (n < num_code_blocks) {
if (!do_end && pRExC_state->code_blocks[n].start == s) {
- pRExC_state->code_blocks[n].start = d;
- assert(dst[d] == '(');
+ pRExC_state->code_blocks[n].start = d - dst - 1;
+ assert(*(d - 1) == '(');
do_end = 1;
}
else if (do_end && pRExC_state->code_blocks[n].end == s) {
- pRExC_state->code_blocks[n].end = d;
- assert(dst[d] == ')');
+ pRExC_state->code_blocks[n].end = d - dst - 1;
+ assert(*(d - 1) == ')');
do_end = 0;
n++;
}
}
s++;
- d++;
}
- dst[d] = '\0';
- *plen_p = d;
+ *d = '\0';
+ *plen_p = d - dst;
*pat_p = (char*) dst;
SAVEFREEPV(*pat_p);
RExC_orig_utf8 = RExC_utf8 = 1;
PL_utf8_foldable = _new_invlist_C_array(_Perl_Any_Folds_invlist);
PL_HasMultiCharFold =
_new_invlist_C_array(_Perl_Folds_To_Multi_Char_invlist);
+
+ /* This is calculated here, because the Perl program that generates the
+ * static global ones doesn't currently have access to
+ * NUM_ANYOF_CODE_POINTS */
+ PL_InBitmap = _new_invlist(2);
+ PL_InBitmap = _add_range_to_invlist(PL_InBitmap, 0,
+ NUM_ANYOF_CODE_POINTS - 1);
}
#endif
if ((!(r->anchored_substr || r->anchored_utf8) || r->anchored_offset)
&& stclass_flag
- && ! (ANYOF_FLAGS(data.start_class) & ANYOF_EMPTY_STRING)
+ && ! (ANYOF_FLAGS(data.start_class) & SSC_MATCHES_EMPTY_STRING)
&& !ssc_is_anything(data.start_class))
{
const U32 n = add_data(pRExC_state, STR_WITH_LEN("f"));
r->check_substr = r->check_utf8 = r->anchored_substr = r->anchored_utf8
= r->float_substr = r->float_utf8 = NULL;
- if (! (ANYOF_FLAGS(data.start_class) & ANYOF_EMPTY_STRING)
+ if (! (ANYOF_FLAGS(data.start_class) & SSC_MATCHES_EMPTY_STRING)
&& ! ssc_is_anything(data.start_class))
{
const U32 n = add_data(pRExC_state, STR_WITH_LEN("f"));
/* Guard against an embedded (?=) or (?<=) with a longer minlen than
the "real" pattern. */
DEBUG_OPTIMISE_r({
- PerlIO_printf(Perl_debug_log,"minlen: %"IVdf" r->minlen:%"IVdf" maxlen:%ld\n",
- (IV)minlen, (IV)r->minlen, RExC_maxlen);
+ PerlIO_printf(Perl_debug_log,"minlen: %"IVdf" r->minlen:%"IVdf" maxlen:%"IVdf"\n",
+ (IV)minlen, (IV)r->minlen, (IV)RExC_maxlen);
});
r->minlenret = minlen;
if (r->minlen < minlen)
/*NOTREACHED*/
case ONCE_PAT_MOD: /* 'o' */
case GLOBAL_PAT_MOD: /* 'g' */
- if (SIZE_ONLY && ckWARN(WARN_REGEXP)) {
+ if (PASS2 && ckWARN(WARN_REGEXP)) {
const I32 wflagbit = *RExC_parse == 'o'
? WASTED_O
: WASTED_G;
break;
case CONTINUE_PAT_MOD: /* 'c' */
- if (SIZE_ONLY && ckWARN(WARN_REGEXP)) {
+ if (PASS2 && ckWARN(WARN_REGEXP)) {
if (! (wastedflags & WASTED_C) ) {
wastedflags |= WASTED_GC;
/* diag_listed_as: Useless (?-%s) - don't use /%s modifier in regex; marked by <-- HERE in m/%s/ */
break;
case KEEPCOPY_PAT_MOD: /* 'p' */
if (flagsp == &negflags) {
- if (SIZE_ONLY)
+ if (PASS2)
ckWARNreg(RExC_parse + 1,"Useless use of (?-p)");
} else {
*flagsp |= RXf_PMf_KEEPCOPY;
if (max < min) { /* If can't match, warn and optimize to fail
unconditionally */
if (SIZE_ONLY) {
- ckWARNreg(RExC_parse, "Quantifier {n,m} with n > m can't match");
/* We can't back off the size because we have to reserve
* enough space for all the things we are about to throw
RExC_size = PREVOPER(RExC_size) - regarglen[(U8)OPFAIL];
}
else {
+ ckWARNreg(RExC_parse, "Quantifier {n,m} with n > m can't match");
RExC_emit = orig_emit;
}
ret = reg_node(pRExC_state, OPFAIL);
&& RExC_parse < RExC_end
&& (*RExC_parse == '?' || *RExC_parse == '+'))
{
- if (SIZE_ONLY) {
+ if (PASS2) {
ckWARN2reg(RExC_parse + 1,
"Useless use of greediness modifier '%c'",
*RExC_parse);
return(ret);
}
-STATIC bool
+STATIC STRLEN
S_grok_bslash_N(pTHX_ RExC_state_t *pRExC_state, regnode** node_p,
- UV *valuep, I32 *flagp, U32 depth, bool in_char_class,
- const bool strict /* Apply stricter parsing rules? */
+ UV *valuep, I32 *flagp, U32 depth, SV** substitute_parse
)
{
and needs to handle the rest. RExC_parse is expected to point at the first
char following the N at the time of the call. On successful return,
RExC_parse has been updated to point to just after the sequence identified
- by this routine, and <*flagp> has been updated.
-
- The \N may be inside (indicated by the boolean <in_char_class>) or outside a
- character class.
-
- \N may begin either a named sequence, or if outside a character class, mean
- to match a non-newline. For non single-quoted regexes, the tokenizer has
- attempted to decide which, and in the case of a named sequence, converted it
+ by this routine, <*flagp> has been updated, and the non-NULL input pointers
+ have been set appropriately.
+
+ The typical case for this is \N{some character name}. This is usually
+ called while parsing the input, filling in or ready to fill in an EXACTish
+ node, and the code point for the character should be returned, so that it
+ can be added to the node, and parsing continued with the next input
+ character. But it may be that instead of a single character the \N{}
+ expands to more than one, a named sequence. In this case any following
+ quantifier applies to the whole sequence, and it is easier, given the code
+ structure that calls this, to handle it from a different area of the code.
+ For this reason, the input parameters can be set so that it returns valid
+ only on one or the other of these cases.
+
+ Another possibility is for the input to be an empty \N{}, which for
+ backwards compatibility we accept, but generate a NOTHING node which should
+ later get optimized out. This is handled from the area of code which can
+ handle a named sequence, so if called with the parameters for the other, it
+ fails.
+
+ Still another possibility is for the \N to mean [^\n], and not a single
+ character or explicit sequence at all. This is determined by context.
+ Again, this is handled from the area of code which can handle a named
+ sequence, so if called with the parameters for the other, it also fails.
+
+ And the final possibility is for the \N to be called from within a bracketed
+ character class. In this case the [^\n] meaning makes no sense, and so is
+ an error. Other anomalous situations are left to the calling code to handle.
+
+ For non-single-quoted regexes, the tokenizer has attempted to decide which
+ of the above applies, and in the case of a named sequence, has converted it
into one of the forms: \N{} (if the sequence is null), or \N{U+c1.c2...},
where c1... are the characters in the sequence. For single-quoted regexes,
the tokenizer passes the \N sequence through unchanged; this code will not
attempt to determine this nor expand those, instead raising a syntax error.
The net effect is that if the beginning of the passed-in pattern isn't '{U+'
or there is no '}', it signals that this \N occurrence means to match a
- non-newline.
+ non-newline. (This mostly was done because of [perl #56444].)
- Only the \N{U+...} form should occur in a character class, for the same
- reason that '.' inside a character class means to just match a period: it
- just doesn't make sense.
+ The API is somewhat convoluted due to historical and the above reasons.
The function raises an error (via vFAIL), and doesn't return for various
- syntax errors. Otherwise it returns TRUE and sets <node_p> or <valuep> on
- success; it returns FALSE otherwise. Returns FALSE, setting *flagp to
- RESTART_UTF8 if the sizing scan needs to be restarted. Such a restart is
- only possible if node_p is non-NULL.
-
+ syntax errors. For other failures, it returns (STRLEN) -1. For successes,
+ it returns a count of how many characters were accounted for by it. (This
+ can be 0 for \N{}; 1 for it meaning [^\n]; and otherwise the number of code
+ points in the sequence. It sets <node_p>, <valuep>, and/or
+ <substitute_parse> on success.
If <valuep> is non-null, it means the caller can accept an input sequence
- consisting of a just a single code point; <*valuep> is set to that value
- if the input is such.
-
- If <node_p> is non-null it signifies that the caller can accept any other
- legal sequence (i.e., one that isn't just a single code point). <*node_p>
- is set as follows:
- 1) \N means not-a-NL: points to a newly created REG_ANY node;
- 2) \N{}: points to a new NOTHING node;
+ consisting of a just a single code point; <*valuep> is set to the value
+ of the only or first code point in the input.
+
+ If <substitute_parse> is non-null, it means the caller can accept an input
+ sequence consisting of one or more code points; <*substitute_parse> is a
+ newly created mortal SV* in this case, containing \x{} escapes representing
+ those code points.
+
+ Both <valuep> and <substitute_parse> can be non-NULL.
+
+ If <node_p> is non-null, <substitute_parse> must be NULL. This signifies
+ that the caller can accept any legal sequence other than a single code
+ point. To wit, <*node_p> is set as follows:
+ 1) \N means not-a-NL: points to a newly created REG_ANY node; return is 1
+ 2) \N{}: points to a new NOTHING node; return is 0
3) otherwise: points to a new EXACT node containing the resolved
- string.
- Note that FALSE is returned for single code point sequences if <valuep> is
- null.
+ string; return is the number of code points in the
+ string. This will never be 1.
+ Note that failure is returned for single code point sequences if <valuep> is
+ null and <node_p> is not.
*/
char * endbrace; /* '}' following the name */
stream */
bool has_multiple_chars; /* true if the input stream contains a sequence of
more than one character */
+ bool in_char_class = substitute_parse != NULL;
+ STRLEN count = 0; /* Number of characters in this sequence */
GET_RE_DEBUG_FLAGS_DECL;
GET_RE_DEBUG_FLAGS;
assert(cBOOL(node_p) ^ cBOOL(valuep)); /* Exactly one should be set */
+ assert(! (node_p && substitute_parse)); /* At most 1 should be set */
/* The [^\n] meaning of \N ignores spaces and comments under the /x
* modifier. The other meaning does not, so use a temporary until we find
if (in_char_class) {
vFAIL("\\N in a character class must be a named character: \\N{...}");
}
- return FALSE;
+ return (STRLEN) -1;
}
RExC_parse--; /* Need to back off so nextchar() doesn't skip the
current char */
*flagp |= HASWIDTH|SIMPLE;
RExC_naughty++;
Set_Node_Length(*node_p, 1); /* MJD */
- return TRUE;
+ return 1;
}
/* Here, we have decided it should be a named character or sequence */
}
if (endbrace == RExC_parse) { /* empty: \N{} */
- bool ret = TRUE;
if (node_p) {
*node_p = reg_node(pRExC_state,NOTHING);
}
- else if (in_char_class) {
- if (SIZE_ONLY && in_char_class) {
- if (strict) {
- RExC_parse++; /* Position after the "}" */
- vFAIL("Zero length \\N{}");
- }
- else {
- ckWARNreg(RExC_parse,
- "Ignoring zero length \\N{} in character class");
- }
- }
- ret = FALSE;
- }
- else {
- return FALSE;
+ else if (! in_char_class) {
+ return (STRLEN) -1;
}
nextchar(pRExC_state);
- return ret;
+ return 0;
}
RExC_uni_semantics = 1; /* Unicode named chars imply Unicode semantics */
* point, and is terminated by the brace */
has_multiple_chars = (endchar < endbrace);
- if (valuep && (! has_multiple_chars || in_char_class)) {
- /* We only pay attention to the first char of
- multichar strings being returned in char classes. I kinda wonder
- if this makes sense as it does change the behaviour
- from earlier versions, OTOH that behaviour was broken
- as well. XXX Solution is to recharacterize as
- [rest-of-class]|multi1|multi2... */
-
+ /* We get the first code point if we want it, and either there is only one,
+ * or we can accept both cases of one and more than one */
+ if (valuep && (substitute_parse || ! has_multiple_chars)) {
STRLEN length_of_hex = (STRLEN)(endchar - RExC_parse);
I32 grok_hex_flags = PERL_SCAN_ALLOW_UNDERSCORES
| PERL_SCAN_DISALLOW_PREFIX
- | (SIZE_ONLY ? PERL_SCAN_SILENT_ILLDIGIT : 0);
+
+ /* No errors in the first pass (See [perl
+ * #122671].) We let the code below find the
+ * errors when there are multiple chars. */
+ | ((SIZE_ONLY || has_multiple_chars)
+ ? PERL_SCAN_SILENT_ILLDIGIT
+ : 0);
*valuep = grok_hex(RExC_parse, &length_of_hex, &grok_hex_flags, NULL);
/* The tokenizer should have guaranteed validity, but it's possible to
- * bypass it by using single quoting, so check */
+ * bypass it by using single quoting, so check. Don't do the check
+ * here when there are multiple chars; we do it below anyway. */
+ if (! has_multiple_chars) {
if (length_of_hex == 0
|| length_of_hex != (STRLEN)(endchar - RExC_parse) )
{
vFAIL("Invalid hexadecimal number in \\N{U+...}");
}
- if (in_char_class && has_multiple_chars) {
- if (strict) {
- RExC_parse = endbrace;
- vFAIL("\\N{} in character class restricted to one character");
- }
- else {
- ckWARNreg(endchar, "Using just the first character returned by \\N{} in character class");
- }
- }
-
RExC_parse = endbrace + 1;
+ return 1;
+ }
}
- else if (! node_p || ! has_multiple_chars) {
- /* Here, the input is legal, but not according to the caller's
- * options. We fail without advancing the parse, so that the
- * caller can try again */
+ /* Here, we should have already handled the case where a single character
+ * is expected and found. So it is a failure if we aren't expecting
+ * multiple chars and got them; or didn't get them but wanted them. We
+ * fail without advancing the parse, so that the caller can try again with
+ * different acceptance criteria */
+ if ((! node_p && ! substitute_parse) || ! has_multiple_chars) {
RExC_parse = p;
- return FALSE;
+ return (STRLEN) -1;
}
- else {
+
+ {
/* What is done here is to convert this to a sub-pattern of the form
- * (?:\x{char1}\x{char2}...)
- * and then call reg recursively. That way, it retains its atomicness,
- * while not having to worry about special handling that some code
- * points may have. toke.c has converted the original Unicode values
- * to native, so that we can just pass on the hex values unchanged. We
- * do have to set a flag to keep recoding from happening in the
- * recursion */
-
- SV * substitute_parse = newSVpvn_flags("?:", 2, SVf_UTF8|SVs_TEMP);
+ * \x{char1}\x{char2}...
+ * and then either return it in <*substitute_parse> if non-null; or
+ * call reg recursively to parse it (enclosing in "(?: ... )" ). That
+ * way, it retains its atomicness, while not having to worry about
+ * special handling that some code points may have. toke.c has
+ * converted the original Unicode values to native, so that we can just
+ * pass on the hex values unchanged. We do have to set a flag to keep
+ * recoding from happening in the recursion */
+
+ SV * dummy = NULL;
STRLEN len;
char *orig_end = RExC_end;
I32 flags;
+ if (substitute_parse) {
+ *substitute_parse = newSVpvs("");
+ }
+ else {
+ substitute_parse = &dummy;
+ *substitute_parse = newSVpvs("?:");
+ }
+ *substitute_parse = sv_2mortal(*substitute_parse);
+
while (RExC_parse < endbrace) {
/* Convert to notation the rest of the code understands */
- sv_catpv(substitute_parse, "\\x{");
- sv_catpvn(substitute_parse, RExC_parse, endchar - RExC_parse);
- sv_catpv(substitute_parse, "}");
+ sv_catpv(*substitute_parse, "\\x{");
+ sv_catpvn(*substitute_parse, RExC_parse, endchar - RExC_parse);
+ sv_catpv(*substitute_parse, "}");
/* Point to the beginning of the next character in the sequence. */
RExC_parse = endchar + 1;
endchar = RExC_parse + strcspn(RExC_parse, ".}");
+
+ count++;
}
- sv_catpv(substitute_parse, ")");
+ if (! in_char_class) {
+ sv_catpv(*substitute_parse, ")");
+ }
- RExC_parse = SvPV(substitute_parse, len);
+ RExC_parse = SvPV(*substitute_parse, len);
/* Don't allow empty number */
- if (len < 8) {
+ if (len < (STRLEN) ((substitute_parse) ? 6 : 8)) {
+ RExC_parse = endbrace;
vFAIL("Invalid hexadecimal number in \\N{U+...}");
}
RExC_end = RExC_parse + len;
/* The values are Unicode, and therefore not subject to recoding */
RExC_override_recoding = 1;
+ if (node_p) {
if (!(*node_p = reg(pRExC_state, 1, &flags, depth+1))) {
if (flags & RESTART_UTF8) {
*flagp = RESTART_UTF8;
- return FALSE;
+ return (STRLEN) -1;
}
FAIL2("panic: reg returned NULL to grok_bslash_N, flags=%#"UVxf"",
(UV) flags);
}
*flagp |= flags&(HASWIDTH|SPSTART|SIMPLE|POSTPONED);
+ }
RExC_parse = endbrace;
RExC_end = orig_end;
nextchar(pRExC_state);
}
- return TRUE;
+ return count;
}
if (LOC || ! FOLD) { /* /l defers folding until runtime */
*character = (U8) code_point;
}
- else { /* Here is /i and not /l (toFOLD() is defined on just
+ else { /* Here is /i and not /l. (toFOLD() is defined on just
ASCII, which isn't the same thing as INVARIANT on
EBCDIC, but it works there, as the extra invariants
fold to themselves) */
? FOLD_FLAGS_NOMIX_ASCII
: 0));
if (downgradable
- && folded == code_point
+ && folded == code_point /* This quickly rules out many
+ cases, avoiding the
+ _invlist_contains_cp() overhead
+ for those. */
&& ! _invlist_contains_cp(PL_utf8_foldable, code_point))
{
OP(node) = EXACT;
ret = reg_node(pRExC_state, CANY);
RExC_seen |= REG_CANY_SEEN;
*flagp |= HASWIDTH|SIMPLE;
- if (SIZE_ONLY) {
+ if (PASS2) {
ckWARNdep(RExC_parse+1, "\\C is deprecated");
}
goto finish_meta_pat;
* special treatment for quantifiers is not needed for such single
* character sequences */
++RExC_parse;
- if (! grok_bslash_N(pRExC_state, &ret, NULL, flagp, depth, FALSE,
- FALSE /* not strict */ )) {
+ if ((STRLEN) -1 == grok_bslash_N(pRExC_state, &ret, NULL, flagp,
+ depth, FALSE))
+ {
if (*flagp & RESTART_UTF8)
return NULL;
RExC_parse--;
* point sequence. Handle those in the switch() above
* */
RExC_parse = p + 1;
- if (! grok_bslash_N(pRExC_state, NULL, &ender,
- flagp, depth, FALSE,
- FALSE /* not strict */ ))
- {
+ if ((STRLEN) -1 == grok_bslash_N(pRExC_state, NULL,
+ &ender,
+ flagp,
+ depth,
+ FALSE
+ )) {
if (*flagp & RESTART_UTF8)
FAIL("panic: grok_bslash_N set RESTART_UTF8");
RExC_parse = p = oldp;
bool valid = grok_bslash_o(&p,
&result,
&error_msg,
- TRUE, /* out warnings */
+ PASS2, /* out warnings */
FALSE, /* not strict */
TRUE, /* Output warnings
for non-
bool valid = grok_bslash_x(&p,
&result,
&error_msg,
- TRUE, /* out warnings */
+ PASS2, /* out warnings */
FALSE, /* not strict */
TRUE, /* Output warnings
for non-
}
case 'c':
p++;
- ender = grok_bslash_c(*p++, SIZE_ONLY);
+ ender = grok_bslash_c(*p++, PASS2);
break;
case '8': case '9': /* must be a backreference */
--p;
REQUIRE_UTF8;
}
p += numlen;
- if (SIZE_ONLY /* like \08, \178 */
+ if (PASS2 /* like \08, \178 */
&& numlen < 3
&& p < RExC_end
&& isDIGIT(*p) && ckWARN(WARN_REGEXP))
if (! RExC_override_recoding) {
SV* enc = PL_encoding;
ender = reg_recode((const char)(U8)ender, &enc);
- if (!enc && SIZE_ONLY)
+ if (!enc && PASS2)
ckWARNreg(p, "Invalid escape in the specified encoding");
REQUIRE_UTF8;
}
UV high;
int i;
- if (end == UV_MAX && start <= 256) {
- ANYOF_FLAGS(node) |= ANYOF_ABOVE_LATIN1_ALL;
+ if (end == UV_MAX && start <= NUM_ANYOF_CODE_POINTS) {
+ ANYOF_FLAGS(node) |= ANYOF_MATCHES_ALL_ABOVE_BITMAP;
}
- else if (end >= 256) {
- ANYOF_FLAGS(node) |= ANYOF_UTF8;
+ else if (end >= NUM_ANYOF_CODE_POINTS) {
+ ANYOF_FLAGS(node) |= ANYOF_HAS_UTF8_NONBITMAP_MATCHES;
}
/* Quit if are above what we should change */
invlist_iterfinish(*invlist_ptr);
/* Done with loop; remove any code points that are in the bitmap from
- * *invlist_ptr; similarly for code points above latin1 if we have a
- * flag to match all of them anyways */
+ * *invlist_ptr; similarly for code points above the bitmap if we have
+ * a flag to match all of them anyways */
if (change_invlist) {
- _invlist_subtract(*invlist_ptr, PL_Latin1, invlist_ptr);
+ _invlist_subtract(*invlist_ptr, PL_InBitmap, invlist_ptr);
}
- if (ANYOF_FLAGS(node) & ANYOF_ABOVE_LATIN1_ALL) {
- _invlist_intersection(*invlist_ptr, PL_Latin1, invlist_ptr);
+ if (ANYOF_FLAGS(node) & ANYOF_MATCHES_ALL_ABOVE_BITMAP) {
+ _invlist_intersection(*invlist_ptr, PL_InBitmap, invlist_ptr);
}
/* If have completely emptied it, remove it completely */
* upon an unescaped ']' that isn't one ending a regclass. To do both
* these things, we need to realize that something preceded by a backslash
* is escaped, so we have to keep track of backslashes */
- if (SIZE_ONLY) {
- UV depth = 0; /* how many nested (?[...]) constructs */
-
+ if (PASS2) {
Perl_ck_warner_d(aTHX_
packWARN(WARN_EXPERIMENTAL__REGEX_SETS),
"The regex_sets feature is experimental" REPORT_LOCATION,
UTF8fARG(UTF,
RExC_end - RExC_start - (RExC_parse - RExC_precomp),
RExC_precomp + (RExC_parse - RExC_precomp)));
+ }
+ else {
+ UV depth = 0; /* how many nested (?[...]) constructs */
while (RExC_parse < RExC_end) {
SV* current = NULL;
default:
/* Use deprecated warning to increase the chances of this being
* output */
- ckWARN2reg_d(RExC_parse, "Perl folding rules are not up-to-date for 0x%02X; please use the perlbug utility to report;", cp);
+ if (PASS2) {
+ ckWARN2reg_d(RExC_parse, "Perl folding rules are not up-to-date for 0x%02X; please use the perlbug utility to report;", cp);
+ }
break;
}
}
if (UCHARAT(RExC_parse) == ']')
goto charclassloop;
-parseit:
while (1) {
if (RExC_parse >= stop_ptr) {
break;
case 'H': namedclass = ANYOF_NHORIZWS; break;
case 'N': /* Handle \N{NAME} in class */
{
- /* We only pay attention to the first char of
- multichar strings being returned. I kinda wonder
- if this makes sense as it does change the behaviour
- from earlier versions, OTOH that behaviour was broken
- as well. */
- if (! grok_bslash_N(pRExC_state, NULL, &value, flagp, depth,
- TRUE, /* => charclass */
- strict))
- {
- if (*flagp & RESTART_UTF8)
- FAIL("panic: grok_bslash_N set RESTART_UTF8");
- goto parseit;
+ SV *as_text;
+ STRLEN cp_count = grok_bslash_N(pRExC_state, NULL, &value,
+ flagp, depth, &as_text);
+ if (*flagp & RESTART_UTF8)
+ FAIL("panic: grok_bslash_N set RESTART_UTF8");
+ if (cp_count != 1) { /* The typical case drops through */
+ assert(cp_count != (STRLEN) -1);
+ if (cp_count == 0) {
+ if (strict) {
+ RExC_parse++; /* Position after the "}" */
+ vFAIL("Zero length \\N{}");
+ }
+ else if (PASS2) {
+ ckWARNreg(RExC_parse,
+ "Ignoring zero length \\N{} in character class");
+ }
+ }
+ else { /* cp_count > 1 */
+ /* We only pay attention to the first char of
+ * multichar strings being returned in char
+ * classes. I kinda wonder if this makes sense as
+ * it does change the behaviour from earlier
+ * versions, OTOH that behaviour was broken as
+ * well. XXX Solution is to recharacterize as
+ * [rest-of-class]|multi1|multi2... */
+ if (strict) {
+ RExC_parse--;
+ vFAIL("\\N{} in character class restricted to one character");
+ }
+ else if (PASS2) {
+ ckWARNreg(RExC_parse, "Using just the first character returned by \\N{} in character class");
+ }
+ break; /* <value> contains the first code
+ point. Drop out of the switch to
+ process it */
+ } /* End of cp_count != 1 */
+
+ /* This element should not be processed further in this
+ * class */
+ element_count--;
+ value = save_value;
+ prevvalue = save_prevvalue;
+ continue; /* Back to top of loop to get next char */
}
+ /* Here, is a single code point, and <value> contains it */
}
break;
case 'p':
* inappropriately, except that any \p{}, including
* this one forces Unicode semantics, which means there
* is no <depends_list> */
- ANYOF_FLAGS(ret) |= ANYOF_NONBITMAP_NON_UTF8;
+ ANYOF_FLAGS(ret)
+ |= ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES;
}
else {
bool valid = grok_bslash_o(&RExC_parse,
&value,
&error_msg,
- SIZE_ONLY, /* warnings in pass
- 1 only */
+ PASS2, /* warnings only in
+ pass 2 */
strict,
silence_non_portable,
UTF);
bool valid = grok_bslash_x(&RExC_parse,
&value,
&error_msg,
- TRUE, /* Output warnings */
+ PASS2, /* Output warnings */
strict,
silence_non_portable,
UTF);
goto recode_encoding;
break;
case 'c':
- value = grok_bslash_c(*RExC_parse++, SIZE_ONLY);
+ value = grok_bslash_c(*RExC_parse++, PASS2);
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7':
if (strict) {
vFAIL("Invalid escape in the specified encoding");
}
- else if (SIZE_ONLY) {
+ else if (PASS2) {
ckWARNreg(RExC_parse,
"Invalid escape in the specified encoding");
}
else {
RExC_emit += ANYOF_POSIXL_SKIP - ANYOF_SKIP;
}
- ANYOF_FLAGS(ret) |= ANYOF_POSIXL;
+ ANYOF_FLAGS(ret) |= ANYOF_MATCHES_POSIXL;
ANYOF_POSIXL_ZERO(ret);
}
/* Coverity thinks it is possible for this to be negative; both
* jhi and khw think it's not, but be safer */
- assert(! (ANYOF_FLAGS(ret) & ANYOF_POSIXL)
+ assert(! (ANYOF_FLAGS(ret) & ANYOF_MATCHES_POSIXL)
|| (namedclass + ((namedclass % 2) ? -1 : 1)) >= 0);
/* See if it already matches the complement of this POSIX
* class */
- if ((ANYOF_FLAGS(ret) & ANYOF_POSIXL)
+ if ((ANYOF_FLAGS(ret) & ANYOF_MATCHES_POSIXL)
&& ANYOF_POSIXL_TEST(ret, namedclass + ((namedclass % 2)
? -1
: 1)))
namedclass % 2 != 0,
posixes_ptr);
}
- continue; /* Go get next character */
}
} /* end of namedclass \blah */
- /* Here, we have a single value. If 'range' is set, it is the ending
- * of a range--check its validity. Later, we will handle each
- * individual code point in the range. If 'range' isn't set, this
- * could be the beginning of a range, so check for that by looking
- * ahead to see if the next real character to be processed is the range
- * indicator--the minus sign */
-
if (skip_white) {
RExC_parse = regpatws(pRExC_state, RExC_parse,
FALSE /* means don't recognize comments */ );
}
+ /* If 'range' is set, 'value' is the ending of a range--check its
+ * validity. (If value isn't a single code point in the case of a
+ * range, we should have figured that out above in the code that
+ * catches false ranges). Later, we will handle each individual code
+ * point in the range. If 'range' isn't set, this could be the
+ * beginning of a range, so check for that by looking ahead to see if
+ * the next real character to be processed is the range indicator--the
+ * minus sign */
+
if (range) {
if (prevvalue > value) /* b-a */ {
const int w = RExC_parse - rangebegin;
/* a bad range like \w-, [:word:]- ? */
if (namedclass > OOB_NAMEDCLASS) {
- if (strict || ckWARN(WARN_REGEXP)) {
- const int w =
- RExC_parse >= rangebegin ?
- RExC_parse - rangebegin : 0;
+ if (strict || (PASS2 && ckWARN(WARN_REGEXP))) {
+ const int w = RExC_parse >= rangebegin
+ ? RExC_parse - rangebegin
+ : 0;
if (strict) {
vFAIL4("False [] range \"%*.*s\"",
w, w, rangebegin);
}
- else {
+ else if (PASS2) {
vWARN4(RExC_parse,
"False [] range \"%*.*s\"",
w, w, rangebegin);
}
}
- /* Here, <prevvalue> is the beginning of the range, if any; or <value>
- * if not */
+ if (namedclass > OOB_NAMEDCLASS) {
+ continue;
+ }
+
+ /* Here, we have a single value, and <prevvalue> is the beginning of
+ * the range, if any; or <value> if not */
/* non-Latin1 code point implies unicode semantics. Must be set in
* pass1 so is there for the whole of pass 2 */
if (DEPENDS_SEMANTICS) {
/* Under /d, everything in the upper half of the Latin1 range
* matches these complements */
- ANYOF_FLAGS(ret) |= ANYOF_NON_UTF8_NON_ASCII_ALL;
+ ANYOF_FLAGS(ret) |= ANYOF_MATCHES_ALL_NON_UTF8_NON_ASCII;
}
else if (AT_LEAST_ASCII_RESTRICTED) {
/* Under /a and /aa, everything above ASCII matches these
else {
cp_list = depends_list;
}
- ANYOF_FLAGS(ret) |= ANYOF_UTF8;
+ ANYOF_FLAGS(ret) |= ANYOF_HAS_UTF8_NONBITMAP_MATCHES;
}
/* If there is a swash and more than one element, we can't use the swash in
{
/* Sets the arg field of an ANYOF-type node 'node', using information about
* the node passed-in. If there is nothing outside the node's bitmap, the
- * arg is set to ANYOF_NONBITMAP_EMPTY. Otherwise, it sets the argument to
+ * arg is set to ANYOF_ONLY_HAS_BITMAP. Otherwise, it sets the argument to
* the count returned by add_data(), having allocated and stored an array,
* av, that that count references, as follows:
* av[0] stores the character class description in its textual form.
if (! cp_list && ! runtime_defns && ! only_utf8_locale_list) {
assert(! (ANYOF_FLAGS(node)
- & (ANYOF_UTF8|ANYOF_NONBITMAP_NON_UTF8)));
- ARG_SET(node, ANYOF_NONBITMAP_EMPTY);
+ & (ANYOF_HAS_UTF8_NONBITMAP_MATCHES
+ |ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES)));
+ ARG_SET(node, ANYOF_ONLY_HAS_BITMAP);
}
else {
AV * const av = newAV();
SV *rv;
assert(ANYOF_FLAGS(node)
- & (ANYOF_UTF8|ANYOF_NONBITMAP_NON_UTF8|ANYOF_LOC_FOLD));
+ & (ANYOF_HAS_UTF8_NONBITMAP_MATCHES
+ |ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES|ANYOF_LOC_FOLD));
av_store(av, 0, (runtime_defns)
? SvREFCNT_inc(runtime_defns) : &PL_sv_undef);
PERL_ARGS_ASSERT__GET_REGCLASS_NONBITMAP_DATA;
assert(ANYOF_FLAGS(node)
- & (ANYOF_UTF8|ANYOF_NONBITMAP_NON_UTF8|ANYOF_LOC_FOLD));
+ & (ANYOF_HAS_UTF8_NONBITMAP_MATCHES
+ |ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES|ANYOF_LOC_FOLD));
if (data && data->count) {
const U32 n = ARG(node);
}
}
- if ((flags & (ANYOF_ABOVE_LATIN1_ALL
- |ANYOF_UTF8
- |ANYOF_NONBITMAP_NON_UTF8
+ if ((flags & (ANYOF_MATCHES_ALL_ABOVE_BITMAP
+ |ANYOF_HAS_UTF8_NONBITMAP_MATCHES
+ |ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES
|ANYOF_LOC_FOLD)))
{
if (do_sep) {
sv_catpvs(sv, "^");
}
- if (flags & ANYOF_NON_UTF8_NON_ASCII_ALL) {
+ if (flags & ANYOF_MATCHES_ALL_NON_UTF8_NON_ASCII) {
sv_catpvs(sv, "{non-utf8-latin1-all}");
}
/* output information about the unicode matching */
- if (flags & ANYOF_ABOVE_LATIN1_ALL)
- sv_catpvs(sv, "{unicode_all}");
- else if (ARG(o) != ANYOF_NONBITMAP_EMPTY) {
+ if (flags & ANYOF_MATCHES_ALL_ABOVE_BITMAP)
+ sv_catpvs(sv, "{above_bitmap_all}");
+ else if (ARG(o) != ANYOF_ONLY_HAS_BITMAP) {
SV *lv; /* Set if there is something outside the bit map. */
bool byte_output = FALSE; /* If something in the bitmap has
been output */
if (*s == '\n') {
const char * const t = ++s;
- if (flags & ANYOF_NONBITMAP_NON_UTF8) {
+ if (flags & ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES) {
sv_catpvs(sv, "{outside bitmap}");
}
else {
#endif
#ifdef DEBUGGING
-
-/* Given that c is a control character, is it one for which we have a
- * mnemonic? */
-#define isMNEMONIC_CNTRL(c) ((isSPACE_A(c) && (c) != '\v') \
- || (c) == '\a' \
- || (c) == '\b' \
- || (c) == ESC_NATIVE)
/* Certain characters are output as a sequence with the first being a
* backslash. */
#define isBACKSLASHED_PUNCT(c) \
((c) == '-' || (c) == ']' || (c) == '\\' || (c) == '^')
STATIC void
-S_put_byte(pTHX_ SV *sv, int c)
+S_put_code_point(pTHX_ SV *sv, UV c)
{
- PERL_ARGS_ASSERT_PUT_BYTE;
-
- if (!isPRINT(c)) {
- switch (c) {
- case '\a': Perl_sv_catpvf(aTHX_ sv, "\\a"); break;
- case '\b': Perl_sv_catpvf(aTHX_ sv, "\\b"); break;
- case ESC_NATIVE: Perl_sv_catpvf(aTHX_ sv, "\\e"); break;
- case '\f': Perl_sv_catpvf(aTHX_ sv, "\\f"); break;
- case '\n': Perl_sv_catpvf(aTHX_ sv, "\\n"); break;
- case '\r': Perl_sv_catpvf(aTHX_ sv, "\\r"); break;
- case '\t': Perl_sv_catpvf(aTHX_ sv, "\\t"); break;
- default: Perl_sv_catpvf(aTHX_ sv, "\\x{%02X}", c); break;
- }
+ PERL_ARGS_ASSERT_PUT_CODE_POINT;
+
+ if (c > 255) {
+ Perl_sv_catpvf(aTHX_ sv, "\\x{%04"UVXf"}", c);
}
- else {
- const char string = c;
+ else if (isPRINT(c)) {
+ const char string = (char) c;
if (isBACKSLASHED_PUNCT(c))
sv_catpvs(sv, "\\");
sv_catpvn(sv, &string, 1);
}
+ else {
+ const char * const mnemonic = cntrl_to_mnemonic((char) c);
+ if (mnemonic) {
+ Perl_sv_catpvf(aTHX_ sv, "%s", mnemonic);
+ }
+ else {
+ Perl_sv_catpvf(aTHX_ sv, "\\x{%02X}", (U8) c);
+ }
+ }
}
#define MAX_PRINT_A MAX_PRINT_A_FOR_USE_ONLY_BY_REGCOMP_DOT_C
{
/* Appends to 'sv' a displayable version of the range of code points from
* 'start' to 'end'. It assumes that only ASCII printables are displayable
- * as-is (though some of these will be escaped by put_byte()). */
+ * as-is (though some of these will be escaped by put_code_point()). */
const unsigned int min_range_count = 3;
PERL_ARGS_ASSERT_PUT_RANGE;
while (start <= end) {
+ UV this_end;
+ const char * format;
+
if (end - start < min_range_count) {
/* Individual chars in short ranges */
for (; start <= end; start++) {
- put_byte(sv, start);
+ put_code_point(sv, start);
}
break;
}
put_range(sv, start, temp_end, FALSE);
}
else { /* Output as a range */
- put_byte(sv, start);
+ put_code_point(sv, start);
sv_catpvs(sv, "-");
- put_byte(sv, temp_end);
+ put_code_point(sv, temp_end);
}
start = temp_end + 1;
continue;
while (start <= end && (isPUNCT_A(start)
|| isSPACE_A(start)))
{
- put_byte(sv, start);
+ put_code_point(sv, start);
start++;
}
continue;
* mnemonic names. Split off any of those at the beginning and end of
* the range to print mnemonically. It isn't possible for many of
* these to be in a row, so this won't overwhelm with output */
- if (isMNEMONIC_CNTRL(start)) {
- while (isMNEMONIC_CNTRL(start) && start <= end) {
- put_byte(sv, start);
- start++;
- }
+ while (isMNEMONIC_CNTRL(start) && start <= end) {
+ put_code_point(sv, start);
+ start++;
}
if (start < end && isMNEMONIC_CNTRL(end)) {
/* Then output the mnemonic trailing controls */
start = temp_end + 1;
while (start <= end) {
- put_byte(sv, start);
+ put_code_point(sv, start);
start++;
}
break;
}
/* As a final resort, output the range or subrange as hex. */
- Perl_sv_catpvf(aTHX_ sv, "\\x{%02" UVXf "}-\\x{%02" UVXf "}",
- start,
- (end < NUM_ANYOF_CODE_POINTS)
- ? end
- : NUM_ANYOF_CODE_POINTS - 1);
+
+ this_end = (end < NUM_ANYOF_CODE_POINTS)
+ ? end
+ : NUM_ANYOF_CODE_POINTS - 1;
+ format = (this_end < 256)
+ ? "\\x{%02"UVXf"}-\\x{%02"UVXf"}"
+ : "\\x{%04"UVXf"}-\\x{%04"UVXf"}";
+ Perl_sv_catpvf(aTHX_ sv, format, start, this_end);
break;
}
}
* ASCII puncts are set, including an extra amount for the backslashed
* ones. */
for (i = 0; i < NUM_ANYOF_CODE_POINTS; i++) {
- if (BITMAP_TEST((U8 *) bitmap,i)) {
+ if (BITMAP_TEST(bitmap, i)) {
*invlist_ptr = add_cp_to_invlist(*invlist_ptr, i);
if (isPUNCT_A(i)) {
punct_count++;
/* Add everything remaining to the list, so when we invert it just
* below, it will be excluded */
- *invlist_ptr = _add_range_to_invlist(*invlist_ptr,
- NUM_ANYOF_CODE_POINTS, UV_MAX);
+ _invlist_union_complement_2nd(*invlist_ptr, PL_InBitmap, invlist_ptr);
_invlist_invert(*invlist_ptr);
}
}
else if (PL_regkind[(U8)op] == ANYOF) {
/* arglen 1 + class block */
- node += 1 + ((ANYOF_FLAGS(node) & ANYOF_POSIXL)
+ node += 1 + ((ANYOF_FLAGS(node) & ANYOF_MATCHES_POSIXL)
? ANYOF_POSIXL_SKIP
: ANYOF_SKIP);
node = NEXTOPER(node);