in reply to Does redo create a new dynamic scope?

Some more info:

I also came up with a concise, minimalistic problem definition:

Why do these two loops have different outputs?

{ print("norm: "); local $_ = 'fred'; for (; /./g ; print("<$&>"),1) { } print("\n"); } { print("next: "); local $_ = 'fred'; for (; /./g ; print("<$&>"),1) { next } print("\n"); }
norm: <f><r><e><d> next: <><><><>

Replies are listed 'Best First'.
Re^2: Does redo create a new dynamic scope?
by shmem (Chancellor) on Jul 19, 2007 at 07:44 UTC
    It seems to me that's because of
    if (cxix < cxstack_ix) dounwind(cxix);

    in PP(pp_next) and PP(pp_redo) in pp_ctl.c. Debugging reveals an additional BLOCK frame which is built around the scope in which a next or redo is found:

    qwurx [shmem] ~ > perl -D4 { print("norm: "); local $_ = 'fred'; for (; /./g ; print("<$&>\n"),1) { } print("\n"); } { print("next: "); local $_ = 'fred'; for (; /./g ; print("<$&>\n"),1) { next } print("\n"); } __END__ (some lines skipped) EXECUTING... (next.pl:0) ENTER scope 2 at pp_hot.c:1694 Entering block 0, type BLOCK (next.pl:2) ENTER scope 3 at pp_ctl.c:1798 (next.pl:2) ENTER scope 4 at pp_ctl.c:1800 Entering block 1, type LOOP (next.pl:4) ENTER scope 5 at pp_ctl.c:1798 (next.pl:4) ENTER scope 6 at pp_ctl.c:1800 Entering block 2, type LOOP norm: <f> <r> <e> <d> (next.pl:4) POPBLOCK scope 6 at pp_ctl.c:1817 Leaving block 2, type LOOP (next.pl:4) LEAVE scope 6 at pp_ctl.c:1843 (next.pl:4) LEAVE scope 5 at pp_ctl.c:1844 (next.pl:2) POPBLOCK scope 4 at pp_ctl.c:1817 Leaving block 1, type LOOP (next.pl:2) LEAVE scope 4 at pp_ctl.c:1843 (next.pl:2) LEAVE scope 3 at pp_ctl.c:1844 (next.pl:8) ENTER scope 3 at pp_ctl.c:1798 (next.pl:8) ENTER scope 4 at pp_ctl.c:1800 Entering block 1, type LOOP (next.pl:10) ENTER scope 5 at pp_ctl.c:1798 (next.pl:10) ENTER scope 6 at pp_ctl.c:1800 Entering block 2, type LOOP (next.pl:10) ENTER scope 7 at pp_hot.c:1694 Entering block 3, type BLOCK (next.pl:10) (Found loop #2) Unwinding block 3, type BLOCK (next.pl:10) TOPBLOCK scope 6 at pp_ctl.c:2073 next: <> (next.pl:10) ENTER scope 7 at pp_hot.c:1694 Entering block 3, type BLOCK (next.pl:10) (Found loop #2) Unwinding block 3, type BLOCK (next.pl:10) TOPBLOCK scope 6 at pp_ctl.c:2073 <> (next.pl:10) ENTER scope 7 at pp_hot.c:1694 Entering block 3, type BLOCK (next.pl:10) (Found loop #2) Unwinding block 3, type BLOCK (next.pl:10) TOPBLOCK scope 6 at pp_ctl.c:2073 <> (next.pl:10) ENTER scope 7 at pp_hot.c:1694 Entering block 3, type BLOCK (next.pl:10) (Found loop #2) Unwinding block 3, type BLOCK (next.pl:10) TOPBLOCK scope 6 at pp_ctl.c:2073 <> (next.pl:10) POPBLOCK scope 6 at pp_ctl.c:1817 Leaving block 2, type LOOP (next.pl:10) LEAVE scope 6 at pp_ctl.c:1843 (next.pl:10) LEAVE scope 5 at pp_ctl.c:1844 (next.pl:8) POPBLOCK scope 4 at pp_ctl.c:1817 Leaving block 1, type LOOP (next.pl:8) LEAVE scope 4 at pp_ctl.c:1843 (next.pl:8) LEAVE scope 3 at pp_ctl.c:1844 (next.pl:0) POPBLOCK scope 2 at pp_hot.c:1804 Leaving block 0, type BLOCK (next.pl:0) LEAVE scope 2 at pp_hot.c:1843 (next.pl:0) Setting up jumplevel bfdb9400, was 816619c (next.pl:0) LEAVE scope 1 at perl.c:645

    update: Things become more clear if we change the 'next' block as follows:

    { print("next: "); local $_ = 'fred'; for (; /./g ; print("<$&>\n"),1) { print "<$&>\n"; next; } print("\n"); }

    which yields

    EXECUTING... (next.pl:0) ENTER scope 2 at pp_hot.c:1694 Entering block 0, type BLOCK (next.pl:2) ENTER scope 3 at pp_ctl.c:1798 (next.pl:2) ENTER scope 4 at pp_ctl.c:1800 Entering block 1, type LOOP (next.pl:4) ENTER scope 5 at pp_ctl.c:1798 (next.pl:4) ENTER scope 6 at pp_ctl.c:1800 Entering block 2, type LOOP (next.pl:4) ENTER scope 7 at pp_hot.c:1694 Entering block 3, type BLOCK next: <f> (next.pl:6) (Found loop #2) Unwinding block 3, type BLOCK (next.pl:6) TOPBLOCK scope 6 at pp_ctl.c:2073 <> (next.pl:4) ENTER scope 7 at pp_hot.c:1694 Entering block 3, type BLOCK <r> (next.pl:6) (Found loop #2) Unwinding block 3, type BLOCK (next.pl:6) TOPBLOCK scope 6 at pp_ctl.c:2073 <> ...

    So, the print in the for() condition is in scope 6, while the print just before next is in scope 7...

    <update>

    What is happening in this loop is that the /./g is evaluated in scope 6. Then the inner loop block is executed (scope 7, block 3). Then that block is left, and all lexical (and match) variables are restored. After that the last part of the for(;;) conditional construct is executed - the print("<$&>\n"),1 - at which time $& happens to have been reset already, because the inner scope has been left, as can be seen with the following snippet:

    { print("next: "); local $_ = 'fred'; for ( print "begin\n"; /./g, print("1<$&>\n") and $& ? 1 : 0 ; print("2<$&>\n"),1) { print "3<$&>\n"; next; } print("\n"); } __END__ next: begin 1<f> 3<f> 2<> 1<r> 3<r> 2<> 1<e> 3<e> 2<> 1<d> 3<d> 2<> 1<>

    Run it under -D4 :-)

    </update>

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}