heredoc after "" in s/// in eval
authorFather Chrysostomos <sprout@cpan.org>
Mon, 20 Aug 2012 19:57:29 +0000 (12:57 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 21 Aug 2012 21:11:01 +0000 (14:11 -0700)
This works fine:

eval ' s//<<END.""/e; print
Just another Perl hacker,
END
'or die $@
__END__
Just another Perl hacker,

But this doesn’t:

eval ' s//"$1".<<END/e; print
Just another Perl hacker,
END
'or die $@
__END__
Can't find string terminator "END" anywhere before EOF at (eval 1) line 1.

It fails because PL_sublex_info.super_buf*, added by commit
0244c3a403, are not localised, so, after the "", s/// sees its own
buffer pointers in those variables, instead of its parent string eval.

This used to happen only with s///e inside s///e, but that was because
here-docs would peek inside the parent linestr buffer only inside
s///e, and not other quote-like operators.  That was fixed in
recent commits.

Simply moving the assignment of super_buf* into sublex_push does solve
the bug for a simple "", as "" does sublex_start, but not sublex_push.
We do need to localise those variables for "${\''}", however.

t/base/lex.t
toke.c

index ce16ef1..d55b189 100644 (file)
@@ -1,6 +1,6 @@
 #!./perl
 
-print "1..57\n";
+print "1..58\n";
 
 $x = 'x';
 
@@ -273,3 +273,10 @@ $test++;
 @a = (1,2,3);
 print "not " unless($a[~~2] == 3);
 print "ok 57\n";
+
+$_ = "";
+eval 's/(?:)/"${\q||}".<<\END/e;
+ok 58 - heredoc after "" in s/// in eval
+END
+';
+print $_ || "not ok 58\n";
diff --git a/toke.c b/toke.c
index ff19bdc..f24fbca 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -2389,8 +2389,6 @@ S_sublex_start(pTHX)
     dVAR;
     const I32 op_type = pl_yylval.ival;
 
-    PL_sublex_info.super_bufptr = PL_bufptr;
-    PL_sublex_info.super_bufend = PL_bufend;
     if (op_type == OP_NULL) {
        pl_yylval.opval = PL_lex_op;
        PL_lex_op = NULL;
@@ -2462,6 +2460,8 @@ S_sublex_push(pTHX)
     SAVEI32(PL_lex_starts);
     SAVEI8(PL_lex_state);
     SAVEPPTR(PL_sublex_info.re_eval_start);
+    SAVEPPTR(PL_sublex_info.super_bufptr);
+    SAVEPPTR(PL_sublex_info.super_bufend);
     SAVEVPTR(PL_lex_inpat);
     SAVEI16(PL_lex_inwhat);
     SAVECOPLINE(PL_curcop);
@@ -2479,6 +2479,8 @@ S_sublex_push(pTHX)
     PL_linestr = PL_lex_stuff;
     PL_lex_stuff = NULL;
     PL_sublex_info.re_eval_start = NULL;
+    PL_sublex_info.super_bufptr = PL_bufptr;
+    PL_sublex_info.super_bufend = PL_bufend;
 
     PL_bufend = PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart
        = SvPVX(PL_linestr);