This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Deparse join("", pos) correctly
authorFather Chrysostomos <sprout@cpan.org>
Wed, 15 Oct 2014 05:52:29 +0000 (22:52 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Wed, 15 Oct 2014 05:52:29 +0000 (22:52 -0700)
I optimised join into stringify if it had a list of one scalar-
returning op.

$ ./perl -Ilib -MO=Deparse -e '$_ = join $foo, $bar'
$_ = "$bar";
-e syntax OK

The problem, though, is that we now create op trees that didn’t happen
before,* and B::Deparse can’t handle them correctly:

$ ./perl -Ilib -MO=Deparse -e '$_ = join $foo, pos'
$_ = "pos($_)";
-e syntax OK

So we need to turn that into:

$_ = join('???', pos);

* Actually, in 5.8 it was possible to interpolate arbitrary expres-
sions after ‘$_[0]->’:

$_ = "\n,rekcah lreP rehtona tsuJ"; sub a{chop}
print "${[bless[]]}[0]->a . reverse $_";

And that, consequently, did not deparse properly.

lib/B/Deparse.pm
lib/B/Deparse.t

index ce86193..f821c8f 100644 (file)
@@ -4476,7 +4476,23 @@ sub dquote {
 }
 
 # OP_STRINGIFY is a listop, but it only ever has one arg
-sub pp_stringify { maybe_targmy(@_, \&dquote) }
+sub pp_stringify {
+    my ($self, $op, $cx) = @_;
+    my $kid = $op->first->sibling;
+    while ($kid->name eq 'null' && !null($kid->first)) {
+       $kid = $kid->first;
+    }
+    if ($kid->name =~ /^(?:const|padsv|rv2sv|av2arylen|gvsv
+                         |aelemfast(?:_lex)?|[ah]elem|join|concat)\z/x) {
+       maybe_targmy(@_, \&dquote);
+    }
+    else {
+       # Actually an optimised join.
+       my $result = listop(@_,"join");
+       $result =~ s/join([( ])/join$1$self->{'ex_const'}, /;
+       $result;
+    }
+}
 
 # tr/// and s/// (and tr[][], tr[]//, tr###, etc)
 # note that tr(from)/to/ is OK, but not tr/from/(to)
index 8a7a425..52e0084 100644 (file)
@@ -1867,3 +1867,10 @@ foreach \%_ ({5, 6}, {7, 8}) {
 foreach \&a (sub { 9; } , sub { 10; } ) {
     die;
 }
+####
+# join $foo, pos
+my $foo;
+$_ = join $foo, pos
+>>>>
+my $foo;
+$_ = join('???', pos $_);