Commit 35bf9d5ee5 for perl
commit 35bf9d5ee5498b7385c02397f9c786579d69c526
Author: Yves Orton <demerphq@gmail.com>
Date: Tue Oct 27 21:36:43 2026 +0100
regcomp: name CURLY capture properties
Use separate properties for capture numbers in CURLYM and CURLYN nodes
and capture floors in CURLYX nodes. The names distinguish these meanings
of FLAGS in the debugger and executor while preserving the node layout.
diff --git a/regcomp.h b/regcomp.h
index ff4315c1c7..814b27b919 100644
--- a/regcomp.h
+++ b/regcomp.h
@@ -634,6 +634,20 @@ struct regnode_ssc {
REGNODE_NEXT_OFFSET_SET((p), (val)); \
} STMT_END
+#define CURLY_CAPTURE_PARENS(p) \
+ (assert(OP(p) == CURLYN || OP(p) == CURLYM), PREVENT_LVALUE(FLAGS(p)))
+#define CURLY_CAPTURE_PARENS_SET(p, val) STMT_START { \
+ assert(OP(p) == CURLYN || OP(p) == CURLYM); \
+ FLAGS(p) = (val); \
+} STMT_END
+
+#define CURLYX_CAPTURE_FLOOR(p) \
+ (assert(OP(p) == CURLYX), PREVENT_LVALUE(FLAGS(p)))
+#define CURLYX_CAPTURE_FLOOR_SET(p, val) STMT_START { \
+ assert(OP(p) == CURLYX); \
+ FLAGS(p) = (val); \
+} STMT_END
+
#define LOGICAL_MODE(p) \
(assert(OP(p) == LOGICAL), PREVENT_LVALUE(FLAGS(p) & EVAL_FLAGS_MASK))
#define LOGICAL_MODE_SET(p, val) STMT_START { \
diff --git a/regcomp_debug.c b/regcomp_debug.c
index 9a36e9bcfd..43bd1a8ae0 100644
--- a/regcomp_debug.c
+++ b/regcomp_debug.c
@@ -635,8 +635,10 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
if (CURLY_HAS_CAPTURES(o))
sv_catpvf(sv, "<%d:%d>", CURLY_FIRST_CAPTURE(o),
CURLY_LAST_CAPTURE(o));
- if (op == CURLYM || op == CURLYN || op == CURLYX)
- sv_catpvf(sv, "[%d]", FLAGS(o)); /* Parenth number */
+ if (op == CURLYM || op == CURLYN)
+ sv_catpvf(sv, "[%d]", CURLY_CAPTURE_PARENS(o));
+ else if (op == CURLYX)
+ sv_catpvf(sv, "[%d]", CURLYX_CAPTURE_FLOOR(o));
sv_catpvf(sv, "{%u,", (unsigned) lo);
if (hi == REG_INFTY)
sv_catpvs(sv, "INFTY");
diff --git a/regcomp_study.c b/regcomp_study.c
index 35e501c71b..d644bb9146 100644
--- a/regcomp_study.c
+++ b/regcomp_study.c
@@ -2549,7 +2549,7 @@ Perl_study_chunk(pTHX_
goto optimize_curly_tail;
case CURLY:
if (stopparen > 0 && (OP(scan) == CURLYN || OP(scan) == CURLYM)
- && (FLAGS(scan) == stopparen))
+ && (CURLY_CAPTURE_PARENS(scan) == stopparen))
{
mincount = 1;
maxcount = 1;
@@ -2560,7 +2560,7 @@ Perl_study_chunk(pTHX_
next = regnext(scan);
if (OP(scan) == CURLYX) {
I32 lp = (data ? *(data->last_closep) : 0);
- FLAGS(scan) = ((lp <= (I32)U8_MAX) ? (U8)lp : U8_MAX);
+ CURLYX_CAPTURE_FLOOR_SET(scan, ((lp <= (I32)U8_MAX) ? (U8)lp : U8_MAX));
}
scan = REGNODE_AFTER(scan);
next_is_eval = (OP(scan) == EVAL);
@@ -2725,8 +2725,8 @@ Perl_study_chunk(pTHX_
RExC_close_parens[PARNO(nxt1)] = REGNODE_OFFSET(nxt) + 2;
}
/* Now we know that nxt2 is the only contents: */
- FLAGS(oscan) = (U8)PARNO(nxt);
OP(oscan) = CURLYN;
+ CURLY_CAPTURE_PARENS_SET(oscan, (U8)PARNO(nxt));
OP(nxt1) = NOTHING; /* was OPEN. */
#ifdef DEBUGGING
@@ -2783,7 +2783,7 @@ Perl_study_chunk(pTHX_
/* note that we have changed the type of oscan to CURLYM here */
regnode *nxt1 = REGNODE_AFTER_type(oscan, tregnode_CURLYM); /* OPEN*/
- FLAGS(oscan) = (U8)PARNO(nxt);
+ CURLY_CAPTURE_PARENS_SET(oscan, (U8)PARNO(nxt));
if (RExC_open_parens) {
/*open->CURLYM*/
RExC_open_parens[PARNO(nxt1)] = REGNODE_OFFSET(oscan);
@@ -2822,7 +2822,7 @@ Perl_study_chunk(pTHX_
depth+1, mutate_ok);
}
else
- FLAGS(oscan) = 0;
+ CURLY_CAPTURE_PARENS_SET(oscan, 0);
}
else if ((OP(oscan) == CURLYX)
/* Possibly mark the corresponding WHILEM node as
diff --git a/regexec.c b/regexec.c
index cd352ba52e..6fd07baee4 100644
--- a/regexec.c
+++ b/regexec.c
@@ -9585,7 +9585,7 @@ NULL
case CURLYX: /* start of /A*B/ (for complex A) */
{
/* No need to save/restore up to this paren */
- I32 parenfloor = FLAGS(scan);
+ I32 parenfloor = CURLYX_CAPTURE_FLOOR(scan);
assert(next); /* keep Coverity happy */
if (OP(REGNODE_BEFORE(next)) == NOTHING) /* LONGJMP */
@@ -10015,8 +10015,8 @@ NULL
ST.lastcloseparen = RXp_LASTCLOSEPAREN(rex);
/* if paren positive, emulate an OPEN/CLOSE around A */
- if (FLAGS(ST.me)) {
- U32 paren = FLAGS(ST.me);
+ if (CURLY_CAPTURE_PARENS(ST.me)) {
+ U32 paren = CURLY_CAPTURE_PARENS(ST.me);
lastopen = paren;
if (paren > maxopenparen)
maxopenparen = paren;
@@ -10063,15 +10063,15 @@ NULL
depth, (IV) ST.count, (IV)ST.alen)
);
- if (FLAGS(ST.me)) {
+ if (CURLY_CAPTURE_PARENS(ST.me)) {
/* emulate CLOSE: mark current A as captured */
- U32 paren = (U32)FLAGS(ST.me);
+ U32 paren = (U32)CURLY_CAPTURE_PARENS(ST.me);
CLOSE_CAPTURE(rex, paren,
HOPc(locinput, -ST.alen) - reginfo->strbeg,
locinput - reginfo->strbeg);
}
- if (EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)FLAGS(ST.me)))
+ if (EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)CURLY_CAPTURE_PARENS(ST.me)))
goto fake_end;
@@ -10088,7 +10088,7 @@ NULL
if (ST.minmod || ST.count < CURLY_MIN_REPEAT(ST.me)
- || EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)FLAGS(ST.me)))
+ || EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)CURLY_CAPTURE_PARENS(ST.me)))
sayNO;
curlym_do_B: /* execute the B in /A{m,n}B/ */
@@ -10137,9 +10137,9 @@ NULL
}
curlym_close_B:
- if (FLAGS(ST.me)) {
+ if (CURLY_CAPTURE_PARENS(ST.me)) {
/* emulate CLOSE: mark current A as captured */
- U32 paren = (U32)FLAGS(ST.me);
+ U32 paren = (U32)CURLY_CAPTURE_PARENS(ST.me);
if (ST.count || is_accepted) {
CLOSE_CAPTURE(rex, paren,
HOPc(locinput, -ST.alen) - reginfo->strbeg,
@@ -10148,7 +10148,7 @@ NULL
else
RXp_OFFSp(rex)[paren].end = -1;
- if (EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)FLAGS(ST.me)))
+ if (EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)CURLY_CAPTURE_PARENS(ST.me)))
{
if (ST.count || is_accepted)
goto fake_end;
@@ -10211,7 +10211,7 @@ NULL
goto repeat;
case CURLYN: /* /(A){m,n}B/ where A is width 1 char */
- ST.paren = FLAGS(scan); /* Which paren to set */
+ ST.paren = CURLY_CAPTURE_PARENS(scan); /* Which paren to set */
ST.lastparen = RXp_LASTPAREN(rex);
ST.lastcloseparen = RXp_LASTCLOSEPAREN(rex);
if (ST.paren > maxopenparen)