summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/B/Deparse.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/B/Deparse.pm')
-rw-r--r--Master/tlpkg/tlperl/lib/B/Deparse.pm803
1 files changed, 569 insertions, 234 deletions
diff --git a/Master/tlpkg/tlperl/lib/B/Deparse.pm b/Master/tlpkg/tlperl/lib/B/Deparse.pm
index f3c304f8263..b0f172d61b3 100644
--- a/Master/tlpkg/tlperl/lib/B/Deparse.pm
+++ b/Master/tlpkg/tlperl/lib/B/Deparse.pm
@@ -14,29 +14,28 @@ use B qw(class main_root main_start main_cv svref_2object opnumber perlstring
OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL OPf_MOD
OPpLVAL_INTRO OPpOUR_INTRO OPpENTERSUB_AMPER OPpSLICE OPpCONST_BARE
OPpTRANS_SQUASH OPpTRANS_DELETE OPpTRANS_COMPLEMENT OPpTARGET_MY
- OPpCONST_ARYBASE OPpEXISTS_SUB OPpSORT_NUMERIC OPpSORT_INTEGER
+ OPpEXISTS_SUB OPpSORT_NUMERIC OPpSORT_INTEGER
OPpSORT_REVERSE
SVf_IOK SVf_NOK SVf_ROK SVf_POK SVpad_OUR SVf_FAKE SVs_RMG SVs_SMG
CVf_METHOD CVf_LVALUE
PMf_KEEP PMf_GLOBAL PMf_CONTINUE PMf_EVAL PMf_ONCE
- PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED),
- ($] < 5.008004 ? () : 'OPpSORT_INPLACE'),
- ($] < 5.008006 ? () : qw(OPpSORT_DESCEND OPpITER_REVERSED)),
- ($] < 5.008009 ? () : qw(OPpCONST_NOVER OPpPAD_STATE)),
- ($] < 5.009 ? 'PMf_SKIPWHITE' : qw(RXf_SKIPWHITE)),
- ($] < 5.011 ? 'CVf_LOCKED' : 'OPpREVERSE_INPLACE'),
- ($] < 5.013 ? () : 'PMf_NONDESTRUCT');
-$VERSION = "1.04";
+ PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED);
+$VERSION = '1.14_01';
use strict;
use vars qw/$AUTOLOAD/;
use warnings ();
+require feature;
BEGIN {
+ # List version-specific constants here.
# Easiest way to keep this code portable between version looks to
# be to fake up a dummy constant that will never actually be true.
foreach (qw(OPpSORT_INPLACE OPpSORT_DESCEND OPpITER_REVERSED OPpCONST_NOVER
- OPpPAD_STATE RXf_SKIPWHITE CVf_LOCKED OPpREVERSE_INPLACE
- PMf_NONDESTRUCT)) {
+ OPpPAD_STATE PMf_SKIPWHITE RXf_SKIPWHITE
+ RXf_PMf_CHARSET RXf_PMf_KEEPCOPY
+ CVf_LOCKED OPpREVERSE_INPLACE OPpSUBSTR_REPL_FIRST
+ PMf_NONDESTRUCT OPpCONST_ARYBASE OPpEVAL_BYTES)) {
+ eval { import B $_ };
no strict 'refs';
*{$_} = sub () {0} unless *{$_}{CODE};
}
@@ -47,10 +46,10 @@ BEGIN {
# - fixed reference constants (\"str")
# - handle empty programs gracefully
# - handle infinite loops (for (;;) {}, while (1) {})
-# - differentiate between `for my $x ...' and `my $x; for $x ...'
+# - differentiate between 'for my $x ...' and 'my $x; for $x ...'
# - various minor cleanups
# - moved globals into an object
-# - added `-u', like B::C
+# - added '-u', like B::C
# - package declarations using cop_stash
# - subs, formats and code sorted by cop_seq
# Changes between 0.51 and 0.52:
@@ -58,10 +57,10 @@ BEGIN {
# - added documentation
# Changes between 0.52 and 0.53:
# - many changes adding precedence contexts and associativity
-# - added `-p' and `-s' output style options
+# - added '-p' and '-s' output style options
# - various other minor fixes
# Changes between 0.53 and 0.54:
-# - added support for new `for (1..100)' optimization,
+# - added support for new 'for (1..100)' optimization,
# thanks to Gisle Aas
# Changes between 0.54 and 0.55:
# - added support for new qr// construct
@@ -70,16 +69,16 @@ BEGIN {
# - tested on base/*.t, cmd/*.t, comp/*.t, io/*.t
# - fixed $# on non-lexicals broken in last big rewrite
# - added temporary fix for change in opcode of OP_STRINGIFY
-# - fixed problem in 0.54's for() patch in `for (@ary)'
+# - fixed problem in 0.54's for() patch in 'for (@ary)'
# - fixed precedence in conditional of ?:
-# - tweaked list paren elimination in `my($x) = @_'
+# - tweaked list paren elimination in 'my($x) = @_'
# - made continue-block detection trickier wrt. null ops
# - fixed various prototype problems in pp_entersub
# - added support for sub prototypes that never get GVs
# - added unquoting for special filehandle first arg in truncate
-# - print doubled rv2gv (a bug) as `*{*GV}' instead of illegal `**GV'
+# - print doubled rv2gv (a bug) as '*{*GV}' instead of illegal '**GV'
# - added semicolons at the ends of blocks
-# - added -l `#line' declaration option -- fixes cmd/subval.t 27,28
+# - added -l '#line' declaration option -- fixes cmd/subval.t 27,28
# Changes between 0.56 and 0.561:
# - fixed multiply-declared my var in pp_truncate (thanks to Sarathy)
# - used new B.pm symbolic constants (done by Nick Ing-Simmons)
@@ -92,7 +91,7 @@ BEGIN {
# Changes after 0.57:
# - added parens in \&foo (patch by Albert Dvornik)
# Changes between 0.57 and 0.58:
-# - fixed `0' statements that weren't being printed
+# - fixed '0' statements that weren't being printed
# - added methods for use from other programs
# (based on patches from James Duncan and Hugo van der Sanden)
# - added -si and -sT to control indenting (also based on a patch from Hugo)
@@ -104,7 +103,7 @@ BEGIN {
# Changes between 0.58 and 0.59
# - added support for Chip's OP_METHOD_NAMED
# - added support for Ilya's OPpTARGET_MY optimization
-# - elided arrows before `()' subscripts when possible
+# - elided arrows before '()' subscripts when possible
# Changes between 0.59 and 0.60
# - support for method attributes was added
# - some warnings fixed
@@ -154,7 +153,7 @@ BEGIN {
# - configurable syntax highlighting: ANSI color, HTML, TeX, etc.
# - more style options: brace style, hex vs. octal, quotes, ...
# - print big ints as hex/octal instead of decimal (heuristic?)
-# - handle `my $x if 0'?
+# - handle 'my $x if 0'?
# - version using op_next instead of op_first/sibling?
# - avoid string copies (pass arrays, one big join?)
# - here-docs?
@@ -220,7 +219,8 @@ BEGIN {
# CV for current sub (or main program) being deparsed
#
# curcvlex:
-# Cached hash of lexical variables for curcv: keys are names,
+# Cached hash of lexical variables for curcv: keys are
+# names prefixed with "m" or "o" (representing my/our), and
# each value is an array of pairs, indicating the cop_seq of scopes
# in which a var of that name is valid.
#
@@ -243,7 +243,8 @@ BEGIN {
#
# subs_declared
# keys are names of subs for which we've printed declarations.
-# That means we can omit parentheses from the arguments.
+# That means we can omit parentheses from the arguments. It also means we
+# need to put CORE:: on core functions of the same name.
#
# subs_deparsed
# Keeps track of fully qualified names of all deparsed subs.
@@ -251,7 +252,7 @@ BEGIN {
# parens: -p
# linenums: -l
# unquote: -q
-# cuddle: ` ' or `\n', depending on -sC
+# cuddle: ' ' or '\n', depending on -sC
# indent_size: -si
# use_tabs: -sT
# ex_const: -sv
@@ -265,7 +266,7 @@ BEGIN {
# they're inside an expression or at statement level, etc. (see
# chart below). When ops with children call deparse on them, they pass
# along their precedence. Fractional values are used to implement
-# associativity (`($x + $y) + $z' => `$x + $y + $y') and related
+# associativity ('($x + $y) + $z' => '$x + $y + $y') and related
# parentheses hacks. The major disadvantage of this scheme is that
# it doesn't know about right sides and left sides, so say if you
# assign a listop to a variable, it can't tell it's allowed to leave
@@ -305,7 +306,7 @@ BEGIN {
# \cS - steal parens (see maybe_parens_unop)
# \n - newline and indent
# \t - increase indent
-# \b - decrease indent (`outdent')
+# \b - decrease indent ('outdent')
# \f - flush left (no indent)
# \cK - kill following semicolon, if any
@@ -471,7 +472,7 @@ sub begin_is_use {
}
sub stash_subs {
- my ($self, $pack) = @_;
+ my ($self, $pack, $seen) = @_;
my (@ret, $stash);
if (!defined $pack) {
$pack = '';
@@ -482,6 +483,10 @@ sub stash_subs {
no strict 'refs';
$stash = \%{"main::$pack"};
}
+ return
+ if ($seen ||= {})->{
+ $INC{"overload.pm"} ? overload::StrVal($stash) : $stash
+ }++;
my %stash = svref_2object($stash)->ARRAY;
while (my ($key, $val) = each %stash) {
my $class = class($val);
@@ -520,9 +525,7 @@ sub stash_subs {
$self->todo($cv, 1);
}
if (class($val->HV) ne "SPECIAL" && $key =~ /::$/) {
- $self->stash_subs($pack . $key)
- unless $pack eq '' && $key eq 'main::';
- # avoid infinite recursion
+ $self->stash_subs($pack . $key, $seen);
}
}
}
@@ -706,6 +709,11 @@ sub coderef2text {
return $self->indent($self->deparse_sub(svref_2object($sub)));
}
+my %strict_bits = do {
+ local $^H;
+ map +($_ => strict::bits($_)), qw/refs subs vars/
+};
+
sub ambient_pragmas {
my $self = shift;
my ($arybase, $hint_bits, $warning_bits, $hinthash) = (0, 0);
@@ -718,7 +726,7 @@ sub ambient_pragmas {
require strict;
if ($val eq 'none') {
- $hint_bits &= ~strict::bits(qw/refs subs vars/);
+ $hint_bits &= $strict_bits{$_} for qw/refs subs vars/;
next();
}
@@ -732,11 +740,15 @@ sub ambient_pragmas {
else {
@names = split' ', $val;
}
- $hint_bits |= strict::bits(@names);
+ $hint_bits |= $strict_bits{$_} for @names;
}
elsif ($name eq '$[') {
- $arybase = $val;
+ if (OPpCONST_ARYBASE) {
+ $arybase = $val;
+ } else {
+ croak "\$[ can't be non-zero on this perl" unless $val == 0;
+ }
}
elsif ($name eq 'integer'
@@ -948,7 +960,7 @@ sub is_state {
return $name eq "nextstate" || $name eq "dbstate" || $name eq "setstate";
}
-sub is_miniwhile { # check for one-line loop (`foo() while $y--')
+sub is_miniwhile { # check for one-line loop ('foo() while $y--')
my $op = shift;
return (!null($op) and null($op->sibling)
and $op->name eq "null" and class($op) eq "UNOP"
@@ -1008,7 +1020,7 @@ sub maybe_parens {
}
}
-# same as above, but get around the `if it looks like a function' rule
+# same as above, but get around the 'if it looks like a function' rule
sub maybe_parens_unop {
my $self = shift;
my($name, $kid, $cx) = @_;
@@ -1017,18 +1029,19 @@ sub maybe_parens_unop {
if ($name eq "umask" && $kid =~ /^\d+$/) {
$kid = sprintf("%#o", $kid);
}
- return "$name($kid)";
+ return $self->keyword($name) . "($kid)";
} else {
$kid = $self->deparse($kid, 16);
if ($name eq "umask" && $kid =~ /^\d+$/) {
$kid = sprintf("%#o", $kid);
}
+ $name = $self->keyword($name);
if (substr($kid, 0, 1) eq "\cS") {
# use kid's parens
return $name . substr($kid, 1);
} elsif (substr($kid, 0, 1) eq "(") {
# avoid looks-like-a-function trap with extra parens
- # (`+' can lead to ambiguities)
+ # ('+' can lead to ambiguities)
return "$name(" . $kid . ")";
} else {
return "$name $kid";
@@ -1093,7 +1106,9 @@ sub maybe_my {
my $self = shift;
my($op, $cx, $text) = @_;
if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
- my $my = $op->private & OPpPAD_STATE ? "state" : "my";
+ my $my = $op->private & OPpPAD_STATE
+ ? $self->keyword("state")
+ : "my";
if (want_scalar($op)) {
return "$my $text";
} else {
@@ -1247,32 +1262,35 @@ 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 = '::';
}
- elsif (($stash eq 'main' && $globalnames{$name})
+ elsif (($stash eq 'main'
+ && ($globalnames{$name} || $name =~ /^[^A-Za-z_:]/))
or ($stash eq $self->{'curstash'} && !$globalnames{$name}
&& ($stash eq 'main' || $name !~ /::/))
- or $name =~ /^[^A-Za-z_:]/)
+ )
{
$stash = "";
} else {
$stash = $stash . "::";
}
- if ($name =~ /^(\^..|{)/) {
+ if (!$raw and $name =~ /^(\^..|{)/) {
$name = "{$name}"; # ${^WARNING_BITS}, etc and ${
}
return $stash . $name;
}
# Return the name to use for a stash variable.
-# If a lexical with the same name is in scope, it may need to be
+# If a lexical with the same name is in scope, or
+# if strictures are enabled, it may need to be
# fully-qualified.
sub stash_variable {
- my ($self, $prefix, $name) = @_;
+ my ($self, $prefix, $name, $cx) = @_;
return "$prefix$name" if $name =~ /::/;
@@ -1281,13 +1299,55 @@ sub stash_variable {
return "$prefix$name";
}
+ if ($name =~ /^[^\w+-]$/) {
+ if (defined $cx && $cx == 26) {
+ if ($prefix eq '@') {
+ return "$prefix\{$name}";
+ }
+ elsif ($name eq '#') { return '${#}' } # "${#}a" vs "$#a"
+ }
+ if ($prefix eq '$#') {
+ return "\$#{$name}";
+ }
+ }
+
+ return $prefix . $self->maybe_qualify($prefix, $name);
+}
+
+# Return just the name, without the prefix. It may be returned as a quoted
+# string. The second return value is a boolean indicating that.
+sub stash_variable_name {
+ my($self, $prefix, $gv) = @_;
+ my $name = $self->gv_name($gv, 1);
+ $name = $self->maybe_qualify($prefix,$name);
+ if ($name =~ /^(?:\S|(?!\d)[\ca-\cz]?(?:\w|::)*|\d+)\z/) {
+ $name =~ s/^([\ca-\cz])/'^'.($1|'@')/e;
+ $name =~ /^(\^..|{)/ and $name = "{$name}";
+ return $name, 0; # not quoted
+ }
+ else {
+ single_delim("q", "'", $name), 1;
+ }
+}
+
+sub maybe_qualify {
+ my ($self,$prefix,$name) = @_;
my $v = ($prefix eq '$#' ? '@' : $prefix) . $name;
- return $prefix .$self->{'curstash'}.'::'. $name if $self->lex_in_scope($v);
- return "$prefix$name";
+ return $name if !$prefix || $name =~ /::/;
+ return $self->{'curstash'}.'::'. $name
+ if
+ $name =~ /^(?!\d)\w/ # alphabetic
+ && $v !~ /^\$[ab]\z/ # not $a or $b
+ && !$globalnames{$name} # not a global name
+ && $self->{hints} & $strict_bits{vars} # strict vars
+ && !$self->lex_in_scope($v,1) # no "our"
+ or $self->lex_in_scope($v); # conflicts with "my" variable
+ return $name;
}
sub lex_in_scope {
- my ($self, $name) = @_;
+ my ($self, $name, $our) = @_;
+ substr $name, 0, 0, = $our ? 'o' : 'm'; # our/my
$self->populate_curcvlex() if !defined $self->{'curcvlex'};
return 0 if !defined($self->{'curcop'});
@@ -1311,7 +1371,6 @@ sub populate_curcvlex {
for (my $i=0; $i<@ns; ++$i) {
next if class($ns[$i]) eq "SPECIAL";
- next if $ns[$i]->FLAGS & SVpad_OUR; # Skip "our" vars
if (class($ns[$i]) eq "PV") {
# Probably that pesky lexical @_
next;
@@ -1322,7 +1381,9 @@ sub populate_curcvlex {
? (0, 999999)
: ($ns[$i]->COP_SEQ_RANGE_LOW, $ns[$i]->COP_SEQ_RANGE_HIGH);
- push @{$self->{'curcvlex'}{$name}}, [$seq_st, $seq_en];
+ push @{$self->{'curcvlex'}{
+ ($ns[$i]->FLAGS & SVpad_OUR ? 'o' : 'm') . $name
+ }}, [$seq_st, $seq_en];
}
}
}
@@ -1388,6 +1449,14 @@ sub seq_subs {
return @text;
}
+sub _features_from_bundle {
+ my ($hints, $hh) = @_;
+ foreach (@{$feature::feature_bundle{@feature::hint_bundles[$hints >> $feature::hint_shift]}}) {
+ $hh->{$feature::feature{$_}} = 1;
+ }
+ return $hh;
+}
+
# Notice how subs and formats are inserted between statements here;
# also $[ assignments and pragmas.
sub pp_nextstate {
@@ -1402,7 +1471,7 @@ sub pp_nextstate {
$self->{'curstash'} = $stash;
}
- if ($self->{'arybase'} != $op->arybase) {
+ if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) {
push @text, '$[ = '. $op->arybase .";\n";
$self->{'arybase'} = $op->arybase;
}
@@ -1429,17 +1498,47 @@ sub pp_nextstate {
}
my $hints = $] < 5.008009 ? $op->private : $op->hints;
+ my $old_hints = $self->{'hints'};
if ($self->{'hints'} != $hints) {
push @text, declare_hints($self->{'hints'}, $hints);
$self->{'hints'} = $hints;
}
- # hack to check that the hint hash hasn't changed
- if ($] > 5.009 &&
- "@{[sort %{$self->{'hinthash'} || {}}]}"
- ne "@{[sort %{$op->hints_hash->HASH || {}}]}") {
- push @text, declare_hinthash($self->{'hinthash'}, $op->hints_hash->HASH, $self->{indent_size});
- $self->{'hinthash'} = $op->hints_hash->HASH;
+ my $newhh;
+ if ($] > 5.009) {
+ $newhh = $op->hints_hash->HASH;
+ }
+
+ if ($] >= 5.015006) {
+ # feature bundle hints
+ my $from = $old_hints & $feature::hint_mask;
+ my $to = $ hints & $feature::hint_mask;
+ if ($from != $to) {
+ if ($to == $feature::hint_mask) {
+ if ($self->{'hinthash'}) {
+ delete $self->{'hinthash'}{$_}
+ for grep /^feature_/, keys %{$self->{'hinthash'}};
+ }
+ else { $self->{'hinthash'} = {} }
+ $self->{'hinthash'}
+ = _features_from_bundle($from, $self->{'hinthash'});
+ }
+ else {
+ my $bundle =
+ $feature::hint_bundles[$to >> $feature::hint_shift];
+ $bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12
+ push @text, "no feature;\n",
+ "use feature ':$bundle';\n";
+ }
+ }
+ }
+
+ if ($] > 5.009) {
+ push @text, declare_hinthash(
+ $self->{'hinthash'}, $newhh,
+ $self->{indent_size}, $self->{hints},
+ );
+ $self->{'hinthash'} = $newhh;
}
# This should go after of any branches that add statements, to
@@ -1486,32 +1585,77 @@ my %ignored_hints = (
'open<' => 1,
'open>' => 1,
':' => 1,
+ 'strict/refs' => 1,
+ 'strict/subs' => 1,
+ 'strict/vars' => 1,
);
+my %rev_feature;
+
sub declare_hinthash {
- my ($from, $to, $indent) = @_;
+ my ($from, $to, $indent, $hints) = @_;
+ my $doing_features =
+ ($hints & $feature::hint_mask) == $feature::hint_mask;
my @decls;
- for my $key (keys %$to) {
+ my @features;
+ my @unfeatures; # bugs?
+ for my $key (sort keys %$to) {
next if $ignored_hints{$key};
- if (!defined $from->{$key} or $from->{$key} ne $to->{$key}) {
- push @decls, qq(\$^H{'$key'} = q($to->{$key}););
+ my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6;
+ next if $is_feature and not $doing_features;
+ if (!exists $from->{$key} or $from->{$key} ne $to->{$key}) {
+ push(@features, $key), next if $is_feature;
+ push @decls,
+ qq(\$^H{) . single_delim("q", "'", $key) . qq(} = )
+ . (
+ defined $to->{$key}
+ ? single_delim("q", "'", $to->{$key})
+ : 'undef'
+ )
+ . qq(;);
}
}
- for my $key (keys %$from) {
+ for my $key (sort keys %$from) {
next if $ignored_hints{$key};
+ my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6;
+ next if $is_feature and not $doing_features;
if (!exists $to->{$key}) {
+ push(@unfeatures, $key), next if $is_feature;
push @decls, qq(delete \$^H{'$key'};);
}
}
- @decls or return '';
- return join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n";
+ my @ret;
+ if (@features || @unfeatures) {
+ if (!%rev_feature) { %rev_feature = reverse %feature::feature }
+ }
+ if (@features) {
+ push @ret, "use feature "
+ . join(", ", map "'$rev_feature{$_}'", @features) . ";\n";
+ }
+ if (@unfeatures) {
+ push @ret, "no feature "
+ . join(", ", map "'$rev_feature{$_}'", @unfeatures)
+ . ";\n";
+ }
+ @decls and
+ push @ret,
+ join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n";
+ return @ret;
}
sub hint_pragmas {
my ($bits) = @_;
- my @pragmas;
+ my (@pragmas, @strict);
push @pragmas, "integer" if $bits & 0x1;
- push @pragmas, "strict 'refs'" if $bits & 0x2;
+ for (sort keys %strict_bits) {
+ push @strict, "'$_'" if $bits & $strict_bits{$_};
+ }
+ if (@strict == keys %strict_bits) {
+ push @pragmas, "strict";
+ }
+ elsif (@strict) {
+ push @pragmas, "strict " . join ', ', @strict;
+ }
push @pragmas, "bytes" if $bits & 0x8;
return @pragmas;
}
@@ -1521,10 +1665,52 @@ sub pp_setstate { pp_nextstate(@_) }
sub pp_unstack { return "" } # see also leaveloop
+my %feature_keywords = (
+ # keyword => 'feature',
+ state => 'state',
+ say => 'say',
+ given => 'switch',
+ when => 'switch',
+ default => 'switch',
+ break => 'switch',
+ evalbytes=>'evalbytes',
+ __SUB__ => '__SUB__',
+ fc => 'fc',
+);
+
+sub keyword {
+ my $self = shift;
+ my $name = shift;
+ return $name if $name =~ /^CORE::/; # just in case
+ if (exists $feature_keywords{$name}) {
+ my $hh;
+ my $hints = $self->{hints} & $feature::hint_mask;
+ if ($hints && $hints != $feature::hint_mask) {
+ $hh = _features_from_bundle($hints);
+ }
+ elsif ($hints) { $hh = $self->{'hinthash'} }
+ return "CORE::$name"
+ if !$hh
+ || !$hh->{"feature_$feature_keywords{$name}"}
+ }
+ if (
+ $name !~ /^(?:chom?p|do|exec|glob|s(?:elect|ystem))\z/
+ && !defined eval{prototype "CORE::$name"}
+ ) { return $name }
+ if (
+ exists $self->{subs_declared}{$name}
+ or
+ exists &{"$self->{curstash}::$name"}
+ ) {
+ return "CORE::$name"
+ }
+ return $name;
+}
+
sub baseop {
my $self = shift;
my($op, $cx, $name) = @_;
- return $name;
+ return $self->keyword($name);
}
sub pp_stub {
@@ -1569,7 +1755,13 @@ sub pfixop {
my($op, $cx, $name, $prec, $flags) = (@_, 0);
my $kid = $op->first;
$kid = $self->deparse($kid, $prec);
- return $self->maybe_parens(($flags & POSTFIX) ? "$kid$name" : "$name$kid",
+ return $self->maybe_parens(($flags & POSTFIX)
+ ? "$kid$name"
+ # avoid confusion with filetests
+ : $name eq '-'
+ && $kid =~ /^[a-zA-Z](?!\w)/
+ ? "$name($kid)"
+ : "$name$kid",
$cx, $prec);
}
@@ -1600,7 +1792,7 @@ sub pp_not {
my $self = shift;
my($op, $cx) = @_;
if ($cx <= 4) {
- $self->pfixop($op, $cx, "not ", 4);
+ $self->listop($op, $cx, "not", $op->first);
} else {
$self->pfixop($op, $cx, "!", 21);
}
@@ -1608,7 +1800,7 @@ sub pp_not {
sub unop {
my $self = shift;
- my($op, $cx, $name) = @_;
+ my($op, $cx, $name, $nollafr) = @_;
my $kid;
if ($op->flags & OPf_KIDS) {
$kid = $op->first;
@@ -1624,9 +1816,18 @@ sub unop {
$kid = $kid->first;
}
+ if ($nollafr) {
+ ($kid = $self->deparse($kid, 16)) =~ s/^\cS//;
+ return $self->maybe_parens(
+ $self->keyword($name) . " $kid", $cx, 16
+ );
+ }
return $self->maybe_parens_unop($name, $kid, $cx);
} else {
- return $name . ($op->flags & OPf_SPECIAL ? "()" : "");
+ return $self->maybe_parens(
+ $self->keyword($name) . ($op->flags & OPf_SPECIAL ? "()" : ""),
+ $cx, 16,
+ );
}
}
@@ -1659,6 +1860,7 @@ sub pp_chr { maybe_targmy(@_, \&unop, "chr") }
sub pp_each { unop(@_, "each") }
sub pp_values { unop(@_, "values") }
sub pp_keys { unop(@_, "keys") }
+{ no strict 'refs'; *{"pp_r$_"} = *{"pp_$_"} for qw< keys each values >; }
sub pp_boolkeys {
# no name because its an optimisation op that has no keyword
unop(@_,"");
@@ -1700,8 +1902,17 @@ sub pp_gmtime { unop(@_, "gmtime") }
sub pp_alarm { unop(@_, "alarm") }
sub pp_sleep { maybe_targmy(@_, \&unop, "sleep") }
-sub pp_dofile { unop(@_, "do") }
-sub pp_entereval { unop(@_, "eval") }
+sub pp_dofile {
+ my $code = unop(@_, "do", 1); # llafr does not apply
+ if ($code =~ s/^((?:CORE::)?do) \{/$1({/) { $code .= ')' }
+ $code;
+}
+sub pp_entereval {
+ unop(
+ @_,
+ $_[1]->private & OPpEVAL_BYTES ? $_[0]->keyword('evalbytes') : "eval"
+ )
+}
sub pp_ghbyname { unop(@_, "gethostbyname") }
sub pp_gnbyname { unop(@_, "getnetbyname") }
@@ -1718,11 +1929,7 @@ sub pp_ggrgid { unop(@_, "getgrgid") }
sub pp_lock { unop(@_, "lock") }
sub pp_continue { unop(@_, "continue"); }
-sub pp_break {
- my ($self, $op) = @_;
- return "" if $op->flags & OPf_SPECIAL;
- unop(@_, "break");
-}
+sub pp_break { unop(@_, "break"); }
sub givwhen {
my $self = shift;
@@ -1731,7 +1938,7 @@ sub givwhen {
my $enterop = $op->first;
my ($head, $block);
if ($enterop->flags & OPf_SPECIAL) {
- $head = "default";
+ $head = $self->keyword("default");
$block = $self->deparse($enterop->first, 0);
}
else {
@@ -1746,8 +1953,8 @@ sub givwhen {
"\b}\cK";
}
-sub pp_leavegiven { givwhen(@_, "given"); }
-sub pp_leavewhen { givwhen(@_, "when"); }
+sub pp_leavegiven { givwhen(@_, $_[0]->keyword("given")); }
+sub pp_leavewhen { givwhen(@_, $_[0]->keyword("when")); }
sub pp_exists {
my $self = shift;
@@ -1804,9 +2011,16 @@ sub pp_require {
my $name = $self->const_sv($op->first)->PV;
$name =~ s[/][::]g;
$name =~ s/\.pm//g;
- return "$opname $name";
+ return $self->maybe_parens("$opname $name", $cx, 16);
} else {
- $self->unop($op, $cx, $op->first->private & OPpCONST_NOVER ? "no" : $opname);
+ $self->unop(
+ $op, $cx,
+ $op->first->name eq 'const'
+ && $op->first->private & OPpCONST_NOVER
+ ? "no"
+ : $opname,
+ 1, # llafr does not apply
+ );
}
}
@@ -1931,33 +2145,38 @@ sub pp_lcfirst { dq_unop(@_, "lcfirst") }
sub pp_uc { dq_unop(@_, "uc") }
sub pp_lc { dq_unop(@_, "lc") }
sub pp_quotemeta { maybe_targmy(@_, \&dq_unop, "quotemeta") }
+sub pp_fc { dq_unop(@_, "fc") }
sub loopex {
my $self = shift;
my ($op, $cx, $name) = @_;
if (class($op) eq "PVOP") {
- return "$name " . $op->pv;
+ $name .= " " . $op->pv;
} elsif (class($op) eq "OP") {
- return $name;
+ # no-op
} elsif (class($op) eq "UNOP") {
- # Note -- loop exits are actually exempt from the
- # looks-like-a-func rule, but a few extra parens won't hurt
- return $self->maybe_parens_unop($name, $op->first, $cx);
+ (my $kid = $self->deparse($op->first, 16)) =~ s/^\cS//;
+ $name .= " $kid";
}
+ return $self->maybe_parens($name, $cx, 16);
}
sub pp_last { loopex(@_, "last") }
sub pp_next { loopex(@_, "next") }
sub pp_redo { loopex(@_, "redo") }
sub pp_goto { loopex(@_, "goto") }
-sub pp_dump { loopex(@_, "dump") }
+sub pp_dump { loopex(@_, "CORE::dump") }
sub ftst {
my $self = shift;
my($op, $cx, $name) = @_;
if (class($op) eq "UNOP") {
- # Genuine `-X' filetests are exempt from the LLAFR, but not
- # l?stat(); for the sake of clarity, give'em all parens
+ # Genuine '-X' filetests are exempt from the LLAFR, but not
+ # l?stat()
+ if ($name =~ /^-/) {
+ (my $kid = $self->deparse($op->first, 16)) =~ s/^\cS//;
+ return $self->maybe_parens("$name $kid", $cx, 16);
+ }
return $self->maybe_parens_unop($name, $op->first, $cx);
} elsif (class($op) =~ /^(SV|PAD)OP$/) {
return $self->maybe_parens_func($name, $self->pp_gv($op, 1), $cx, 16);
@@ -2006,7 +2225,7 @@ sub assoc_class {
my $op = shift;
my $name = $op->name;
if ($name eq "concat" and $op->first->name eq "concat") {
- # avoid spurious `=' -- see comment in pp_concat
+ # avoid spurious '=' -- see comment in pp_concat
return "concat";
}
if ($name eq "null" and class($op) eq "UNOP"
@@ -2023,7 +2242,7 @@ sub assoc_class {
return $name . ($op->flags & OPf_STACKED ? "=" : "");
}
-# Left associative operators, like `+', for which
+# Left associative operators, like '+', for which
# $a + $b + $c is equivalent to ($a + $b) + $c
BEGIN {
@@ -2054,7 +2273,7 @@ sub deparse_binop_left {
}
}
-# Right associative operators, like `=', for which
+# Right associative operators, like '=', for which
# $a = $b = $c is equivalent to $a = ($b = $c)
BEGIN {
@@ -2161,9 +2380,9 @@ sub pp_smartmatch {
}
}
-# `.' is special because concats-of-concats are optimized to save copying
+# '.' is special because concats-of-concats are optimized to save copying
# by making all but the first concat stacked. The effect is as if the
-# programmer had written `($a . $b) .= $c', except legal.
+# programmer had written '($a . $b) .= $c', except legal.
sub pp_concat { maybe_targmy(@_, \&real_concat) }
sub real_concat {
my $self = shift;
@@ -2181,7 +2400,7 @@ sub real_concat {
return $self->maybe_parens("$left .$eq $right", $cx, $prec);
}
-# `x' is weird when the left arg is a list
+# 'x' is weird when the left arg is a list
sub pp_repeat {
my $self = shift;
my($op, $cx) = @_;
@@ -2277,20 +2496,41 @@ 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,$quoted) =
+ $self->stash_variable_name("", $self->gv_or_padgv($op));
+ $quoted ? $name : "*$name";
+ }
+ else {
+ $self->deparse($op, 6);
+ }
+}
+
sub listop {
my $self = shift;
- my($op, $cx, $name) = @_;
+ my($op, $cx, $name, $kid, $nollafr) = @_;
my(@exprs);
my $parens = ($cx >= 5) || $self->{'parens'};
- my $kid = $op->first->sibling;
- return $name if null $kid;
+ $kid ||= $op->first->sibling;
+ # If there are no arguments, add final parentheses (or parenthesize the
+ # whole thing if the llafr does not apply) to account for cases like
+ # (return)+1 or setpgrp()+1. When the llafr does not apply, we use a
+ # precedence of 6 (< comma), as "return, 1" does not need parentheses.
+ if (null $kid) {
+ return $nollafr
+ ? $self->maybe_parens($self->keyword($name), $cx, 7)
+ : $self->keyword($name) . '()' x (7 < $cx);
+ }
my $first;
$name = "socketpair" if $name eq "sockpair";
+ my $fullname = $self->keyword($name);
my $proto = prototype("CORE::$name");
if (defined $proto
&& $proto =~ /^;?\*/
- && $kid->name eq "rv2gv") {
- $first = $self->deparse($kid->first, 6);
+ && $kid->name eq "rv2gv" && !($kid->private & OPpLVAL_INTRO)) {
+ $first = $self->rv2gv_or_string($kid->first);
}
else {
$first = $self->deparse($kid, 6);
@@ -2298,29 +2538,43 @@ sub listop {
if ($name eq "chmod" && $first =~ /^\d+$/) {
$first = sprintf("%#o", $first);
}
- $first = "+$first" if not $parens and substr($first, 0, 1) eq "(";
+ $first = "+$first"
+ if not $parens and not $nollafr and substr($first, 0, 1) eq "(";
push @exprs, $first;
$kid = $kid->sibling;
- if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv") {
- push @exprs, $self->deparse($kid->first, 6);
+ if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv"
+ && !($kid->private & OPpLVAL_INTRO)) {
+ push @exprs, $first = $self->rv2gv_or_string($kid->first);
$kid = $kid->sibling;
}
for (; !null($kid); $kid = $kid->sibling) {
push @exprs, $self->deparse($kid, 6);
}
if ($name eq "reverse" && ($op->private & OPpREVERSE_INPLACE)) {
- return "$exprs[0] = $name" . ($parens ? "($exprs[0])" : " $exprs[0]");
+ return "$exprs[0] = $fullname"
+ . ($parens ? "($exprs[0])" : " $exprs[0]");
}
- if ($parens) {
- return "$name(" . join(", ", @exprs) . ")";
+ if ($parens && $nollafr) {
+ return "($fullname " . join(", ", @exprs) . ")";
+ } elsif ($parens) {
+ return "$fullname(" . join(", ", @exprs) . ")";
} else {
- return "$name " . join(", ", @exprs);
+ return "$fullname " . join(", ", @exprs);
}
}
sub pp_bless { listop(@_, "bless") }
sub pp_atan2 { maybe_targmy(@_, \&listop, "atan2") }
-sub pp_substr { maybe_local(@_, listop(@_, "substr")) }
+sub pp_substr {
+ my ($self,$op,$cx) = @_;
+ if ($op->private & OPpSUBSTR_REPL_FIRST) {
+ return
+ listop($self, $op, 7, "substr", $op->first->sibling->sibling)
+ . " = "
+ . $self->deparse($op->first->sibling, 7);
+ }
+ maybe_local(@_, listop(@_, "substr"))
+}
sub pp_vec { maybe_local(@_, listop(@_, "vec")) }
sub pp_index { maybe_targmy(@_, \&listop, "index") }
sub pp_rindex { maybe_targmy(@_, \&listop, "rindex") }
@@ -2336,9 +2590,7 @@ sub pp_unshift { maybe_targmy(@_, \&listop, "unshift") }
sub pp_reverse { listop(@_, "reverse") }
sub pp_warn { listop(@_, "warn") }
sub pp_die { listop(@_, "die") }
-# Actually, return is exempt from the LLAFR (see examples in this very
-# module!), but for consistency's sake, ignore that fact
-sub pp_return { listop(@_, "return") }
+sub pp_return { listop(@_, "return", undef, 1) } # llafr does not apply
sub pp_open { listop(@_, "open") }
sub pp_pipe_op { listop(@_, "pipe") }
sub pp_tie { listop(@_, "tie") }
@@ -2404,13 +2656,13 @@ sub pp_syscall { listop(@_, "syscall") }
sub pp_glob {
my $self = shift;
my($op, $cx) = @_;
- if ($op->flags & OPf_SPECIAL) {
- return $self->deparse($op->first->sibling);
- }
my $text = $self->dq($op->first->sibling); # skip pushmark
+ my $keyword =
+ $op->flags & OPf_SPECIAL ? 'glob' : $self->keyword('glob');
if ($text =~ /^\$?(\w|::|\`)+$/ # could look like a readline
- or $text =~ /[<>]/) {
- return 'glob(' . single_delim('qq', '"', $text) . ')';
+ or $keyword =~ /^CORE::/
+ or $text =~ /[<>]/) {
+ return "$keyword(" . single_delim('qq', '"', $text) . ')';
} else {
return '<' . $text . '>';
}
@@ -2435,10 +2687,11 @@ sub pp_truncate {
$fh = "+$fh" if not $parens and substr($fh, 0, 1) eq "(";
}
my $len = $self->deparse($kid->sibling, 6);
+ my $name = $self->keyword('truncate');
if ($parens) {
- return "truncate($fh, $len)";
+ return "$name($fh, $len)";
} else {
- return "truncate $fh, $len";
+ return "$name $fh, $len";
}
}
@@ -2446,7 +2699,7 @@ sub indirop {
my $self = shift;
my($op, $cx, $name) = @_;
my($expr, @exprs);
- my $kid = $op->first->sibling;
+ my $firstkid = my $kid = $op->first->sibling;
my $indir = "";
if ($op->flags & OPf_STACKED) {
$indir = $kid;
@@ -2470,19 +2723,20 @@ sub indirop {
$indir = '{$b cmp $a} ';
}
for (; !null($kid); $kid = $kid->sibling) {
- $expr = $self->deparse($kid, 6);
+ $expr = $self->deparse($kid, !$indir && $kid == $firstkid && $name eq "sort" && $firstkid->name eq "entersub" ? 16 : 6);
push @exprs, $expr;
}
- my $name2 = $name;
+ my $name2;
if ($name eq "sort" && $op->private & OPpSORT_REVERSE) {
- $name2 = 'reverse sort';
+ $name2 = $self->keyword('reverse') . ' ' . $self->keyword('sort');
}
+ else { $name2 = $self->keyword($name) }
if ($name eq "sort" && ($op->private & OPpSORT_INPLACE)) {
return "$exprs[0] = $name2 $indir $exprs[0]";
}
my $args = $indir . join(", ", @exprs);
- if ($indir ne "" and $name eq "sort") {
+ if ($indir ne "" && $name eq "sort") {
# We don't want to say "sort(f 1, 2, 3)", since perl -w will
# give bareword warnings in that case. Therefore if context
# requires, we'll put parens around the outside "(sort f 1, 2,
@@ -2494,6 +2748,13 @@ sub indirop {
} else {
return "$name2 $args";
}
+ } elsif (
+ !$indir && $name eq "sort"
+ && $op->first->sibling->name eq 'entersub'
+ ) {
+ # We cannot say sort foo(bar), as foo will be interpreted as a
+ # comparison routine. We have to say sort(...) in that case.
+ return "$name2($args)";
} else {
return $self->maybe_parens_func($name2, $args, $cx, 5);
}
@@ -2535,6 +2796,7 @@ sub pp_list {
my($op, $cx) = @_;
my($expr, @exprs);
my $kid = $op->first->sibling; # skip pushmark
+ return '' if class($kid) eq 'NULL';
my $lop;
my $local = "either"; # could be local(...), my(...), state(...) or our(...)
for ($lop = $kid; !null($lop); $lop = $lop->sibling) {
@@ -2712,7 +2974,7 @@ sub loop_common {
$var = "\$" . $self->deparse($var, 1);
}
$body = $kid->first->first->sibling; # skip OP_AND and OP_ITER
- if (!is_state $body->first and $body->first->name ne "stub") {
+ if (!is_state $body->first and $body->first->name !~ /^(?:stub|leave|scope)$/) {
confess unless $var eq '$_';
$body = $body->first;
return $self->deparse($body, 2) . " foreach ($ary)";
@@ -2786,10 +3048,9 @@ sub pp_leavetry {
return "eval {\n\t" . $self->pp_leave(@_) . "\n\b}";
}
-BEGIN { eval "sub OP_CONST () {" . opnumber("const") . "}" }
-BEGIN { eval "sub OP_STRINGIFY () {" . opnumber("stringify") . "}" }
-BEGIN { eval "sub OP_RV2SV () {" . opnumber("rv2sv") . "}" }
-BEGIN { eval "sub OP_LIST () {" . opnumber("list") . "}" }
+BEGIN { for (qw[ const stringify rv2sv list glob ]) {
+ eval "sub OP_\U$_ () { " . opnumber($_) . "}"
+}}
sub pp_null {
my $self = shift;
@@ -2807,6 +3068,14 @@ sub pp_null {
return $self->pp_scope($op->first, $cx);
} elsif ($op->targ == OP_STRINGIFY) {
return $self->dquote($op, $cx);
+ } elsif ($op->targ == OP_GLOB) {
+ return $self->pp_glob(
+ $op->first # entersub
+ ->first # ex-list
+ ->first # pushmark
+ ->sibling, # glob
+ $cx
+ );
} elsif (!null($op->first->sibling) and
$op->first->sibling->name eq "readline" and
$op->first->sibling->flags & OPf_STACKED) {
@@ -2877,7 +3146,7 @@ sub pp_gvsv {
my($op, $cx) = @_;
my $gv = $self->gv_or_padgv($op);
return $self->maybe_local($op, $cx, $self->stash_variable("\$",
- $self->gv_name($gv)));
+ $self->gv_name($gv), $cx));
}
sub pp_gv {
@@ -2887,22 +3156,23 @@ sub pp_gv {
return $self->gv_name($gv);
}
+sub pp_aelemfast_lex {
+ my $self = shift;
+ my($op, $cx) = @_;
+ my $name = $self->padname($op->targ);
+ $name =~ s/^@/\$/;
+ return $name . "[" . ($op->private + $self->{'arybase'}) . "]";
+}
+
sub pp_aelemfast {
my $self = shift;
my($op, $cx) = @_;
- my $name;
- if ($op->flags & OPf_SPECIAL) { # optimised PADAV
- $name = $self->padname($op->targ);
- $name =~ s/^@/\$/;
- }
- else {
- my $gv = $self->gv_or_padgv($op);
- $name = $self->gv_name($gv);
- $name = $self->{'curstash'}."::$name"
- if $name !~ /::/ && $self->lex_in_scope('@'.$name);
- $name = '$' . $name;
- }
+ # optimised PADAV, pre 5.15
+ return $self->pp_aelemfast_lex(@_) if ($op->flags & OPf_SPECIAL);
+ my $gv = $self->gv_or_padgv($op);
+ my($name,$quoted) = $self->stash_variable_name('@',$gv);
+ $name = $quoted ? "$name->" : '$' . $name;
return $name . "[" . ($op->private + $self->{'arybase'}) . "]";
}
@@ -2916,7 +3186,7 @@ sub rv2x {
}
my $kid = $op->first;
if ($kid->name eq "gv") {
- return $self->stash_variable($type, $self->deparse($kid, 0));
+ return $self->stash_variable($type, $self->deparse($kid, 0), $cx);
} elsif (is_scalar $kid) {
my $str = $self->deparse($kid, 0);
if ($str =~ /^\$([^\w\d])\z/) {
@@ -3025,13 +3295,15 @@ sub elem_or_slice_array_name
} elsif (is_scope($array)) { # ${expr}[0]
return "{" . $self->deparse($array, 0) . "}";
} elsif ($array->name eq "gv") {
- $array = $self->gv_name($self->gv_or_padgv($array));
- if ($array !~ /::/) {
- my $prefix = ($left eq '[' ? '@' : '%');
- $array = $self->{curstash}.'::'.$array
- if $self->lex_in_scope($prefix . $array);
+ ($array, my $quoted) =
+ $self->stash_variable_name(
+ $left eq '[' ? '@' : '%', $self->gv_or_padgv($array)
+ );
+ if (!$allow_arrow && $quoted) {
+ # This cannot happen.
+ die "Invalid variable name $array for slice";
}
- return $array;
+ return $quoted ? "$array->" : $array;
} elsif (!$allow_arrow || is_scalar $array) { # $x[0], $$x[0], ...
return $self->deparse($array, 24);
} else {
@@ -3089,7 +3361,8 @@ sub elem {
}
if (my $array_name=$self->elem_or_slice_array_name
($array, $left, $padname, 1)) {
- return "\$" . $array_name . $left . $idx . $right;
+ return ($array_name =~ /->\z/ ? $array_name : "\$" . $array_name)
+ . $left . $idx . $right;
} else {
# $x[20][3]{hi} or expr->[20]
my $arrow = is_subscriptable($array) ? "" : "->";
@@ -3177,7 +3450,7 @@ sub _method {
# doesn't get flattened by the append_elem that adds the method,
# making a (object, arg1, arg2, ...) list where the object
# usually is. This can be distinguished from
- # `($obj, $arg1, $arg2)->meth()' (which is legal if $arg2 is an
+ # '($obj, $arg1, $arg2)->meth()' (which is legal if $arg2 is an
# object) because in the later the list is in scalar context
# as the left side of -> always is, while in the former
# the list is in list context as method arguments always are.
@@ -3192,7 +3465,7 @@ sub _method {
} else {
$obj = $kid;
$kid = $kid->sibling;
- for (; !null ($kid->sibling) && $kid->name ne "method_named";
+ for (; !null ($kid->sibling) && $kid->name!~/^method(?:_named)?\z/;
$kid = $kid->sibling) {
push @exprs, $kid
}
@@ -3211,7 +3484,8 @@ sub _method {
}
return { method => $meth, variable_method => ref($meth),
- object => $obj, args => \@exprs };
+ object => $obj, args => \@exprs },
+ $cx;
}
# compat function only
@@ -3222,12 +3496,22 @@ sub method {
}
sub e_method {
- my ($self, $info) = @_;
+ my ($self, $info, $cx) = @_;
my $obj = $self->deparse($info->{object}, 24);
my $meth = $info->{method};
$meth = $self->deparse($meth, 1) if $info->{variable_method};
my $args = join(", ", map { $self->deparse($_, 6) } @{$info->{args}} );
+ if ($info->{object}->name eq 'scope' && want_list $info->{object}) {
+ # method { $object }
+ # This must be deparsed this way to preserve list context
+ # of $object.
+ my $need_paren = $cx >= 6;
+ return '(' x $need_paren
+ . $meth . substr($obj,2) # chop off the "do"
+ . " $args"
+ . ')' x $need_paren;
+ }
my $kid = $obj . "->" . $meth;
if (length $args) {
return $kid . "(" . $args . ")"; # parens mandatory
@@ -3310,7 +3594,7 @@ sub check_proto {
}
}
}
- return "&" if $proto and !$doneok; # too few args and no `;'
+ return "&" if $proto and !$doneok; # too few args and no ';'
return "&" if @args; # too many args
return ("", join ", ", @reals);
}
@@ -3390,13 +3674,14 @@ sub pp_entersub {
$args = join(", ", map($self->deparse($_, 6), @exprs));
}
if ($prefix or $amper) {
+ if ($kid eq '&') { $kid = "{$kid}" } # &{&} cannot be written as &&
if ($op->flags & OPf_STACKED) {
return $prefix . $amper . $kid . "(" . $args . ")";
} else {
return $prefix . $amper. $kid;
}
} else {
- # It's a syntax error to call CORE::GLOBAL::foo without a prefix,
+ # It's a syntax error to call CORE::GLOBAL::foo with a prefix,
# so it must have been translated from a keyword call. Translate
# it back.
$kid =~ s/^CORE::GLOBAL:://;
@@ -3732,6 +4017,16 @@ sub const {
}
return "{" . join(", ", @elts) . "}";
} elsif (class($ref) eq "CV") {
+ BEGIN {
+ if ($] > 5.0150051) {
+ require overloading;
+ unimport overloading;
+ }
+ }
+ if ($] > 5.0150051 && $self->{curcv} &&
+ $self->{curcv}->object_2svref == $ref->object_2svref) {
+ return $self->keyword("__SUB__");
+ }
return "sub " . $self->deparse_sub($ref);
}
if ($ref->FLAGS & SVs_SMG) {
@@ -3785,7 +4080,7 @@ sub pp_const {
if ($op->private & OPpCONST_ARYBASE) {
return '$[';
}
-# if ($op->private & OPpCONST_BARE) { # trouble with `=>' autoquoting
+# if ($op->private & OPpCONST_BARE) { # trouble with '=>' autoquoting
# return $self->const_sv($op)->PV;
# }
my $sv = $self->const_sv($op);
@@ -3820,6 +4115,8 @@ sub dq {
return '\l' . $self->dq($op->first->sibling);
} elsif ($type eq "quotemeta") {
return '\Q' . $self->dq($op->first->sibling) . '\E';
+ } elsif ($type eq "fc") {
+ return '\F' . $self->dq($op->first->sibling) . '\E';
} elsif ($type eq "join") {
return $self->deparse($op->last, 26); # was join($", @ary)
} else {
@@ -3833,7 +4130,10 @@ sub pp_backtick {
# skip pushmark if it exists (readpipe() vs ``)
my $child = $op->first->sibling->isa('B::NULL')
? $op->first : $op->first->sibling;
- return single_delim("qx", '`', $self->dq($child));
+ if ($self->pure_string($child)) {
+ return single_delim("qx", '`', $self->dq($child, 1));
+ }
+ unop($self, @_, "readpipe");
}
sub dquote {
@@ -3859,7 +4159,7 @@ sub double_delim {
if (($succeed, $to) = balanced_delim($to) and $succeed) {
return "$from$to";
} else {
- for $delim ('/', '"', '#') { # note no `'' -- s''' is special
+ for $delim ('/', '"', '#') { # note no "'" -- s''' is special
return "$from$delim$to$delim" if index($to, $delim) == -1;
}
$to =~ s[/][\\/]g;
@@ -4138,10 +4438,14 @@ sub re_dq {
return '\l' . $self->re_dq($op->first->sibling, $extended);
} elsif ($type eq "quotemeta") {
return '\Q' . $self->re_dq($op->first->sibling, $extended) . '\E';
+ } elsif ($type eq "fc") {
+ return '\F' . $self->re_dq($op->first->sibling, $extended) . '\E';
} elsif ($type eq "join") {
return $self->deparse($op->last, 26); # was join($", @ary)
} else {
- return $self->deparse($op, 26);
+ my $ret = $self->deparse($op, 26);
+ $ret =~ s/^\$([(|)])\z/\${$1}/; # $( $| $) need braces
+ return $ret;
}
}
@@ -4150,10 +4454,10 @@ sub pure_string {
return 0 if null $op;
my $type = $op->name;
- if ($type eq 'const') {
+ if ($type eq 'const' || $type eq 'av2arylen') {
return 1;
}
- elsif ($type =~ /^[ul]c(first)?$/ || $type eq 'quotemeta') {
+ elsif ($type =~ /^(?:[ul]c(first)?|fc)$/ || $type eq 'quotemeta') {
return $self->pure_string($op->first->sibling);
}
elsif ($type eq 'join') {
@@ -4175,9 +4479,12 @@ sub pure_string {
return 1;
}
elsif ($type eq "null" and $op->can('first') and not null $op->first and
- $op->first->name eq "null" and $op->first->can('first')
+ ($op->first->name eq "null" and $op->first->can('first')
and not null $op->first->first and
- $op->first->first->name eq "aelemfast") {
+ $op->first->first->name eq "aelemfast"
+ or
+ $op->first->name =~ /^aelemfast(?:_lex)?\z/
+ )) {
return 1;
}
else {
@@ -4216,6 +4523,38 @@ sub pp_regcomp {
return (($self->regcomp($op, $cx, 0))[0]);
}
+sub re_flags {
+ my ($self, $op) = @_;
+ my $flags = '';
+ my $pmflags = $op->pmflags;
+ $flags .= "g" if $pmflags & PMf_GLOBAL;
+ $flags .= "i" if $pmflags & PMf_FOLD;
+ $flags .= "m" if $pmflags & PMf_MULTILINE;
+ $flags .= "o" if $pmflags & PMf_KEEP;
+ $flags .= "s" if $pmflags & PMf_SINGLELINE;
+ $flags .= "x" if $pmflags & PMf_EXTENDED;
+ $flags .= "p" if $pmflags & RXf_PMf_KEEPCOPY;
+ if (my $charset = $pmflags & RXf_PMf_CHARSET) {
+ # Hardcoding this is fragile, but B does not yet export the
+ # constants we need.
+ $flags .= qw(d l u a aa)[$charset >> 5]
+ }
+ # The /d flag is indicated by 0; only show it if necessary.
+ elsif ($self->{hinthash} and
+ $self->{hinthash}{reflags_charset}
+ || $self->{hinthash}{feature_unicode}
+ or $self->{hints} & $feature::hint_mask
+ && ($self->{hints} & $feature::hint_mask)
+ != $feature::hint_mask
+ && do {
+ $self->{hints} & $feature::hint_uni8bit;
+ }
+ ) {
+ $flags .= 'd';
+ }
+ $flags;
+}
+
# osmic acid -- see osmium tetroxide
my %matchwords;
@@ -4234,7 +4573,8 @@ sub matchop {
$kid = $kid->sibling;
}
my $quote = 1;
- my $extended = ($op->pmflags & PMf_EXTENDED);
+ my $pmflags = $op->pmflags;
+ my $extended = ($pmflags & PMf_EXTENDED);
my $rhs_bound_to_defsv;
if (null $kid) {
my $unbacked = re_unback($op->precomp);
@@ -4247,18 +4587,18 @@ sub matchop {
carp("found ".$kid->name." where regcomp expected");
} else {
($re, $quote) = $self->regcomp($kid, 21, $extended);
- $rhs_bound_to_defsv = 1 if $kid->first->first->flags & OPf_SPECIAL;
+ my $matchop = $kid->first->first;
+ if ($matchop->name =~ /^(?:match|transr?|subst)\z/
+ && $matchop->flags & OPf_SPECIAL) {
+ $rhs_bound_to_defsv = 1;
+ }
}
my $flags = "";
- $flags .= "c" if $op->pmflags & PMf_CONTINUE;
- $flags .= "g" if $op->pmflags & PMf_GLOBAL;
- $flags .= "i" if $op->pmflags & PMf_FOLD;
- $flags .= "m" if $op->pmflags & PMf_MULTILINE;
- $flags .= "o" if $op->pmflags & PMf_KEEP;
- $flags .= "s" if $op->pmflags & PMf_SINGLELINE;
- $flags .= "x" if $op->pmflags & PMf_EXTENDED;
+ $flags .= "c" if $pmflags & PMf_CONTINUE;
+ $flags .= $self->re_flags($op);
+ $flags = join '', sort split //, $flags;
$flags = $matchwords{$flags} if $matchwords{$flags};
- if ($op->pmflags & PMf_ONCE) { # only one kind of delimiter works here
+ if ($pmflags & PMf_ONCE) { # only one kind of delimiter works here
$re =~ s/\?/\\?/g;
$re = "?$re?";
} elsif ($quote) {
@@ -4282,6 +4622,8 @@ sub pp_match { matchop(@_, "m", "/") }
sub pp_pushre { matchop(@_, "m", "/") }
sub pp_qr { matchop(@_, "qr", "") }
+sub pp_runcv { unop(@_, "__SUB__"); }
+
sub pp_split {
my $self = shift;
my($op, $cx) = @_;
@@ -4301,7 +4643,7 @@ sub pp_split {
} elsif (!ref($replroot) and $replroot > 0) {
$gv = $self->padval($replroot);
}
- $ary = $self->stash_variable('@', $self->gv_name($gv)) if $gv;
+ $ary = $self->stash_variable('@', $self->gv_name($gv), $cx) if $gv;
for (; !null($kid); $kid = $kid->sibling) {
push @exprs, $self->deparse($kid, 6);
@@ -4332,7 +4674,7 @@ my %substwords;
map($substwords{join "", sort split //, $_} = $_, 'ego', 'egoism', 'em',
'es', 'ex', 'exes', 'gee', 'go', 'goes', 'ie', 'ism', 'iso', 'me',
'meese', 'meso', 'mig', 'mix', 'os', 'ox', 'oxime', 'see', 'seem',
- 'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi',
+ 'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi', 'rogue',
'sir', 'rise', 'smore', 'more', 'seer', 'rome', 'gore', 'grim', 'grime',
'or', 'rose', 'rosie');
@@ -4347,6 +4689,7 @@ sub pp_subst {
$kid = $kid->sibling;
}
my $flags = "";
+ my $pmflags = $op->pmflags;
if (null($op->pmreplroot)) {
$repl = $self->dq($kid);
$kid = $kid->sibling;
@@ -4356,13 +4699,13 @@ sub pp_subst {
$repl = $repl->first;
$flags .= "e";
}
- if ($op->pmflags & PMf_EVAL) {
+ if ($pmflags & PMf_EVAL) {
$repl = $self->deparse($repl->first, 0);
} else {
$repl = $self->dq($repl);
}
}
- my $extended = ($op->pmflags & PMf_EXTENDED);
+ my $extended = ($pmflags & PMf_EXTENDED);
if (null $kid) {
my $unbacked = re_unback($op->precomp);
if ($extended) {
@@ -4374,14 +4717,10 @@ sub pp_subst {
} else {
($re) = $self->regcomp($kid, 1, $extended);
}
- $flags .= "e" if $op->pmflags & PMf_EVAL;
- $flags .= "r" if $op->pmflags & PMf_NONDESTRUCT;
- $flags .= "g" if $op->pmflags & PMf_GLOBAL;
- $flags .= "i" if $op->pmflags & PMf_FOLD;
- $flags .= "m" if $op->pmflags & PMf_MULTILINE;
- $flags .= "o" if $op->pmflags & PMf_KEEP;
- $flags .= "s" if $op->pmflags & PMf_SINGLELINE;
- $flags .= "x" if $extended;
+ $flags .= "r" if $pmflags & PMf_NONDESTRUCT;
+ $flags .= "e" if $pmflags & PMf_EVAL;
+ $flags .= $self->re_flags($op);
+ $flags = join '', sort split //, $flags;
$flags = $substwords{$flags} if $substwords{$flags};
if ($binop) {
return $self->maybe_parens("$var =~ s"
@@ -4408,18 +4747,18 @@ B<perl> B<-MO=Deparse>[B<,-d>][B<,-f>I<FILE>][B<,-p>][B<,-q>][B<,-l>]
B::Deparse is a backend module for the Perl compiler that generates
perl source code, based on the internal compiled structure that perl
-itself creates after parsing a program. The output of B::Deparse won't
+itself creates after parsing a program. The output of B::Deparse won't
be exactly the same as the original source, since perl doesn't keep
track of comments or whitespace, and there isn't a one-to-one
correspondence between perl's syntactical constructions and their
-compiled form, but it will often be close. When you use the B<-p>
+compiled form, but it will often be close. When you use the B<-p>
option, the output also includes parentheses even when they are not
required by precedence, which can make it easy to see if perl is
parsing your expressions the way you intended.
While B::Deparse goes to some lengths to try to figure out what your
original program was doing, some parts of the language can still trip
-it up; it still fails even on some parts of Perl's own test suite. If
+it up; it still fails even on some parts of Perl's own test suite. If
you encounter a failure other than the most common ones described in
the BUGS section below, you can help contribute to B::Deparse's
ongoing development by submitting a bug report with a small
@@ -4436,7 +4775,7 @@ the '-MO=Deparse', separated by a comma but not any white space.
Output data values (when they appear as constants) using Data::Dumper.
Without this option, B::Deparse will use some simple routines of its
-own for the same purpose. Currently, Data::Dumper is better for some
+own for the same purpose. Currently, Data::Dumper is better for some
kinds of data (such as complex structures with sharing and
self-reference) while the built-in routines are better for others
(such as odd floating-point values).
@@ -4444,8 +4783,9 @@ self-reference) while the built-in routines are better for others
=item B<-f>I<FILE>
Normally, B::Deparse deparses the main code of a program, and all the subs
-defined in the same file. To include subs defined in other files, pass the
-B<-f> option with the filename. You can pass the B<-f> option several times, to
+defined in the same file. To include subs defined in
+other files, pass the B<-f> option with the filename.
+You can pass the B<-f> option several times, to
include more than one secondary file. (Most of the time you don't want to
use it at all.) You can also use this option to include subs which are
defined in the scope of a B<#line> directive with two parameters.
@@ -4457,11 +4797,11 @@ locations of the original code.
=item B<-p>
-Print extra parentheses. Without this option, B::Deparse includes
+Print extra parentheses. Without this option, B::Deparse includes
parentheses in its output only when they are needed, based on the
-structure of your program. With B<-p>, it uses parentheses (almost)
-whenever they would be legal. This can be useful if you are used to
-LISP, or if you want to see how perl parses your input. If you say
+structure of your program. With B<-p>, it uses parentheses (almost)
+whenever they would be legal. This can be useful if you are used to
+LISP, or if you want to see how perl parses your input. If you say
if ($var & 0x7f == 65) {print "Gimme an A!"}
print ($which ? $a : $b), "\n";
@@ -4480,8 +4820,8 @@ perl optimized away a constant value).
=item B<-P>
-Disable prototype checking. With this option, all function calls are
-deparsed as if no prototype was defined for them. In other words,
+Disable prototype checking. With this option, all function calls are
+deparsed as if no prototype was defined for them. In other words,
perl -MO=Deparse,-P -e 'sub foo (\@) { 1 } foo @x'
@@ -4497,7 +4837,7 @@ making clear how the parameters are actually passed to C<foo>.
=item B<-q>
Expand double-quoted strings into the corresponding combinations of
-concatenation, uc, ucfirst, lc, lcfirst, quotemeta, and join. For
+concatenation, uc, ucfirst, lc, lcfirst, quotemeta, and join. For
instance, print
print "Hello, $world, @ladies, \u$gentlemen\E, \u\L$me!";
@@ -4509,21 +4849,21 @@ as
Note that the expanded form represents the way perl handles such
constructions internally -- this option actually turns off the reverse
-translation that B::Deparse usually does. On the other hand, note that
+translation that B::Deparse usually does. On the other hand, note that
C<$x = "$y"> is not the same as C<$x = $y>: the former makes the value
of $y into a string before doing the assignment.
=item B<-s>I<LETTERS>
-Tweak the style of B::Deparse's output. The letters should follow
-directly after the 's', with no space or punctuation. The following
+Tweak the style of B::Deparse's output. The letters should follow
+directly after the 's', with no space or punctuation. The following
options are available:
=over 4
=item B<C>
-Cuddle C<elsif>, C<else>, and C<continue> blocks. For example, print
+Cuddle C<elsif>, C<else>, and C<continue> blocks. For example, print
if (...) {
...
@@ -4544,11 +4884,11 @@ The default is not to cuddle.
=item B<i>I<NUMBER>
-Indent lines by multiples of I<NUMBER> columns. The default is 4 columns.
+Indent lines by multiples of I<NUMBER> columns. The default is 4 columns.
=item B<T>
-Use tabs for each 8 columns of indent. The default is to use only spaces.
+Use tabs for each 8 columns of indent. The default is to use only spaces.
For instance, if the style options are B<-si4T>, a line that's indented
3 times will be preceded by one tab and four spaces; if the options were
B<-si8T>, the same line would be preceded by three tabs.
@@ -4557,14 +4897,14 @@ B<-si8T>, the same line would be preceded by three tabs.
Print I<STRING> for the value of a constant that can't be determined
because it was optimized away (mnemonic: this happens when a constant
-is used in B<v>oid context). The end of the string is marked by a period.
+is used in B<v>oid context). The end of the string is marked by a period.
The string should be a valid perl expression, generally a constant.
Note that unless it's a number, it probably needs to be quoted, and on
-a command line quotes need to be protected from the shell. Some
+a command line quotes need to be protected from the shell. Some
conventional values include 0, 1, 42, '', 'foo', and
'Useless use of constant omitted' (which may need to be
B<-sv"'Useless use of constant omitted'.">
-or something similar depending on your shell). The default is '???'.
+or something similar depending on your shell). The default is '???'.
If you're using B::Deparse on a module or other file that's require'd,
you shouldn't use a value that evaluates to false, since the customary
true constant at the end of a module will be in void context when the
@@ -4575,8 +4915,8 @@ file is compiled as a main program.
=item B<-x>I<LEVEL>
Expand conventional syntax constructions into equivalent ones that expose
-their internal operation. I<LEVEL> should be a digit, with higher values
-meaning more expansion. As with B<-q>, this actually involves turning off
+their internal operation. I<LEVEL> should be a digit, with higher values
+meaning more expansion. As with B<-q>, this actually involves turning off
special cases in B::Deparse's normal operations.
If I<LEVEL> is at least 3, C<for> loops will be translated into equivalent
@@ -4657,7 +4997,7 @@ programs.
$deparse = B::Deparse->new(OPTIONS)
Create an object to store the state of a deparsing operation and any
-options. The options are the same as those that can be given on the
+options. The options are the same as those that can be given on the
command line (see L</OPTIONS>); options that are separated by commas
after B<-MO=Deparse> should be given as separate strings.
@@ -4666,7 +5006,7 @@ after B<-MO=Deparse> should be given as separate strings.
$deparse->ambient_pragmas(strict => 'all', '$[' => $[);
The compilation of a subroutine can be affected by a few compiler
-directives, B<pragmas>. These are:
+directives, B<pragmas>. These are:
=over 4
@@ -4703,15 +5043,15 @@ use re;
Ordinarily, if you use B::Deparse on a subroutine which has
been compiled in the presence of one or more of these pragmas,
the output will include statements to turn on the appropriate
-directives. So if you then compile the code returned by coderef2text,
+directives. So if you then compile the code returned by coderef2text,
it will behave the same way as the subroutine which you deparsed.
However, you may know that you intend to use the results in a
-particular context, where some pragmas are already in scope. In
+particular context, where some pragmas are already in scope. In
this case, you use the B<ambient_pragmas> method to describe the
assumptions you wish to make.
-Not all of the options currently have any useful effect. See
+Not all of the options currently have any useful effect. See
L</BUGS> for more details.
The parameters it accepts are:
@@ -4721,7 +5061,7 @@ The parameters it accepts are:
=item strict
Takes a string, possibly containing several values separated
-by whitespace. The special values "all" and "none" mean what you'd
+by whitespace. The special values "all" and "none" mean what you'd
expect.
$deparse->ambient_pragmas(strict => 'subs refs');
@@ -4729,6 +5069,7 @@ expect.
=item $[
Takes a number, the value of the array base $[.
+Cannot be non-zero on Perl 5.15.3 or later.
=item bytes
@@ -4742,7 +5083,7 @@ be in the ambient scope, otherwise not.
=item re
Takes a string, possibly containing a whitespace-separated list of
-values. The values "all" and "none" are special. It's also permissible
+values. The values "all" and "none" are special. It's also permissible
to pass an array reference here.
$deparser->ambient_pragmas(re => 'eval');
@@ -4751,14 +5092,14 @@ to pass an array reference here.
=item warnings
Takes a string, possibly containing a whitespace-separated list of
-values. The values "all" and "none" are special, again. It's also
+values. The values "all" and "none" are special, again. It's also
permissible to pass an array reference here.
$deparser->ambient_pragmas(warnings => [qw[void io]]);
If one of the values is the string "FATAL", then all the warnings
in that list will be considered fatal, just as with the B<warnings>
-pragma itself. Should you need to specify that some warnings are
+pragma itself. Should you need to specify that some warnings are
fatal, and others are merely enabled, you can pass the B<warnings>
parameter twice:
@@ -4803,10 +5144,10 @@ stored in the special hash %^H.
Return source code for the body of a subroutine (a block, optionally
preceded by a prototype in parens), given a reference to the
-sub. Because a subroutine can have no names, or more than one name,
+sub. Because a subroutine can have no names, or more than one name,
this method doesn't return a complete subroutine definition -- if you
want to eval the result, you should prepend "sub subname ", or "sub "
-for an anonymous function constructor. Unless the sub was defined in
+for an anonymous function constructor. Unless the sub was defined in
the main:: package, the code will include a package declaration.
=head1 BUGS
@@ -4816,7 +5157,8 @@ the main:: package, the code will include a package declaration.
=item *
The only pragmas to be completely supported are: C<use warnings>,
-C<use strict 'refs'>, C<use bytes>, and C<use integer>. (C<$[>, which
+C<use strict>, C<use bytes>, C<use integer>
+and C<use feature>. (C<$[>, which
behaves like a pragma, is also supported.)
Excepting those listed above, we're currently unable to guarantee that
@@ -4831,7 +5173,7 @@ than in the input file.
In fact, the above is a specific instance of a more general problem:
we can't guarantee to produce BEGIN blocks or C<use> declarations in
-exactly the right place. So if you use a module which affects compilation
+exactly the right place. So if you use a module which affects compilation
(such as by over-riding keywords, overloading constants or whatever)
then the output code might not work as intended.
@@ -4840,14 +5182,6 @@ from the Perl core to fix.
=item *
-If a keyword is over-ridden, and your program explicitly calls
-the built-in version by using CORE::keyword, the output of B::Deparse
-will not reflect this. If you run the resulting code, it will call
-the over-ridden version rather than the built-in one. (Maybe there
-should be an option to B<always> print keyword calls as C<CORE::name>.)
-
-=item *
-
Some constants don't print correctly either with or without B<-d>.
For instance, neither B::Deparse nor Data::Dumper know how to print
dual-valued scalars correctly, as in:
@@ -4865,7 +5199,8 @@ produced is already ordinary Perl which shouldn't be filtered again.
=item *
-Optimised away statements are rendered as '???'. This includes statements that
+Optimised away statements are rendered as
+'???'. This includes statements that
have a compile-time side-effect, such as the obscure
my $x if 0;
@@ -4879,7 +5214,7 @@ which is not, consequently, deparsed correctly.
=item *
Lexical (my) variables declared in scopes external to a subroutine
-appear in code2ref output text as package variables. This is a tricky
+appear in code2ref output text as package variables. This is a tricky
problem, as perl has no native facility for referring to a lexical variable
defined within a different scope, although L<PadWalker> is a good start.