summaryrefslogtreecommitdiff
path: root/dist
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-12-20 22:53:13 -0800
committerFather Chrysostomos <sprout@cpan.org>2011-12-20 23:30:04 -0800
commitb89b72572533bd5be1cc901f1d10aadca7e64154 (patch)
treef9b9b1a4817275695568145221302d4e8a28dfee /dist
parent3e58017a75042bfef5966f41ba7799b045f69388 (diff)
downloadperl-b89b72572533bd5be1cc901f1d10aadca7e64154.tar.gz
[perl #91416] Deparse open("blah blah blah") properly
‘open bareword’ compiles down to open `--+--pushmark `--gv whereas ‘open "string"’ compiles down to open `--+--pushmark `--rv2gv `----gv the same as ‘open *glob’. B::Deparse was deparsing the child of the rv2gv, in order to deparse things like open(my $fh...) as they were entered, instead of open(*my $fh), which wouldn’t work. gvops were being deparsed as the name. But this meant that ‘open "open"’ would be deparsed as ‘open open’, which does something different, ‘open’ being a keyword. It also did that with ‘open '%^$^$%'’, which would deparse without the quotation marks. This commit changes the deparsing of filehandle-op -> rv2gv -> gv, by keeping the explicit * present if the name of the gv is a valid identifier (so open("foo") and open(*foo), which compile identi- cally, both come out as open(*foo)), or by using quotation marks if it is not.
Diffstat (limited to 'dist')
-rw-r--r--dist/B-Deparse/Deparse.pm26
-rw-r--r--dist/B-Deparse/t/deparse.t11
2 files changed, 33 insertions, 4 deletions
diff --git a/dist/B-Deparse/Deparse.pm b/dist/B-Deparse/Deparse.pm
index 6639c4df4f..6a4d8cb78a 100644
--- a/dist/B-Deparse/Deparse.pm
+++ b/dist/B-Deparse/Deparse.pm
@@ -1252,9 +1252,10 @@ BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
sub gv_name {
my $self = shift;
my $gv = shift;
+ my $raw = shift;
Carp::confess() unless ref($gv) eq "B::GV";
my $stash = $gv->STASH->NAME;
- my $name = $gv->SAFENAME;
+ my $name = $raw ? $gv->NAME : $gv->SAFENAME;
if ($stash eq 'main' && $name =~ /^::/) {
$stash = '::';
}
@@ -1267,7 +1268,7 @@ Carp::confess() unless ref($gv) eq "B::GV";
} else {
$stash = $stash . "::";
}
- if ($name =~ /^(\^..|{)/) {
+ if (!$raw and $name =~ /^(\^..|{)/) {
$name = "{$name}"; # ${^WARNING_BITS}, etc and ${
}
return $stash . $name;
@@ -2369,6 +2370,23 @@ sub pp_andassign { logassignop(@_, "&&=") }
sub pp_orassign { logassignop(@_, "||=") }
sub pp_dorassign { logassignop(@_, "//=") }
+sub rv2gv_or_string {
+ my($self,$op) = @_;
+ if ($op->name eq "gv") { # could be open("open") or open("###")
+ my $name = $self->gv_name($self->gv_or_padgv($op), 1);
+ if ($name =~ /^(?:\S|(?!\d)[\ca-\cz]?\w*|\d+)\z/) {
+ $name =~ s/^([\ca-\cz])/'^'.($1|'@')/e;
+ $name =~ /^(\^..|{)/ ? "*{$name}" : "*$name";
+ }
+ else {
+ single_delim("q", "'", $name);
+ }
+ }
+ else {
+ $self->deparse($op, 6);
+ }
+}
+
sub listop {
my $self = shift;
my($op, $cx, $name, $kid, $nollafr) = @_;
@@ -2391,7 +2409,7 @@ sub listop {
if (defined $proto
&& $proto =~ /^;?\*/
&& $kid->name eq "rv2gv" && !($kid->private & OPpLVAL_INTRO)) {
- $first = $self->deparse($kid->first, 6);
+ $first = $self->rv2gv_or_string($kid->first);
}
else {
$first = $self->deparse($kid, 6);
@@ -2405,7 +2423,7 @@ sub listop {
$kid = $kid->sibling;
if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv"
&& !($kid->private & OPpLVAL_INTRO)) {
- push @exprs, $self->deparse($kid->first, 6);
+ push @exprs, $first = $self->rv2gv_or_string($kid->first);
$kid = $kid->sibling;
}
for (; !null($kid); $kid = $kid->sibling) {
diff --git a/dist/B-Deparse/t/deparse.t b/dist/B-Deparse/t/deparse.t
index 22f2cb533e..be9cbb6d29 100644
--- a/dist/B-Deparse/t/deparse.t
+++ b/dist/B-Deparse/t/deparse.t
@@ -891,6 +891,17 @@ $_ = ($a xor not +($1 || 2) ** 2);
open local *FH;
pipe local *FH, local *FH;
####
+# [perl #91416] open "string"
+open 'open';
+open '####';
+open '^A';
+open "\ca";
+>>>>
+open *open;
+open '####';
+open '^A';
+open *^A;
+####
# [perl #74740] -(f()) vs -f()
$_ = -(f());
####