In perl.git, the branch blead has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/3188a8216e19cb1020af7615e3178daab8a865d6?hp=a958cfbb8cface09cefb76d5846a867ac7c600dd>

- Log -----------------------------------------------------------------
commit 3188a8216e19cb1020af7615e3178daab8a865d6
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sun Oct 5 22:32:23 2014 -0700

    Deparse with CORE:: to avoid lex sub conflicts
    
    If a lexical sub with the same name as a keyword is in scope, we need
    to deparse the keyword with a CORE:: prefix.
    
    This commit handles most of the cases, but there are a few exceptional
    cases remaining.

M       lib/B/Deparse-core.t
M       lib/B/Deparse.pm

commit c837f29ae94c2404c0fbd82b1dbcc195a35a9183
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sun Oct 5 17:30:59 2014 -0700

    Deparse-core.t: Fix ineffective tests
    
    In a958cfbb8, I accidentally changed this to test ‘test::foo()’,
    rather than ‘foo()’ deparsing as ‘test::foo()’, which was what I
    had intended.

M       lib/B/Deparse-core.t

commit a21eb52b1988ec2828792ad77f68a17dda3e6feb
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sun Oct 5 17:25:57 2014 -0700

    Correct ‘"my" variable "&f::b"...’ message
    
    "my" variable &foo::bar can't be in a package at - line 2, near "my sub 
foo::bar"
    
    It should say ‘subroutine’, not ‘variable’.  When I implemented 
lexi-
    cal subs, I thought I caught all these, must I missed this one.

M       perl.h
M       pod/perldiag.pod
M       t/lib/croak/toke
M       toke.c

commit 82a7b38ebca5ead4666341f73512665b295afd51
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sun Oct 5 17:15:43 2014 -0700

    toke.c: Add comment for greppability

M       toke.c

commit 20ed5f007e3724a22784725ed36aeaad036be0ff
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sun Oct 5 17:10:59 2014 -0700

    Reorder t/lib/croak/toke
    
    to put string terminator errors all in one place.

M       t/lib/croak/toke
-----------------------------------------------------------------------

Summary of changes:
 lib/B/Deparse-core.t | 55 +++++++++++++++++++++++++++++++++++++++++-----------
 lib/B/Deparse.pm     | 38 +++++++++++++++++++++++-------------
 perl.h               |  2 +-
 pod/perldiag.pod     | 10 ++++++++++
 t/lib/croak/toke     | 41 +++++++++++++++++++++++++--------------
 toke.c               |  5 ++++-
 6 files changed, 109 insertions(+), 42 deletions(-)

