diff options
author | David Mitchell <davem@iabyn.com> | 2011-11-30 13:40:15 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2011-12-19 15:06:05 +0000 |
commit | 55a50eaac0e929d43694e9a84b983e96b95f2a08 (patch) | |
tree | 555b4dc441bb2b0c791e33adf345cad3d60884ce /regcomp.c | |
parent | cff13853c58adf9f0a479ee51925f74395dba8ae (diff) | |
download | perl-55a50eaac0e929d43694e9a84b983e96b95f2a08.tar.gz |
preserve code blocks in interpolated qr//s
This now works:
{ my $x = 1; $r = qr/(??{$x})/ }
my $x = 2;
print "ok\n" if "1" =~ /^$r$/;
When a qr// is interpolated into another pattern, the pattern is still
recompiled using the stringified qr, but now the pre-compiled code blocks
from the qr are reused rather than being re-compiled, so it behaves like a
closure.
Note that this makes some tests in regexp_qr_embed_thr.t fail, due to a
pre-existing threads bug, which can be summarised as:
use threads;
my $s = threads->new(sub { return sub { $::x = 1} })->join;
$s->();
print "\$::x=[$::x]\n";
which prints undef, not 1, since the *::x is cloned into the child thread,
then cloned back into the parent as part of the CV (linked from the pad)
being returned in the join. The cloning/join code isn't clever enough
to realise that the back-cloned *::x is the same as the original *::x, so
the main thread ends up with two copies.
This manifests itself in the re tests as
my $re = threads->new( sub { qr/(?{$::x = 1 })/ })->join();
where, since the returned qr// is now a closure, it suffers from the same
glob duplication in the parent.
So I've disabled 4 re_tests tests under threads for now.
Diffstat (limited to 'regcomp.c')
-rw-r--r-- | regcomp.c | 77 |
1 files changed, 66 insertions, 11 deletions
@@ -4703,13 +4703,15 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, for (svp = patternp; svp < patternp + pat_count; svp++) { SV *sv, *msv = *svp; + SV *rx; bool code = 0; if (o) { if (o->op_type == OP_NULL && (o->op_flags & OPf_SPECIAL)) { + assert(n < pRExC_state->num_code_blocks); + pRExC_state->code_blocks[n].start = SvCUR(pat); + pRExC_state->code_blocks[n].block = o; + pRExC_state->code_blocks[n].src_regex = NULL; n++; - assert(n <= pRExC_state->num_code_blocks); - pRExC_state->code_blocks[n-1].start = SvCUR(pat); - pRExC_state->code_blocks[n-1].block = o; code = 1; o = o->op_sibling; /* skip CONST */ assert(o); @@ -4717,6 +4719,40 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, o = o->op_sibling;; } + /* extract any code blocks within any embedded qr//'s */ + rx = msv; + if (SvROK(rx)) + rx = SvRV(rx); + if (SvTYPE(rx) == SVt_REGEXP + && RX_ENGINE((REGEXP*)rx) == RE_ENGINE_PTR) + { + + RXi_GET_DECL(((struct regexp*)SvANY(rx)), ri); + if (ri->num_code_blocks) { + int i; + Renew(pRExC_state->code_blocks, + pRExC_state->num_code_blocks + ri->num_code_blocks, + struct reg_code_block); + pRExC_state->num_code_blocks += ri->num_code_blocks; + for (i=0; i < ri->num_code_blocks; i++) { + struct reg_code_block *src, *dst; + STRLEN offset = SvCUR(pat) + + ((struct regexp *)SvANY(rx))->pre_prefix; + assert(n < pRExC_state->num_code_blocks); + src = &ri->code_blocks[i]; + dst = &pRExC_state->code_blocks[n]; + dst->start = src->start + offset; + dst->end = src->end + offset; + dst->block = src->block; + dst->src_regex = (REGEXP*) SvREFCNT_inc( (SV*) + src->src_regex + ? src->src_regex + : (REGEXP*)rx); + n++; + } + } + } + if ((SvAMAGIC(pat) || SvAMAGIC(msv)) && (sv = amagic_call(pat, msv, concat_amg, AMGf_assign))) { @@ -4783,6 +4819,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, assert(i+1 < pRExC_state->num_code_blocks); pRExC_state->code_blocks[++i].start = SvCUR(pat); pRExC_state->code_blocks[i].block = o; + pRExC_state->code_blocks[i].src_regex = NULL; is_code = 1; } } @@ -4795,7 +4832,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, exp = SvPV_nomg(pat, plen); - if (eng && eng != &PL_core_reg_engine) { + if (eng && eng != RE_ENGINE_PTR) { if ((SvUTF8(pat) && IN_BYTES) || SvGMAGICAL(pat) || SvAMAGIC(pat)) { @@ -7515,16 +7552,24 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth) - RExC_start) ) { /* this is a pre-compiled literal (?{}) */ - RExC_parse = RExC_start + - pRExC_state->code_blocks[pRExC_state->code_index].end; + struct reg_code_block *cb = + &pRExC_state->code_blocks[pRExC_state->code_index]; + RExC_parse = RExC_start + cb->end; if (SIZE_ONLY) RExC_seen_evals++; else { - OP *o = - pRExC_state->code_blocks[pRExC_state->code_index].block; - n = add_data(pRExC_state, 1, + OP *o = cb->block; + if (cb->src_regex) { + n = add_data(pRExC_state, 2, "rl"); + RExC_rxi->data->data[n] = + (void*)SvREFCNT_inc((SV*)cb->src_regex); + RExC_rxi->data->data[n+1] = (void*)o->op_next; + } + else { + n = add_data(pRExC_state, 1, (RExC_flags & PMf_HAS_CV) ? "L" : "l"); - RExC_rxi->data->data[n] = (void*)o->op_next; + RExC_rxi->data->data[n] = (void*)o->op_next; + } } pRExC_state->code_index++; } @@ -12208,8 +12253,12 @@ Perl_regfree_internal(pTHX_ REGEXP * const rx) if (ri->u.offsets) Safefree(ri->u.offsets); /* 20010421 MJD */ #endif - if (ri->code_blocks) + if (ri->code_blocks) { + int n; + for (n = 0; n < ri->num_code_blocks; n++) + SvREFCNT_dec(ri->code_blocks[n].src_regex); Safefree(ri->code_blocks); + } if (ri->data) { int n = ri->data->count; @@ -12221,6 +12270,7 @@ Perl_regfree_internal(pTHX_ REGEXP * const rx) /* If you add a ->what type here, update the comment in regcomp.h */ switch (ri->data->what[n]) { case 'a': + case 'r': case 's': case 'S': case 'u': @@ -12443,10 +12493,14 @@ Perl_regdupe_internal(pTHX_ REGEXP * const rx, CLONE_PARAMS *param) reti->num_code_blocks = ri->num_code_blocks; if (ri->code_blocks) { + int n; Newxc(reti->code_blocks, ri->num_code_blocks, struct reg_code_block, struct reg_code_block); Copy(ri->code_blocks, reti->code_blocks, ri->num_code_blocks, struct reg_code_block); + for (n = 0; n < ri->num_code_blocks; n++) + reti->code_blocks[n].src_regex = (REGEXP*) + sv_dup_inc((SV*)(ri->code_blocks[n].src_regex), param); } else reti->code_blocks = NULL; @@ -12469,6 +12523,7 @@ Perl_regdupe_internal(pTHX_ REGEXP * const rx, CLONE_PARAMS *param) /* legal options are one of: sSfpontTua see also regcomp.h and pregfree() */ case 'a': /* actually an AV, but the dup function is identical. */ + case 'r': case 's': case 'S': case 'p': /* actually an AV, but the dup function is identical. */ |