diff options
author | Karl Berry <karl@freefriends.org> | 2012-11-20 18:08:54 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2012-11-20 18:08:54 +0000 |
commit | c5add2ea5067382269ae6f19e345fda0b9a7bd21 (patch) | |
tree | 02f512fda46d93079c9dc59c0d76f0e398150f83 /Master/tlpkg/tlperl/lib/B | |
parent | 6c35e87bdc5a3f64833dbbc42e7d42e683db9d5b (diff) |
perl 5.16.2, compiled without optimization for Windows (from siep)
git-svn-id: svn://tug.org/texlive/trunk@28315 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/tlperl/lib/B')
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Concise.pm | 38 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Debug.pm | 4 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Deparse.pm | 803 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Lint.pm | 2 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Lint/Debug.pm | 17 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Terse.pm | 12 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/B/Xref.pm | 52 |
7 files changed, 667 insertions, 261 deletions
diff --git a/Master/tlpkg/tlperl/lib/B/Concise.pm b/Master/tlpkg/tlperl/lib/B/Concise.pm index 014a4df84d1..6db2e0ce95c 100644 --- a/Master/tlpkg/tlperl/lib/B/Concise.pm +++ b/Master/tlpkg/tlperl/lib/B/Concise.pm @@ -14,7 +14,7 @@ use warnings; # uses #3 and #4, since warnings uses Carp use Exporter (); # use #5 -our $VERSION = "0.83"; +our $VERSION = "0.89"; our @ISA = qw(Exporter); our @EXPORT_OK = qw( set_style set_style_standard add_callback concise_subref concise_cv concise_main @@ -595,12 +595,13 @@ our %priv; # used to display each opcode's BASEOP.op_private values $priv{$_}{128} = "LVINTRO" for ("pos", "substr", "vec", "threadsv", "gvsv", "rv2sv", "rv2hv", "rv2gv", "rv2av", "rv2arylen", "aelem", "helem", "aslice", "hslice", "padsv", - "padav", "padhv", "enteriter"); + "padav", "padhv", "enteriter", "entersub"); $priv{$_}{64} = "REFC" for ("leave", "leavesub", "leavesublv", "leavewrite"); $priv{"aassign"}{64} = "COMMON"; $priv{"aassign"}{32} = $] < 5.009 ? "PHASH" : "STATE"; $priv{"sassign"}{32} = "STATE"; $priv{"sassign"}{64} = "BKWARD"; +$priv{"sassign"}{128}= "CV2GV"; $priv{$_}{64} = "RTIME" for ("match", "subst", "substcont", "qr"); @{$priv{"trans"}}{1,2,4,8,16,64} = ("<UTF", ">UTF", "IDENT", "SQUASH", "DEL", "COMPL", "GROWS"); @@ -611,12 +612,16 @@ $priv{$_}{4} = "DREFed" for (qw(rv2sv rv2av rv2hv)); @{$priv{$_}}{32,64,96} = ("DREFAV", "DREFHV", "DREFSV") for (qw(rv2gv rv2sv padsv aelem helem)); $priv{$_}{16} = "STATE" for ("padav", "padhv", "padsv"); -@{$priv{"entersub"}}{16,32,64} = ("DBG","TARG","NOMOD"); -@{$priv{$_}}{4,8,128} = ("INARGS","AMPER","NO()") for ("entersub", "rv2cv"); +@{$priv{rv2gv}}{4,16} = qw "NOINIT FAKE"; +@{$priv{"entersub"}}{1,4,16,32,64} = qw( INARGS TARG DBG DEREF ); +@{$priv{rv2cv}}{1,8,128} = ("CONST","AMPER","NO()"); $priv{"gv"}{32} = "EARLYCV"; $priv{"aelem"}{16} = $priv{"helem"}{16} = "LVDEFER"; $priv{$_}{16} = "OURINTR" for ("gvsv", "rv2sv", "rv2av", "rv2hv", "r2gv", "enteriter"); +$priv{$_}{8} = 'LVSUB' for qw(rv2av rv2gv rv2hv padav padhv aelem helem + aslice hslice av2arylen keys rkeys substr pos vec); +$priv{substr}{16} = 'REPL1ST'; $priv{$_}{16} = "TARGMY" for (map(($_,"s$_"),"chop", "chomp"), map(($_,"i_$_"), "postinc", "postdec", "multiply", "divide", "modulo", @@ -630,7 +635,8 @@ $priv{$_}{16} = "TARGMY" "exec", "kill", "getppid", "getpgrp", "setpgrp", "getpriority", "setpriority", "time", "sleep"); $priv{$_}{4} = "REVERSED" for ("enteriter", "iter"); -@{$priv{"const"}}{4,8,16,32,64,128} = ("SHORT","STRICT","ENTERED",'$[',"BARE","WARN"); +@{$priv{"const"}}{2,4,8,16,64,128} = + ("NOVER","SHORT","STRICT","ENTERED","BARE","WARN"); $priv{"flip"}{64} = $priv{"flop"}{64} = "LINENUM"; $priv{"list"}{64} = "GUESSED"; $priv{"delete"}{64} = "SLICE"; @@ -643,10 +649,10 @@ $priv{"threadsv"}{64} = "SVREFd"; $priv{"exit"}{128} = "VMS"; $priv{$_}{2} = "FTACCESS" for ("ftrread", "ftrwrite", "ftrexec", "fteread", "ftewrite", "fteexec"); -$priv{"entereval"}{2} = "HAS_HH"; +@{$priv{"entereval"}}{2,4,8,16} = qw "HAS_HH UNI BYTES COPHH"; if ($] >= 5.009) { # Stacked filetests are post 5.8.x - $priv{$_}{4} = "FTSTACKED" + @{$priv{$_}}{4,8,16} = ("FTSTACKED","FTSTACKING","FTAFTERt") for ("ftrread", "ftrwrite", "ftrexec", "fteread", "ftewrite", "fteexec", "ftis", "fteowned", "ftrowned", "ftzero", "ftsize", "ftmtime", "ftatime", "ftctime", "ftsock", "ftchr", "ftblk", "ftfile", "ftdir", @@ -656,13 +662,15 @@ if ($] >= 5.009) { $priv{$_}{2} = "GREPLEX" for ("mapwhile", "mapstart", "grepwhile", "grepstart"); } +$priv{$_}{128} = '+1' for qw "caller wantarray runcv"; +@{$priv{coreargs}}{1,2,64,128} = ('DREF1','DREF2','$MOD','MARK'); our %hints; # used to display each COP's op_hints values # strict refs, subs, vars -@hints{2,512,1024} = ('$', '&', '*'); -# integers, locale, bytes, arybase -@hints{1,4,8,16,32} = ('i', 'l', 'b', '['); +@hints{2,512,1024,32,64,128} = ('$', '&', '*', 'x$', 'x&', 'x*'); +# integers, locale, bytes +@hints{1,4,8,16} = ('i', 'l', 'b'); # block scope, localise %^H, $^OPEN (in), $^OPEN (out) @hints{256,131072,262144,524288} = ('{','%','<','>'); # overload new integer, float, binary, string, re @@ -850,9 +858,7 @@ sub concise_op { my $ln = $op->line; $loc .= ":$ln"; my($stash, $cseq) = ($op->stash->NAME, $op->cop_seq - $cop_seq_base); - my $arybase = $op->arybase; - $arybase = $arybase ? ' $[=' . $arybase : ""; - $h{arg} = "($label$stash $cseq $loc$arybase)"; + $h{arg} = "($label$stash $cseq $loc)"; if ($show_src) { fill_srclines($pathnm) unless exists $srclines{$pathnm}; # Would love to retain Jim's use of // but this code needs to be @@ -1255,7 +1261,7 @@ usual convention for Arabic numerals, and the default. =item B<-littleendian> -Print seqence numbers with the least significant digit first. This is +Print sequence numbers with the least significant digit first. This is obviously mutually exclusive with bigendian. =back @@ -1541,10 +1547,12 @@ string if this is not a COP. Here are the symbols used: $ strict refs & strict subs * strict vars + x$ explicit use/no strict refs + x& explicit use/no strict subs + x* explicit use/no strict vars i integers l locale b bytes - [ arybase { block scope % localise %^H < open in diff --git a/Master/tlpkg/tlperl/lib/B/Debug.pm b/Master/tlpkg/tlperl/lib/B/Debug.pm index 17f026d9fa8..fb8db3ff20b 100644 --- a/Master/tlpkg/tlperl/lib/B/Debug.pm +++ b/Master/tlpkg/tlperl/lib/B/Debug.pm @@ -1,6 +1,6 @@ package B::Debug; -our $VERSION = '1.16'; +our $VERSION = '1.17'; use strict; require 5.006; @@ -414,6 +414,6 @@ Copyright (c) 2008, 2010 Reini Urban distribution. You should also have received a copy of the GNU General Public License, in the file named "Copying". If not, you can get one from the Perl distribution or else write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. =cut 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. diff --git a/Master/tlpkg/tlperl/lib/B/Lint.pm b/Master/tlpkg/tlperl/lib/B/Lint.pm index a38ee323d0d..a080af778df 100644 --- a/Master/tlpkg/tlperl/lib/B/Lint.pm +++ b/Master/tlpkg/tlperl/lib/B/Lint.pm @@ -1,6 +1,6 @@ package B::Lint; -our $VERSION = '1.13'; ## no critic +our $VERSION = '1.14'; ## no critic =head1 NAME diff --git a/Master/tlpkg/tlperl/lib/B/Lint/Debug.pm b/Master/tlpkg/tlperl/lib/B/Lint/Debug.pm index 1a4bf31f7f6..6ba09708cbf 100644 --- a/Master/tlpkg/tlperl/lib/B/Lint/Debug.pm +++ b/Master/tlpkg/tlperl/lib/B/Lint/Debug.pm @@ -1,6 +1,6 @@ package B::Lint::Debug; -our $VERSION = '1.12'; +our $VERSION = '1.14'; =head1 NAME @@ -13,13 +13,15 @@ should not be loaded unless you're debugging. =cut -package B::SPECIAL; +package # hide from PAUSE + B::SPECIAL; use overload '""' => sub { my $self = shift @_; "SPECIAL($$self)"; }; -package B::OP; +package # hide from PAUSE + B::OP; use overload '""' => sub { my $self = shift @_; my $class = ref $self; @@ -28,7 +30,8 @@ use overload '""' => sub { "$class($name)"; }; -package B::SVOP; +package # hide from PAUSE + B::SVOP; use overload '""' => sub { my $self = shift @_; my $class = ref $self; @@ -37,7 +40,8 @@ use overload '""' => sub { "$class($name," . $self->sv . "," . $self->gv . ")"; }; -package B::SPECIAL; +package # hide from PAUSE + B::SPECIAL; sub DESTROY { } our $AUTOLOAD; @@ -45,7 +49,8 @@ sub AUTOLOAD { my $cx = 0; print "AUTOLOAD $AUTOLOAD\n"; - package DB; + package # hide from PAUSE + DB; while ( my @stuff = caller $cx ) { print "$cx: [@DB::args] [@stuff]\n"; diff --git a/Master/tlpkg/tlperl/lib/B/Terse.pm b/Master/tlpkg/tlperl/lib/B/Terse.pm index 562c58abd83..8e551c5a62f 100644 --- a/Master/tlpkg/tlperl/lib/B/Terse.pm +++ b/Master/tlpkg/tlperl/lib/B/Terse.pm @@ -1,6 +1,6 @@ package B::Terse; -our $VERSION = '1.05'; +our $VERSION = '1.06'; use strict; use B qw(class @specialsv_name); @@ -78,7 +78,15 @@ B::Terse - Walk Perl syntax tree, printing terse info about ops =head1 DESCRIPTION -This version of B::Terse is really just a wrapper that calls B::Concise +This module prints the contents of the parse tree, but without as much +information as L<B::Debug>. For comparison, C<print "Hello, world."> +produced 96 lines of output from B::Debug, but only 6 from B::Terse. + +This module is useful for people who are writing their own back end, +or who are learning about the Perl internals. It's not useful to the +average programmer. + +This version of B::Terse is really just a wrapper that calls L<B::Concise> with the B<-terse> option. It is provided for compatibility with old scripts (and habits) but using B::Concise directly is now recommended instead. diff --git a/Master/tlpkg/tlperl/lib/B/Xref.pm b/Master/tlpkg/tlperl/lib/B/Xref.pm index 64e677ccb82..f3a362c3f6a 100644 --- a/Master/tlpkg/tlperl/lib/B/Xref.pm +++ b/Master/tlpkg/tlperl/lib/B/Xref.pm @@ -1,6 +1,6 @@ package B::Xref; -our $VERSION = '1.02'; +our $VERSION = '1.03'; =head1 NAME @@ -48,6 +48,56 @@ letter "i". Subroutine and method calls are indicated by the character "&". Subroutine definitions are indicated by "s" and format definitions by "f". +For instance, here's part of the report from the I<pod2man> program that +comes with Perl: + + Subroutine clear_noremap + Package (lexical) + $ready_to_print i1069, 1079 + Package main + $& 1086 + $. 1086 + $0 1086 + $1 1087 + $2 1085, 1085 + $3 1085, 1085 + $ARGV 1086 + %HTML_Escapes 1085, 1085 + +This shows the variables used in the subroutine C<clear_noremap>. The +variable C<$ready_to_print> is a my() (lexical) variable, +B<i>ntroduced (first declared with my()) on line 1069, and used on +line 1079. The variable C<$&> from the main package is used on 1086, +and so on. + +A line number may be prefixed by a single letter: + +=over 4 + +=item i + +Lexical variable introduced (declared with my()) for the first time. + +=item & + +Subroutine or method call. + +=item s + +Subroutine defined. + +=item r + +Format defined. + +=back + +The most useful option the cross referencer has is to save the report +to a separate file. For instance, to save the report on +I<myperlprogram> to the file I<report>: + + $ perl -MO=Xref,-oreport myperlprogram + =head1 OPTIONS Option words are separated by commas (not whitespace) and follow the |