diff --git a/lib/B/Deparse-core.t b/lib/B/Deparse-core.t
index 2446622..c624218 100644
--- a/lib/B/Deparse-core.t
+++ b/lib/B/Deparse-core.t
@@ -36,7 +36,7 @@ BEGIN {
 
 use strict;
 use Test::More;
-plan tests => 2071;
+plan tests => 4018;
 
 use feature (sprintf(":%vd", $^V)); # to avoid relying on the feature
                                     # logic to add CORE::
@@ -51,7 +51,7 @@ my %SEEN_STRENGH;
 # deparse "() = $expr", and see if it matches $expected_expr
 
 sub testit {
-    my ($keyword, $expr, $expected_expr) = @_;
+    my ($keyword, $expr, $expected_expr, $lexsub) = @_;
 
     $expected_expr //= $expr;
     $SEEN{$keyword} = 1;
@@ -68,7 +68,8 @@ sub testit {
 
        if ($lex == 2) {
            my $repl = 'my $a';
-           if ($expr =~ /\bmap\(\$a|CORE::(chomp|chop|lstat|stat)\b/) {
+           if ($expr =~ /CORE::(chomp|chop|lstat|stat)\b/
+            or $expr =~ ($lexsub ? qr/::map\(\$a/ : qr/\bmap\(\$a/)) {
                # for some reason only these do:
                #  'foo my $a, $b,' => foo my($a), $b, ...
                #  the rest don't parenthesize the my var.
@@ -78,10 +79,20 @@ sub testit {
        }
 
        my $desc = "$keyword: lex=$lex $expr => $expected_expr";
+       $desc .= " (lex sub)" if $lexsub;
 
 
        my $code_ref;
-       {
+       if ($lexsub) {
+           package lexsubtest;
+           no warnings 'experimental::lexical_subs';
+           use feature 'lexical_subs';
+           no strict 'vars';
+           $code_ref =
+               eval "sub { state sub $keyword; ${vars}() = $expr }"
+                           || die "$@ in $expr";
+       }
+       else {
            package test;
            use subs ();
            import subs $keyword;
@@ -92,7 +103,7 @@ sub testit {
        my $got_text = $deparse->coderef2text($code_ref);
 
        unless ($got_text =~ /^\{
-    package test;
+    package (?:lexsub)?test;
     BEGIN \{\$\{\^WARNING_BITS} = "[^"]*"}
     use strict 'refs', 'subs';
     use feature [^\n]+
@@ -131,13 +142,16 @@ sub do_infix_keyword {
     # so no need for Deparse to disambiguate with CORE::
     testit $keyword, "(\$a CORE::$keyword \$b)", $exp;
     testit $keyword, "(\$a $keyword \$b)", $exp;
+    testit $keyword, "(\$a CORE::$keyword \$b)", $exp, 1;
+    testit $keyword, "(\$a $keyword \$b)", $exp, 1;
     if (!$strong) {
        # B::Deparse fully qualifies any sub whose name is a keyword,
        # imported or not, since the importedness may not be reproduced by
        # the deparsed code.  x is special.
-       $keyword =~ s/^(?!x\z)/test::/;
-       testit $keyword, "$keyword(\$a, \$b)", "$keyword(\$a, \$b);";
+       my $pre = "test::" x ($keyword ne 'x');
+       testit $keyword, "$keyword(\$a, \$b)", "$pre$keyword(\$a, \$b);";
     }
+    testit $keyword, "$keyword(\$a, \$b)", "$keyword(\$a, \$b);", 1;
 }
 
 # test a keyword that is as tandard op/function, like 'index(...)'.
@@ -153,20 +167,30 @@ sub do_std_keyword {
     $SEEN_STRENGH{$keyword} = $strong;
 
     for my $core (0,1) { # if true, add CORE:: to keyword being deparsed
+      for my $lexsub (0,1) { # if true, define lex sub
        my @code;
        for my $do_exp(0, 1) { # first create expr, then expected-expr
            my @args = map "\$$_", (undef,"a".."z")[1..$narg];
-           push @args, '$_' if $dollar && $do_exp && ($strong || $core);
+           push @args, '$_'
+               if $dollar && $do_exp && ($strong && !$lexsub or $core);
            my $args = join(', ', @args);
-           $args = ((!$core && !$strong) || $parens)
+            # XXX $lex_parens is temporary, until lex subs are
+            #     deparsed properly.
+           my $lex_parens =
+               !$core && $do_exp && $lexsub && $keyword ne 'map';
+           $args = ((!$core && !$strong) || $parens || $lex_parens)
                        ? "($args)"
                        :  @args ? " $args" : "";
            push @code, (($core && !($do_exp && $strong))
-                          ? "CORE::"
+                        ? "CORE::"
+                        : $lexsub && $do_exp
+                          ? "CORE::" x $core
                           : $do_exp && !$core && !$strong ? "test::" : "")
                                                        . "$keyword$args;";
        }
-       testit $keyword, @code; # code[0]: to run; code[1]: expected
+       # code[0]: to run; code[1]: expected
+       testit $keyword, @code, $lexsub;
+      }
     }
 }
 
@@ -211,6 +235,10 @@ testit dbmopen  => 'CORE::dbmopen(%foo, $bar, $baz);';
 testit dbmclose => 'CORE::dbmclose %foo;';
 
 testit delete   => 'CORE::delete $h{\'foo\'};', 'delete $h{\'foo\'};';
+testit delete   => 'CORE::delete $h{\'foo\'};', undef, 1;
+testit delete   => 'CORE::delete @h{\'foo\'};', undef, 1;
+testit delete   => 'CORE::delete $h[0];', undef, 1;
+testit delete   => 'CORE::delete @h[0];', undef, 1;
 testit delete   => 'delete $h{\'foo\'};',       'delete $h{\'foo\'};';
 
 # do is listed as strong, but only do { block } is strong;
@@ -219,6 +247,8 @@ testit do       => 'CORE::do $a;';
 testit do       => 'do $a;',                    'test::do($a);';
 testit do       => 'CORE::do { 1 }',
                   "do {\n        1\n    };";
+testit do       => 'CORE::do { 1 }',
+                  "CORE::do {\n        1\n    };", 1;
 testit do       => 'do { 1 };',
                   "do {\n        1\n    };";
 
@@ -227,6 +257,9 @@ testit each     => 'CORE::each %bar;';
 testit eof      => 'CORE::eof();';
 
 testit exists   => 'CORE::exists $h{\'foo\'};', 'exists $h{\'foo\'};';
+testit exists   => 'CORE::exists $h{\'foo\'};', undef, 1;
+testit exists   => 'CORE::exists &foo;', undef, 1;
+testit exists   => 'CORE::exists $h[0];', undef, 1;
 testit exists   => 'exists $h{\'foo\'};',       'exists $h{\'foo\'};';
 
 testit exec     => 'CORE::exec($foo $bar);';
diff --git a/lib/B/Deparse.pm b/lib/B/Deparse.pm
index 424e248..b84217d 100644
--- a/lib/B/Deparse.pm
+++ b/lib/B/Deparse.pm
@@ -1222,7 +1222,7 @@ sub maybe_local {
        my @our_local;
        push @our_local, "local" if $priv & OPpLVAL_INTRO;
        push @our_local, "our"   if $priv & $our_intro;
-       my $our_local = join " ", @our_local;
+       my $our_local = join " ", map $self->keyword($_), @our_local;
        if( $our_local[-1] eq 'our' ) {
            if ( $text !~ /^\W(\w+::)*\w+\z/
             and !utf8::decode($text) || $text !~ /^\W(\w+::)*\w+\z/
@@ -1276,9 +1276,8 @@ sub maybe_my {
                   && $op->name =~ /[ah]v\z/
                   && ($op->flags & (OPf_PARENS|OPf_REF)) == OPf_PARENS;
     if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
-       my $my = $op->private & OPpPAD_STATE
-           ? $self->keyword("state")
-           : "my";
+       my $my =
+           $self->keyword($op->private & OPpPAD_STATE ? "state" : "my");
        if ($padname->FLAGS & SVpad_TYPED) {
            $my .= ' ' . $padname->SvSTASH->NAME;
        }
@@ -1377,7 +1376,10 @@ sub scopeop {
     }
     if ($cx > 0) { # inside an expression, (a do {} while for lineseq)
        my $body = $self->lineseq($op, 0, @kids);
-       return is_lexical_subs(@kids) ? $body : "do {\n\t$body\n\b}";
+       return is_lexical_subs(@kids)
+               ? $body
+               : ($self->lex_in_scope("&do") ? "CORE::do" : "do")
+                . " {\n\t$body\n\b}";
     } else {
        my $lineseq = $self->lineseq($op, $cx, @kids);
        return (length ($lineseq) ? "$lineseq;" : "");
@@ -1888,6 +1890,9 @@ sub keyword {
     if (exists $feature_keywords{$name}) {
        return "CORE::$name" if not $self->feature_enabled($name);
     }
+    if ($self->lex_in_scope("&$name")) {
+       return "CORE::$name";
+    }
     if ($strong_proto_keywords{$name}
         || ($name !~ /^(?:chom?p|do|exec|glob|s(?:elect|ystem))\z/
            && !defined eval{prototype "CORE::$name"})
@@ -2155,17 +2160,18 @@ sub pp_exists {
     my $self = shift;
     my($op, $cx) = @_;
     my $arg;
+    my $name = $self->keyword("exists");
     if ($op->private & OPpEXISTS_SUB) {
        # Checking for the existence of a subroutine
-       return $self->maybe_parens_func("exists",
+       return $self->maybe_parens_func($name,
                                $self->pp_rv2cv($op->first, 16), $cx, 16);
     }
     if ($op->flags & OPf_SPECIAL) {
        # Array element, not hash element
-       return $self->maybe_parens_func("exists",
+       return $self->maybe_parens_func($name,
                                $self->pp_aelem($op->first, 16), $cx, 16);
     }
-    return $self->maybe_parens_func("exists", $self->pp_helem($op->first, 16),
+    return $self->maybe_parens_func($name, $self->pp_helem($op->first, 16),
                                    $cx, 16);
 }
 
@@ -2173,24 +2179,25 @@ sub pp_delete {
     my $self = shift;
     my($op, $cx) = @_;
     my $arg;
+    my $name = $self->keyword("delete");
     if ($op->private & OPpSLICE) {
        if ($op->flags & OPf_SPECIAL) {
            # Deleting from an array, not a hash
-           return $self->maybe_parens_func("delete",
+           return $self->maybe_parens_func($name,
                                        $self->pp_aslice($op->first, 16),
                                        $cx, 16);
        }
-       return $self->maybe_parens_func("delete",
+       return $self->maybe_parens_func($name,
                                        $self->pp_hslice($op->first, 16),
                                        $cx, 16);
     } else {
        if ($op->flags & OPf_SPECIAL) {
            # Deleting from an array, not a hash
-           return $self->maybe_parens_func("delete",
+           return $self->maybe_parens_func($name,
                                        $self->pp_aelem($op->first, 16),
                                        $cx, 16);
        }
-       return $self->maybe_parens_func("delete",
+       return $self->maybe_parens_func($name,
                                        $self->pp_helem($op->first, 16),
                                        $cx, 16);
     }
@@ -2993,7 +3000,8 @@ sub mapop {
        $expr = $self->deparse($kid, 6);
        push @exprs, $expr if defined $expr;
     }
-    return $self->maybe_parens_func($name, $code . join(", ", @exprs), $cx, 5);
+    return $self->maybe_parens_func($self->keyword($name),
+                                   $code . join(", ", @exprs), $cx, 5);
 }
 
 sub pp_mapwhile { mapop(@_, "map") }
@@ -3069,6 +3077,7 @@ sub pp_list {
        $type = $newtype;
     }
     $local = "" if $local eq "either"; # no point if it's all undefs
+    $local &&= $self->keyword($local);
     $local .= " $type " if $local && length $type;
     return $self->deparse($kid, $cx) if null $kid->sibling and not $local;
     for (; !null($kid); $kid = $kid->sibling) {
@@ -3333,7 +3342,8 @@ sub pp_null {
                                   . $self->deparse($op->first->sibling, 20),
                                   $cx, 20);
     } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) {
-       return "do {\n\t". $self->deparse($op->first, $cx) ."\n\b};";
+       return ($self->lex_in_scope("&do") ? "CORE::do" : "do")
+            . " {\n\t". $self->deparse($op->first, $cx) ."\n\b};";
     } elsif (!null($op->first->sibling) and
             $op->first->sibling->name eq "null" and
             class($op->first->sibling) eq "UNOP" and
diff --git a/perl.h b/perl.h
index b958d74..e6e1320 100644
--- a/perl.h
+++ b/perl.h
@@ -4600,7 +4600,7 @@ EXTCONST char PL_no_dir_func[]
 EXTCONST char PL_no_func[]
   INIT("The %s function is unimplemented");
 EXTCONST char PL_no_myglob[]
-  INIT("\"%s\" variable %s can't be in a package");
+  INIT("\"%s\" %se %s can't be in a package");
 EXTCONST char PL_no_localize_ref[]
   INIT("Can't localize through a reference");
 EXTCONST char PL_memory_wrap[]
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index b4559ce..cfb8a07 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -3280,6 +3280,11 @@ See L<perlfunc/pack>.
 (F) Lexically scoped subroutines are not yet implemented.  Don't try
 that yet.
 
+=item "my" subroutine %s can't be in a package
+
+(F) Lexically scoped subroutines aren't in a package, so it doesn't make
+sense to try to declare one with a package qualifier on the front.
+
 =item "my %s" used in sort comparison
 
 (W syntax) The package variables $a and $b are used for sort comparisons.
@@ -5211,6 +5216,11 @@ unless there was a failure.  You probably wanted to use 
system()
 instead, which does return.  To suppress this warning, put the exec() in
 a block by itself.
 
+=item "state" subroutine %s can't be in a package
+
+(F) Lexically scoped subroutines aren't in a package, so it doesn't make
+sense to try to declare one with a package qualifier on the front.
+
 =item "state %s" used in sort comparison
 
 (W syntax) The package variables $a and $b are used for sort comparisons.
diff --git a/t/lib/croak/toke b/t/lib/croak/toke
index 0572094..9c8dd54 100644
--- a/t/lib/croak/toke
+++ b/t/lib/croak/toke
@@ -9,6 +9,21 @@ eval "s//<<foo/e"; die $@
 EXPECT
 Can't find string terminator "foo" anywhere before EOF at (eval 1) line 1.
 ########
+# NAME Unterminated qw//
+qw/
+EXPECT
+Can't find string terminator "/" anywhere before EOF at - line 1.
+########
+# NAME Unterminated q//
+qw/
+EXPECT
+Can't find string terminator "/" anywhere before EOF at - line 1.
+########
+# NAME Unterminated ''
+'
+EXPECT
+Can't find string terminator "'" anywhere before EOF at - line 1.
+########
 # NAME /\N{/
 /\N{/
 EXPECT
@@ -34,6 +49,17 @@ EXPECT
 The lexical_subs feature is experimental at - line 2.
 Missing name in "state sub" at - line 2.
 ########
+# NAME my sub pack::foo
+use feature 'lexical_subs', 'state';
+my sub foo::bar;
+state sub foo::bear;
+EXPECT
+The lexical_subs feature is experimental at - line 2.
+The lexical_subs feature is experimental at - line 3.
+"my" subroutine &foo::bar can't be in a package at - line 2, near "my sub 
foo::bar"
+"state" subroutine &foo::bear can't be in a package at - line 3, near "state 
sub foo::bear"
+Execution of - aborted due to compilation errors.
+########
 # NAME Integer constant overloading returning undef
 use overload;
 BEGIN { overload::constant integer => sub {}; undef *^H }
@@ -134,18 +160,3 @@ Execution of - aborted due to compilation errors.
 <<"foo
 EXPECT
 Unterminated delimiter for here document at - line 1.
-########
-# NAME Unterminated qw//
-qw/
-EXPECT
-Can't find string terminator "/" anywhere before EOF at - line 1.
-########
-# NAME Unterminated q//
-qw/
-EXPECT
-Can't find string terminator "/" anywhere before EOF at - line 1.
-########
-# NAME Unterminated ''
-'
-EXPECT
-Can't find string terminator "'" anywhere before EOF at - line 1.
diff --git a/toke.c b/toke.c
index ff4c789..9efdd80 100644
--- a/toke.c
+++ b/toke.c
@@ -8114,10 +8114,13 @@ S_pending_ident(pTHX)
         }
         else {
             if (has_colon) {
+                /* "my" variable %s can't be in a package */
                 /* PL_no_myglob is constant */
                 GCC_DIAG_IGNORE(-Wformat-nonliteral);
                 yyerror_pv(Perl_form(aTHX_ PL_no_myglob,
-                           PL_in_my == KEY_my ? "my" : "state", PL_tokenbuf),
+                            PL_in_my == KEY_my ? "my" : "state",
+                            *PL_tokenbuf == '&' ? "subroutin" : "variabl",
+                            PL_tokenbuf),
                             UTF ? SVf_UTF8 : 0);
                 GCC_DIAG_RESTORE;
             }

--
Perl5 Master Repository

Reply via email to