This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix deparsing of glob(my $x) and CORE::glob
authorFather Chrysostomos <sprout@cpan.org>
Sun, 10 Nov 2013 05:15:32 +0000 (21:15 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 10 Nov 2013 06:07:34 +0000 (22:07 -0800)
A git bisect run like this:

$ ../perl.git/Porting/bisect.pl --start=v5.12.0 --end=v5.18.0 -e 'use B::Deparse; die if new B::Deparse->coderef2text(sub{glob my $x}) =~ /</'

points to v5.13.8-86-gd1bea3d as being the commit that cause it to
output <my $x>.

But my local 5.14.4 installation still outputs glob(my $x), so I am
not sure which commit is responsible.  I suspect it changed multi-
ple times.

In any case, B::Deparse was expecting the argument to pp_glob always
to be a string, which is certainly not guaranteed.

This commit also causes CORE::glob to be deparsed correctly.  glob is
one of those oddities like require that gets only half-overridden by
overrides.  In this particular case the built-in pp_glob is still
used, but takes a different code path depending on whether it was pre-
fixed with CORE::.  So, while glob is a strong keyword, it needs to be
treated as a weak one for deparsing purposes.

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

index eaa2689..f839e88 100644 (file)
@@ -36,7 +36,7 @@ BEGIN {
 
 use strict;
 use Test::More;
-plan tests => 2063;
+plan tests => 2071;
 
 use feature (sprintf(":%vd", $^V)); # to avoid relying on the feature
                                     # logic to add CORE::
@@ -62,8 +62,6 @@ sub testit {
     for my $lex (0, 1, 2) {
        if ($lex) {
            next if $keyword =~ /local|our|state|my/;
-           # XXX glob(my $x) incorrectly becomes <my $x>
-           next if $keyword eq 'glob';
        }
        my $vars = $lex == 1 ? 'my($a, $b, $c, $d, $e);' . "\n    " : "";
 
@@ -225,13 +223,10 @@ testit exists   => 'exists $h{\'foo\'};',       'exists $h{\'foo\'};';
 
 testit exec     => 'CORE::exec($foo $bar);';
 
-# glob($x) gets deparsed as glob("$x").
-# Whether this is correct, I don't know; but I didn't want
-# to start messing with the whole glob/readline/<> mess - DAPM.
-testit glob     => 'glob;',                       'glob("$_");';
-testit glob     => 'CORE::glob;',                 'glob("$_");';
-testit glob     => 'glob $a;',                    'glob("$a");';
-testit glob     => 'CORE::glob $a;',              'glob("$a");';
+testit glob     => 'glob;',                       'glob($_);';
+testit glob     => 'CORE::glob;',                 'CORE::glob($_);';
+testit glob     => 'glob $a;',                    'glob($a);';
+testit glob     => 'CORE::glob $a;',              'CORE::glob($a);';
 
 testit grep     => 'CORE::grep { $a } $b, $c',    'grep({$a;} $b, $c);';
 
index 5ea01cb..3800171 100644 (file)
@@ -1811,7 +1811,6 @@ my %feature_keywords = (
 # keywords that are strong and also have a prototype
 #
 my %strong_proto_keywords = map { $_ => 1 } qw(
-    glob
     pos
     prototype
     scalar
@@ -2810,13 +2809,19 @@ sub pp_syscall { listop(@_, "syscall") }
 sub pp_glob {
     my $self = shift;
     my($op, $cx) = @_;
-    my $text = $self->dq($op->first->sibling);  # skip pushmark
+    my $kid = $op->first->sibling;  # skip pushmark
     my $keyword =
        $op->flags & OPf_SPECIAL ? 'glob' : $self->keyword('glob');
-    if ($text =~ /^\$?(\w|::|\`)+$/ # could look like a readline
-       or $keyword =~ /^CORE::/
+    my $text;
+    if ($keyword =~ /^CORE::/
+       or $kid->name ne 'const'
+       or ($text = $self->dq($kid))
+            =~ /^\$?(\w|::|\`)+$/ # could look like a readline
         or $text =~ /[<>]/) {
-       return "$keyword(" . single_delim('qq', '"', $text) . ')';
+       $text = $self->deparse($kid);
+       return $cx >= 5 || $self->{'parens'}
+           ? "$keyword($text)"
+           : "$keyword $text";
     } else {
        return '<' . $text . '>';
     }