1*0Sstevel@tonic-gate# B::Deparse.pm 2*0Sstevel@tonic-gate# Copyright (c) 1998-2000, 2002, 2003 Stephen McCamant. All rights reserved. 3*0Sstevel@tonic-gate# This module is free software; you can redistribute and/or modify 4*0Sstevel@tonic-gate# it under the same terms as Perl itself. 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate# This is based on the module of the same name by Malcolm Beattie, 7*0Sstevel@tonic-gate# but essentially none of his code remains. 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gatepackage B::Deparse; 10*0Sstevel@tonic-gateuse Carp; 11*0Sstevel@tonic-gateuse B qw(class main_root main_start main_cv svref_2object opnumber perlstring 12*0Sstevel@tonic-gate OPf_WANT OPf_WANT_VOID OPf_WANT_SCALAR OPf_WANT_LIST 13*0Sstevel@tonic-gate OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL OPf_MOD 14*0Sstevel@tonic-gate OPpLVAL_INTRO OPpOUR_INTRO OPpENTERSUB_AMPER OPpSLICE OPpCONST_BARE 15*0Sstevel@tonic-gate OPpTRANS_SQUASH OPpTRANS_DELETE OPpTRANS_COMPLEMENT OPpTARGET_MY 16*0Sstevel@tonic-gate OPpCONST_ARYBASE OPpEXISTS_SUB OPpSORT_NUMERIC OPpSORT_INTEGER 17*0Sstevel@tonic-gate OPpSORT_REVERSE OPpSORT_INPLACE 18*0Sstevel@tonic-gate SVf_IOK SVf_NOK SVf_ROK SVf_POK SVpad_OUR SVf_FAKE SVs_RMG SVs_SMG 19*0Sstevel@tonic-gate CVf_METHOD CVf_LOCKED CVf_LVALUE 20*0Sstevel@tonic-gate PMf_KEEP PMf_GLOBAL PMf_CONTINUE PMf_EVAL PMf_ONCE PMf_SKIPWHITE 21*0Sstevel@tonic-gate PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED); 22*0Sstevel@tonic-gate# Not sure if I really should have this as maint's version, given that Deparse 23*0Sstevel@tonic-gate# differs from blead. (latter has // support) 24*0Sstevel@tonic-gate$VERSION = 0.66; 25*0Sstevel@tonic-gateuse strict; 26*0Sstevel@tonic-gateuse vars qw/$AUTOLOAD/; 27*0Sstevel@tonic-gateuse warnings (); 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate# Changes between 0.50 and 0.51: 30*0Sstevel@tonic-gate# - fixed nulled leave with live enter in sort { } 31*0Sstevel@tonic-gate# - fixed reference constants (\"str") 32*0Sstevel@tonic-gate# - handle empty programs gracefully 33*0Sstevel@tonic-gate# - handle infinte loops (for (;;) {}, while (1) {}) 34*0Sstevel@tonic-gate# - differentiate between `for my $x ...' and `my $x; for $x ...' 35*0Sstevel@tonic-gate# - various minor cleanups 36*0Sstevel@tonic-gate# - moved globals into an object 37*0Sstevel@tonic-gate# - added `-u', like B::C 38*0Sstevel@tonic-gate# - package declarations using cop_stash 39*0Sstevel@tonic-gate# - subs, formats and code sorted by cop_seq 40*0Sstevel@tonic-gate# Changes between 0.51 and 0.52: 41*0Sstevel@tonic-gate# - added pp_threadsv (special variables under USE_5005THREADS) 42*0Sstevel@tonic-gate# - added documentation 43*0Sstevel@tonic-gate# Changes between 0.52 and 0.53: 44*0Sstevel@tonic-gate# - many changes adding precedence contexts and associativity 45*0Sstevel@tonic-gate# - added `-p' and `-s' output style options 46*0Sstevel@tonic-gate# - various other minor fixes 47*0Sstevel@tonic-gate# Changes between 0.53 and 0.54: 48*0Sstevel@tonic-gate# - added support for new `for (1..100)' optimization, 49*0Sstevel@tonic-gate# thanks to Gisle Aas 50*0Sstevel@tonic-gate# Changes between 0.54 and 0.55: 51*0Sstevel@tonic-gate# - added support for new qr// construct 52*0Sstevel@tonic-gate# - added support for new pp_regcreset OP 53*0Sstevel@tonic-gate# Changes between 0.55 and 0.56: 54*0Sstevel@tonic-gate# - tested on base/*.t, cmd/*.t, comp/*.t, io/*.t 55*0Sstevel@tonic-gate# - fixed $# on non-lexicals broken in last big rewrite 56*0Sstevel@tonic-gate# - added temporary fix for change in opcode of OP_STRINGIFY 57*0Sstevel@tonic-gate# - fixed problem in 0.54's for() patch in `for (@ary)' 58*0Sstevel@tonic-gate# - fixed precedence in conditional of ?: 59*0Sstevel@tonic-gate# - tweaked list paren elimination in `my($x) = @_' 60*0Sstevel@tonic-gate# - made continue-block detection trickier wrt. null ops 61*0Sstevel@tonic-gate# - fixed various prototype problems in pp_entersub 62*0Sstevel@tonic-gate# - added support for sub prototypes that never get GVs 63*0Sstevel@tonic-gate# - added unquoting for special filehandle first arg in truncate 64*0Sstevel@tonic-gate# - print doubled rv2gv (a bug) as `*{*GV}' instead of illegal `**GV' 65*0Sstevel@tonic-gate# - added semicolons at the ends of blocks 66*0Sstevel@tonic-gate# - added -l `#line' declaration option -- fixes cmd/subval.t 27,28 67*0Sstevel@tonic-gate# Changes between 0.56 and 0.561: 68*0Sstevel@tonic-gate# - fixed multiply-declared my var in pp_truncate (thanks to Sarathy) 69*0Sstevel@tonic-gate# - used new B.pm symbolic constants (done by Nick Ing-Simmons) 70*0Sstevel@tonic-gate# Changes between 0.561 and 0.57: 71*0Sstevel@tonic-gate# - stylistic changes to symbolic constant stuff 72*0Sstevel@tonic-gate# - handled scope in s///e replacement code 73*0Sstevel@tonic-gate# - added unquote option for expanding "" into concats, etc. 74*0Sstevel@tonic-gate# - split method and proto parts of pp_entersub into separate functions 75*0Sstevel@tonic-gate# - various minor cleanups 76*0Sstevel@tonic-gate# Changes after 0.57: 77*0Sstevel@tonic-gate# - added parens in \&foo (patch by Albert Dvornik) 78*0Sstevel@tonic-gate# Changes between 0.57 and 0.58: 79*0Sstevel@tonic-gate# - fixed `0' statements that weren't being printed 80*0Sstevel@tonic-gate# - added methods for use from other programs 81*0Sstevel@tonic-gate# (based on patches from James Duncan and Hugo van der Sanden) 82*0Sstevel@tonic-gate# - added -si and -sT to control indenting (also based on a patch from Hugo) 83*0Sstevel@tonic-gate# - added -sv to print something else instead of '???' 84*0Sstevel@tonic-gate# - preliminary version of utf8 tr/// handling 85*0Sstevel@tonic-gate# Changes after 0.58: 86*0Sstevel@tonic-gate# - uses of $op->ppaddr changed to new $op->name (done by Sarathy) 87*0Sstevel@tonic-gate# - added support for Hugo's new OP_SETSTATE (like nextstate) 88*0Sstevel@tonic-gate# Changes between 0.58 and 0.59 89*0Sstevel@tonic-gate# - added support for Chip's OP_METHOD_NAMED 90*0Sstevel@tonic-gate# - added support for Ilya's OPpTARGET_MY optimization 91*0Sstevel@tonic-gate# - elided arrows before `()' subscripts when possible 92*0Sstevel@tonic-gate# Changes between 0.59 and 0.60 93*0Sstevel@tonic-gate# - support for method attribues was added 94*0Sstevel@tonic-gate# - some warnings fixed 95*0Sstevel@tonic-gate# - separate recognition of constant subs 96*0Sstevel@tonic-gate# - rewrote continue block handling, now recoginizing for loops 97*0Sstevel@tonic-gate# - added more control of expanding control structures 98*0Sstevel@tonic-gate# Changes between 0.60 and 0.61 (mostly by Robin Houston) 99*0Sstevel@tonic-gate# - many bug-fixes 100*0Sstevel@tonic-gate# - support for pragmas and 'use' 101*0Sstevel@tonic-gate# - support for the little-used $[ variable 102*0Sstevel@tonic-gate# - support for __DATA__ sections 103*0Sstevel@tonic-gate# - UTF8 support 104*0Sstevel@tonic-gate# - BEGIN, CHECK, INIT and END blocks 105*0Sstevel@tonic-gate# - scoping of subroutine declarations fixed 106*0Sstevel@tonic-gate# - compile-time output from the input program can be suppressed, so that the 107*0Sstevel@tonic-gate# output is just the deparsed code. (a change to O.pm in fact) 108*0Sstevel@tonic-gate# - our() declarations 109*0Sstevel@tonic-gate# - *all* the known bugs are now listed in the BUGS section 110*0Sstevel@tonic-gate# - comprehensive test mechanism (TEST -deparse) 111*0Sstevel@tonic-gate# Changes between 0.62 and 0.63 (mostly by Rafael Garcia-Suarez) 112*0Sstevel@tonic-gate# - bug-fixes 113*0Sstevel@tonic-gate# - new switch -P 114*0Sstevel@tonic-gate# - support for command-line switches (-l, -0, etc.) 115*0Sstevel@tonic-gate# Changes between 0.63 and 0.64 116*0Sstevel@tonic-gate# - support for //, CHECK blocks, and assertions 117*0Sstevel@tonic-gate# - improved handling of foreach loops and lexicals 118*0Sstevel@tonic-gate# - option to use Data::Dumper for constants 119*0Sstevel@tonic-gate# - more bug fixes 120*0Sstevel@tonic-gate# - discovered lots more bugs not yet fixed 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate# Todo: 123*0Sstevel@tonic-gate# (See also BUGS section at the end of this file) 124*0Sstevel@tonic-gate# 125*0Sstevel@tonic-gate# - finish tr/// changes 126*0Sstevel@tonic-gate# - add option for even more parens (generalize \&foo change) 127*0Sstevel@tonic-gate# - left/right context 128*0Sstevel@tonic-gate# - copy comments (look at real text with $^P?) 129*0Sstevel@tonic-gate# - avoid semis in one-statement blocks 130*0Sstevel@tonic-gate# - associativity of &&=, ||=, ?: 131*0Sstevel@tonic-gate# - ',' => '=>' (auto-unquote?) 132*0Sstevel@tonic-gate# - break long lines ("\r" as discretionary break?) 133*0Sstevel@tonic-gate# - configurable syntax highlighting: ANSI color, HTML, TeX, etc. 134*0Sstevel@tonic-gate# - more style options: brace style, hex vs. octal, quotes, ... 135*0Sstevel@tonic-gate# - print big ints as hex/octal instead of decimal (heuristic?) 136*0Sstevel@tonic-gate# - handle `my $x if 0'? 137*0Sstevel@tonic-gate# - version using op_next instead of op_first/sibling? 138*0Sstevel@tonic-gate# - avoid string copies (pass arrays, one big join?) 139*0Sstevel@tonic-gate# - here-docs? 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate# Current test.deparse failures 142*0Sstevel@tonic-gate# comp/assertions 38 - disabled assertions should be like "my($x) if 0" 143*0Sstevel@tonic-gate# 'sub f : assertion {}; no assertions; my $x=1; {f(my $x=2); print "$x\n"}' 144*0Sstevel@tonic-gate# comp/hints 6 - location of BEGIN blocks wrt. block openings 145*0Sstevel@tonic-gate# run/switchI 1 - missing -I switches entirely 146*0Sstevel@tonic-gate# perl -Ifoo -e 'print @INC' 147*0Sstevel@tonic-gate# op/caller 2 - warning mask propagates backwards before warnings::register 148*0Sstevel@tonic-gate# 'use warnings; BEGIN {${^WARNING_BITS} eq "U"x12;} use warnings::register' 149*0Sstevel@tonic-gate# op/getpid 2 - can't assign to shared my() declaration (threads only) 150*0Sstevel@tonic-gate# 'my $x : shared = 5' 151*0Sstevel@tonic-gate# op/override 7 - parens on overriden require change v-string interpretation 152*0Sstevel@tonic-gate# 'BEGIN{*CORE::GLOBAL::require=sub {}} require v5.6' 153*0Sstevel@tonic-gate# c.f. 'BEGIN { *f = sub {0} }; f 2' 154*0Sstevel@tonic-gate# op/pat 774 - losing Unicode-ness of Latin1-only strings 155*0Sstevel@tonic-gate# 'use charnames ":short"; $x="\N{latin:a with acute}"' 156*0Sstevel@tonic-gate# op/recurse 12 - missing parens on recursive call makes it look like method 157*0Sstevel@tonic-gate# 'sub f { f($x) }' 158*0Sstevel@tonic-gate# op/subst 90 - inconsistent handling of utf8 under "use utf8" 159*0Sstevel@tonic-gate# op/taint 29 - "use re 'taint'" deparsed in the wrong place wrt. block open 160*0Sstevel@tonic-gate# op/tiehandle compile - "use strict" deparsed in the wrong place 161*0Sstevel@tonic-gate# uni/tr_ several 162*0Sstevel@tonic-gate# ext/B/t/xref 11 - line numbers when we add newlines to one-line subs 163*0Sstevel@tonic-gate# ext/Data/Dumper/t/dumper compile 164*0Sstevel@tonic-gate# ext/DB_file/several 165*0Sstevel@tonic-gate# ext/Encode/several 166*0Sstevel@tonic-gate# ext/Ernno/Errno warnings 167*0Sstevel@tonic-gate# ext/IO/lib/IO/t/io_sel 23 168*0Sstevel@tonic-gate# ext/PerlIO/t/encoding compile 169*0Sstevel@tonic-gate# ext/POSIX/t/posix 6 170*0Sstevel@tonic-gate# ext/Socket/Socket 8 171*0Sstevel@tonic-gate# ext/Storable/t/croak compile 172*0Sstevel@tonic-gate# lib/Attribute/Handlers/t/multi compile 173*0Sstevel@tonic-gate# lib/bignum/ several 174*0Sstevel@tonic-gate# lib/charnames 35 175*0Sstevel@tonic-gate# lib/constant 32 176*0Sstevel@tonic-gate# lib/English 40 177*0Sstevel@tonic-gate# lib/ExtUtils/t/bytes 4 178*0Sstevel@tonic-gate# lib/File/DosGlob compile 179*0Sstevel@tonic-gate# lib/Filter/Simple/t/data 1 180*0Sstevel@tonic-gate# lib/Math/BigInt/t/constant 1 181*0Sstevel@tonic-gate# lib/Net/t/config Deparse-warning 182*0Sstevel@tonic-gate# lib/overload compile 183*0Sstevel@tonic-gate# lib/Switch/ several 184*0Sstevel@tonic-gate# lib/Symbol 4 185*0Sstevel@tonic-gate# lib/Test/Simple several 186*0Sstevel@tonic-gate# lib/Term/Complete 187*0Sstevel@tonic-gate# lib/Tie/File/t/29_downcopy 5 188*0Sstevel@tonic-gate# lib/vars 22 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate# Object fields (were globals): 191*0Sstevel@tonic-gate# 192*0Sstevel@tonic-gate# avoid_local: 193*0Sstevel@tonic-gate# (local($a), local($b)) and local($a, $b) have the same internal 194*0Sstevel@tonic-gate# representation but the short form looks better. We notice we can 195*0Sstevel@tonic-gate# use a large-scale local when checking the list, but need to prevent 196*0Sstevel@tonic-gate# individual locals too. This hash holds the addresses of OPs that 197*0Sstevel@tonic-gate# have already had their local-ness accounted for. The same thing 198*0Sstevel@tonic-gate# is done with my(). 199*0Sstevel@tonic-gate# 200*0Sstevel@tonic-gate# curcv: 201*0Sstevel@tonic-gate# CV for current sub (or main program) being deparsed 202*0Sstevel@tonic-gate# 203*0Sstevel@tonic-gate# curcvlex: 204*0Sstevel@tonic-gate# Cached hash of lexical variables for curcv: keys are names, 205*0Sstevel@tonic-gate# each value is an array of pairs, indicating the cop_seq of scopes 206*0Sstevel@tonic-gate# in which a var of that name is valid. 207*0Sstevel@tonic-gate# 208*0Sstevel@tonic-gate# curcop: 209*0Sstevel@tonic-gate# COP for statement being deparsed 210*0Sstevel@tonic-gate# 211*0Sstevel@tonic-gate# curstash: 212*0Sstevel@tonic-gate# name of the current package for deparsed code 213*0Sstevel@tonic-gate# 214*0Sstevel@tonic-gate# subs_todo: 215*0Sstevel@tonic-gate# array of [cop_seq, CV, is_format?] for subs and formats we still 216*0Sstevel@tonic-gate# want to deparse 217*0Sstevel@tonic-gate# 218*0Sstevel@tonic-gate# protos_todo: 219*0Sstevel@tonic-gate# as above, but [name, prototype] for subs that never got a GV 220*0Sstevel@tonic-gate# 221*0Sstevel@tonic-gate# subs_done, forms_done: 222*0Sstevel@tonic-gate# keys are addresses of GVs for subs and formats we've already 223*0Sstevel@tonic-gate# deparsed (or at least put into subs_todo) 224*0Sstevel@tonic-gate# 225*0Sstevel@tonic-gate# subs_declared 226*0Sstevel@tonic-gate# keys are names of subs for which we've printed declarations. 227*0Sstevel@tonic-gate# That means we can omit parentheses from the arguments. 228*0Sstevel@tonic-gate# 229*0Sstevel@tonic-gate# subs_deparsed 230*0Sstevel@tonic-gate# Keeps track of fully qualified names of all deparsed subs. 231*0Sstevel@tonic-gate# 232*0Sstevel@tonic-gate# parens: -p 233*0Sstevel@tonic-gate# linenums: -l 234*0Sstevel@tonic-gate# unquote: -q 235*0Sstevel@tonic-gate# cuddle: ` ' or `\n', depending on -sC 236*0Sstevel@tonic-gate# indent_size: -si 237*0Sstevel@tonic-gate# use_tabs: -sT 238*0Sstevel@tonic-gate# ex_const: -sv 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate# A little explanation of how precedence contexts and associativity 241*0Sstevel@tonic-gate# work: 242*0Sstevel@tonic-gate# 243*0Sstevel@tonic-gate# deparse() calls each per-op subroutine with an argument $cx (short 244*0Sstevel@tonic-gate# for context, but not the same as the cx* in the perl core), which is 245*0Sstevel@tonic-gate# a number describing the op's parents in terms of precedence, whether 246*0Sstevel@tonic-gate# they're inside an expression or at statement level, etc. (see 247*0Sstevel@tonic-gate# chart below). When ops with children call deparse on them, they pass 248*0Sstevel@tonic-gate# along their precedence. Fractional values are used to implement 249*0Sstevel@tonic-gate# associativity (`($x + $y) + $z' => `$x + $y + $y') and related 250*0Sstevel@tonic-gate# parentheses hacks. The major disadvantage of this scheme is that 251*0Sstevel@tonic-gate# it doesn't know about right sides and left sides, so say if you 252*0Sstevel@tonic-gate# assign a listop to a variable, it can't tell it's allowed to leave 253*0Sstevel@tonic-gate# the parens off the listop. 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate# Precedences: 256*0Sstevel@tonic-gate# 26 [TODO] inside interpolation context ("") 257*0Sstevel@tonic-gate# 25 left terms and list operators (leftward) 258*0Sstevel@tonic-gate# 24 left -> 259*0Sstevel@tonic-gate# 23 nonassoc ++ -- 260*0Sstevel@tonic-gate# 22 right ** 261*0Sstevel@tonic-gate# 21 right ! ~ \ and unary + and - 262*0Sstevel@tonic-gate# 20 left =~ !~ 263*0Sstevel@tonic-gate# 19 left * / % x 264*0Sstevel@tonic-gate# 18 left + - . 265*0Sstevel@tonic-gate# 17 left << >> 266*0Sstevel@tonic-gate# 16 nonassoc named unary operators 267*0Sstevel@tonic-gate# 15 nonassoc < > <= >= lt gt le ge 268*0Sstevel@tonic-gate# 14 nonassoc == != <=> eq ne cmp 269*0Sstevel@tonic-gate# 13 left & 270*0Sstevel@tonic-gate# 12 left | ^ 271*0Sstevel@tonic-gate# 11 left && 272*0Sstevel@tonic-gate# 10 left || 273*0Sstevel@tonic-gate# 9 nonassoc .. ... 274*0Sstevel@tonic-gate# 8 right ?: 275*0Sstevel@tonic-gate# 7 right = += -= *= etc. 276*0Sstevel@tonic-gate# 6 left , => 277*0Sstevel@tonic-gate# 5 nonassoc list operators (rightward) 278*0Sstevel@tonic-gate# 4 right not 279*0Sstevel@tonic-gate# 3 left and 280*0Sstevel@tonic-gate# 2 left or xor 281*0Sstevel@tonic-gate# 1 statement modifiers 282*0Sstevel@tonic-gate# 0.5 statements, but still print scopes as do { ... } 283*0Sstevel@tonic-gate# 0 statement level 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate# Nonprinting characters with special meaning: 286*0Sstevel@tonic-gate# \cS - steal parens (see maybe_parens_unop) 287*0Sstevel@tonic-gate# \n - newline and indent 288*0Sstevel@tonic-gate# \t - increase indent 289*0Sstevel@tonic-gate# \b - decrease indent (`outdent') 290*0Sstevel@tonic-gate# \f - flush left (no indent) 291*0Sstevel@tonic-gate# \cK - kill following semicolon, if any 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gatesub null { 294*0Sstevel@tonic-gate my $op = shift; 295*0Sstevel@tonic-gate return class($op) eq "NULL"; 296*0Sstevel@tonic-gate} 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gatesub todo { 299*0Sstevel@tonic-gate my $self = shift; 300*0Sstevel@tonic-gate my($cv, $is_form) = @_; 301*0Sstevel@tonic-gate return unless ($cv->FILE eq $0 || exists $self->{files}{$cv->FILE}); 302*0Sstevel@tonic-gate my $seq; 303*0Sstevel@tonic-gate if ($cv->OUTSIDE_SEQ) { 304*0Sstevel@tonic-gate $seq = $cv->OUTSIDE_SEQ; 305*0Sstevel@tonic-gate } elsif (!null($cv->START) and is_state($cv->START)) { 306*0Sstevel@tonic-gate $seq = $cv->START->cop_seq; 307*0Sstevel@tonic-gate } else { 308*0Sstevel@tonic-gate $seq = 0; 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate push @{$self->{'subs_todo'}}, [$seq, $cv, $is_form]; 311*0Sstevel@tonic-gate unless ($is_form || class($cv->STASH) eq 'SPECIAL') { 312*0Sstevel@tonic-gate $self->{'subs_deparsed'}{$cv->STASH->NAME."::".$cv->GV->NAME} = 1; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate} 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gatesub next_todo { 317*0Sstevel@tonic-gate my $self = shift; 318*0Sstevel@tonic-gate my $ent = shift @{$self->{'subs_todo'}}; 319*0Sstevel@tonic-gate my $cv = $ent->[1]; 320*0Sstevel@tonic-gate my $gv = $cv->GV; 321*0Sstevel@tonic-gate my $name = $self->gv_name($gv); 322*0Sstevel@tonic-gate if ($ent->[2]) { 323*0Sstevel@tonic-gate return "format $name =\n" 324*0Sstevel@tonic-gate . $self->deparse_format($ent->[1]). "\n"; 325*0Sstevel@tonic-gate } else { 326*0Sstevel@tonic-gate $self->{'subs_declared'}{$name} = 1; 327*0Sstevel@tonic-gate if ($name eq "BEGIN") { 328*0Sstevel@tonic-gate my $use_dec = $self->begin_is_use($cv); 329*0Sstevel@tonic-gate if (defined ($use_dec) and $self->{'expand'} < 5) { 330*0Sstevel@tonic-gate return () if 0 == length($use_dec); 331*0Sstevel@tonic-gate return $use_dec; 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate my $l = ''; 335*0Sstevel@tonic-gate if ($self->{'linenums'}) { 336*0Sstevel@tonic-gate my $line = $gv->LINE; 337*0Sstevel@tonic-gate my $file = $gv->FILE; 338*0Sstevel@tonic-gate $l = "\n\f#line $line \"$file\"\n"; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate my $p = ''; 341*0Sstevel@tonic-gate if (class($cv->STASH) ne "SPECIAL") { 342*0Sstevel@tonic-gate my $stash = $cv->STASH->NAME; 343*0Sstevel@tonic-gate if ($stash ne $self->{'curstash'}) { 344*0Sstevel@tonic-gate $p = "package $stash;\n"; 345*0Sstevel@tonic-gate $name = "$self->{'curstash'}::$name" unless $name =~ /::/; 346*0Sstevel@tonic-gate $self->{'curstash'} = $stash; 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate $name =~ s/^\Q$stash\E:://; 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate return "${p}${l}sub $name " . $self->deparse_sub($cv); 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate} 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate# Return a "use" declaration for this BEGIN block, if appropriate 355*0Sstevel@tonic-gatesub begin_is_use { 356*0Sstevel@tonic-gate my ($self, $cv) = @_; 357*0Sstevel@tonic-gate my $root = $cv->ROOT; 358*0Sstevel@tonic-gate local @$self{qw'curcv curcvlex'} = ($cv); 359*0Sstevel@tonic-gate#require B::Debug; 360*0Sstevel@tonic-gate#B::walkoptree($cv->ROOT, "debug"); 361*0Sstevel@tonic-gate my $lineseq = $root->first; 362*0Sstevel@tonic-gate return if $lineseq->name ne "lineseq"; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate my $req_op = $lineseq->first->sibling; 365*0Sstevel@tonic-gate return if $req_op->name ne "require"; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate my $module; 368*0Sstevel@tonic-gate if ($req_op->first->private & OPpCONST_BARE) { 369*0Sstevel@tonic-gate # Actually it should always be a bareword 370*0Sstevel@tonic-gate $module = $self->const_sv($req_op->first)->PV; 371*0Sstevel@tonic-gate $module =~ s[/][::]g; 372*0Sstevel@tonic-gate $module =~ s/.pm$//; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate else { 375*0Sstevel@tonic-gate $module = $self->const($self->const_sv($req_op->first), 6); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate my $version; 379*0Sstevel@tonic-gate my $version_op = $req_op->sibling; 380*0Sstevel@tonic-gate return if class($version_op) eq "NULL"; 381*0Sstevel@tonic-gate if ($version_op->name eq "lineseq") { 382*0Sstevel@tonic-gate # We have a version parameter; skip nextstate & pushmark 383*0Sstevel@tonic-gate my $constop = $version_op->first->next->next; 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate return unless $self->const_sv($constop)->PV eq $module; 386*0Sstevel@tonic-gate $constop = $constop->sibling; 387*0Sstevel@tonic-gate $version = $self->const_sv($constop); 388*0Sstevel@tonic-gate if (class($version) eq "IV") { 389*0Sstevel@tonic-gate $version = $version->int_value; 390*0Sstevel@tonic-gate } elsif (class($version) eq "NV") { 391*0Sstevel@tonic-gate $version = $version->NV; 392*0Sstevel@tonic-gate } elsif (class($version) ne "PVMG") { 393*0Sstevel@tonic-gate # Includes PVIV and PVNV 394*0Sstevel@tonic-gate $version = $version->PV; 395*0Sstevel@tonic-gate } else { 396*0Sstevel@tonic-gate # version specified as a v-string 397*0Sstevel@tonic-gate $version = 'v'.join '.', map ord, split //, $version->PV; 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate $constop = $constop->sibling; 400*0Sstevel@tonic-gate return if $constop->name ne "method_named"; 401*0Sstevel@tonic-gate return if $self->const_sv($constop)->PV ne "VERSION"; 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate $lineseq = $version_op->sibling; 405*0Sstevel@tonic-gate return if $lineseq->name ne "lineseq"; 406*0Sstevel@tonic-gate my $entersub = $lineseq->first->sibling; 407*0Sstevel@tonic-gate if ($entersub->name eq "stub") { 408*0Sstevel@tonic-gate return "use $module $version ();\n" if defined $version; 409*0Sstevel@tonic-gate return "use $module ();\n"; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate return if $entersub->name ne "entersub"; 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate # See if there are import arguments 414*0Sstevel@tonic-gate my $args = ''; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate my $svop = $entersub->first->sibling; # Skip over pushmark 417*0Sstevel@tonic-gate return unless $self->const_sv($svop)->PV eq $module; 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate # Pull out the arguments 420*0Sstevel@tonic-gate for ($svop=$svop->sibling; $svop->name ne "method_named"; 421*0Sstevel@tonic-gate $svop = $svop->sibling) { 422*0Sstevel@tonic-gate $args .= ", " if length($args); 423*0Sstevel@tonic-gate $args .= $self->deparse($svop, 6); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate my $use = 'use'; 427*0Sstevel@tonic-gate my $method_named = $svop; 428*0Sstevel@tonic-gate return if $method_named->name ne "method_named"; 429*0Sstevel@tonic-gate my $method_name = $self->const_sv($method_named)->PV; 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate if ($method_name eq "unimport") { 432*0Sstevel@tonic-gate $use = 'no'; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate # Certain pragmas are dealt with using hint bits, 436*0Sstevel@tonic-gate # so we ignore them here 437*0Sstevel@tonic-gate if ($module eq 'strict' || $module eq 'integer' 438*0Sstevel@tonic-gate || $module eq 'bytes' || $module eq 'warnings') { 439*0Sstevel@tonic-gate return ""; 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate if (defined $version && length $args) { 443*0Sstevel@tonic-gate return "$use $module $version ($args);\n"; 444*0Sstevel@tonic-gate } elsif (defined $version) { 445*0Sstevel@tonic-gate return "$use $module $version;\n"; 446*0Sstevel@tonic-gate } elsif (length $args) { 447*0Sstevel@tonic-gate return "$use $module ($args);\n"; 448*0Sstevel@tonic-gate } else { 449*0Sstevel@tonic-gate return "$use $module;\n"; 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate} 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gatesub stash_subs { 454*0Sstevel@tonic-gate my ($self, $pack) = @_; 455*0Sstevel@tonic-gate my (@ret, $stash); 456*0Sstevel@tonic-gate if (!defined $pack) { 457*0Sstevel@tonic-gate $pack = ''; 458*0Sstevel@tonic-gate $stash = \%::; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate else { 461*0Sstevel@tonic-gate $pack =~ s/(::)?$/::/; 462*0Sstevel@tonic-gate no strict 'refs'; 463*0Sstevel@tonic-gate $stash = \%$pack; 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate my %stash = svref_2object($stash)->ARRAY; 466*0Sstevel@tonic-gate while (my ($key, $val) = each %stash) { 467*0Sstevel@tonic-gate next if $key eq 'main::'; # avoid infinite recursion 468*0Sstevel@tonic-gate my $class = class($val); 469*0Sstevel@tonic-gate if ($class eq "PV") { 470*0Sstevel@tonic-gate # Just a prototype. As an ugly but fairly effective way 471*0Sstevel@tonic-gate # to find out if it belongs here is to see if the AUTOLOAD 472*0Sstevel@tonic-gate # (if any) for the stash was defined in one of our files. 473*0Sstevel@tonic-gate my $A = $stash{"AUTOLOAD"}; 474*0Sstevel@tonic-gate if (defined ($A) && class($A) eq "GV" && defined($A->CV) 475*0Sstevel@tonic-gate && class($A->CV) eq "CV") { 476*0Sstevel@tonic-gate my $AF = $A->FILE; 477*0Sstevel@tonic-gate next unless $AF eq $0 || exists $self->{'files'}{$AF}; 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate push @{$self->{'protos_todo'}}, [$pack . $key, $val->PV]; 480*0Sstevel@tonic-gate } elsif ($class eq "IV") { 481*0Sstevel@tonic-gate # Just a name. As above. 482*0Sstevel@tonic-gate my $A = $stash{"AUTOLOAD"}; 483*0Sstevel@tonic-gate if (defined ($A) && class($A) eq "GV" && defined($A->CV) 484*0Sstevel@tonic-gate && class($A->CV) eq "CV") { 485*0Sstevel@tonic-gate my $AF = $A->FILE; 486*0Sstevel@tonic-gate next unless $AF eq $0 || exists $self->{'files'}{$AF}; 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate push @{$self->{'protos_todo'}}, [$pack . $key, undef]; 489*0Sstevel@tonic-gate } elsif ($class eq "GV") { 490*0Sstevel@tonic-gate if (class(my $cv = $val->CV) ne "SPECIAL") { 491*0Sstevel@tonic-gate next if $self->{'subs_done'}{$$val}++; 492*0Sstevel@tonic-gate next if $$val != ${$cv->GV}; # Ignore imposters 493*0Sstevel@tonic-gate $self->todo($cv, 0); 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate if (class(my $cv = $val->FORM) ne "SPECIAL") { 496*0Sstevel@tonic-gate next if $self->{'forms_done'}{$$val}++; 497*0Sstevel@tonic-gate next if $$val != ${$cv->GV}; # Ignore imposters 498*0Sstevel@tonic-gate $self->todo($cv, 1); 499*0Sstevel@tonic-gate } 500*0Sstevel@tonic-gate if (class($val->HV) ne "SPECIAL" && $key =~ /::$/) { 501*0Sstevel@tonic-gate $self->stash_subs($pack . $key); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate} 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gatesub print_protos { 508*0Sstevel@tonic-gate my $self = shift; 509*0Sstevel@tonic-gate my $ar; 510*0Sstevel@tonic-gate my @ret; 511*0Sstevel@tonic-gate foreach $ar (@{$self->{'protos_todo'}}) { 512*0Sstevel@tonic-gate my $proto = (defined $ar->[1] ? " (". $ar->[1] . ")" : ""); 513*0Sstevel@tonic-gate push @ret, "sub " . $ar->[0] . "$proto;\n"; 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate delete $self->{'protos_todo'}; 516*0Sstevel@tonic-gate return @ret; 517*0Sstevel@tonic-gate} 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gatesub style_opts { 520*0Sstevel@tonic-gate my $self = shift; 521*0Sstevel@tonic-gate my $opts = shift; 522*0Sstevel@tonic-gate my $opt; 523*0Sstevel@tonic-gate while (length($opt = substr($opts, 0, 1))) { 524*0Sstevel@tonic-gate if ($opt eq "C") { 525*0Sstevel@tonic-gate $self->{'cuddle'} = " "; 526*0Sstevel@tonic-gate $opts = substr($opts, 1); 527*0Sstevel@tonic-gate } elsif ($opt eq "i") { 528*0Sstevel@tonic-gate $opts =~ s/^i(\d+)//; 529*0Sstevel@tonic-gate $self->{'indent_size'} = $1; 530*0Sstevel@tonic-gate } elsif ($opt eq "T") { 531*0Sstevel@tonic-gate $self->{'use_tabs'} = 1; 532*0Sstevel@tonic-gate $opts = substr($opts, 1); 533*0Sstevel@tonic-gate } elsif ($opt eq "v") { 534*0Sstevel@tonic-gate $opts =~ s/^v([^.]*)(.|$)//; 535*0Sstevel@tonic-gate $self->{'ex_const'} = $1; 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate} 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gatesub new { 541*0Sstevel@tonic-gate my $class = shift; 542*0Sstevel@tonic-gate my $self = bless {}, $class; 543*0Sstevel@tonic-gate $self->{'cuddle'} = "\n"; 544*0Sstevel@tonic-gate $self->{'curcop'} = undef; 545*0Sstevel@tonic-gate $self->{'curstash'} = "main"; 546*0Sstevel@tonic-gate $self->{'ex_const'} = "'???'"; 547*0Sstevel@tonic-gate $self->{'expand'} = 0; 548*0Sstevel@tonic-gate $self->{'files'} = {}; 549*0Sstevel@tonic-gate $self->{'indent_size'} = 4; 550*0Sstevel@tonic-gate $self->{'linenums'} = 0; 551*0Sstevel@tonic-gate $self->{'parens'} = 0; 552*0Sstevel@tonic-gate $self->{'subs_todo'} = []; 553*0Sstevel@tonic-gate $self->{'unquote'} = 0; 554*0Sstevel@tonic-gate $self->{'use_dumper'} = 0; 555*0Sstevel@tonic-gate $self->{'use_tabs'} = 0; 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate $self->{'ambient_arybase'} = 0; 558*0Sstevel@tonic-gate $self->{'ambient_warnings'} = undef; # Assume no lexical warnings 559*0Sstevel@tonic-gate $self->{'ambient_hints'} = 0; 560*0Sstevel@tonic-gate $self->init(); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate while (my $arg = shift @_) { 563*0Sstevel@tonic-gate if ($arg eq "-d") { 564*0Sstevel@tonic-gate $self->{'use_dumper'} = 1; 565*0Sstevel@tonic-gate require Data::Dumper; 566*0Sstevel@tonic-gate } elsif ($arg =~ /^-f(.*)/) { 567*0Sstevel@tonic-gate $self->{'files'}{$1} = 1; 568*0Sstevel@tonic-gate } elsif ($arg eq "-l") { 569*0Sstevel@tonic-gate $self->{'linenums'} = 1; 570*0Sstevel@tonic-gate } elsif ($arg eq "-p") { 571*0Sstevel@tonic-gate $self->{'parens'} = 1; 572*0Sstevel@tonic-gate } elsif ($arg eq "-P") { 573*0Sstevel@tonic-gate $self->{'noproto'} = 1; 574*0Sstevel@tonic-gate } elsif ($arg eq "-q") { 575*0Sstevel@tonic-gate $self->{'unquote'} = 1; 576*0Sstevel@tonic-gate } elsif (substr($arg, 0, 2) eq "-s") { 577*0Sstevel@tonic-gate $self->style_opts(substr $arg, 2); 578*0Sstevel@tonic-gate } elsif ($arg =~ /^-x(\d)$/) { 579*0Sstevel@tonic-gate $self->{'expand'} = $1; 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate return $self; 583*0Sstevel@tonic-gate} 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate{ 586*0Sstevel@tonic-gate # Mask out the bits that L<warnings::register> uses 587*0Sstevel@tonic-gate my $WARN_MASK; 588*0Sstevel@tonic-gate BEGIN { 589*0Sstevel@tonic-gate $WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all}; 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate sub WARN_MASK () { 592*0Sstevel@tonic-gate return $WARN_MASK; 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate} 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate# Initialise the contextual information, either from 597*0Sstevel@tonic-gate# defaults provided with the ambient_pragmas method, 598*0Sstevel@tonic-gate# or from perl's own defaults otherwise. 599*0Sstevel@tonic-gatesub init { 600*0Sstevel@tonic-gate my $self = shift; 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate $self->{'arybase'} = $self->{'ambient_arybase'}; 603*0Sstevel@tonic-gate $self->{'warnings'} = defined ($self->{'ambient_warnings'}) 604*0Sstevel@tonic-gate ? $self->{'ambient_warnings'} & WARN_MASK 605*0Sstevel@tonic-gate : undef; 606*0Sstevel@tonic-gate $self->{'hints'} = $self->{'ambient_hints'} & 0xFF; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate # also a convenient place to clear out subs_declared 609*0Sstevel@tonic-gate delete $self->{'subs_declared'}; 610*0Sstevel@tonic-gate} 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gatesub compile { 613*0Sstevel@tonic-gate my(@args) = @_; 614*0Sstevel@tonic-gate return sub { 615*0Sstevel@tonic-gate my $self = B::Deparse->new(@args); 616*0Sstevel@tonic-gate # First deparse command-line args 617*0Sstevel@tonic-gate if (defined $^I) { # deparse -i 618*0Sstevel@tonic-gate print q(BEGIN { $^I = ).perlstring($^I).qq(; }\n); 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate if ($^W) { # deparse -w 621*0Sstevel@tonic-gate print qq(BEGIN { \$^W = $^W; }\n); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate if ($/ ne "\n" or defined $O::savebackslash) { # deparse -l and -0 624*0Sstevel@tonic-gate my $fs = perlstring($/) || 'undef'; 625*0Sstevel@tonic-gate my $bs = perlstring($O::savebackslash) || 'undef'; 626*0Sstevel@tonic-gate print qq(BEGIN { \$/ = $fs; \$\\ = $bs; }\n); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate my @BEGINs = B::begin_av->isa("B::AV") ? B::begin_av->ARRAY : (); 629*0Sstevel@tonic-gate my @CHECKs = B::check_av->isa("B::AV") ? B::check_av->ARRAY : (); 630*0Sstevel@tonic-gate my @INITs = B::init_av->isa("B::AV") ? B::init_av->ARRAY : (); 631*0Sstevel@tonic-gate my @ENDs = B::end_av->isa("B::AV") ? B::end_av->ARRAY : (); 632*0Sstevel@tonic-gate for my $block (@BEGINs, @CHECKs, @INITs, @ENDs) { 633*0Sstevel@tonic-gate $self->todo($block, 0); 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate $self->stash_subs(); 636*0Sstevel@tonic-gate local($SIG{"__DIE__"}) = 637*0Sstevel@tonic-gate sub { 638*0Sstevel@tonic-gate if ($self->{'curcop'}) { 639*0Sstevel@tonic-gate my $cop = $self->{'curcop'}; 640*0Sstevel@tonic-gate my($line, $file) = ($cop->line, $cop->file); 641*0Sstevel@tonic-gate print STDERR "While deparsing $file near line $line,\n"; 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate }; 644*0Sstevel@tonic-gate $self->{'curcv'} = main_cv; 645*0Sstevel@tonic-gate $self->{'curcvlex'} = undef; 646*0Sstevel@tonic-gate print $self->print_protos; 647*0Sstevel@tonic-gate @{$self->{'subs_todo'}} = 648*0Sstevel@tonic-gate sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}}; 649*0Sstevel@tonic-gate print $self->indent($self->deparse_root(main_root)), "\n" 650*0Sstevel@tonic-gate unless null main_root; 651*0Sstevel@tonic-gate my @text; 652*0Sstevel@tonic-gate while (scalar(@{$self->{'subs_todo'}})) { 653*0Sstevel@tonic-gate push @text, $self->next_todo; 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate print $self->indent(join("", @text)), "\n" if @text; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate # Print __DATA__ section, if necessary 658*0Sstevel@tonic-gate no strict 'refs'; 659*0Sstevel@tonic-gate my $laststash = defined $self->{'curcop'} 660*0Sstevel@tonic-gate ? $self->{'curcop'}->stash->NAME : $self->{'curstash'}; 661*0Sstevel@tonic-gate if (defined *{$laststash."::DATA"}{IO}) { 662*0Sstevel@tonic-gate print "package $laststash;\n" 663*0Sstevel@tonic-gate unless $laststash eq $self->{'curstash'}; 664*0Sstevel@tonic-gate print "__DATA__\n"; 665*0Sstevel@tonic-gate print readline(*{$laststash."::DATA"}); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate } 668*0Sstevel@tonic-gate} 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gatesub coderef2text { 671*0Sstevel@tonic-gate my $self = shift; 672*0Sstevel@tonic-gate my $sub = shift; 673*0Sstevel@tonic-gate croak "Usage: ->coderef2text(CODEREF)" unless UNIVERSAL::isa($sub, "CODE"); 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate $self->init(); 676*0Sstevel@tonic-gate return $self->indent($self->deparse_sub(svref_2object($sub))); 677*0Sstevel@tonic-gate} 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gatesub ambient_pragmas { 680*0Sstevel@tonic-gate my $self = shift; 681*0Sstevel@tonic-gate my ($arybase, $hint_bits, $warning_bits) = (0, 0); 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate while (@_ > 1) { 684*0Sstevel@tonic-gate my $name = shift(); 685*0Sstevel@tonic-gate my $val = shift(); 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate if ($name eq 'strict') { 688*0Sstevel@tonic-gate require strict; 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate if ($val eq 'none') { 691*0Sstevel@tonic-gate $hint_bits &= ~strict::bits(qw/refs subs vars/); 692*0Sstevel@tonic-gate next(); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate my @names; 696*0Sstevel@tonic-gate if ($val eq "all") { 697*0Sstevel@tonic-gate @names = qw/refs subs vars/; 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate elsif (ref $val) { 700*0Sstevel@tonic-gate @names = @$val; 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate else { 703*0Sstevel@tonic-gate @names = split' ', $val; 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate $hint_bits |= strict::bits(@names); 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate elsif ($name eq '$[') { 709*0Sstevel@tonic-gate $arybase = $val; 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate elsif ($name eq 'integer' 713*0Sstevel@tonic-gate || $name eq 'bytes' 714*0Sstevel@tonic-gate || $name eq 'utf8') { 715*0Sstevel@tonic-gate require "$name.pm"; 716*0Sstevel@tonic-gate if ($val) { 717*0Sstevel@tonic-gate $hint_bits |= ${$::{"${name}::"}{"hint_bits"}}; 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate else { 720*0Sstevel@tonic-gate $hint_bits &= ~${$::{"${name}::"}{"hint_bits"}}; 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate elsif ($name eq 're') { 725*0Sstevel@tonic-gate require re; 726*0Sstevel@tonic-gate if ($val eq 'none') { 727*0Sstevel@tonic-gate $hint_bits &= ~re::bits(qw/taint eval/); 728*0Sstevel@tonic-gate next(); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate my @names; 732*0Sstevel@tonic-gate if ($val eq 'all') { 733*0Sstevel@tonic-gate @names = qw/taint eval/; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate elsif (ref $val) { 736*0Sstevel@tonic-gate @names = @$val; 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate else { 739*0Sstevel@tonic-gate @names = split' ',$val; 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate $hint_bits |= re::bits(@names); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate elsif ($name eq 'warnings') { 745*0Sstevel@tonic-gate if ($val eq 'none') { 746*0Sstevel@tonic-gate $warning_bits = $warnings::NONE; 747*0Sstevel@tonic-gate next(); 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate my @names; 751*0Sstevel@tonic-gate if (ref $val) { 752*0Sstevel@tonic-gate @names = @$val; 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate else { 755*0Sstevel@tonic-gate @names = split/\s+/, $val; 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate $warning_bits = $warnings::NONE if !defined ($warning_bits); 759*0Sstevel@tonic-gate $warning_bits |= warnings::bits(@names); 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate elsif ($name eq 'warning_bits') { 763*0Sstevel@tonic-gate $warning_bits = $val; 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate elsif ($name eq 'hint_bits') { 767*0Sstevel@tonic-gate $hint_bits = $val; 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate else { 771*0Sstevel@tonic-gate croak "Unknown pragma type: $name"; 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate if (@_) { 775*0Sstevel@tonic-gate croak "The ambient_pragmas method expects an even number of args"; 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate $self->{'ambient_arybase'} = $arybase; 779*0Sstevel@tonic-gate $self->{'ambient_warnings'} = $warning_bits; 780*0Sstevel@tonic-gate $self->{'ambient_hints'} = $hint_bits; 781*0Sstevel@tonic-gate} 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate# This method is the inner loop, so try to keep it simple 784*0Sstevel@tonic-gatesub deparse { 785*0Sstevel@tonic-gate my $self = shift; 786*0Sstevel@tonic-gate my($op, $cx) = @_; 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate Carp::confess("Null op in deparse") if !defined($op) 789*0Sstevel@tonic-gate || class($op) eq "NULL"; 790*0Sstevel@tonic-gate my $meth = "pp_" . $op->name; 791*0Sstevel@tonic-gate return $self->$meth($op, $cx); 792*0Sstevel@tonic-gate} 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gatesub indent { 795*0Sstevel@tonic-gate my $self = shift; 796*0Sstevel@tonic-gate my $txt = shift; 797*0Sstevel@tonic-gate my @lines = split(/\n/, $txt); 798*0Sstevel@tonic-gate my $leader = ""; 799*0Sstevel@tonic-gate my $level = 0; 800*0Sstevel@tonic-gate my $line; 801*0Sstevel@tonic-gate for $line (@lines) { 802*0Sstevel@tonic-gate my $cmd = substr($line, 0, 1); 803*0Sstevel@tonic-gate if ($cmd eq "\t" or $cmd eq "\b") { 804*0Sstevel@tonic-gate $level += ($cmd eq "\t" ? 1 : -1) * $self->{'indent_size'}; 805*0Sstevel@tonic-gate if ($self->{'use_tabs'}) { 806*0Sstevel@tonic-gate $leader = "\t" x ($level / 8) . " " x ($level % 8); 807*0Sstevel@tonic-gate } else { 808*0Sstevel@tonic-gate $leader = " " x $level; 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate $line = substr($line, 1); 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate if (substr($line, 0, 1) eq "\f") { 813*0Sstevel@tonic-gate $line = substr($line, 1); # no indent 814*0Sstevel@tonic-gate } else { 815*0Sstevel@tonic-gate $line = $leader . $line; 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate $line =~ s/\cK;?//g; 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate return join("\n", @lines); 820*0Sstevel@tonic-gate} 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gatesub deparse_sub { 823*0Sstevel@tonic-gate my $self = shift; 824*0Sstevel@tonic-gate my $cv = shift; 825*0Sstevel@tonic-gate my $proto = ""; 826*0Sstevel@tonic-gateCarp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL"); 827*0Sstevel@tonic-gateCarp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL"); 828*0Sstevel@tonic-gate local $self->{'curcop'} = $self->{'curcop'}; 829*0Sstevel@tonic-gate if ($cv->FLAGS & SVf_POK) { 830*0Sstevel@tonic-gate $proto = "(". $cv->PV . ") "; 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE)) { 833*0Sstevel@tonic-gate $proto .= ": "; 834*0Sstevel@tonic-gate $proto .= "lvalue " if $cv->CvFLAGS & CVf_LVALUE; 835*0Sstevel@tonic-gate $proto .= "locked " if $cv->CvFLAGS & CVf_LOCKED; 836*0Sstevel@tonic-gate $proto .= "method " if $cv->CvFLAGS & CVf_METHOD; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate local($self->{'curcv'}) = $cv; 840*0Sstevel@tonic-gate local($self->{'curcvlex'}); 841*0Sstevel@tonic-gate local(@$self{qw'curstash warnings hints'}) 842*0Sstevel@tonic-gate = @$self{qw'curstash warnings hints'}; 843*0Sstevel@tonic-gate my $body; 844*0Sstevel@tonic-gate if (not null $cv->ROOT) { 845*0Sstevel@tonic-gate my $lineseq = $cv->ROOT->first; 846*0Sstevel@tonic-gate if ($lineseq->name eq "lineseq") { 847*0Sstevel@tonic-gate my @ops; 848*0Sstevel@tonic-gate for(my$o=$lineseq->first; $$o; $o=$o->sibling) { 849*0Sstevel@tonic-gate push @ops, $o; 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate $body = $self->lineseq(undef, @ops).";"; 852*0Sstevel@tonic-gate my $scope_en = $self->find_scope_en($lineseq); 853*0Sstevel@tonic-gate if (defined $scope_en) { 854*0Sstevel@tonic-gate my $subs = join"", $self->seq_subs($scope_en); 855*0Sstevel@tonic-gate $body .= ";\n$subs" if length($subs); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate else { 859*0Sstevel@tonic-gate $body = $self->deparse($cv->ROOT->first, 0); 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate else { 863*0Sstevel@tonic-gate my $sv = $cv->const_sv; 864*0Sstevel@tonic-gate if ($$sv) { 865*0Sstevel@tonic-gate # uh-oh. inlinable sub... format it differently 866*0Sstevel@tonic-gate return $proto . "{ " . $self->const($sv, 0) . " }\n"; 867*0Sstevel@tonic-gate } else { # XSUB? (or just a declaration) 868*0Sstevel@tonic-gate return "$proto;\n"; 869*0Sstevel@tonic-gate } 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate return $proto ."{\n\t$body\n\b}" ."\n"; 872*0Sstevel@tonic-gate} 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gatesub deparse_format { 875*0Sstevel@tonic-gate my $self = shift; 876*0Sstevel@tonic-gate my $form = shift; 877*0Sstevel@tonic-gate my @text; 878*0Sstevel@tonic-gate local($self->{'curcv'}) = $form; 879*0Sstevel@tonic-gate local($self->{'curcvlex'}); 880*0Sstevel@tonic-gate local($self->{'in_format'}) = 1; 881*0Sstevel@tonic-gate local(@$self{qw'curstash warnings hints'}) 882*0Sstevel@tonic-gate = @$self{qw'curstash warnings hints'}; 883*0Sstevel@tonic-gate my $op = $form->ROOT; 884*0Sstevel@tonic-gate my $kid; 885*0Sstevel@tonic-gate return "\f." if $op->first->name eq 'stub' 886*0Sstevel@tonic-gate || $op->first->name eq 'nextstate'; 887*0Sstevel@tonic-gate $op = $op->first->first; # skip leavewrite, lineseq 888*0Sstevel@tonic-gate while (not null $op) { 889*0Sstevel@tonic-gate $op = $op->sibling; # skip nextstate 890*0Sstevel@tonic-gate my @exprs; 891*0Sstevel@tonic-gate $kid = $op->first->sibling; # skip pushmark 892*0Sstevel@tonic-gate push @text, "\f".$self->const_sv($kid)->PV; 893*0Sstevel@tonic-gate $kid = $kid->sibling; 894*0Sstevel@tonic-gate for (; not null $kid; $kid = $kid->sibling) { 895*0Sstevel@tonic-gate push @exprs, $self->deparse($kid, 0); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate push @text, "\f".join(", ", @exprs)."\n" if @exprs; 898*0Sstevel@tonic-gate $op = $op->sibling; 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate return join("", @text) . "\f."; 901*0Sstevel@tonic-gate} 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gatesub is_scope { 904*0Sstevel@tonic-gate my $op = shift; 905*0Sstevel@tonic-gate return $op->name eq "leave" || $op->name eq "scope" 906*0Sstevel@tonic-gate || $op->name eq "lineseq" 907*0Sstevel@tonic-gate || ($op->name eq "null" && class($op) eq "UNOP" 908*0Sstevel@tonic-gate && (is_scope($op->first) || $op->first->name eq "enter")); 909*0Sstevel@tonic-gate} 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gatesub is_state { 912*0Sstevel@tonic-gate my $name = $_[0]->name; 913*0Sstevel@tonic-gate return $name eq "nextstate" || $name eq "dbstate" || $name eq "setstate"; 914*0Sstevel@tonic-gate} 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gatesub is_miniwhile { # check for one-line loop (`foo() while $y--') 917*0Sstevel@tonic-gate my $op = shift; 918*0Sstevel@tonic-gate return (!null($op) and null($op->sibling) 919*0Sstevel@tonic-gate and $op->name eq "null" and class($op) eq "UNOP" 920*0Sstevel@tonic-gate and (($op->first->name =~ /^(and|or)$/ 921*0Sstevel@tonic-gate and $op->first->first->sibling->name eq "lineseq") 922*0Sstevel@tonic-gate or ($op->first->name eq "lineseq" 923*0Sstevel@tonic-gate and not null $op->first->first->sibling 924*0Sstevel@tonic-gate and $op->first->first->sibling->name eq "unstack") 925*0Sstevel@tonic-gate )); 926*0Sstevel@tonic-gate} 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate# Check if the op and its sibling are the initialization and the rest of a 929*0Sstevel@tonic-gate# for (..;..;..) { ... } loop 930*0Sstevel@tonic-gatesub is_for_loop { 931*0Sstevel@tonic-gate my $op = shift; 932*0Sstevel@tonic-gate # This OP might be almost anything, though it won't be a 933*0Sstevel@tonic-gate # nextstate. (It's the initialization, so in the canonical case it 934*0Sstevel@tonic-gate # will be an sassign.) The sibling is a lineseq whose first child 935*0Sstevel@tonic-gate # is a nextstate and whose second is a leaveloop. 936*0Sstevel@tonic-gate my $lseq = $op->sibling; 937*0Sstevel@tonic-gate if (!is_state $op and !null($lseq) and $lseq->name eq "lineseq") { 938*0Sstevel@tonic-gate if ($lseq->first && !null($lseq->first) && is_state($lseq->first) 939*0Sstevel@tonic-gate && (my $sib = $lseq->first->sibling)) { 940*0Sstevel@tonic-gate return (!null($sib) && $sib->name eq "leaveloop"); 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate return 0; 944*0Sstevel@tonic-gate} 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gatesub is_scalar { 947*0Sstevel@tonic-gate my $op = shift; 948*0Sstevel@tonic-gate return ($op->name eq "rv2sv" or 949*0Sstevel@tonic-gate $op->name eq "padsv" or 950*0Sstevel@tonic-gate $op->name eq "gv" or # only in array/hash constructs 951*0Sstevel@tonic-gate $op->flags & OPf_KIDS && !null($op->first) 952*0Sstevel@tonic-gate && $op->first->name eq "gvsv"); 953*0Sstevel@tonic-gate} 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gatesub maybe_parens { 956*0Sstevel@tonic-gate my $self = shift; 957*0Sstevel@tonic-gate my($text, $cx, $prec) = @_; 958*0Sstevel@tonic-gate if ($prec < $cx # unary ops nest just fine 959*0Sstevel@tonic-gate or $prec == $cx and $cx != 4 and $cx != 16 and $cx != 21 960*0Sstevel@tonic-gate or $self->{'parens'}) 961*0Sstevel@tonic-gate { 962*0Sstevel@tonic-gate $text = "($text)"; 963*0Sstevel@tonic-gate # In a unop, let parent reuse our parens; see maybe_parens_unop 964*0Sstevel@tonic-gate $text = "\cS" . $text if $cx == 16; 965*0Sstevel@tonic-gate return $text; 966*0Sstevel@tonic-gate } else { 967*0Sstevel@tonic-gate return $text; 968*0Sstevel@tonic-gate } 969*0Sstevel@tonic-gate} 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate# same as above, but get around the `if it looks like a function' rule 972*0Sstevel@tonic-gatesub maybe_parens_unop { 973*0Sstevel@tonic-gate my $self = shift; 974*0Sstevel@tonic-gate my($name, $kid, $cx) = @_; 975*0Sstevel@tonic-gate if ($cx > 16 or $self->{'parens'}) { 976*0Sstevel@tonic-gate $kid = $self->deparse($kid, 1); 977*0Sstevel@tonic-gate if ($name eq "umask" && $kid =~ /^\d+$/) { 978*0Sstevel@tonic-gate $kid = sprintf("%#o", $kid); 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate return "$name($kid)"; 981*0Sstevel@tonic-gate } else { 982*0Sstevel@tonic-gate $kid = $self->deparse($kid, 16); 983*0Sstevel@tonic-gate if ($name eq "umask" && $kid =~ /^\d+$/) { 984*0Sstevel@tonic-gate $kid = sprintf("%#o", $kid); 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate if (substr($kid, 0, 1) eq "\cS") { 987*0Sstevel@tonic-gate # use kid's parens 988*0Sstevel@tonic-gate return $name . substr($kid, 1); 989*0Sstevel@tonic-gate } elsif (substr($kid, 0, 1) eq "(") { 990*0Sstevel@tonic-gate # avoid looks-like-a-function trap with extra parens 991*0Sstevel@tonic-gate # (`+' can lead to ambiguities) 992*0Sstevel@tonic-gate return "$name(" . $kid . ")"; 993*0Sstevel@tonic-gate } else { 994*0Sstevel@tonic-gate return "$name $kid"; 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate } 997*0Sstevel@tonic-gate} 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gatesub maybe_parens_func { 1000*0Sstevel@tonic-gate my $self = shift; 1001*0Sstevel@tonic-gate my($func, $text, $cx, $prec) = @_; 1002*0Sstevel@tonic-gate if ($prec <= $cx or substr($text, 0, 1) eq "(" or $self->{'parens'}) { 1003*0Sstevel@tonic-gate return "$func($text)"; 1004*0Sstevel@tonic-gate } else { 1005*0Sstevel@tonic-gate return "$func $text"; 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate} 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gatesub maybe_local { 1010*0Sstevel@tonic-gate my $self = shift; 1011*0Sstevel@tonic-gate my($op, $cx, $text) = @_; 1012*0Sstevel@tonic-gate my $our_intro = ($op->name =~ /^(gv|rv2)[ash]v$/) ? OPpOUR_INTRO : 0; 1013*0Sstevel@tonic-gate if ($op->private & (OPpLVAL_INTRO|$our_intro) 1014*0Sstevel@tonic-gate and not $self->{'avoid_local'}{$$op}) { 1015*0Sstevel@tonic-gate my $our_local = ($op->private & OPpLVAL_INTRO) ? "local" : "our"; 1016*0Sstevel@tonic-gate if( $our_local eq 'our' ) { 1017*0Sstevel@tonic-gate die "Unexpected our($text)\n" unless $text =~ /^\W(\w+::)*\w+\z/; 1018*0Sstevel@tonic-gate $text =~ s/(\w+::)+//; 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate if (want_scalar($op)) { 1021*0Sstevel@tonic-gate return "$our_local $text"; 1022*0Sstevel@tonic-gate } else { 1023*0Sstevel@tonic-gate return $self->maybe_parens_func("$our_local", $text, $cx, 16); 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate } else { 1026*0Sstevel@tonic-gate return $text; 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate} 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gatesub maybe_targmy { 1031*0Sstevel@tonic-gate my $self = shift; 1032*0Sstevel@tonic-gate my($op, $cx, $func, @args) = @_; 1033*0Sstevel@tonic-gate if ($op->private & OPpTARGET_MY) { 1034*0Sstevel@tonic-gate my $var = $self->padname($op->targ); 1035*0Sstevel@tonic-gate my $val = $func->($self, $op, 7, @args); 1036*0Sstevel@tonic-gate return $self->maybe_parens("$var = $val", $cx, 7); 1037*0Sstevel@tonic-gate } else { 1038*0Sstevel@tonic-gate return $func->($self, $op, $cx, @args); 1039*0Sstevel@tonic-gate } 1040*0Sstevel@tonic-gate} 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gatesub padname_sv { 1043*0Sstevel@tonic-gate my $self = shift; 1044*0Sstevel@tonic-gate my $targ = shift; 1045*0Sstevel@tonic-gate return $self->{'curcv'}->PADLIST->ARRAYelt(0)->ARRAYelt($targ); 1046*0Sstevel@tonic-gate} 1047*0Sstevel@tonic-gate 1048*0Sstevel@tonic-gatesub maybe_my { 1049*0Sstevel@tonic-gate my $self = shift; 1050*0Sstevel@tonic-gate my($op, $cx, $text) = @_; 1051*0Sstevel@tonic-gate if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) { 1052*0Sstevel@tonic-gate if (want_scalar($op)) { 1053*0Sstevel@tonic-gate return "my $text"; 1054*0Sstevel@tonic-gate } else { 1055*0Sstevel@tonic-gate return $self->maybe_parens_func("my", $text, $cx, 16); 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate } else { 1058*0Sstevel@tonic-gate return $text; 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate} 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate# The following OPs don't have functions: 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate# pp_padany -- does not exist after parsing 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gatesub AUTOLOAD { 1067*0Sstevel@tonic-gate if ($AUTOLOAD =~ s/^.*::pp_//) { 1068*0Sstevel@tonic-gate warn "unexpected OP_".uc $AUTOLOAD; 1069*0Sstevel@tonic-gate return "XXX"; 1070*0Sstevel@tonic-gate } else { 1071*0Sstevel@tonic-gate die "Undefined subroutine $AUTOLOAD called"; 1072*0Sstevel@tonic-gate } 1073*0Sstevel@tonic-gate} 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gatesub DESTROY {} # Do not AUTOLOAD 1076*0Sstevel@tonic-gate 1077*0Sstevel@tonic-gate# $root should be the op which represents the root of whatever 1078*0Sstevel@tonic-gate# we're sequencing here. If it's undefined, then we don't append 1079*0Sstevel@tonic-gate# any subroutine declarations to the deparsed ops, otherwise we 1080*0Sstevel@tonic-gate# append appropriate declarations. 1081*0Sstevel@tonic-gatesub lineseq { 1082*0Sstevel@tonic-gate my($self, $root, @ops) = @_; 1083*0Sstevel@tonic-gate my($expr, @exprs); 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate my $out_cop = $self->{'curcop'}; 1086*0Sstevel@tonic-gate my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef; 1087*0Sstevel@tonic-gate my $limit_seq; 1088*0Sstevel@tonic-gate if (defined $root) { 1089*0Sstevel@tonic-gate $limit_seq = $out_seq; 1090*0Sstevel@tonic-gate my $nseq; 1091*0Sstevel@tonic-gate $nseq = $self->find_scope_st($root->sibling) if ${$root->sibling}; 1092*0Sstevel@tonic-gate $limit_seq = $nseq if !defined($limit_seq) 1093*0Sstevel@tonic-gate or defined($nseq) && $nseq < $limit_seq; 1094*0Sstevel@tonic-gate } 1095*0Sstevel@tonic-gate $limit_seq = $self->{'limit_seq'} 1096*0Sstevel@tonic-gate if defined($self->{'limit_seq'}) 1097*0Sstevel@tonic-gate && (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq); 1098*0Sstevel@tonic-gate local $self->{'limit_seq'} = $limit_seq; 1099*0Sstevel@tonic-gate for (my $i = 0; $i < @ops; $i++) { 1100*0Sstevel@tonic-gate $expr = ""; 1101*0Sstevel@tonic-gate if (is_state $ops[$i]) { 1102*0Sstevel@tonic-gate $expr = $self->deparse($ops[$i], 0); 1103*0Sstevel@tonic-gate $i++; 1104*0Sstevel@tonic-gate if ($i > $#ops) { 1105*0Sstevel@tonic-gate push @exprs, $expr; 1106*0Sstevel@tonic-gate last; 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate } 1109*0Sstevel@tonic-gate if (!is_state $ops[$i] and (my $ls = $ops[$i+1]) and 1110*0Sstevel@tonic-gate !null($ops[$i+1]) and $ops[$i+1]->name eq "lineseq") 1111*0Sstevel@tonic-gate { 1112*0Sstevel@tonic-gate if ($ls->first && !null($ls->first) && is_state($ls->first) 1113*0Sstevel@tonic-gate && (my $sib = $ls->first->sibling)) { 1114*0Sstevel@tonic-gate if (!null($sib) && $sib->name eq "leaveloop") { 1115*0Sstevel@tonic-gate push @exprs, $expr . $self->for_loop($ops[$i], 0); 1116*0Sstevel@tonic-gate $i++; 1117*0Sstevel@tonic-gate next; 1118*0Sstevel@tonic-gate } 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate } 1121*0Sstevel@tonic-gate $expr .= $self->deparse($ops[$i], (@ops != 1)/2); 1122*0Sstevel@tonic-gate $expr =~ s/;\n?\z//; 1123*0Sstevel@tonic-gate push @exprs, $expr; 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate my $body = join(";\n", grep {length} @exprs); 1126*0Sstevel@tonic-gate my $subs = ""; 1127*0Sstevel@tonic-gate if (defined $root && defined $limit_seq && !$self->{'in_format'}) { 1128*0Sstevel@tonic-gate $subs = join "\n", $self->seq_subs($limit_seq); 1129*0Sstevel@tonic-gate } 1130*0Sstevel@tonic-gate return join(";\n", grep {length} $body, $subs); 1131*0Sstevel@tonic-gate} 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gatesub scopeop { 1134*0Sstevel@tonic-gate my($real_block, $self, $op, $cx) = @_; 1135*0Sstevel@tonic-gate my $kid; 1136*0Sstevel@tonic-gate my @kids; 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate local(@$self{qw'curstash warnings hints'}) 1139*0Sstevel@tonic-gate = @$self{qw'curstash warnings hints'} if $real_block; 1140*0Sstevel@tonic-gate if ($real_block) { 1141*0Sstevel@tonic-gate $kid = $op->first->sibling; # skip enter 1142*0Sstevel@tonic-gate if (is_miniwhile($kid)) { 1143*0Sstevel@tonic-gate my $top = $kid->first; 1144*0Sstevel@tonic-gate my $name = $top->name; 1145*0Sstevel@tonic-gate if ($name eq "and") { 1146*0Sstevel@tonic-gate $name = "while"; 1147*0Sstevel@tonic-gate } elsif ($name eq "or") { 1148*0Sstevel@tonic-gate $name = "until"; 1149*0Sstevel@tonic-gate } else { # no conditional -> while 1 or until 0 1150*0Sstevel@tonic-gate return $self->deparse($top->first, 1) . " while 1"; 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate my $cond = $top->first; 1153*0Sstevel@tonic-gate my $body = $cond->sibling->first; # skip lineseq 1154*0Sstevel@tonic-gate $cond = $self->deparse($cond, 1); 1155*0Sstevel@tonic-gate $body = $self->deparse($body, 1); 1156*0Sstevel@tonic-gate return "$body $name $cond"; 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate } else { 1159*0Sstevel@tonic-gate $kid = $op->first; 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 1162*0Sstevel@tonic-gate push @kids, $kid; 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate if ($cx > 0) { # inside an expression, (a do {} while for lineseq) 1165*0Sstevel@tonic-gate return "do {\n\t" . $self->lineseq($op, @kids) . "\n\b}"; 1166*0Sstevel@tonic-gate } else { 1167*0Sstevel@tonic-gate my $lineseq = $self->lineseq($op, @kids); 1168*0Sstevel@tonic-gate return (length ($lineseq) ? "$lineseq;" : ""); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate} 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gatesub pp_scope { scopeop(0, @_); } 1173*0Sstevel@tonic-gatesub pp_lineseq { scopeop(0, @_); } 1174*0Sstevel@tonic-gatesub pp_leave { scopeop(1, @_); } 1175*0Sstevel@tonic-gate 1176*0Sstevel@tonic-gate# This is a special case of scopeop and lineseq, for the case of the 1177*0Sstevel@tonic-gate# main_root. The difference is that we print the output statements as 1178*0Sstevel@tonic-gate# soon as we get them, for the sake of impatient users. 1179*0Sstevel@tonic-gatesub deparse_root { 1180*0Sstevel@tonic-gate my $self = shift; 1181*0Sstevel@tonic-gate my($op) = @_; 1182*0Sstevel@tonic-gate local(@$self{qw'curstash warnings hints'}) 1183*0Sstevel@tonic-gate = @$self{qw'curstash warnings hints'}; 1184*0Sstevel@tonic-gate my @kids; 1185*0Sstevel@tonic-gate for (my $kid = $op->first->sibling; !null($kid); $kid = $kid->sibling) { 1186*0Sstevel@tonic-gate push @kids, $kid; 1187*0Sstevel@tonic-gate } 1188*0Sstevel@tonic-gate for (my $i = 0; $i < @kids; $i++) { 1189*0Sstevel@tonic-gate my $expr = ""; 1190*0Sstevel@tonic-gate if (is_state $kids[$i]) { 1191*0Sstevel@tonic-gate $expr = $self->deparse($kids[$i], 0); 1192*0Sstevel@tonic-gate $i++; 1193*0Sstevel@tonic-gate if ($i > $#kids) { 1194*0Sstevel@tonic-gate print $self->indent($expr); 1195*0Sstevel@tonic-gate last; 1196*0Sstevel@tonic-gate } 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate if (is_for_loop($kids[$i])) { 1199*0Sstevel@tonic-gate $expr .= $self->for_loop($kids[$i], 0); 1200*0Sstevel@tonic-gate $expr .= ";\n" unless $i == $#kids; 1201*0Sstevel@tonic-gate print $self->indent($expr); 1202*0Sstevel@tonic-gate $i++; 1203*0Sstevel@tonic-gate next; 1204*0Sstevel@tonic-gate } 1205*0Sstevel@tonic-gate $expr .= $self->deparse($kids[$i], (@kids != 1)/2); 1206*0Sstevel@tonic-gate $expr =~ s/;\n?\z//; 1207*0Sstevel@tonic-gate $expr .= ";"; 1208*0Sstevel@tonic-gate print $self->indent($expr); 1209*0Sstevel@tonic-gate print "\n" unless $i == $#kids; 1210*0Sstevel@tonic-gate } 1211*0Sstevel@tonic-gate} 1212*0Sstevel@tonic-gate 1213*0Sstevel@tonic-gate# The BEGIN {} is used here because otherwise this code isn't executed 1214*0Sstevel@tonic-gate# when you run B::Deparse on itself. 1215*0Sstevel@tonic-gatemy %globalnames; 1216*0Sstevel@tonic-gateBEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC", 1217*0Sstevel@tonic-gate "ENV", "ARGV", "ARGVOUT", "_"); } 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gatesub gv_name { 1220*0Sstevel@tonic-gate my $self = shift; 1221*0Sstevel@tonic-gate my $gv = shift; 1222*0Sstevel@tonic-gateCarp::confess() unless ref($gv) eq "B::GV"; 1223*0Sstevel@tonic-gate my $stash = $gv->STASH->NAME; 1224*0Sstevel@tonic-gate my $name = $gv->SAFENAME; 1225*0Sstevel@tonic-gate if (($stash eq 'main' && $globalnames{$name}) 1226*0Sstevel@tonic-gate or ($stash eq $self->{'curstash'} && !$globalnames{$name}) 1227*0Sstevel@tonic-gate or $name =~ /^[^A-Za-z_]/) 1228*0Sstevel@tonic-gate { 1229*0Sstevel@tonic-gate $stash = ""; 1230*0Sstevel@tonic-gate } else { 1231*0Sstevel@tonic-gate $stash = $stash . "::"; 1232*0Sstevel@tonic-gate } 1233*0Sstevel@tonic-gate if ($name =~ /^(\^..|{)/) { 1234*0Sstevel@tonic-gate $name = "{$name}"; # ${^WARNING_BITS}, etc and ${ 1235*0Sstevel@tonic-gate } 1236*0Sstevel@tonic-gate return $stash . $name; 1237*0Sstevel@tonic-gate} 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate# Return the name to use for a stash variable. 1240*0Sstevel@tonic-gate# If a lexical with the same name is in scope, it may need to be 1241*0Sstevel@tonic-gate# fully-qualified. 1242*0Sstevel@tonic-gatesub stash_variable { 1243*0Sstevel@tonic-gate my ($self, $prefix, $name) = @_; 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate return "$prefix$name" if $name =~ /::/; 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate unless ($prefix eq '$' || $prefix eq '@' || #' 1248*0Sstevel@tonic-gate $prefix eq '%' || $prefix eq '$#') { 1249*0Sstevel@tonic-gate return "$prefix$name"; 1250*0Sstevel@tonic-gate } 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate my $v = ($prefix eq '$#' ? '@' : $prefix) . $name; 1253*0Sstevel@tonic-gate return $prefix .$self->{'curstash'}.'::'. $name if $self->lex_in_scope($v); 1254*0Sstevel@tonic-gate return "$prefix$name"; 1255*0Sstevel@tonic-gate} 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gatesub lex_in_scope { 1258*0Sstevel@tonic-gate my ($self, $name) = @_; 1259*0Sstevel@tonic-gate $self->populate_curcvlex() if !defined $self->{'curcvlex'}; 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate return 0 if !defined($self->{'curcop'}); 1262*0Sstevel@tonic-gate my $seq = $self->{'curcop'}->cop_seq; 1263*0Sstevel@tonic-gate return 0 if !exists $self->{'curcvlex'}{$name}; 1264*0Sstevel@tonic-gate for my $a (@{$self->{'curcvlex'}{$name}}) { 1265*0Sstevel@tonic-gate my ($st, $en) = @$a; 1266*0Sstevel@tonic-gate return 1 if $seq > $st && $seq <= $en; 1267*0Sstevel@tonic-gate } 1268*0Sstevel@tonic-gate return 0; 1269*0Sstevel@tonic-gate} 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gatesub populate_curcvlex { 1272*0Sstevel@tonic-gate my $self = shift; 1273*0Sstevel@tonic-gate for (my $cv = $self->{'curcv'}; class($cv) eq "CV"; $cv = $cv->OUTSIDE) { 1274*0Sstevel@tonic-gate my $padlist = $cv->PADLIST; 1275*0Sstevel@tonic-gate # an undef CV still in lexical chain 1276*0Sstevel@tonic-gate next if class($padlist) eq "SPECIAL"; 1277*0Sstevel@tonic-gate my @padlist = $padlist->ARRAY; 1278*0Sstevel@tonic-gate my @ns = $padlist[0]->ARRAY; 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate for (my $i=0; $i<@ns; ++$i) { 1281*0Sstevel@tonic-gate next if class($ns[$i]) eq "SPECIAL"; 1282*0Sstevel@tonic-gate next if $ns[$i]->FLAGS & SVpad_OUR; # Skip "our" vars 1283*0Sstevel@tonic-gate if (class($ns[$i]) eq "PV") { 1284*0Sstevel@tonic-gate # Probably that pesky lexical @_ 1285*0Sstevel@tonic-gate next; 1286*0Sstevel@tonic-gate } 1287*0Sstevel@tonic-gate my $name = $ns[$i]->PVX; 1288*0Sstevel@tonic-gate my ($seq_st, $seq_en) = 1289*0Sstevel@tonic-gate ($ns[$i]->FLAGS & SVf_FAKE) 1290*0Sstevel@tonic-gate ? (0, 999999) 1291*0Sstevel@tonic-gate : ($ns[$i]->NVX, $ns[$i]->IVX); 1292*0Sstevel@tonic-gate 1293*0Sstevel@tonic-gate push @{$self->{'curcvlex'}{$name}}, [$seq_st, $seq_en]; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate} 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gatesub find_scope_st { ((find_scope(@_))[0]); } 1299*0Sstevel@tonic-gatesub find_scope_en { ((find_scope(@_))[1]); } 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate# Recurses down the tree, looking for pad variable introductions and COPs 1302*0Sstevel@tonic-gatesub find_scope { 1303*0Sstevel@tonic-gate my ($self, $op, $scope_st, $scope_en) = @_; 1304*0Sstevel@tonic-gate carp("Undefined op in find_scope") if !defined $op; 1305*0Sstevel@tonic-gate return ($scope_st, $scope_en) unless $op->flags & OPf_KIDS; 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate for (my $o=$op->first; $$o; $o=$o->sibling) { 1308*0Sstevel@tonic-gate if ($o->name =~ /^pad.v$/ && $o->private & OPpLVAL_INTRO) { 1309*0Sstevel@tonic-gate my $s = int($self->padname_sv($o->targ)->NVX); 1310*0Sstevel@tonic-gate my $e = $self->padname_sv($o->targ)->IVX; 1311*0Sstevel@tonic-gate $scope_st = $s if !defined($scope_st) || $s < $scope_st; 1312*0Sstevel@tonic-gate $scope_en = $e if !defined($scope_en) || $e > $scope_en; 1313*0Sstevel@tonic-gate } 1314*0Sstevel@tonic-gate elsif (is_state($o)) { 1315*0Sstevel@tonic-gate my $c = $o->cop_seq; 1316*0Sstevel@tonic-gate $scope_st = $c if !defined($scope_st) || $c < $scope_st; 1317*0Sstevel@tonic-gate $scope_en = $c if !defined($scope_en) || $c > $scope_en; 1318*0Sstevel@tonic-gate } 1319*0Sstevel@tonic-gate elsif ($o->flags & OPf_KIDS) { 1320*0Sstevel@tonic-gate ($scope_st, $scope_en) = 1321*0Sstevel@tonic-gate $self->find_scope($o, $scope_st, $scope_en) 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate } 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate return ($scope_st, $scope_en); 1326*0Sstevel@tonic-gate} 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate# Returns a list of subs which should be inserted before the COP 1329*0Sstevel@tonic-gatesub cop_subs { 1330*0Sstevel@tonic-gate my ($self, $op, $out_seq) = @_; 1331*0Sstevel@tonic-gate my $seq = $op->cop_seq; 1332*0Sstevel@tonic-gate # If we have nephews, then our sequence number indicates 1333*0Sstevel@tonic-gate # the cop_seq of the end of some sort of scope. 1334*0Sstevel@tonic-gate if (class($op->sibling) ne "NULL" && $op->sibling->flags & OPf_KIDS 1335*0Sstevel@tonic-gate and my $nseq = $self->find_scope_st($op->sibling) ) { 1336*0Sstevel@tonic-gate $seq = $nseq; 1337*0Sstevel@tonic-gate } 1338*0Sstevel@tonic-gate $seq = $out_seq if defined($out_seq) && $out_seq < $seq; 1339*0Sstevel@tonic-gate return $self->seq_subs($seq); 1340*0Sstevel@tonic-gate} 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gatesub seq_subs { 1343*0Sstevel@tonic-gate my ($self, $seq) = @_; 1344*0Sstevel@tonic-gate my @text; 1345*0Sstevel@tonic-gate#push @text, "# ($seq)\n"; 1346*0Sstevel@tonic-gate 1347*0Sstevel@tonic-gate return "" if !defined $seq; 1348*0Sstevel@tonic-gate while (scalar(@{$self->{'subs_todo'}}) 1349*0Sstevel@tonic-gate and $seq > $self->{'subs_todo'}[0][0]) { 1350*0Sstevel@tonic-gate push @text, $self->next_todo; 1351*0Sstevel@tonic-gate } 1352*0Sstevel@tonic-gate return @text; 1353*0Sstevel@tonic-gate} 1354*0Sstevel@tonic-gate 1355*0Sstevel@tonic-gate# Notice how subs and formats are inserted between statements here; 1356*0Sstevel@tonic-gate# also $[ assignments and pragmas. 1357*0Sstevel@tonic-gatesub pp_nextstate { 1358*0Sstevel@tonic-gate my $self = shift; 1359*0Sstevel@tonic-gate my($op, $cx) = @_; 1360*0Sstevel@tonic-gate $self->{'curcop'} = $op; 1361*0Sstevel@tonic-gate my @text; 1362*0Sstevel@tonic-gate push @text, $self->cop_subs($op); 1363*0Sstevel@tonic-gate push @text, $op->label . ": " if $op->label; 1364*0Sstevel@tonic-gate my $stash = $op->stashpv; 1365*0Sstevel@tonic-gate if ($stash ne $self->{'curstash'}) { 1366*0Sstevel@tonic-gate push @text, "package $stash;\n"; 1367*0Sstevel@tonic-gate $self->{'curstash'} = $stash; 1368*0Sstevel@tonic-gate } 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate if ($self->{'arybase'} != $op->arybase) { 1371*0Sstevel@tonic-gate push @text, '$[ = '. $op->arybase .";\n"; 1372*0Sstevel@tonic-gate $self->{'arybase'} = $op->arybase; 1373*0Sstevel@tonic-gate } 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate my $warnings = $op->warnings; 1376*0Sstevel@tonic-gate my $warning_bits; 1377*0Sstevel@tonic-gate if ($warnings->isa("B::SPECIAL") && $$warnings == 4) { 1378*0Sstevel@tonic-gate $warning_bits = $warnings::Bits{"all"} & WARN_MASK; 1379*0Sstevel@tonic-gate } 1380*0Sstevel@tonic-gate elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) { 1381*0Sstevel@tonic-gate $warning_bits = $warnings::NONE; 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate elsif ($warnings->isa("B::SPECIAL")) { 1384*0Sstevel@tonic-gate $warning_bits = undef; 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate else { 1387*0Sstevel@tonic-gate $warning_bits = $warnings->PV & WARN_MASK; 1388*0Sstevel@tonic-gate } 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gate if (defined ($warning_bits) and 1391*0Sstevel@tonic-gate !defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) { 1392*0Sstevel@tonic-gate push @text, declare_warnings($self->{'warnings'}, $warning_bits); 1393*0Sstevel@tonic-gate $self->{'warnings'} = $warning_bits; 1394*0Sstevel@tonic-gate } 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate if ($self->{'hints'} != $op->private) { 1397*0Sstevel@tonic-gate push @text, declare_hints($self->{'hints'}, $op->private); 1398*0Sstevel@tonic-gate $self->{'hints'} = $op->private; 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate # This should go after of any branches that add statements, to 1402*0Sstevel@tonic-gate # increase the chances that it refers to the same line it did in 1403*0Sstevel@tonic-gate # the original program. 1404*0Sstevel@tonic-gate if ($self->{'linenums'}) { 1405*0Sstevel@tonic-gate push @text, "\f#line " . $op->line . 1406*0Sstevel@tonic-gate ' "' . $op->file, qq'"\n'; 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate return join("", @text); 1410*0Sstevel@tonic-gate} 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gatesub declare_warnings { 1413*0Sstevel@tonic-gate my ($from, $to) = @_; 1414*0Sstevel@tonic-gate if (($to & WARN_MASK) eq warnings::bits("all")) { 1415*0Sstevel@tonic-gate return "use warnings;\n"; 1416*0Sstevel@tonic-gate } 1417*0Sstevel@tonic-gate elsif (($to & WARN_MASK) eq "\0"x length($to)) { 1418*0Sstevel@tonic-gate return "no warnings;\n"; 1419*0Sstevel@tonic-gate } 1420*0Sstevel@tonic-gate return "BEGIN {\${^WARNING_BITS} = ".perlstring($to)."}\n"; 1421*0Sstevel@tonic-gate} 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gatesub declare_hints { 1424*0Sstevel@tonic-gate my ($from, $to) = @_; 1425*0Sstevel@tonic-gate my $use = $to & ~$from; 1426*0Sstevel@tonic-gate my $no = $from & ~$to; 1427*0Sstevel@tonic-gate my $decls = ""; 1428*0Sstevel@tonic-gate for my $pragma (hint_pragmas($use)) { 1429*0Sstevel@tonic-gate $decls .= "use $pragma;\n"; 1430*0Sstevel@tonic-gate } 1431*0Sstevel@tonic-gate for my $pragma (hint_pragmas($no)) { 1432*0Sstevel@tonic-gate $decls .= "no $pragma;\n"; 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate return $decls; 1435*0Sstevel@tonic-gate} 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gatesub hint_pragmas { 1438*0Sstevel@tonic-gate my ($bits) = @_; 1439*0Sstevel@tonic-gate my @pragmas; 1440*0Sstevel@tonic-gate push @pragmas, "integer" if $bits & 0x1; 1441*0Sstevel@tonic-gate push @pragmas, "strict 'refs'" if $bits & 0x2; 1442*0Sstevel@tonic-gate push @pragmas, "bytes" if $bits & 0x8; 1443*0Sstevel@tonic-gate return @pragmas; 1444*0Sstevel@tonic-gate} 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gatesub pp_dbstate { pp_nextstate(@_) } 1447*0Sstevel@tonic-gatesub pp_setstate { pp_nextstate(@_) } 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gatesub pp_unstack { return "" } # see also leaveloop 1450*0Sstevel@tonic-gate 1451*0Sstevel@tonic-gatesub baseop { 1452*0Sstevel@tonic-gate my $self = shift; 1453*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 1454*0Sstevel@tonic-gate return $name; 1455*0Sstevel@tonic-gate} 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gatesub pp_stub { 1458*0Sstevel@tonic-gate my $self = shift; 1459*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 1460*0Sstevel@tonic-gate if ($cx >= 1) { 1461*0Sstevel@tonic-gate return "()"; 1462*0Sstevel@tonic-gate } 1463*0Sstevel@tonic-gate else { 1464*0Sstevel@tonic-gate return "();"; 1465*0Sstevel@tonic-gate } 1466*0Sstevel@tonic-gate} 1467*0Sstevel@tonic-gatesub pp_wantarray { baseop(@_, "wantarray") } 1468*0Sstevel@tonic-gatesub pp_fork { baseop(@_, "fork") } 1469*0Sstevel@tonic-gatesub pp_wait { maybe_targmy(@_, \&baseop, "wait") } 1470*0Sstevel@tonic-gatesub pp_getppid { maybe_targmy(@_, \&baseop, "getppid") } 1471*0Sstevel@tonic-gatesub pp_time { maybe_targmy(@_, \&baseop, "time") } 1472*0Sstevel@tonic-gatesub pp_tms { baseop(@_, "times") } 1473*0Sstevel@tonic-gatesub pp_ghostent { baseop(@_, "gethostent") } 1474*0Sstevel@tonic-gatesub pp_gnetent { baseop(@_, "getnetent") } 1475*0Sstevel@tonic-gatesub pp_gprotoent { baseop(@_, "getprotoent") } 1476*0Sstevel@tonic-gatesub pp_gservent { baseop(@_, "getservent") } 1477*0Sstevel@tonic-gatesub pp_ehostent { baseop(@_, "endhostent") } 1478*0Sstevel@tonic-gatesub pp_enetent { baseop(@_, "endnetent") } 1479*0Sstevel@tonic-gatesub pp_eprotoent { baseop(@_, "endprotoent") } 1480*0Sstevel@tonic-gatesub pp_eservent { baseop(@_, "endservent") } 1481*0Sstevel@tonic-gatesub pp_gpwent { baseop(@_, "getpwent") } 1482*0Sstevel@tonic-gatesub pp_spwent { baseop(@_, "setpwent") } 1483*0Sstevel@tonic-gatesub pp_epwent { baseop(@_, "endpwent") } 1484*0Sstevel@tonic-gatesub pp_ggrent { baseop(@_, "getgrent") } 1485*0Sstevel@tonic-gatesub pp_sgrent { baseop(@_, "setgrent") } 1486*0Sstevel@tonic-gatesub pp_egrent { baseop(@_, "endgrent") } 1487*0Sstevel@tonic-gatesub pp_getlogin { baseop(@_, "getlogin") } 1488*0Sstevel@tonic-gate 1489*0Sstevel@tonic-gatesub POSTFIX () { 1 } 1490*0Sstevel@tonic-gate 1491*0Sstevel@tonic-gate# I couldn't think of a good short name, but this is the category of 1492*0Sstevel@tonic-gate# symbolic unary operators with interesting precedence 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gatesub pfixop { 1495*0Sstevel@tonic-gate my $self = shift; 1496*0Sstevel@tonic-gate my($op, $cx, $name, $prec, $flags) = (@_, 0); 1497*0Sstevel@tonic-gate my $kid = $op->first; 1498*0Sstevel@tonic-gate $kid = $self->deparse($kid, $prec); 1499*0Sstevel@tonic-gate return $self->maybe_parens(($flags & POSTFIX) ? "$kid$name" : "$name$kid", 1500*0Sstevel@tonic-gate $cx, $prec); 1501*0Sstevel@tonic-gate} 1502*0Sstevel@tonic-gate 1503*0Sstevel@tonic-gatesub pp_preinc { pfixop(@_, "++", 23) } 1504*0Sstevel@tonic-gatesub pp_predec { pfixop(@_, "--", 23) } 1505*0Sstevel@tonic-gatesub pp_postinc { maybe_targmy(@_, \&pfixop, "++", 23, POSTFIX) } 1506*0Sstevel@tonic-gatesub pp_postdec { maybe_targmy(@_, \&pfixop, "--", 23, POSTFIX) } 1507*0Sstevel@tonic-gatesub pp_i_preinc { pfixop(@_, "++", 23) } 1508*0Sstevel@tonic-gatesub pp_i_predec { pfixop(@_, "--", 23) } 1509*0Sstevel@tonic-gatesub pp_i_postinc { maybe_targmy(@_, \&pfixop, "++", 23, POSTFIX) } 1510*0Sstevel@tonic-gatesub pp_i_postdec { maybe_targmy(@_, \&pfixop, "--", 23, POSTFIX) } 1511*0Sstevel@tonic-gatesub pp_complement { maybe_targmy(@_, \&pfixop, "~", 21) } 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gatesub pp_negate { maybe_targmy(@_, \&real_negate) } 1514*0Sstevel@tonic-gatesub real_negate { 1515*0Sstevel@tonic-gate my $self = shift; 1516*0Sstevel@tonic-gate my($op, $cx) = @_; 1517*0Sstevel@tonic-gate if ($op->first->name =~ /^(i_)?negate$/) { 1518*0Sstevel@tonic-gate # avoid --$x 1519*0Sstevel@tonic-gate $self->pfixop($op, $cx, "-", 21.5); 1520*0Sstevel@tonic-gate } else { 1521*0Sstevel@tonic-gate $self->pfixop($op, $cx, "-", 21); 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate} 1524*0Sstevel@tonic-gatesub pp_i_negate { pp_negate(@_) } 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gatesub pp_not { 1527*0Sstevel@tonic-gate my $self = shift; 1528*0Sstevel@tonic-gate my($op, $cx) = @_; 1529*0Sstevel@tonic-gate if ($cx <= 4) { 1530*0Sstevel@tonic-gate $self->pfixop($op, $cx, "not ", 4); 1531*0Sstevel@tonic-gate } else { 1532*0Sstevel@tonic-gate $self->pfixop($op, $cx, "!", 21); 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate} 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gatesub unop { 1537*0Sstevel@tonic-gate my $self = shift; 1538*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 1539*0Sstevel@tonic-gate my $kid; 1540*0Sstevel@tonic-gate if ($op->flags & OPf_KIDS) { 1541*0Sstevel@tonic-gate $kid = $op->first; 1542*0Sstevel@tonic-gate if (defined prototype("CORE::$name") 1543*0Sstevel@tonic-gate && prototype("CORE::$name") =~ /^;?\*/ 1544*0Sstevel@tonic-gate && $kid->name eq "rv2gv") { 1545*0Sstevel@tonic-gate $kid = $kid->first; 1546*0Sstevel@tonic-gate } 1547*0Sstevel@tonic-gate 1548*0Sstevel@tonic-gate return $self->maybe_parens_unop($name, $kid, $cx); 1549*0Sstevel@tonic-gate } else { 1550*0Sstevel@tonic-gate return $name . ($op->flags & OPf_SPECIAL ? "()" : ""); 1551*0Sstevel@tonic-gate } 1552*0Sstevel@tonic-gate} 1553*0Sstevel@tonic-gate 1554*0Sstevel@tonic-gatesub pp_chop { maybe_targmy(@_, \&unop, "chop") } 1555*0Sstevel@tonic-gatesub pp_chomp { maybe_targmy(@_, \&unop, "chomp") } 1556*0Sstevel@tonic-gatesub pp_schop { maybe_targmy(@_, \&unop, "chop") } 1557*0Sstevel@tonic-gatesub pp_schomp { maybe_targmy(@_, \&unop, "chomp") } 1558*0Sstevel@tonic-gatesub pp_defined { unop(@_, "defined") } 1559*0Sstevel@tonic-gatesub pp_undef { unop(@_, "undef") } 1560*0Sstevel@tonic-gatesub pp_study { unop(@_, "study") } 1561*0Sstevel@tonic-gatesub pp_ref { unop(@_, "ref") } 1562*0Sstevel@tonic-gatesub pp_pos { maybe_local(@_, unop(@_, "pos")) } 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gatesub pp_sin { maybe_targmy(@_, \&unop, "sin") } 1565*0Sstevel@tonic-gatesub pp_cos { maybe_targmy(@_, \&unop, "cos") } 1566*0Sstevel@tonic-gatesub pp_rand { maybe_targmy(@_, \&unop, "rand") } 1567*0Sstevel@tonic-gatesub pp_srand { unop(@_, "srand") } 1568*0Sstevel@tonic-gatesub pp_exp { maybe_targmy(@_, \&unop, "exp") } 1569*0Sstevel@tonic-gatesub pp_log { maybe_targmy(@_, \&unop, "log") } 1570*0Sstevel@tonic-gatesub pp_sqrt { maybe_targmy(@_, \&unop, "sqrt") } 1571*0Sstevel@tonic-gatesub pp_int { maybe_targmy(@_, \&unop, "int") } 1572*0Sstevel@tonic-gatesub pp_hex { maybe_targmy(@_, \&unop, "hex") } 1573*0Sstevel@tonic-gatesub pp_oct { maybe_targmy(@_, \&unop, "oct") } 1574*0Sstevel@tonic-gatesub pp_abs { maybe_targmy(@_, \&unop, "abs") } 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gatesub pp_length { maybe_targmy(@_, \&unop, "length") } 1577*0Sstevel@tonic-gatesub pp_ord { maybe_targmy(@_, \&unop, "ord") } 1578*0Sstevel@tonic-gatesub pp_chr { maybe_targmy(@_, \&unop, "chr") } 1579*0Sstevel@tonic-gate 1580*0Sstevel@tonic-gatesub pp_each { unop(@_, "each") } 1581*0Sstevel@tonic-gatesub pp_values { unop(@_, "values") } 1582*0Sstevel@tonic-gatesub pp_keys { unop(@_, "keys") } 1583*0Sstevel@tonic-gatesub pp_pop { unop(@_, "pop") } 1584*0Sstevel@tonic-gatesub pp_shift { unop(@_, "shift") } 1585*0Sstevel@tonic-gate 1586*0Sstevel@tonic-gatesub pp_caller { unop(@_, "caller") } 1587*0Sstevel@tonic-gatesub pp_reset { unop(@_, "reset") } 1588*0Sstevel@tonic-gatesub pp_exit { unop(@_, "exit") } 1589*0Sstevel@tonic-gatesub pp_prototype { unop(@_, "prototype") } 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gatesub pp_close { unop(@_, "close") } 1592*0Sstevel@tonic-gatesub pp_fileno { unop(@_, "fileno") } 1593*0Sstevel@tonic-gatesub pp_umask { unop(@_, "umask") } 1594*0Sstevel@tonic-gatesub pp_untie { unop(@_, "untie") } 1595*0Sstevel@tonic-gatesub pp_tied { unop(@_, "tied") } 1596*0Sstevel@tonic-gatesub pp_dbmclose { unop(@_, "dbmclose") } 1597*0Sstevel@tonic-gatesub pp_getc { unop(@_, "getc") } 1598*0Sstevel@tonic-gatesub pp_eof { unop(@_, "eof") } 1599*0Sstevel@tonic-gatesub pp_tell { unop(@_, "tell") } 1600*0Sstevel@tonic-gatesub pp_getsockname { unop(@_, "getsockname") } 1601*0Sstevel@tonic-gatesub pp_getpeername { unop(@_, "getpeername") } 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gatesub pp_chdir { maybe_targmy(@_, \&unop, "chdir") } 1604*0Sstevel@tonic-gatesub pp_chroot { maybe_targmy(@_, \&unop, "chroot") } 1605*0Sstevel@tonic-gatesub pp_readlink { unop(@_, "readlink") } 1606*0Sstevel@tonic-gatesub pp_rmdir { maybe_targmy(@_, \&unop, "rmdir") } 1607*0Sstevel@tonic-gatesub pp_readdir { unop(@_, "readdir") } 1608*0Sstevel@tonic-gatesub pp_telldir { unop(@_, "telldir") } 1609*0Sstevel@tonic-gatesub pp_rewinddir { unop(@_, "rewinddir") } 1610*0Sstevel@tonic-gatesub pp_closedir { unop(@_, "closedir") } 1611*0Sstevel@tonic-gatesub pp_getpgrp { maybe_targmy(@_, \&unop, "getpgrp") } 1612*0Sstevel@tonic-gatesub pp_localtime { unop(@_, "localtime") } 1613*0Sstevel@tonic-gatesub pp_gmtime { unop(@_, "gmtime") } 1614*0Sstevel@tonic-gatesub pp_alarm { unop(@_, "alarm") } 1615*0Sstevel@tonic-gatesub pp_sleep { maybe_targmy(@_, \&unop, "sleep") } 1616*0Sstevel@tonic-gate 1617*0Sstevel@tonic-gatesub pp_dofile { unop(@_, "do") } 1618*0Sstevel@tonic-gatesub pp_entereval { unop(@_, "eval") } 1619*0Sstevel@tonic-gate 1620*0Sstevel@tonic-gatesub pp_ghbyname { unop(@_, "gethostbyname") } 1621*0Sstevel@tonic-gatesub pp_gnbyname { unop(@_, "getnetbyname") } 1622*0Sstevel@tonic-gatesub pp_gpbyname { unop(@_, "getprotobyname") } 1623*0Sstevel@tonic-gatesub pp_shostent { unop(@_, "sethostent") } 1624*0Sstevel@tonic-gatesub pp_snetent { unop(@_, "setnetent") } 1625*0Sstevel@tonic-gatesub pp_sprotoent { unop(@_, "setprotoent") } 1626*0Sstevel@tonic-gatesub pp_sservent { unop(@_, "setservent") } 1627*0Sstevel@tonic-gatesub pp_gpwnam { unop(@_, "getpwnam") } 1628*0Sstevel@tonic-gatesub pp_gpwuid { unop(@_, "getpwuid") } 1629*0Sstevel@tonic-gatesub pp_ggrnam { unop(@_, "getgrnam") } 1630*0Sstevel@tonic-gatesub pp_ggrgid { unop(@_, "getgrgid") } 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gatesub pp_lock { unop(@_, "lock") } 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gatesub pp_exists { 1635*0Sstevel@tonic-gate my $self = shift; 1636*0Sstevel@tonic-gate my($op, $cx) = @_; 1637*0Sstevel@tonic-gate my $arg; 1638*0Sstevel@tonic-gate if ($op->private & OPpEXISTS_SUB) { 1639*0Sstevel@tonic-gate # Checking for the existence of a subroutine 1640*0Sstevel@tonic-gate return $self->maybe_parens_func("exists", 1641*0Sstevel@tonic-gate $self->pp_rv2cv($op->first, 16), $cx, 16); 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate if ($op->flags & OPf_SPECIAL) { 1644*0Sstevel@tonic-gate # Array element, not hash element 1645*0Sstevel@tonic-gate return $self->maybe_parens_func("exists", 1646*0Sstevel@tonic-gate $self->pp_aelem($op->first, 16), $cx, 16); 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate return $self->maybe_parens_func("exists", $self->pp_helem($op->first, 16), 1649*0Sstevel@tonic-gate $cx, 16); 1650*0Sstevel@tonic-gate} 1651*0Sstevel@tonic-gate 1652*0Sstevel@tonic-gatesub pp_delete { 1653*0Sstevel@tonic-gate my $self = shift; 1654*0Sstevel@tonic-gate my($op, $cx) = @_; 1655*0Sstevel@tonic-gate my $arg; 1656*0Sstevel@tonic-gate if ($op->private & OPpSLICE) { 1657*0Sstevel@tonic-gate if ($op->flags & OPf_SPECIAL) { 1658*0Sstevel@tonic-gate # Deleting from an array, not a hash 1659*0Sstevel@tonic-gate return $self->maybe_parens_func("delete", 1660*0Sstevel@tonic-gate $self->pp_aslice($op->first, 16), 1661*0Sstevel@tonic-gate $cx, 16); 1662*0Sstevel@tonic-gate } 1663*0Sstevel@tonic-gate return $self->maybe_parens_func("delete", 1664*0Sstevel@tonic-gate $self->pp_hslice($op->first, 16), 1665*0Sstevel@tonic-gate $cx, 16); 1666*0Sstevel@tonic-gate } else { 1667*0Sstevel@tonic-gate if ($op->flags & OPf_SPECIAL) { 1668*0Sstevel@tonic-gate # Deleting from an array, not a hash 1669*0Sstevel@tonic-gate return $self->maybe_parens_func("delete", 1670*0Sstevel@tonic-gate $self->pp_aelem($op->first, 16), 1671*0Sstevel@tonic-gate $cx, 16); 1672*0Sstevel@tonic-gate } 1673*0Sstevel@tonic-gate return $self->maybe_parens_func("delete", 1674*0Sstevel@tonic-gate $self->pp_helem($op->first, 16), 1675*0Sstevel@tonic-gate $cx, 16); 1676*0Sstevel@tonic-gate } 1677*0Sstevel@tonic-gate} 1678*0Sstevel@tonic-gate 1679*0Sstevel@tonic-gatesub pp_require { 1680*0Sstevel@tonic-gate my $self = shift; 1681*0Sstevel@tonic-gate my($op, $cx) = @_; 1682*0Sstevel@tonic-gate if (class($op) eq "UNOP" and $op->first->name eq "const" 1683*0Sstevel@tonic-gate and $op->first->private & OPpCONST_BARE) 1684*0Sstevel@tonic-gate { 1685*0Sstevel@tonic-gate my $name = $self->const_sv($op->first)->PV; 1686*0Sstevel@tonic-gate $name =~ s[/][::]g; 1687*0Sstevel@tonic-gate $name =~ s/\.pm//g; 1688*0Sstevel@tonic-gate return "require $name"; 1689*0Sstevel@tonic-gate } else { 1690*0Sstevel@tonic-gate $self->unop($op, $cx, "require"); 1691*0Sstevel@tonic-gate } 1692*0Sstevel@tonic-gate} 1693*0Sstevel@tonic-gate 1694*0Sstevel@tonic-gatesub pp_scalar { 1695*0Sstevel@tonic-gate my $self = shift; 1696*0Sstevel@tonic-gate my($op, $cv) = @_; 1697*0Sstevel@tonic-gate my $kid = $op->first; 1698*0Sstevel@tonic-gate if (not null $kid->sibling) { 1699*0Sstevel@tonic-gate # XXX Was a here-doc 1700*0Sstevel@tonic-gate return $self->dquote($op); 1701*0Sstevel@tonic-gate } 1702*0Sstevel@tonic-gate $self->unop(@_, "scalar"); 1703*0Sstevel@tonic-gate} 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gatesub padval { 1707*0Sstevel@tonic-gate my $self = shift; 1708*0Sstevel@tonic-gate my $targ = shift; 1709*0Sstevel@tonic-gate return $self->{'curcv'}->PADLIST->ARRAYelt(1)->ARRAYelt($targ); 1710*0Sstevel@tonic-gate} 1711*0Sstevel@tonic-gate 1712*0Sstevel@tonic-gatesub pp_refgen { 1713*0Sstevel@tonic-gate my $self = shift; 1714*0Sstevel@tonic-gate my($op, $cx) = @_; 1715*0Sstevel@tonic-gate my $kid = $op->first; 1716*0Sstevel@tonic-gate if ($kid->name eq "null") { 1717*0Sstevel@tonic-gate $kid = $kid->first; 1718*0Sstevel@tonic-gate if ($kid->name eq "anonlist" || $kid->name eq "anonhash") { 1719*0Sstevel@tonic-gate my($pre, $post) = @{{"anonlist" => ["[","]"], 1720*0Sstevel@tonic-gate "anonhash" => ["{","}"]}->{$kid->name}}; 1721*0Sstevel@tonic-gate my($expr, @exprs); 1722*0Sstevel@tonic-gate $kid = $kid->first->sibling; # skip pushmark 1723*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 1724*0Sstevel@tonic-gate $expr = $self->deparse($kid, 6); 1725*0Sstevel@tonic-gate push @exprs, $expr; 1726*0Sstevel@tonic-gate } 1727*0Sstevel@tonic-gate return $pre . join(", ", @exprs) . $post; 1728*0Sstevel@tonic-gate } elsif (!null($kid->sibling) and 1729*0Sstevel@tonic-gate $kid->sibling->name eq "anoncode") { 1730*0Sstevel@tonic-gate return "sub " . 1731*0Sstevel@tonic-gate $self->deparse_sub($self->padval($kid->sibling->targ)); 1732*0Sstevel@tonic-gate } elsif ($kid->name eq "pushmark") { 1733*0Sstevel@tonic-gate my $sib_name = $kid->sibling->name; 1734*0Sstevel@tonic-gate if ($sib_name =~ /^(pad|rv2)[ah]v$/ 1735*0Sstevel@tonic-gate and not $kid->sibling->flags & OPf_REF) 1736*0Sstevel@tonic-gate { 1737*0Sstevel@tonic-gate # The @a in \(@a) isn't in ref context, but only when the 1738*0Sstevel@tonic-gate # parens are there. 1739*0Sstevel@tonic-gate return "\\(" . $self->pp_list($op->first) . ")"; 1740*0Sstevel@tonic-gate } elsif ($sib_name eq 'entersub') { 1741*0Sstevel@tonic-gate my $text = $self->deparse($kid->sibling, 1); 1742*0Sstevel@tonic-gate # Always show parens for \(&func()), but only with -p otherwise 1743*0Sstevel@tonic-gate $text = "($text)" if $self->{'parens'} 1744*0Sstevel@tonic-gate or $kid->sibling->private & OPpENTERSUB_AMPER; 1745*0Sstevel@tonic-gate return "\\$text"; 1746*0Sstevel@tonic-gate } 1747*0Sstevel@tonic-gate } 1748*0Sstevel@tonic-gate } 1749*0Sstevel@tonic-gate $self->pfixop($op, $cx, "\\", 20); 1750*0Sstevel@tonic-gate} 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gatesub pp_srefgen { pp_refgen(@_) } 1753*0Sstevel@tonic-gate 1754*0Sstevel@tonic-gatesub pp_readline { 1755*0Sstevel@tonic-gate my $self = shift; 1756*0Sstevel@tonic-gate my($op, $cx) = @_; 1757*0Sstevel@tonic-gate my $kid = $op->first; 1758*0Sstevel@tonic-gate $kid = $kid->first if $kid->name eq "rv2gv"; # <$fh> 1759*0Sstevel@tonic-gate return "<" . $self->deparse($kid, 1) . ">" if is_scalar($kid); 1760*0Sstevel@tonic-gate return $self->unop($op, $cx, "readline"); 1761*0Sstevel@tonic-gate} 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gatesub pp_rcatline { 1764*0Sstevel@tonic-gate my $self = shift; 1765*0Sstevel@tonic-gate my($op) = @_; 1766*0Sstevel@tonic-gate return "<" . $self->gv_name($self->gv_or_padgv($op)) . ">"; 1767*0Sstevel@tonic-gate} 1768*0Sstevel@tonic-gate 1769*0Sstevel@tonic-gate# Unary operators that can occur as pseudo-listops inside double quotes 1770*0Sstevel@tonic-gatesub dq_unop { 1771*0Sstevel@tonic-gate my $self = shift; 1772*0Sstevel@tonic-gate my($op, $cx, $name, $prec, $flags) = (@_, 0, 0); 1773*0Sstevel@tonic-gate my $kid; 1774*0Sstevel@tonic-gate if ($op->flags & OPf_KIDS) { 1775*0Sstevel@tonic-gate $kid = $op->first; 1776*0Sstevel@tonic-gate # If there's more than one kid, the first is an ex-pushmark. 1777*0Sstevel@tonic-gate $kid = $kid->sibling if not null $kid->sibling; 1778*0Sstevel@tonic-gate return $self->maybe_parens_unop($name, $kid, $cx); 1779*0Sstevel@tonic-gate } else { 1780*0Sstevel@tonic-gate return $name . ($op->flags & OPf_SPECIAL ? "()" : ""); 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate} 1783*0Sstevel@tonic-gate 1784*0Sstevel@tonic-gatesub pp_ucfirst { dq_unop(@_, "ucfirst") } 1785*0Sstevel@tonic-gatesub pp_lcfirst { dq_unop(@_, "lcfirst") } 1786*0Sstevel@tonic-gatesub pp_uc { dq_unop(@_, "uc") } 1787*0Sstevel@tonic-gatesub pp_lc { dq_unop(@_, "lc") } 1788*0Sstevel@tonic-gatesub pp_quotemeta { maybe_targmy(@_, \&dq_unop, "quotemeta") } 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gatesub loopex { 1791*0Sstevel@tonic-gate my $self = shift; 1792*0Sstevel@tonic-gate my ($op, $cx, $name) = @_; 1793*0Sstevel@tonic-gate if (class($op) eq "PVOP") { 1794*0Sstevel@tonic-gate return "$name " . $op->pv; 1795*0Sstevel@tonic-gate } elsif (class($op) eq "OP") { 1796*0Sstevel@tonic-gate return $name; 1797*0Sstevel@tonic-gate } elsif (class($op) eq "UNOP") { 1798*0Sstevel@tonic-gate # Note -- loop exits are actually exempt from the 1799*0Sstevel@tonic-gate # looks-like-a-func rule, but a few extra parens won't hurt 1800*0Sstevel@tonic-gate return $self->maybe_parens_unop($name, $op->first, $cx); 1801*0Sstevel@tonic-gate } 1802*0Sstevel@tonic-gate} 1803*0Sstevel@tonic-gate 1804*0Sstevel@tonic-gatesub pp_last { loopex(@_, "last") } 1805*0Sstevel@tonic-gatesub pp_next { loopex(@_, "next") } 1806*0Sstevel@tonic-gatesub pp_redo { loopex(@_, "redo") } 1807*0Sstevel@tonic-gatesub pp_goto { loopex(@_, "goto") } 1808*0Sstevel@tonic-gatesub pp_dump { loopex(@_, "dump") } 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gatesub ftst { 1811*0Sstevel@tonic-gate my $self = shift; 1812*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 1813*0Sstevel@tonic-gate if (class($op) eq "UNOP") { 1814*0Sstevel@tonic-gate # Genuine `-X' filetests are exempt from the LLAFR, but not 1815*0Sstevel@tonic-gate # l?stat(); for the sake of clarity, give'em all parens 1816*0Sstevel@tonic-gate return $self->maybe_parens_unop($name, $op->first, $cx); 1817*0Sstevel@tonic-gate } elsif (class($op) =~ /^(SV|PAD)OP$/) { 1818*0Sstevel@tonic-gate return $self->maybe_parens_func($name, $self->pp_gv($op, 1), $cx, 16); 1819*0Sstevel@tonic-gate } else { # I don't think baseop filetests ever survive ck_ftst, but... 1820*0Sstevel@tonic-gate return $name; 1821*0Sstevel@tonic-gate } 1822*0Sstevel@tonic-gate} 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gatesub pp_lstat { ftst(@_, "lstat") } 1825*0Sstevel@tonic-gatesub pp_stat { ftst(@_, "stat") } 1826*0Sstevel@tonic-gatesub pp_ftrread { ftst(@_, "-R") } 1827*0Sstevel@tonic-gatesub pp_ftrwrite { ftst(@_, "-W") } 1828*0Sstevel@tonic-gatesub pp_ftrexec { ftst(@_, "-X") } 1829*0Sstevel@tonic-gatesub pp_fteread { ftst(@_, "-r") } 1830*0Sstevel@tonic-gatesub pp_ftewrite { ftst(@_, "-w") } 1831*0Sstevel@tonic-gatesub pp_fteexec { ftst(@_, "-x") } 1832*0Sstevel@tonic-gatesub pp_ftis { ftst(@_, "-e") } 1833*0Sstevel@tonic-gatesub pp_fteowned { ftst(@_, "-O") } 1834*0Sstevel@tonic-gatesub pp_ftrowned { ftst(@_, "-o") } 1835*0Sstevel@tonic-gatesub pp_ftzero { ftst(@_, "-z") } 1836*0Sstevel@tonic-gatesub pp_ftsize { ftst(@_, "-s") } 1837*0Sstevel@tonic-gatesub pp_ftmtime { ftst(@_, "-M") } 1838*0Sstevel@tonic-gatesub pp_ftatime { ftst(@_, "-A") } 1839*0Sstevel@tonic-gatesub pp_ftctime { ftst(@_, "-C") } 1840*0Sstevel@tonic-gatesub pp_ftsock { ftst(@_, "-S") } 1841*0Sstevel@tonic-gatesub pp_ftchr { ftst(@_, "-c") } 1842*0Sstevel@tonic-gatesub pp_ftblk { ftst(@_, "-b") } 1843*0Sstevel@tonic-gatesub pp_ftfile { ftst(@_, "-f") } 1844*0Sstevel@tonic-gatesub pp_ftdir { ftst(@_, "-d") } 1845*0Sstevel@tonic-gatesub pp_ftpipe { ftst(@_, "-p") } 1846*0Sstevel@tonic-gatesub pp_ftlink { ftst(@_, "-l") } 1847*0Sstevel@tonic-gatesub pp_ftsuid { ftst(@_, "-u") } 1848*0Sstevel@tonic-gatesub pp_ftsgid { ftst(@_, "-g") } 1849*0Sstevel@tonic-gatesub pp_ftsvtx { ftst(@_, "-k") } 1850*0Sstevel@tonic-gatesub pp_fttty { ftst(@_, "-t") } 1851*0Sstevel@tonic-gatesub pp_fttext { ftst(@_, "-T") } 1852*0Sstevel@tonic-gatesub pp_ftbinary { ftst(@_, "-B") } 1853*0Sstevel@tonic-gate 1854*0Sstevel@tonic-gatesub SWAP_CHILDREN () { 1 } 1855*0Sstevel@tonic-gatesub ASSIGN () { 2 } # has OP= variant 1856*0Sstevel@tonic-gatesub LIST_CONTEXT () { 4 } # Assignment is in list context 1857*0Sstevel@tonic-gate 1858*0Sstevel@tonic-gatemy(%left, %right); 1859*0Sstevel@tonic-gate 1860*0Sstevel@tonic-gatesub assoc_class { 1861*0Sstevel@tonic-gate my $op = shift; 1862*0Sstevel@tonic-gate my $name = $op->name; 1863*0Sstevel@tonic-gate if ($name eq "concat" and $op->first->name eq "concat") { 1864*0Sstevel@tonic-gate # avoid spurious `=' -- see comment in pp_concat 1865*0Sstevel@tonic-gate return "concat"; 1866*0Sstevel@tonic-gate } 1867*0Sstevel@tonic-gate if ($name eq "null" and class($op) eq "UNOP" 1868*0Sstevel@tonic-gate and $op->first->name =~ /^(and|x?or)$/ 1869*0Sstevel@tonic-gate and null $op->first->sibling) 1870*0Sstevel@tonic-gate { 1871*0Sstevel@tonic-gate # Like all conditional constructs, OP_ANDs and OP_ORs are topped 1872*0Sstevel@tonic-gate # with a null that's used as the common end point of the two 1873*0Sstevel@tonic-gate # flows of control. For precedence purposes, ignore it. 1874*0Sstevel@tonic-gate # (COND_EXPRs have these too, but we don't bother with 1875*0Sstevel@tonic-gate # their associativity). 1876*0Sstevel@tonic-gate return assoc_class($op->first); 1877*0Sstevel@tonic-gate } 1878*0Sstevel@tonic-gate return $name . ($op->flags & OPf_STACKED ? "=" : ""); 1879*0Sstevel@tonic-gate} 1880*0Sstevel@tonic-gate 1881*0Sstevel@tonic-gate# Left associative operators, like `+', for which 1882*0Sstevel@tonic-gate# $a + $b + $c is equivalent to ($a + $b) + $c 1883*0Sstevel@tonic-gate 1884*0Sstevel@tonic-gateBEGIN { 1885*0Sstevel@tonic-gate %left = ('multiply' => 19, 'i_multiply' => 19, 1886*0Sstevel@tonic-gate 'divide' => 19, 'i_divide' => 19, 1887*0Sstevel@tonic-gate 'modulo' => 19, 'i_modulo' => 19, 1888*0Sstevel@tonic-gate 'repeat' => 19, 1889*0Sstevel@tonic-gate 'add' => 18, 'i_add' => 18, 1890*0Sstevel@tonic-gate 'subtract' => 18, 'i_subtract' => 18, 1891*0Sstevel@tonic-gate 'concat' => 18, 1892*0Sstevel@tonic-gate 'left_shift' => 17, 'right_shift' => 17, 1893*0Sstevel@tonic-gate 'bit_and' => 13, 1894*0Sstevel@tonic-gate 'bit_or' => 12, 'bit_xor' => 12, 1895*0Sstevel@tonic-gate 'and' => 3, 1896*0Sstevel@tonic-gate 'or' => 2, 'xor' => 2, 1897*0Sstevel@tonic-gate ); 1898*0Sstevel@tonic-gate} 1899*0Sstevel@tonic-gate 1900*0Sstevel@tonic-gatesub deparse_binop_left { 1901*0Sstevel@tonic-gate my $self = shift; 1902*0Sstevel@tonic-gate my($op, $left, $prec) = @_; 1903*0Sstevel@tonic-gate if ($left{assoc_class($op)} && $left{assoc_class($left)} 1904*0Sstevel@tonic-gate and $left{assoc_class($op)} == $left{assoc_class($left)}) 1905*0Sstevel@tonic-gate { 1906*0Sstevel@tonic-gate return $self->deparse($left, $prec - .00001); 1907*0Sstevel@tonic-gate } else { 1908*0Sstevel@tonic-gate return $self->deparse($left, $prec); 1909*0Sstevel@tonic-gate } 1910*0Sstevel@tonic-gate} 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate# Right associative operators, like `=', for which 1913*0Sstevel@tonic-gate# $a = $b = $c is equivalent to $a = ($b = $c) 1914*0Sstevel@tonic-gate 1915*0Sstevel@tonic-gateBEGIN { 1916*0Sstevel@tonic-gate %right = ('pow' => 22, 1917*0Sstevel@tonic-gate 'sassign=' => 7, 'aassign=' => 7, 1918*0Sstevel@tonic-gate 'multiply=' => 7, 'i_multiply=' => 7, 1919*0Sstevel@tonic-gate 'divide=' => 7, 'i_divide=' => 7, 1920*0Sstevel@tonic-gate 'modulo=' => 7, 'i_modulo=' => 7, 1921*0Sstevel@tonic-gate 'repeat=' => 7, 1922*0Sstevel@tonic-gate 'add=' => 7, 'i_add=' => 7, 1923*0Sstevel@tonic-gate 'subtract=' => 7, 'i_subtract=' => 7, 1924*0Sstevel@tonic-gate 'concat=' => 7, 1925*0Sstevel@tonic-gate 'left_shift=' => 7, 'right_shift=' => 7, 1926*0Sstevel@tonic-gate 'bit_and=' => 7, 1927*0Sstevel@tonic-gate 'bit_or=' => 7, 'bit_xor=' => 7, 1928*0Sstevel@tonic-gate 'andassign' => 7, 1929*0Sstevel@tonic-gate 'orassign' => 7, 1930*0Sstevel@tonic-gate ); 1931*0Sstevel@tonic-gate} 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gatesub deparse_binop_right { 1934*0Sstevel@tonic-gate my $self = shift; 1935*0Sstevel@tonic-gate my($op, $right, $prec) = @_; 1936*0Sstevel@tonic-gate if ($right{assoc_class($op)} && $right{assoc_class($right)} 1937*0Sstevel@tonic-gate and $right{assoc_class($op)} == $right{assoc_class($right)}) 1938*0Sstevel@tonic-gate { 1939*0Sstevel@tonic-gate return $self->deparse($right, $prec - .00001); 1940*0Sstevel@tonic-gate } else { 1941*0Sstevel@tonic-gate return $self->deparse($right, $prec); 1942*0Sstevel@tonic-gate } 1943*0Sstevel@tonic-gate} 1944*0Sstevel@tonic-gate 1945*0Sstevel@tonic-gatesub binop { 1946*0Sstevel@tonic-gate my $self = shift; 1947*0Sstevel@tonic-gate my ($op, $cx, $opname, $prec, $flags) = (@_, 0); 1948*0Sstevel@tonic-gate my $left = $op->first; 1949*0Sstevel@tonic-gate my $right = $op->last; 1950*0Sstevel@tonic-gate my $eq = ""; 1951*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED && $flags & ASSIGN) { 1952*0Sstevel@tonic-gate $eq = "="; 1953*0Sstevel@tonic-gate $prec = 7; 1954*0Sstevel@tonic-gate } 1955*0Sstevel@tonic-gate if ($flags & SWAP_CHILDREN) { 1956*0Sstevel@tonic-gate ($left, $right) = ($right, $left); 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate $left = $self->deparse_binop_left($op, $left, $prec); 1959*0Sstevel@tonic-gate $left = "($left)" if $flags & LIST_CONTEXT 1960*0Sstevel@tonic-gate && $left !~ /^(my|our|local|)[\@\(]/; 1961*0Sstevel@tonic-gate $right = $self->deparse_binop_right($op, $right, $prec); 1962*0Sstevel@tonic-gate return $self->maybe_parens("$left $opname$eq $right", $cx, $prec); 1963*0Sstevel@tonic-gate} 1964*0Sstevel@tonic-gate 1965*0Sstevel@tonic-gatesub pp_add { maybe_targmy(@_, \&binop, "+", 18, ASSIGN) } 1966*0Sstevel@tonic-gatesub pp_multiply { maybe_targmy(@_, \&binop, "*", 19, ASSIGN) } 1967*0Sstevel@tonic-gatesub pp_subtract { maybe_targmy(@_, \&binop, "-",18, ASSIGN) } 1968*0Sstevel@tonic-gatesub pp_divide { maybe_targmy(@_, \&binop, "/", 19, ASSIGN) } 1969*0Sstevel@tonic-gatesub pp_modulo { maybe_targmy(@_, \&binop, "%", 19, ASSIGN) } 1970*0Sstevel@tonic-gatesub pp_i_add { maybe_targmy(@_, \&binop, "+", 18, ASSIGN) } 1971*0Sstevel@tonic-gatesub pp_i_multiply { maybe_targmy(@_, \&binop, "*", 19, ASSIGN) } 1972*0Sstevel@tonic-gatesub pp_i_subtract { maybe_targmy(@_, \&binop, "-", 18, ASSIGN) } 1973*0Sstevel@tonic-gatesub pp_i_divide { maybe_targmy(@_, \&binop, "/", 19, ASSIGN) } 1974*0Sstevel@tonic-gatesub pp_i_modulo { maybe_targmy(@_, \&binop, "%", 19, ASSIGN) } 1975*0Sstevel@tonic-gatesub pp_pow { maybe_targmy(@_, \&binop, "**", 22, ASSIGN) } 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gatesub pp_left_shift { maybe_targmy(@_, \&binop, "<<", 17, ASSIGN) } 1978*0Sstevel@tonic-gatesub pp_right_shift { maybe_targmy(@_, \&binop, ">>", 17, ASSIGN) } 1979*0Sstevel@tonic-gatesub pp_bit_and { maybe_targmy(@_, \&binop, "&", 13, ASSIGN) } 1980*0Sstevel@tonic-gatesub pp_bit_or { maybe_targmy(@_, \&binop, "|", 12, ASSIGN) } 1981*0Sstevel@tonic-gatesub pp_bit_xor { maybe_targmy(@_, \&binop, "^", 12, ASSIGN) } 1982*0Sstevel@tonic-gate 1983*0Sstevel@tonic-gatesub pp_eq { binop(@_, "==", 14) } 1984*0Sstevel@tonic-gatesub pp_ne { binop(@_, "!=", 14) } 1985*0Sstevel@tonic-gatesub pp_lt { binop(@_, "<", 15) } 1986*0Sstevel@tonic-gatesub pp_gt { binop(@_, ">", 15) } 1987*0Sstevel@tonic-gatesub pp_ge { binop(@_, ">=", 15) } 1988*0Sstevel@tonic-gatesub pp_le { binop(@_, "<=", 15) } 1989*0Sstevel@tonic-gatesub pp_ncmp { binop(@_, "<=>", 14) } 1990*0Sstevel@tonic-gatesub pp_i_eq { binop(@_, "==", 14) } 1991*0Sstevel@tonic-gatesub pp_i_ne { binop(@_, "!=", 14) } 1992*0Sstevel@tonic-gatesub pp_i_lt { binop(@_, "<", 15) } 1993*0Sstevel@tonic-gatesub pp_i_gt { binop(@_, ">", 15) } 1994*0Sstevel@tonic-gatesub pp_i_ge { binop(@_, ">=", 15) } 1995*0Sstevel@tonic-gatesub pp_i_le { binop(@_, "<=", 15) } 1996*0Sstevel@tonic-gatesub pp_i_ncmp { binop(@_, "<=>", 14) } 1997*0Sstevel@tonic-gate 1998*0Sstevel@tonic-gatesub pp_seq { binop(@_, "eq", 14) } 1999*0Sstevel@tonic-gatesub pp_sne { binop(@_, "ne", 14) } 2000*0Sstevel@tonic-gatesub pp_slt { binop(@_, "lt", 15) } 2001*0Sstevel@tonic-gatesub pp_sgt { binop(@_, "gt", 15) } 2002*0Sstevel@tonic-gatesub pp_sge { binop(@_, "ge", 15) } 2003*0Sstevel@tonic-gatesub pp_sle { binop(@_, "le", 15) } 2004*0Sstevel@tonic-gatesub pp_scmp { binop(@_, "cmp", 14) } 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gatesub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) } 2007*0Sstevel@tonic-gatesub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN | LIST_CONTEXT) } 2008*0Sstevel@tonic-gate 2009*0Sstevel@tonic-gate# `.' is special because concats-of-concats are optimized to save copying 2010*0Sstevel@tonic-gate# by making all but the first concat stacked. The effect is as if the 2011*0Sstevel@tonic-gate# programmer had written `($a . $b) .= $c', except legal. 2012*0Sstevel@tonic-gatesub pp_concat { maybe_targmy(@_, \&real_concat) } 2013*0Sstevel@tonic-gatesub real_concat { 2014*0Sstevel@tonic-gate my $self = shift; 2015*0Sstevel@tonic-gate my($op, $cx) = @_; 2016*0Sstevel@tonic-gate my $left = $op->first; 2017*0Sstevel@tonic-gate my $right = $op->last; 2018*0Sstevel@tonic-gate my $eq = ""; 2019*0Sstevel@tonic-gate my $prec = 18; 2020*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED and $op->first->name ne "concat") { 2021*0Sstevel@tonic-gate $eq = "="; 2022*0Sstevel@tonic-gate $prec = 7; 2023*0Sstevel@tonic-gate } 2024*0Sstevel@tonic-gate $left = $self->deparse_binop_left($op, $left, $prec); 2025*0Sstevel@tonic-gate $right = $self->deparse_binop_right($op, $right, $prec); 2026*0Sstevel@tonic-gate return $self->maybe_parens("$left .$eq $right", $cx, $prec); 2027*0Sstevel@tonic-gate} 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate# `x' is weird when the left arg is a list 2030*0Sstevel@tonic-gatesub pp_repeat { 2031*0Sstevel@tonic-gate my $self = shift; 2032*0Sstevel@tonic-gate my($op, $cx) = @_; 2033*0Sstevel@tonic-gate my $left = $op->first; 2034*0Sstevel@tonic-gate my $right = $op->last; 2035*0Sstevel@tonic-gate my $eq = ""; 2036*0Sstevel@tonic-gate my $prec = 19; 2037*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED) { 2038*0Sstevel@tonic-gate $eq = "="; 2039*0Sstevel@tonic-gate $prec = 7; 2040*0Sstevel@tonic-gate } 2041*0Sstevel@tonic-gate if (null($right)) { # list repeat; count is inside left-side ex-list 2042*0Sstevel@tonic-gate my $kid = $left->first->sibling; # skip pushmark 2043*0Sstevel@tonic-gate my @exprs; 2044*0Sstevel@tonic-gate for (; !null($kid->sibling); $kid = $kid->sibling) { 2045*0Sstevel@tonic-gate push @exprs, $self->deparse($kid, 6); 2046*0Sstevel@tonic-gate } 2047*0Sstevel@tonic-gate $right = $kid; 2048*0Sstevel@tonic-gate $left = "(" . join(", ", @exprs). ")"; 2049*0Sstevel@tonic-gate } else { 2050*0Sstevel@tonic-gate $left = $self->deparse_binop_left($op, $left, $prec); 2051*0Sstevel@tonic-gate } 2052*0Sstevel@tonic-gate $right = $self->deparse_binop_right($op, $right, $prec); 2053*0Sstevel@tonic-gate return $self->maybe_parens("$left x$eq $right", $cx, $prec); 2054*0Sstevel@tonic-gate} 2055*0Sstevel@tonic-gate 2056*0Sstevel@tonic-gatesub range { 2057*0Sstevel@tonic-gate my $self = shift; 2058*0Sstevel@tonic-gate my ($op, $cx, $type) = @_; 2059*0Sstevel@tonic-gate my $left = $op->first; 2060*0Sstevel@tonic-gate my $right = $left->sibling; 2061*0Sstevel@tonic-gate $left = $self->deparse($left, 9); 2062*0Sstevel@tonic-gate $right = $self->deparse($right, 9); 2063*0Sstevel@tonic-gate return $self->maybe_parens("$left $type $right", $cx, 9); 2064*0Sstevel@tonic-gate} 2065*0Sstevel@tonic-gate 2066*0Sstevel@tonic-gatesub pp_flop { 2067*0Sstevel@tonic-gate my $self = shift; 2068*0Sstevel@tonic-gate my($op, $cx) = @_; 2069*0Sstevel@tonic-gate my $flip = $op->first; 2070*0Sstevel@tonic-gate my $type = ($flip->flags & OPf_SPECIAL) ? "..." : ".."; 2071*0Sstevel@tonic-gate return $self->range($flip->first, $cx, $type); 2072*0Sstevel@tonic-gate} 2073*0Sstevel@tonic-gate 2074*0Sstevel@tonic-gate# one-line while/until is handled in pp_leave 2075*0Sstevel@tonic-gate 2076*0Sstevel@tonic-gatesub logop { 2077*0Sstevel@tonic-gate my $self = shift; 2078*0Sstevel@tonic-gate my ($op, $cx, $lowop, $lowprec, $highop, $highprec, $blockname) = @_; 2079*0Sstevel@tonic-gate my $left = $op->first; 2080*0Sstevel@tonic-gate my $right = $op->first->sibling; 2081*0Sstevel@tonic-gate if ($cx < 1 and is_scope($right) and $blockname 2082*0Sstevel@tonic-gate and $self->{'expand'} < 7) 2083*0Sstevel@tonic-gate { # if ($a) {$b} 2084*0Sstevel@tonic-gate $left = $self->deparse($left, 1); 2085*0Sstevel@tonic-gate $right = $self->deparse($right, 0); 2086*0Sstevel@tonic-gate return "$blockname ($left) {\n\t$right\n\b}\cK"; 2087*0Sstevel@tonic-gate } elsif ($cx < 1 and $blockname and not $self->{'parens'} 2088*0Sstevel@tonic-gate and $self->{'expand'} < 7) { # $b if $a 2089*0Sstevel@tonic-gate $right = $self->deparse($right, 1); 2090*0Sstevel@tonic-gate $left = $self->deparse($left, 1); 2091*0Sstevel@tonic-gate return "$right $blockname $left"; 2092*0Sstevel@tonic-gate } elsif ($cx > $lowprec and $highop) { # $a && $b 2093*0Sstevel@tonic-gate $left = $self->deparse_binop_left($op, $left, $highprec); 2094*0Sstevel@tonic-gate $right = $self->deparse_binop_right($op, $right, $highprec); 2095*0Sstevel@tonic-gate return $self->maybe_parens("$left $highop $right", $cx, $highprec); 2096*0Sstevel@tonic-gate } else { # $a and $b 2097*0Sstevel@tonic-gate $left = $self->deparse_binop_left($op, $left, $lowprec); 2098*0Sstevel@tonic-gate $right = $self->deparse_binop_right($op, $right, $lowprec); 2099*0Sstevel@tonic-gate return $self->maybe_parens("$left $lowop $right", $cx, $lowprec); 2100*0Sstevel@tonic-gate } 2101*0Sstevel@tonic-gate} 2102*0Sstevel@tonic-gate 2103*0Sstevel@tonic-gatesub pp_and { logop(@_, "and", 3, "&&", 11, "if") } 2104*0Sstevel@tonic-gatesub pp_or { logop(@_, "or", 2, "||", 10, "unless") } 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate# xor is syntactically a logop, but it's really a binop (contrary to 2107*0Sstevel@tonic-gate# old versions of opcode.pl). Syntax is what matters here. 2108*0Sstevel@tonic-gatesub pp_xor { logop(@_, "xor", 2, "", 0, "") } 2109*0Sstevel@tonic-gate 2110*0Sstevel@tonic-gatesub logassignop { 2111*0Sstevel@tonic-gate my $self = shift; 2112*0Sstevel@tonic-gate my ($op, $cx, $opname) = @_; 2113*0Sstevel@tonic-gate my $left = $op->first; 2114*0Sstevel@tonic-gate my $right = $op->first->sibling->first; # skip sassign 2115*0Sstevel@tonic-gate $left = $self->deparse($left, 7); 2116*0Sstevel@tonic-gate $right = $self->deparse($right, 7); 2117*0Sstevel@tonic-gate return $self->maybe_parens("$left $opname $right", $cx, 7); 2118*0Sstevel@tonic-gate} 2119*0Sstevel@tonic-gate 2120*0Sstevel@tonic-gatesub pp_andassign { logassignop(@_, "&&=") } 2121*0Sstevel@tonic-gatesub pp_orassign { logassignop(@_, "||=") } 2122*0Sstevel@tonic-gate 2123*0Sstevel@tonic-gatesub listop { 2124*0Sstevel@tonic-gate my $self = shift; 2125*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 2126*0Sstevel@tonic-gate my(@exprs); 2127*0Sstevel@tonic-gate my $parens = ($cx >= 5) || $self->{'parens'}; 2128*0Sstevel@tonic-gate my $kid = $op->first->sibling; 2129*0Sstevel@tonic-gate return $name if null $kid; 2130*0Sstevel@tonic-gate my $first; 2131*0Sstevel@tonic-gate $name = "socketpair" if $name eq "sockpair"; 2132*0Sstevel@tonic-gate my $proto = prototype("CORE::$name"); 2133*0Sstevel@tonic-gate if (defined $proto 2134*0Sstevel@tonic-gate && $proto =~ /^;?\*/ 2135*0Sstevel@tonic-gate && $kid->name eq "rv2gv") { 2136*0Sstevel@tonic-gate $first = $self->deparse($kid->first, 6); 2137*0Sstevel@tonic-gate } 2138*0Sstevel@tonic-gate else { 2139*0Sstevel@tonic-gate $first = $self->deparse($kid, 6); 2140*0Sstevel@tonic-gate } 2141*0Sstevel@tonic-gate if ($name eq "chmod" && $first =~ /^\d+$/) { 2142*0Sstevel@tonic-gate $first = sprintf("%#o", $first); 2143*0Sstevel@tonic-gate } 2144*0Sstevel@tonic-gate $first = "+$first" if not $parens and substr($first, 0, 1) eq "("; 2145*0Sstevel@tonic-gate push @exprs, $first; 2146*0Sstevel@tonic-gate $kid = $kid->sibling; 2147*0Sstevel@tonic-gate if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv") { 2148*0Sstevel@tonic-gate push @exprs, $self->deparse($kid->first, 6); 2149*0Sstevel@tonic-gate $kid = $kid->sibling; 2150*0Sstevel@tonic-gate } 2151*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 2152*0Sstevel@tonic-gate push @exprs, $self->deparse($kid, 6); 2153*0Sstevel@tonic-gate } 2154*0Sstevel@tonic-gate if ($parens) { 2155*0Sstevel@tonic-gate return "$name(" . join(", ", @exprs) . ")"; 2156*0Sstevel@tonic-gate } else { 2157*0Sstevel@tonic-gate return "$name " . join(", ", @exprs); 2158*0Sstevel@tonic-gate } 2159*0Sstevel@tonic-gate} 2160*0Sstevel@tonic-gate 2161*0Sstevel@tonic-gatesub pp_bless { listop(@_, "bless") } 2162*0Sstevel@tonic-gatesub pp_atan2 { maybe_targmy(@_, \&listop, "atan2") } 2163*0Sstevel@tonic-gatesub pp_substr { maybe_local(@_, listop(@_, "substr")) } 2164*0Sstevel@tonic-gatesub pp_vec { maybe_local(@_, listop(@_, "vec")) } 2165*0Sstevel@tonic-gatesub pp_index { maybe_targmy(@_, \&listop, "index") } 2166*0Sstevel@tonic-gatesub pp_rindex { maybe_targmy(@_, \&listop, "rindex") } 2167*0Sstevel@tonic-gatesub pp_sprintf { maybe_targmy(@_, \&listop, "sprintf") } 2168*0Sstevel@tonic-gatesub pp_formline { listop(@_, "formline") } # see also deparse_format 2169*0Sstevel@tonic-gatesub pp_crypt { maybe_targmy(@_, \&listop, "crypt") } 2170*0Sstevel@tonic-gatesub pp_unpack { listop(@_, "unpack") } 2171*0Sstevel@tonic-gatesub pp_pack { listop(@_, "pack") } 2172*0Sstevel@tonic-gatesub pp_join { maybe_targmy(@_, \&listop, "join") } 2173*0Sstevel@tonic-gatesub pp_splice { listop(@_, "splice") } 2174*0Sstevel@tonic-gatesub pp_push { maybe_targmy(@_, \&listop, "push") } 2175*0Sstevel@tonic-gatesub pp_unshift { maybe_targmy(@_, \&listop, "unshift") } 2176*0Sstevel@tonic-gatesub pp_reverse { listop(@_, "reverse") } 2177*0Sstevel@tonic-gatesub pp_warn { listop(@_, "warn") } 2178*0Sstevel@tonic-gatesub pp_die { listop(@_, "die") } 2179*0Sstevel@tonic-gate# Actually, return is exempt from the LLAFR (see examples in this very 2180*0Sstevel@tonic-gate# module!), but for consistency's sake, ignore that fact 2181*0Sstevel@tonic-gatesub pp_return { listop(@_, "return") } 2182*0Sstevel@tonic-gatesub pp_open { listop(@_, "open") } 2183*0Sstevel@tonic-gatesub pp_pipe_op { listop(@_, "pipe") } 2184*0Sstevel@tonic-gatesub pp_tie { listop(@_, "tie") } 2185*0Sstevel@tonic-gatesub pp_binmode { listop(@_, "binmode") } 2186*0Sstevel@tonic-gatesub pp_dbmopen { listop(@_, "dbmopen") } 2187*0Sstevel@tonic-gatesub pp_sselect { listop(@_, "select") } 2188*0Sstevel@tonic-gatesub pp_select { listop(@_, "select") } 2189*0Sstevel@tonic-gatesub pp_read { listop(@_, "read") } 2190*0Sstevel@tonic-gatesub pp_sysopen { listop(@_, "sysopen") } 2191*0Sstevel@tonic-gatesub pp_sysseek { listop(@_, "sysseek") } 2192*0Sstevel@tonic-gatesub pp_sysread { listop(@_, "sysread") } 2193*0Sstevel@tonic-gatesub pp_syswrite { listop(@_, "syswrite") } 2194*0Sstevel@tonic-gatesub pp_send { listop(@_, "send") } 2195*0Sstevel@tonic-gatesub pp_recv { listop(@_, "recv") } 2196*0Sstevel@tonic-gatesub pp_seek { listop(@_, "seek") } 2197*0Sstevel@tonic-gatesub pp_fcntl { listop(@_, "fcntl") } 2198*0Sstevel@tonic-gatesub pp_ioctl { listop(@_, "ioctl") } 2199*0Sstevel@tonic-gatesub pp_flock { maybe_targmy(@_, \&listop, "flock") } 2200*0Sstevel@tonic-gatesub pp_socket { listop(@_, "socket") } 2201*0Sstevel@tonic-gatesub pp_sockpair { listop(@_, "sockpair") } 2202*0Sstevel@tonic-gatesub pp_bind { listop(@_, "bind") } 2203*0Sstevel@tonic-gatesub pp_connect { listop(@_, "connect") } 2204*0Sstevel@tonic-gatesub pp_listen { listop(@_, "listen") } 2205*0Sstevel@tonic-gatesub pp_accept { listop(@_, "accept") } 2206*0Sstevel@tonic-gatesub pp_shutdown { listop(@_, "shutdown") } 2207*0Sstevel@tonic-gatesub pp_gsockopt { listop(@_, "getsockopt") } 2208*0Sstevel@tonic-gatesub pp_ssockopt { listop(@_, "setsockopt") } 2209*0Sstevel@tonic-gatesub pp_chown { maybe_targmy(@_, \&listop, "chown") } 2210*0Sstevel@tonic-gatesub pp_unlink { maybe_targmy(@_, \&listop, "unlink") } 2211*0Sstevel@tonic-gatesub pp_chmod { maybe_targmy(@_, \&listop, "chmod") } 2212*0Sstevel@tonic-gatesub pp_utime { maybe_targmy(@_, \&listop, "utime") } 2213*0Sstevel@tonic-gatesub pp_rename { maybe_targmy(@_, \&listop, "rename") } 2214*0Sstevel@tonic-gatesub pp_link { maybe_targmy(@_, \&listop, "link") } 2215*0Sstevel@tonic-gatesub pp_symlink { maybe_targmy(@_, \&listop, "symlink") } 2216*0Sstevel@tonic-gatesub pp_mkdir { maybe_targmy(@_, \&listop, "mkdir") } 2217*0Sstevel@tonic-gatesub pp_open_dir { listop(@_, "opendir") } 2218*0Sstevel@tonic-gatesub pp_seekdir { listop(@_, "seekdir") } 2219*0Sstevel@tonic-gatesub pp_waitpid { maybe_targmy(@_, \&listop, "waitpid") } 2220*0Sstevel@tonic-gatesub pp_system { maybe_targmy(@_, \&listop, "system") } 2221*0Sstevel@tonic-gatesub pp_exec { maybe_targmy(@_, \&listop, "exec") } 2222*0Sstevel@tonic-gatesub pp_kill { maybe_targmy(@_, \&listop, "kill") } 2223*0Sstevel@tonic-gatesub pp_setpgrp { maybe_targmy(@_, \&listop, "setpgrp") } 2224*0Sstevel@tonic-gatesub pp_getpriority { maybe_targmy(@_, \&listop, "getpriority") } 2225*0Sstevel@tonic-gatesub pp_setpriority { maybe_targmy(@_, \&listop, "setpriority") } 2226*0Sstevel@tonic-gatesub pp_shmget { listop(@_, "shmget") } 2227*0Sstevel@tonic-gatesub pp_shmctl { listop(@_, "shmctl") } 2228*0Sstevel@tonic-gatesub pp_shmread { listop(@_, "shmread") } 2229*0Sstevel@tonic-gatesub pp_shmwrite { listop(@_, "shmwrite") } 2230*0Sstevel@tonic-gatesub pp_msgget { listop(@_, "msgget") } 2231*0Sstevel@tonic-gatesub pp_msgctl { listop(@_, "msgctl") } 2232*0Sstevel@tonic-gatesub pp_msgsnd { listop(@_, "msgsnd") } 2233*0Sstevel@tonic-gatesub pp_msgrcv { listop(@_, "msgrcv") } 2234*0Sstevel@tonic-gatesub pp_semget { listop(@_, "semget") } 2235*0Sstevel@tonic-gatesub pp_semctl { listop(@_, "semctl") } 2236*0Sstevel@tonic-gatesub pp_semop { listop(@_, "semop") } 2237*0Sstevel@tonic-gatesub pp_ghbyaddr { listop(@_, "gethostbyaddr") } 2238*0Sstevel@tonic-gatesub pp_gnbyaddr { listop(@_, "getnetbyaddr") } 2239*0Sstevel@tonic-gatesub pp_gpbynumber { listop(@_, "getprotobynumber") } 2240*0Sstevel@tonic-gatesub pp_gsbyname { listop(@_, "getservbyname") } 2241*0Sstevel@tonic-gatesub pp_gsbyport { listop(@_, "getservbyport") } 2242*0Sstevel@tonic-gatesub pp_syscall { listop(@_, "syscall") } 2243*0Sstevel@tonic-gate 2244*0Sstevel@tonic-gatesub pp_glob { 2245*0Sstevel@tonic-gate my $self = shift; 2246*0Sstevel@tonic-gate my($op, $cx) = @_; 2247*0Sstevel@tonic-gate my $text = $self->dq($op->first->sibling); # skip pushmark 2248*0Sstevel@tonic-gate if ($text =~ /^\$?(\w|::|\`)+$/ # could look like a readline 2249*0Sstevel@tonic-gate or $text =~ /[<>]/) { 2250*0Sstevel@tonic-gate return 'glob(' . single_delim('qq', '"', $text) . ')'; 2251*0Sstevel@tonic-gate } else { 2252*0Sstevel@tonic-gate return '<' . $text . '>'; 2253*0Sstevel@tonic-gate } 2254*0Sstevel@tonic-gate} 2255*0Sstevel@tonic-gate 2256*0Sstevel@tonic-gate# Truncate is special because OPf_SPECIAL makes a bareword first arg 2257*0Sstevel@tonic-gate# be a filehandle. This could probably be better fixed in the core 2258*0Sstevel@tonic-gate# by moving the GV lookup into ck_truc. 2259*0Sstevel@tonic-gate 2260*0Sstevel@tonic-gatesub pp_truncate { 2261*0Sstevel@tonic-gate my $self = shift; 2262*0Sstevel@tonic-gate my($op, $cx) = @_; 2263*0Sstevel@tonic-gate my(@exprs); 2264*0Sstevel@tonic-gate my $parens = ($cx >= 5) || $self->{'parens'}; 2265*0Sstevel@tonic-gate my $kid = $op->first->sibling; 2266*0Sstevel@tonic-gate my $fh; 2267*0Sstevel@tonic-gate if ($op->flags & OPf_SPECIAL) { 2268*0Sstevel@tonic-gate # $kid is an OP_CONST 2269*0Sstevel@tonic-gate $fh = $self->const_sv($kid)->PV; 2270*0Sstevel@tonic-gate } else { 2271*0Sstevel@tonic-gate $fh = $self->deparse($kid, 6); 2272*0Sstevel@tonic-gate $fh = "+$fh" if not $parens and substr($fh, 0, 1) eq "("; 2273*0Sstevel@tonic-gate } 2274*0Sstevel@tonic-gate my $len = $self->deparse($kid->sibling, 6); 2275*0Sstevel@tonic-gate if ($parens) { 2276*0Sstevel@tonic-gate return "truncate($fh, $len)"; 2277*0Sstevel@tonic-gate } else { 2278*0Sstevel@tonic-gate return "truncate $fh, $len"; 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate} 2281*0Sstevel@tonic-gate 2282*0Sstevel@tonic-gatesub indirop { 2283*0Sstevel@tonic-gate my $self = shift; 2284*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 2285*0Sstevel@tonic-gate my($expr, @exprs); 2286*0Sstevel@tonic-gate my $kid = $op->first->sibling; 2287*0Sstevel@tonic-gate my $indir = ""; 2288*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED) { 2289*0Sstevel@tonic-gate $indir = $kid; 2290*0Sstevel@tonic-gate $indir = $indir->first; # skip rv2gv 2291*0Sstevel@tonic-gate if (is_scope($indir)) { 2292*0Sstevel@tonic-gate $indir = "{" . $self->deparse($indir, 0) . "}"; 2293*0Sstevel@tonic-gate $indir = "{;}" if $indir eq "{}"; 2294*0Sstevel@tonic-gate } elsif ($indir->name eq "const" && $indir->private & OPpCONST_BARE) { 2295*0Sstevel@tonic-gate $indir = $self->const_sv($indir)->PV; 2296*0Sstevel@tonic-gate } else { 2297*0Sstevel@tonic-gate $indir = $self->deparse($indir, 24); 2298*0Sstevel@tonic-gate } 2299*0Sstevel@tonic-gate $indir = $indir . " "; 2300*0Sstevel@tonic-gate $kid = $kid->sibling; 2301*0Sstevel@tonic-gate } 2302*0Sstevel@tonic-gate if ($name eq "sort" && $op->private & (OPpSORT_NUMERIC | OPpSORT_INTEGER)) { 2303*0Sstevel@tonic-gate $indir = ($op->private & OPpSORT_REVERSE) ? '{$b <=> $a} ' 2304*0Sstevel@tonic-gate : '{$a <=> $b} '; 2305*0Sstevel@tonic-gate } 2306*0Sstevel@tonic-gate elsif ($name eq "sort" && $op->private & OPpSORT_REVERSE) { 2307*0Sstevel@tonic-gate $indir = '{$b cmp $a} '; 2308*0Sstevel@tonic-gate } 2309*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 2310*0Sstevel@tonic-gate $expr = $self->deparse($kid, 6); 2311*0Sstevel@tonic-gate push @exprs, $expr; 2312*0Sstevel@tonic-gate } 2313*0Sstevel@tonic-gate if ($name eq "sort" && ($op->private & OPpSORT_INPLACE)) { 2314*0Sstevel@tonic-gate return "$exprs[0] = sort $indir $exprs[0]"; 2315*0Sstevel@tonic-gate } 2316*0Sstevel@tonic-gate 2317*0Sstevel@tonic-gate my $args = $indir . join(", ", @exprs); 2318*0Sstevel@tonic-gate if ($indir ne "" and $name eq "sort") { 2319*0Sstevel@tonic-gate # We don't want to say "sort(f 1, 2, 3)", since perl -w will 2320*0Sstevel@tonic-gate # give bareword warnings in that case. Therefore if context 2321*0Sstevel@tonic-gate # requires, we'll put parens around the outside "(sort f 1, 2, 2322*0Sstevel@tonic-gate # 3)". Unfortunately, we'll currently think the parens are 2323*0Sstevel@tonic-gate # neccessary more often that they really are, because we don't 2324*0Sstevel@tonic-gate # distinguish which side of an assignment we're on. 2325*0Sstevel@tonic-gate if ($cx >= 5) { 2326*0Sstevel@tonic-gate return "($name $args)"; 2327*0Sstevel@tonic-gate } else { 2328*0Sstevel@tonic-gate return "$name $args"; 2329*0Sstevel@tonic-gate } 2330*0Sstevel@tonic-gate } else { 2331*0Sstevel@tonic-gate return $self->maybe_parens_func($name, $args, $cx, 5); 2332*0Sstevel@tonic-gate } 2333*0Sstevel@tonic-gate 2334*0Sstevel@tonic-gate} 2335*0Sstevel@tonic-gate 2336*0Sstevel@tonic-gatesub pp_prtf { indirop(@_, "printf") } 2337*0Sstevel@tonic-gatesub pp_print { indirop(@_, "print") } 2338*0Sstevel@tonic-gatesub pp_sort { indirop(@_, "sort") } 2339*0Sstevel@tonic-gate 2340*0Sstevel@tonic-gatesub mapop { 2341*0Sstevel@tonic-gate my $self = shift; 2342*0Sstevel@tonic-gate my($op, $cx, $name) = @_; 2343*0Sstevel@tonic-gate my($expr, @exprs); 2344*0Sstevel@tonic-gate my $kid = $op->first; # this is the (map|grep)start 2345*0Sstevel@tonic-gate $kid = $kid->first->sibling; # skip a pushmark 2346*0Sstevel@tonic-gate my $code = $kid->first; # skip a null 2347*0Sstevel@tonic-gate if (is_scope $code) { 2348*0Sstevel@tonic-gate $code = "{" . $self->deparse($code, 0) . "} "; 2349*0Sstevel@tonic-gate } else { 2350*0Sstevel@tonic-gate $code = $self->deparse($code, 24) . ", "; 2351*0Sstevel@tonic-gate } 2352*0Sstevel@tonic-gate $kid = $kid->sibling; 2353*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 2354*0Sstevel@tonic-gate $expr = $self->deparse($kid, 6); 2355*0Sstevel@tonic-gate push @exprs, $expr if defined $expr; 2356*0Sstevel@tonic-gate } 2357*0Sstevel@tonic-gate return $self->maybe_parens_func($name, $code . join(", ", @exprs), $cx, 5); 2358*0Sstevel@tonic-gate} 2359*0Sstevel@tonic-gate 2360*0Sstevel@tonic-gatesub pp_mapwhile { mapop(@_, "map") } 2361*0Sstevel@tonic-gatesub pp_grepwhile { mapop(@_, "grep") } 2362*0Sstevel@tonic-gate 2363*0Sstevel@tonic-gatesub pp_list { 2364*0Sstevel@tonic-gate my $self = shift; 2365*0Sstevel@tonic-gate my($op, $cx) = @_; 2366*0Sstevel@tonic-gate my($expr, @exprs); 2367*0Sstevel@tonic-gate my $kid = $op->first->sibling; # skip pushmark 2368*0Sstevel@tonic-gate my $lop; 2369*0Sstevel@tonic-gate my $local = "either"; # could be local(...), my(...) or our(...) 2370*0Sstevel@tonic-gate for ($lop = $kid; !null($lop); $lop = $lop->sibling) { 2371*0Sstevel@tonic-gate # This assumes that no other private flags equal 128, and that 2372*0Sstevel@tonic-gate # OPs that store things other than flags in their op_private, 2373*0Sstevel@tonic-gate # like OP_AELEMFAST, won't be immediate children of a list. 2374*0Sstevel@tonic-gate # 2375*0Sstevel@tonic-gate # OP_ENTERSUB can break this logic, so check for it. 2376*0Sstevel@tonic-gate # I suspect that open and exit can too. 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate if (!($lop->private & (OPpLVAL_INTRO|OPpOUR_INTRO) 2379*0Sstevel@tonic-gate or $lop->name eq "undef") 2380*0Sstevel@tonic-gate or $lop->name eq "entersub" 2381*0Sstevel@tonic-gate or $lop->name eq "exit" 2382*0Sstevel@tonic-gate or $lop->name eq "open") 2383*0Sstevel@tonic-gate { 2384*0Sstevel@tonic-gate $local = ""; # or not 2385*0Sstevel@tonic-gate last; 2386*0Sstevel@tonic-gate } 2387*0Sstevel@tonic-gate if ($lop->name =~ /^pad[ash]v$/) { # my() 2388*0Sstevel@tonic-gate ($local = "", last) if $local eq "local" || $local eq "our"; 2389*0Sstevel@tonic-gate $local = "my"; 2390*0Sstevel@tonic-gate } elsif ($lop->name =~ /^(gv|rv2)[ash]v$/ 2391*0Sstevel@tonic-gate && $lop->private & OPpOUR_INTRO 2392*0Sstevel@tonic-gate or $lop->name eq "null" && $lop->first->name eq "gvsv" 2393*0Sstevel@tonic-gate && $lop->first->private & OPpOUR_INTRO) { # our() 2394*0Sstevel@tonic-gate ($local = "", last) if $local eq "my" || $local eq "local"; 2395*0Sstevel@tonic-gate $local = "our"; 2396*0Sstevel@tonic-gate } elsif ($lop->name ne "undef") { # local() 2397*0Sstevel@tonic-gate ($local = "", last) if $local eq "my" || $local eq "our"; 2398*0Sstevel@tonic-gate $local = "local"; 2399*0Sstevel@tonic-gate } 2400*0Sstevel@tonic-gate } 2401*0Sstevel@tonic-gate $local = "" if $local eq "either"; # no point if it's all undefs 2402*0Sstevel@tonic-gate return $self->deparse($kid, $cx) if null $kid->sibling and not $local; 2403*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 2404*0Sstevel@tonic-gate if ($local) { 2405*0Sstevel@tonic-gate if (class($kid) eq "UNOP" and $kid->first->name eq "gvsv") { 2406*0Sstevel@tonic-gate $lop = $kid->first; 2407*0Sstevel@tonic-gate } else { 2408*0Sstevel@tonic-gate $lop = $kid; 2409*0Sstevel@tonic-gate } 2410*0Sstevel@tonic-gate $self->{'avoid_local'}{$$lop}++; 2411*0Sstevel@tonic-gate $expr = $self->deparse($kid, 6); 2412*0Sstevel@tonic-gate delete $self->{'avoid_local'}{$$lop}; 2413*0Sstevel@tonic-gate } else { 2414*0Sstevel@tonic-gate $expr = $self->deparse($kid, 6); 2415*0Sstevel@tonic-gate } 2416*0Sstevel@tonic-gate push @exprs, $expr; 2417*0Sstevel@tonic-gate } 2418*0Sstevel@tonic-gate if ($local) { 2419*0Sstevel@tonic-gate return "$local(" . join(", ", @exprs) . ")"; 2420*0Sstevel@tonic-gate } else { 2421*0Sstevel@tonic-gate return $self->maybe_parens( join(", ", @exprs), $cx, 6); 2422*0Sstevel@tonic-gate } 2423*0Sstevel@tonic-gate} 2424*0Sstevel@tonic-gate 2425*0Sstevel@tonic-gatesub is_ifelse_cont { 2426*0Sstevel@tonic-gate my $op = shift; 2427*0Sstevel@tonic-gate return ($op->name eq "null" and class($op) eq "UNOP" 2428*0Sstevel@tonic-gate and $op->first->name =~ /^(and|cond_expr)$/ 2429*0Sstevel@tonic-gate and is_scope($op->first->first->sibling)); 2430*0Sstevel@tonic-gate} 2431*0Sstevel@tonic-gate 2432*0Sstevel@tonic-gatesub pp_cond_expr { 2433*0Sstevel@tonic-gate my $self = shift; 2434*0Sstevel@tonic-gate my($op, $cx) = @_; 2435*0Sstevel@tonic-gate my $cond = $op->first; 2436*0Sstevel@tonic-gate my $true = $cond->sibling; 2437*0Sstevel@tonic-gate my $false = $true->sibling; 2438*0Sstevel@tonic-gate my $cuddle = $self->{'cuddle'}; 2439*0Sstevel@tonic-gate unless ($cx < 1 and (is_scope($true) and $true->name ne "null") and 2440*0Sstevel@tonic-gate (is_scope($false) || is_ifelse_cont($false)) 2441*0Sstevel@tonic-gate and $self->{'expand'} < 7) { 2442*0Sstevel@tonic-gate $cond = $self->deparse($cond, 8); 2443*0Sstevel@tonic-gate $true = $self->deparse($true, 8); 2444*0Sstevel@tonic-gate $false = $self->deparse($false, 8); 2445*0Sstevel@tonic-gate return $self->maybe_parens("$cond ? $true : $false", $cx, 8); 2446*0Sstevel@tonic-gate } 2447*0Sstevel@tonic-gate 2448*0Sstevel@tonic-gate $cond = $self->deparse($cond, 1); 2449*0Sstevel@tonic-gate $true = $self->deparse($true, 0); 2450*0Sstevel@tonic-gate my $head = "if ($cond) {\n\t$true\n\b}"; 2451*0Sstevel@tonic-gate my @elsifs; 2452*0Sstevel@tonic-gate while (!null($false) and is_ifelse_cont($false)) { 2453*0Sstevel@tonic-gate my $newop = $false->first; 2454*0Sstevel@tonic-gate my $newcond = $newop->first; 2455*0Sstevel@tonic-gate my $newtrue = $newcond->sibling; 2456*0Sstevel@tonic-gate $false = $newtrue->sibling; # last in chain is OP_AND => no else 2457*0Sstevel@tonic-gate $newcond = $self->deparse($newcond, 1); 2458*0Sstevel@tonic-gate $newtrue = $self->deparse($newtrue, 0); 2459*0Sstevel@tonic-gate push @elsifs, "elsif ($newcond) {\n\t$newtrue\n\b}"; 2460*0Sstevel@tonic-gate } 2461*0Sstevel@tonic-gate if (!null($false)) { 2462*0Sstevel@tonic-gate $false = $cuddle . "else {\n\t" . 2463*0Sstevel@tonic-gate $self->deparse($false, 0) . "\n\b}\cK"; 2464*0Sstevel@tonic-gate } else { 2465*0Sstevel@tonic-gate $false = "\cK"; 2466*0Sstevel@tonic-gate } 2467*0Sstevel@tonic-gate return $head . join($cuddle, "", @elsifs) . $false; 2468*0Sstevel@tonic-gate} 2469*0Sstevel@tonic-gate 2470*0Sstevel@tonic-gatesub loop_common { 2471*0Sstevel@tonic-gate my $self = shift; 2472*0Sstevel@tonic-gate my($op, $cx, $init) = @_; 2473*0Sstevel@tonic-gate my $enter = $op->first; 2474*0Sstevel@tonic-gate my $kid = $enter->sibling; 2475*0Sstevel@tonic-gate local(@$self{qw'curstash warnings hints'}) 2476*0Sstevel@tonic-gate = @$self{qw'curstash warnings hints'}; 2477*0Sstevel@tonic-gate my $head = ""; 2478*0Sstevel@tonic-gate my $bare = 0; 2479*0Sstevel@tonic-gate my $body; 2480*0Sstevel@tonic-gate my $cond = undef; 2481*0Sstevel@tonic-gate if ($kid->name eq "lineseq") { # bare or infinite loop 2482*0Sstevel@tonic-gate if ($kid->last->name eq "unstack") { # infinite 2483*0Sstevel@tonic-gate $head = "while (1) "; # Can't use for(;;) if there's a continue 2484*0Sstevel@tonic-gate $cond = ""; 2485*0Sstevel@tonic-gate } else { 2486*0Sstevel@tonic-gate $bare = 1; 2487*0Sstevel@tonic-gate } 2488*0Sstevel@tonic-gate $body = $kid; 2489*0Sstevel@tonic-gate } elsif ($enter->name eq "enteriter") { # foreach 2490*0Sstevel@tonic-gate my $ary = $enter->first->sibling; # first was pushmark 2491*0Sstevel@tonic-gate my $var = $ary->sibling; 2492*0Sstevel@tonic-gate if ($enter->flags & OPf_STACKED 2493*0Sstevel@tonic-gate and not null $ary->first->sibling->sibling) 2494*0Sstevel@tonic-gate { 2495*0Sstevel@tonic-gate $ary = $self->deparse($ary->first->sibling, 9) . " .. " . 2496*0Sstevel@tonic-gate $self->deparse($ary->first->sibling->sibling, 9); 2497*0Sstevel@tonic-gate } else { 2498*0Sstevel@tonic-gate $ary = $self->deparse($ary, 1); 2499*0Sstevel@tonic-gate } 2500*0Sstevel@tonic-gate if (null $var) { 2501*0Sstevel@tonic-gate if ($enter->flags & OPf_SPECIAL) { # thread special var 2502*0Sstevel@tonic-gate $var = $self->pp_threadsv($enter, 1); 2503*0Sstevel@tonic-gate } else { # regular my() variable 2504*0Sstevel@tonic-gate $var = $self->pp_padsv($enter, 1); 2505*0Sstevel@tonic-gate } 2506*0Sstevel@tonic-gate } elsif ($var->name eq "rv2gv") { 2507*0Sstevel@tonic-gate $var = $self->pp_rv2sv($var, 1); 2508*0Sstevel@tonic-gate if ($enter->private & OPpOUR_INTRO) { 2509*0Sstevel@tonic-gate # our declarations don't have package names 2510*0Sstevel@tonic-gate $var =~ s/^(.).*::/$1/; 2511*0Sstevel@tonic-gate $var = "our $var"; 2512*0Sstevel@tonic-gate } 2513*0Sstevel@tonic-gate } elsif ($var->name eq "gv") { 2514*0Sstevel@tonic-gate $var = "\$" . $self->deparse($var, 1); 2515*0Sstevel@tonic-gate } 2516*0Sstevel@tonic-gate $head = "foreach $var ($ary) "; 2517*0Sstevel@tonic-gate $body = $kid->first->first->sibling; # skip OP_AND and OP_ITER 2518*0Sstevel@tonic-gate } elsif ($kid->name eq "null") { # while/until 2519*0Sstevel@tonic-gate $kid = $kid->first; 2520*0Sstevel@tonic-gate my $name = {"and" => "while", "or" => "until"}->{$kid->name}; 2521*0Sstevel@tonic-gate $cond = $self->deparse($kid->first, 1); 2522*0Sstevel@tonic-gate $head = "$name ($cond) "; 2523*0Sstevel@tonic-gate $body = $kid->first->sibling; 2524*0Sstevel@tonic-gate } elsif ($kid->name eq "stub") { # bare and empty 2525*0Sstevel@tonic-gate return "{;}"; # {} could be a hashref 2526*0Sstevel@tonic-gate } 2527*0Sstevel@tonic-gate # If there isn't a continue block, then the next pointer for the loop 2528*0Sstevel@tonic-gate # will point to the unstack, which is kid's last child, except 2529*0Sstevel@tonic-gate # in a bare loop, when it will point to the leaveloop. When neither of 2530*0Sstevel@tonic-gate # these conditions hold, then the second-to-last child is the continue 2531*0Sstevel@tonic-gate # block (or the last in a bare loop). 2532*0Sstevel@tonic-gate my $cont_start = $enter->nextop; 2533*0Sstevel@tonic-gate my $cont; 2534*0Sstevel@tonic-gate if ($$cont_start != $$op && ${$cont_start} != ${$body->last}) { 2535*0Sstevel@tonic-gate if ($bare) { 2536*0Sstevel@tonic-gate $cont = $body->last; 2537*0Sstevel@tonic-gate } else { 2538*0Sstevel@tonic-gate $cont = $body->first; 2539*0Sstevel@tonic-gate while (!null($cont->sibling->sibling)) { 2540*0Sstevel@tonic-gate $cont = $cont->sibling; 2541*0Sstevel@tonic-gate } 2542*0Sstevel@tonic-gate } 2543*0Sstevel@tonic-gate my $state = $body->first; 2544*0Sstevel@tonic-gate my $cuddle = $self->{'cuddle'}; 2545*0Sstevel@tonic-gate my @states; 2546*0Sstevel@tonic-gate for (; $$state != $$cont; $state = $state->sibling) { 2547*0Sstevel@tonic-gate push @states, $state; 2548*0Sstevel@tonic-gate } 2549*0Sstevel@tonic-gate $body = $self->lineseq(undef, @states); 2550*0Sstevel@tonic-gate if (defined $cond and not is_scope $cont and $self->{'expand'} < 3) { 2551*0Sstevel@tonic-gate $head = "for ($init; $cond; " . $self->deparse($cont, 1) .") "; 2552*0Sstevel@tonic-gate $cont = "\cK"; 2553*0Sstevel@tonic-gate } else { 2554*0Sstevel@tonic-gate $cont = $cuddle . "continue {\n\t" . 2555*0Sstevel@tonic-gate $self->deparse($cont, 0) . "\n\b}\cK"; 2556*0Sstevel@tonic-gate } 2557*0Sstevel@tonic-gate } else { 2558*0Sstevel@tonic-gate return "" if !defined $body; 2559*0Sstevel@tonic-gate if (length $init) { 2560*0Sstevel@tonic-gate $head = "for ($init; $cond;) "; 2561*0Sstevel@tonic-gate } 2562*0Sstevel@tonic-gate $cont = "\cK"; 2563*0Sstevel@tonic-gate $body = $self->deparse($body, 0); 2564*0Sstevel@tonic-gate } 2565*0Sstevel@tonic-gate $body =~ s/;?$/;\n/; 2566*0Sstevel@tonic-gate 2567*0Sstevel@tonic-gate return $head . "{\n\t" . $body . "\b}" . $cont; 2568*0Sstevel@tonic-gate} 2569*0Sstevel@tonic-gate 2570*0Sstevel@tonic-gatesub pp_leaveloop { loop_common(@_, "") } 2571*0Sstevel@tonic-gate 2572*0Sstevel@tonic-gatesub for_loop { 2573*0Sstevel@tonic-gate my $self = shift; 2574*0Sstevel@tonic-gate my($op, $cx) = @_; 2575*0Sstevel@tonic-gate my $init = $self->deparse($op, 1); 2576*0Sstevel@tonic-gate return $self->loop_common($op->sibling->first->sibling, $cx, $init); 2577*0Sstevel@tonic-gate} 2578*0Sstevel@tonic-gate 2579*0Sstevel@tonic-gatesub pp_leavetry { 2580*0Sstevel@tonic-gate my $self = shift; 2581*0Sstevel@tonic-gate return "eval {\n\t" . $self->pp_leave(@_) . "\n\b}"; 2582*0Sstevel@tonic-gate} 2583*0Sstevel@tonic-gate 2584*0Sstevel@tonic-gateBEGIN { eval "sub OP_CONST () {" . opnumber("const") . "}" } 2585*0Sstevel@tonic-gateBEGIN { eval "sub OP_STRINGIFY () {" . opnumber("stringify") . "}" } 2586*0Sstevel@tonic-gateBEGIN { eval "sub OP_RV2SV () {" . opnumber("rv2sv") . "}" } 2587*0Sstevel@tonic-gateBEGIN { eval "sub OP_LIST () {" . opnumber("list") . "}" } 2588*0Sstevel@tonic-gate 2589*0Sstevel@tonic-gatesub pp_null { 2590*0Sstevel@tonic-gate my $self = shift; 2591*0Sstevel@tonic-gate my($op, $cx) = @_; 2592*0Sstevel@tonic-gate if (class($op) eq "OP") { 2593*0Sstevel@tonic-gate # old value is lost 2594*0Sstevel@tonic-gate return $self->{'ex_const'} if $op->targ == OP_CONST; 2595*0Sstevel@tonic-gate } elsif ($op->first->name eq "pushmark") { 2596*0Sstevel@tonic-gate return $self->pp_list($op, $cx); 2597*0Sstevel@tonic-gate } elsif ($op->first->name eq "enter") { 2598*0Sstevel@tonic-gate return $self->pp_leave($op, $cx); 2599*0Sstevel@tonic-gate } elsif ($op->targ == OP_STRINGIFY) { 2600*0Sstevel@tonic-gate return $self->dquote($op, $cx); 2601*0Sstevel@tonic-gate } elsif (!null($op->first->sibling) and 2602*0Sstevel@tonic-gate $op->first->sibling->name eq "readline" and 2603*0Sstevel@tonic-gate $op->first->sibling->flags & OPf_STACKED) { 2604*0Sstevel@tonic-gate return $self->maybe_parens($self->deparse($op->first, 7) . " = " 2605*0Sstevel@tonic-gate . $self->deparse($op->first->sibling, 7), 2606*0Sstevel@tonic-gate $cx, 7); 2607*0Sstevel@tonic-gate } elsif (!null($op->first->sibling) and 2608*0Sstevel@tonic-gate $op->first->sibling->name eq "trans" and 2609*0Sstevel@tonic-gate $op->first->sibling->flags & OPf_STACKED) { 2610*0Sstevel@tonic-gate return $self->maybe_parens($self->deparse($op->first, 20) . " =~ " 2611*0Sstevel@tonic-gate . $self->deparse($op->first->sibling, 20), 2612*0Sstevel@tonic-gate $cx, 20); 2613*0Sstevel@tonic-gate } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) { 2614*0Sstevel@tonic-gate return "do {\n\t". $self->deparse($op->first, $cx) ."\n\b};"; 2615*0Sstevel@tonic-gate } elsif (!null($op->first->sibling) and 2616*0Sstevel@tonic-gate $op->first->sibling->name eq "null" and 2617*0Sstevel@tonic-gate class($op->first->sibling) eq "UNOP" and 2618*0Sstevel@tonic-gate $op->first->sibling->first->flags & OPf_STACKED and 2619*0Sstevel@tonic-gate $op->first->sibling->first->name eq "rcatline") { 2620*0Sstevel@tonic-gate return $self->maybe_parens($self->deparse($op->first, 18) . " .= " 2621*0Sstevel@tonic-gate . $self->deparse($op->first->sibling, 18), 2622*0Sstevel@tonic-gate $cx, 18); 2623*0Sstevel@tonic-gate } else { 2624*0Sstevel@tonic-gate return $self->deparse($op->first, $cx); 2625*0Sstevel@tonic-gate } 2626*0Sstevel@tonic-gate} 2627*0Sstevel@tonic-gate 2628*0Sstevel@tonic-gatesub padname { 2629*0Sstevel@tonic-gate my $self = shift; 2630*0Sstevel@tonic-gate my $targ = shift; 2631*0Sstevel@tonic-gate return $self->padname_sv($targ)->PVX; 2632*0Sstevel@tonic-gate} 2633*0Sstevel@tonic-gate 2634*0Sstevel@tonic-gatesub padany { 2635*0Sstevel@tonic-gate my $self = shift; 2636*0Sstevel@tonic-gate my $op = shift; 2637*0Sstevel@tonic-gate return substr($self->padname($op->targ), 1); # skip $/@/% 2638*0Sstevel@tonic-gate} 2639*0Sstevel@tonic-gate 2640*0Sstevel@tonic-gatesub pp_padsv { 2641*0Sstevel@tonic-gate my $self = shift; 2642*0Sstevel@tonic-gate my($op, $cx) = @_; 2643*0Sstevel@tonic-gate return $self->maybe_my($op, $cx, $self->padname($op->targ)); 2644*0Sstevel@tonic-gate} 2645*0Sstevel@tonic-gate 2646*0Sstevel@tonic-gatesub pp_padav { pp_padsv(@_) } 2647*0Sstevel@tonic-gatesub pp_padhv { pp_padsv(@_) } 2648*0Sstevel@tonic-gate 2649*0Sstevel@tonic-gatemy @threadsv_names; 2650*0Sstevel@tonic-gate 2651*0Sstevel@tonic-gateBEGIN { 2652*0Sstevel@tonic-gate @threadsv_names = ("_", "1", "2", "3", "4", "5", "6", "7", "8", "9", 2653*0Sstevel@tonic-gate "&", "`", "'", "+", "/", ".", ",", "\\", '"', ";", 2654*0Sstevel@tonic-gate "^", "-", "%", "=", "|", "~", ":", "^A", "^E", 2655*0Sstevel@tonic-gate "!", "@"); 2656*0Sstevel@tonic-gate} 2657*0Sstevel@tonic-gate 2658*0Sstevel@tonic-gatesub pp_threadsv { 2659*0Sstevel@tonic-gate my $self = shift; 2660*0Sstevel@tonic-gate my($op, $cx) = @_; 2661*0Sstevel@tonic-gate return $self->maybe_local($op, $cx, "\$" . $threadsv_names[$op->targ]); 2662*0Sstevel@tonic-gate} 2663*0Sstevel@tonic-gate 2664*0Sstevel@tonic-gatesub gv_or_padgv { 2665*0Sstevel@tonic-gate my $self = shift; 2666*0Sstevel@tonic-gate my $op = shift; 2667*0Sstevel@tonic-gate if (class($op) eq "PADOP") { 2668*0Sstevel@tonic-gate return $self->padval($op->padix); 2669*0Sstevel@tonic-gate } else { # class($op) eq "SVOP" 2670*0Sstevel@tonic-gate return $op->gv; 2671*0Sstevel@tonic-gate } 2672*0Sstevel@tonic-gate} 2673*0Sstevel@tonic-gate 2674*0Sstevel@tonic-gatesub pp_gvsv { 2675*0Sstevel@tonic-gate my $self = shift; 2676*0Sstevel@tonic-gate my($op, $cx) = @_; 2677*0Sstevel@tonic-gate my $gv = $self->gv_or_padgv($op); 2678*0Sstevel@tonic-gate return $self->maybe_local($op, $cx, $self->stash_variable("\$", 2679*0Sstevel@tonic-gate $self->gv_name($gv))); 2680*0Sstevel@tonic-gate} 2681*0Sstevel@tonic-gate 2682*0Sstevel@tonic-gatesub pp_gv { 2683*0Sstevel@tonic-gate my $self = shift; 2684*0Sstevel@tonic-gate my($op, $cx) = @_; 2685*0Sstevel@tonic-gate my $gv = $self->gv_or_padgv($op); 2686*0Sstevel@tonic-gate return $self->gv_name($gv); 2687*0Sstevel@tonic-gate} 2688*0Sstevel@tonic-gate 2689*0Sstevel@tonic-gatesub pp_aelemfast { 2690*0Sstevel@tonic-gate my $self = shift; 2691*0Sstevel@tonic-gate my($op, $cx) = @_; 2692*0Sstevel@tonic-gate my $name; 2693*0Sstevel@tonic-gate if ($op->flags & OPf_SPECIAL) { # optimised PADAV 2694*0Sstevel@tonic-gate $name = $self->padname($op->targ); 2695*0Sstevel@tonic-gate $name =~ s/^@/\$/; 2696*0Sstevel@tonic-gate } 2697*0Sstevel@tonic-gate else { 2698*0Sstevel@tonic-gate my $gv = $self->gv_or_padgv($op); 2699*0Sstevel@tonic-gate $name = $self->gv_name($gv); 2700*0Sstevel@tonic-gate $name = $self->{'curstash'}."::$name" 2701*0Sstevel@tonic-gate if $name !~ /::/ && $self->lex_in_scope('@'.$name); 2702*0Sstevel@tonic-gate $name = '$' . $name; 2703*0Sstevel@tonic-gate } 2704*0Sstevel@tonic-gate 2705*0Sstevel@tonic-gate return $name . "[" . ($op->private + $self->{'arybase'}) . "]"; 2706*0Sstevel@tonic-gate} 2707*0Sstevel@tonic-gate 2708*0Sstevel@tonic-gatesub rv2x { 2709*0Sstevel@tonic-gate my $self = shift; 2710*0Sstevel@tonic-gate my($op, $cx, $type) = @_; 2711*0Sstevel@tonic-gate 2712*0Sstevel@tonic-gate if (class($op) eq 'NULL' || !$op->can("first")) { 2713*0Sstevel@tonic-gate carp("Unexpected op in pp_rv2x"); 2714*0Sstevel@tonic-gate return 'XXX'; 2715*0Sstevel@tonic-gate } 2716*0Sstevel@tonic-gate my $kid = $op->first; 2717*0Sstevel@tonic-gate if ($kid->name eq "gv") { 2718*0Sstevel@tonic-gate return $self->stash_variable($type, $self->deparse($kid, 0)); 2719*0Sstevel@tonic-gate } elsif (is_scalar $kid) { 2720*0Sstevel@tonic-gate my $str = $self->deparse($kid, 0); 2721*0Sstevel@tonic-gate if ($str =~ /^\$([^\w\d])\z/) { 2722*0Sstevel@tonic-gate # "$$+" isn't a legal way to write the scalar dereference 2723*0Sstevel@tonic-gate # of $+, since the lexer can't tell you aren't trying to 2724*0Sstevel@tonic-gate # do something like "$$ + 1" to get one more than your 2725*0Sstevel@tonic-gate # PID. Either "${$+}" or "$${+}" are workable 2726*0Sstevel@tonic-gate # disambiguations, but if the programmer did the former, 2727*0Sstevel@tonic-gate # they'd be in the "else" clause below rather than here. 2728*0Sstevel@tonic-gate # It's not clear if this should somehow be unified with 2729*0Sstevel@tonic-gate # the code in dq and re_dq that also adds lexer 2730*0Sstevel@tonic-gate # disambiguation braces. 2731*0Sstevel@tonic-gate $str = '$' . "{$1}"; #' 2732*0Sstevel@tonic-gate } 2733*0Sstevel@tonic-gate return $type . $str; 2734*0Sstevel@tonic-gate } else { 2735*0Sstevel@tonic-gate return $type . "{" . $self->deparse($kid, 0) . "}"; 2736*0Sstevel@tonic-gate } 2737*0Sstevel@tonic-gate} 2738*0Sstevel@tonic-gate 2739*0Sstevel@tonic-gatesub pp_rv2sv { maybe_local(@_, rv2x(@_, "\$")) } 2740*0Sstevel@tonic-gatesub pp_rv2hv { maybe_local(@_, rv2x(@_, "%")) } 2741*0Sstevel@tonic-gatesub pp_rv2gv { maybe_local(@_, rv2x(@_, "*")) } 2742*0Sstevel@tonic-gate 2743*0Sstevel@tonic-gate# skip rv2av 2744*0Sstevel@tonic-gatesub pp_av2arylen { 2745*0Sstevel@tonic-gate my $self = shift; 2746*0Sstevel@tonic-gate my($op, $cx) = @_; 2747*0Sstevel@tonic-gate if ($op->first->name eq "padav") { 2748*0Sstevel@tonic-gate return $self->maybe_local($op, $cx, '$#' . $self->padany($op->first)); 2749*0Sstevel@tonic-gate } else { 2750*0Sstevel@tonic-gate return $self->maybe_local($op, $cx, 2751*0Sstevel@tonic-gate $self->rv2x($op->first, $cx, '$#')); 2752*0Sstevel@tonic-gate } 2753*0Sstevel@tonic-gate} 2754*0Sstevel@tonic-gate 2755*0Sstevel@tonic-gate# skip down to the old, ex-rv2cv 2756*0Sstevel@tonic-gatesub pp_rv2cv { 2757*0Sstevel@tonic-gate my ($self, $op, $cx) = @_; 2758*0Sstevel@tonic-gate if (!null($op->first) && $op->first->name eq 'null' && 2759*0Sstevel@tonic-gate $op->first->targ eq OP_LIST) 2760*0Sstevel@tonic-gate { 2761*0Sstevel@tonic-gate return $self->rv2x($op->first->first->sibling, $cx, "&") 2762*0Sstevel@tonic-gate } 2763*0Sstevel@tonic-gate else { 2764*0Sstevel@tonic-gate return $self->rv2x($op, $cx, "") 2765*0Sstevel@tonic-gate } 2766*0Sstevel@tonic-gate} 2767*0Sstevel@tonic-gate 2768*0Sstevel@tonic-gatesub list_const { 2769*0Sstevel@tonic-gate my $self = shift; 2770*0Sstevel@tonic-gate my($cx, @list) = @_; 2771*0Sstevel@tonic-gate my @a = map $self->const($_, 6), @list; 2772*0Sstevel@tonic-gate if (@a == 0) { 2773*0Sstevel@tonic-gate return "()"; 2774*0Sstevel@tonic-gate } elsif (@a == 1) { 2775*0Sstevel@tonic-gate return $a[0]; 2776*0Sstevel@tonic-gate } elsif ( @a > 2 and !grep(!/^-?\d+$/, @a)) { 2777*0Sstevel@tonic-gate # collapse (-1,0,1,2) into (-1..2) 2778*0Sstevel@tonic-gate my ($s, $e) = @a[0,-1]; 2779*0Sstevel@tonic-gate my $i = $s; 2780*0Sstevel@tonic-gate return $self->maybe_parens("$s..$e", $cx, 9) 2781*0Sstevel@tonic-gate unless grep $i++ != $_, @a; 2782*0Sstevel@tonic-gate } 2783*0Sstevel@tonic-gate return $self->maybe_parens(join(", ", @a), $cx, 6); 2784*0Sstevel@tonic-gate} 2785*0Sstevel@tonic-gate 2786*0Sstevel@tonic-gatesub pp_rv2av { 2787*0Sstevel@tonic-gate my $self = shift; 2788*0Sstevel@tonic-gate my($op, $cx) = @_; 2789*0Sstevel@tonic-gate my $kid = $op->first; 2790*0Sstevel@tonic-gate if ($kid->name eq "const") { # constant list 2791*0Sstevel@tonic-gate my $av = $self->const_sv($kid); 2792*0Sstevel@tonic-gate return $self->list_const($cx, $av->ARRAY); 2793*0Sstevel@tonic-gate } else { 2794*0Sstevel@tonic-gate return $self->maybe_local($op, $cx, $self->rv2x($op, $cx, "\@")); 2795*0Sstevel@tonic-gate } 2796*0Sstevel@tonic-gate } 2797*0Sstevel@tonic-gate 2798*0Sstevel@tonic-gatesub is_subscriptable { 2799*0Sstevel@tonic-gate my $op = shift; 2800*0Sstevel@tonic-gate if ($op->name =~ /^[ahg]elem/) { 2801*0Sstevel@tonic-gate return 1; 2802*0Sstevel@tonic-gate } elsif ($op->name eq "entersub") { 2803*0Sstevel@tonic-gate my $kid = $op->first; 2804*0Sstevel@tonic-gate return 0 unless null $kid->sibling; 2805*0Sstevel@tonic-gate $kid = $kid->first; 2806*0Sstevel@tonic-gate $kid = $kid->sibling until null $kid->sibling; 2807*0Sstevel@tonic-gate return 0 if is_scope($kid); 2808*0Sstevel@tonic-gate $kid = $kid->first; 2809*0Sstevel@tonic-gate return 0 if $kid->name eq "gv"; 2810*0Sstevel@tonic-gate return 0 if is_scalar($kid); 2811*0Sstevel@tonic-gate return is_subscriptable($kid); 2812*0Sstevel@tonic-gate } else { 2813*0Sstevel@tonic-gate return 0; 2814*0Sstevel@tonic-gate } 2815*0Sstevel@tonic-gate} 2816*0Sstevel@tonic-gate 2817*0Sstevel@tonic-gatesub elem { 2818*0Sstevel@tonic-gate my $self = shift; 2819*0Sstevel@tonic-gate my ($op, $cx, $left, $right, $padname) = @_; 2820*0Sstevel@tonic-gate my($array, $idx) = ($op->first, $op->first->sibling); 2821*0Sstevel@tonic-gate unless ($array->name eq $padname) { # Maybe this has been fixed 2822*0Sstevel@tonic-gate $array = $array->first; # skip rv2av (or ex-rv2av in _53+) 2823*0Sstevel@tonic-gate } 2824*0Sstevel@tonic-gate if ($array->name eq $padname) { 2825*0Sstevel@tonic-gate $array = $self->padany($array); 2826*0Sstevel@tonic-gate } elsif (is_scope($array)) { # ${expr}[0] 2827*0Sstevel@tonic-gate $array = "{" . $self->deparse($array, 0) . "}"; 2828*0Sstevel@tonic-gate } elsif ($array->name eq "gv") { 2829*0Sstevel@tonic-gate $array = $self->gv_name($self->gv_or_padgv($array)); 2830*0Sstevel@tonic-gate if ($array !~ /::/) { 2831*0Sstevel@tonic-gate my $prefix = ($left eq '[' ? '@' : '%'); 2832*0Sstevel@tonic-gate $array = $self->{curstash}.'::'.$array 2833*0Sstevel@tonic-gate if $self->lex_in_scope($prefix . $array); 2834*0Sstevel@tonic-gate } 2835*0Sstevel@tonic-gate } elsif (is_scalar $array) { # $x[0], $$x[0], ... 2836*0Sstevel@tonic-gate $array = $self->deparse($array, 24); 2837*0Sstevel@tonic-gate } else { 2838*0Sstevel@tonic-gate # $x[20][3]{hi} or expr->[20] 2839*0Sstevel@tonic-gate my $arrow = is_subscriptable($array) ? "" : "->"; 2840*0Sstevel@tonic-gate return $self->deparse($array, 24) . $arrow . 2841*0Sstevel@tonic-gate $left . $self->deparse($idx, 1) . $right; 2842*0Sstevel@tonic-gate } 2843*0Sstevel@tonic-gate $idx = $self->deparse($idx, 1); 2844*0Sstevel@tonic-gate 2845*0Sstevel@tonic-gate # Outer parens in an array index will confuse perl 2846*0Sstevel@tonic-gate # if we're interpolating in a regular expression, i.e. 2847*0Sstevel@tonic-gate # /$x$foo[(-1)]/ is *not* the same as /$x$foo[-1]/ 2848*0Sstevel@tonic-gate # 2849*0Sstevel@tonic-gate # If $self->{parens}, then an initial '(' will 2850*0Sstevel@tonic-gate # definitely be paired with a final ')'. If 2851*0Sstevel@tonic-gate # !$self->{parens}, the misleading parens won't 2852*0Sstevel@tonic-gate # have been added in the first place. 2853*0Sstevel@tonic-gate # 2854*0Sstevel@tonic-gate # [You might think that we could get "(...)...(...)" 2855*0Sstevel@tonic-gate # where the initial and final parens do not match 2856*0Sstevel@tonic-gate # each other. But we can't, because the above would 2857*0Sstevel@tonic-gate # only happen if there's an infix binop between the 2858*0Sstevel@tonic-gate # two pairs of parens, and *that* means that the whole 2859*0Sstevel@tonic-gate # expression would be parenthesized as well.] 2860*0Sstevel@tonic-gate # 2861*0Sstevel@tonic-gate $idx =~ s/^\((.*)\)$/$1/ if $self->{'parens'}; 2862*0Sstevel@tonic-gate 2863*0Sstevel@tonic-gate # Hash-element braces will autoquote a bareword inside themselves. 2864*0Sstevel@tonic-gate # We need to make sure that C<$hash{warn()}> doesn't come out as 2865*0Sstevel@tonic-gate # C<$hash{warn}>, which has a quite different meaning. Currently 2866*0Sstevel@tonic-gate # B::Deparse will always quote strings, even if the string was a 2867*0Sstevel@tonic-gate # bareword in the original (i.e. the OPpCONST_BARE flag is ignored 2868*0Sstevel@tonic-gate # for constant strings.) So we can cheat slightly here - if we see 2869*0Sstevel@tonic-gate # a bareword, we know that it is supposed to be a function call. 2870*0Sstevel@tonic-gate # 2871*0Sstevel@tonic-gate $idx =~ s/^([A-Za-z_]\w*)$/$1()/; 2872*0Sstevel@tonic-gate 2873*0Sstevel@tonic-gate return "\$" . $array . $left . $idx . $right; 2874*0Sstevel@tonic-gate} 2875*0Sstevel@tonic-gate 2876*0Sstevel@tonic-gatesub pp_aelem { maybe_local(@_, elem(@_, "[", "]", "padav")) } 2877*0Sstevel@tonic-gatesub pp_helem { maybe_local(@_, elem(@_, "{", "}", "padhv")) } 2878*0Sstevel@tonic-gate 2879*0Sstevel@tonic-gatesub pp_gelem { 2880*0Sstevel@tonic-gate my $self = shift; 2881*0Sstevel@tonic-gate my($op, $cx) = @_; 2882*0Sstevel@tonic-gate my($glob, $part) = ($op->first, $op->last); 2883*0Sstevel@tonic-gate $glob = $glob->first; # skip rv2gv 2884*0Sstevel@tonic-gate $glob = $glob->first if $glob->name eq "rv2gv"; # this one's a bug 2885*0Sstevel@tonic-gate my $scope = is_scope($glob); 2886*0Sstevel@tonic-gate $glob = $self->deparse($glob, 0); 2887*0Sstevel@tonic-gate $part = $self->deparse($part, 1); 2888*0Sstevel@tonic-gate return "*" . ($scope ? "{$glob}" : $glob) . "{$part}"; 2889*0Sstevel@tonic-gate} 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gatesub slice { 2892*0Sstevel@tonic-gate my $self = shift; 2893*0Sstevel@tonic-gate my ($op, $cx, $left, $right, $regname, $padname) = @_; 2894*0Sstevel@tonic-gate my $last; 2895*0Sstevel@tonic-gate my(@elems, $kid, $array, $list); 2896*0Sstevel@tonic-gate if (class($op) eq "LISTOP") { 2897*0Sstevel@tonic-gate $last = $op->last; 2898*0Sstevel@tonic-gate } else { # ex-hslice inside delete() 2899*0Sstevel@tonic-gate for ($kid = $op->first; !null $kid->sibling; $kid = $kid->sibling) {} 2900*0Sstevel@tonic-gate $last = $kid; 2901*0Sstevel@tonic-gate } 2902*0Sstevel@tonic-gate $array = $last; 2903*0Sstevel@tonic-gate $array = $array->first 2904*0Sstevel@tonic-gate if $array->name eq $regname or $array->name eq "null"; 2905*0Sstevel@tonic-gate if (is_scope($array)) { 2906*0Sstevel@tonic-gate $array = "{" . $self->deparse($array, 0) . "}"; 2907*0Sstevel@tonic-gate } elsif ($array->name eq $padname) { 2908*0Sstevel@tonic-gate $array = $self->padany($array); 2909*0Sstevel@tonic-gate } else { 2910*0Sstevel@tonic-gate $array = $self->deparse($array, 24); 2911*0Sstevel@tonic-gate } 2912*0Sstevel@tonic-gate $kid = $op->first->sibling; # skip pushmark 2913*0Sstevel@tonic-gate if ($kid->name eq "list") { 2914*0Sstevel@tonic-gate $kid = $kid->first->sibling; # skip list, pushmark 2915*0Sstevel@tonic-gate for (; !null $kid; $kid = $kid->sibling) { 2916*0Sstevel@tonic-gate push @elems, $self->deparse($kid, 6); 2917*0Sstevel@tonic-gate } 2918*0Sstevel@tonic-gate $list = join(", ", @elems); 2919*0Sstevel@tonic-gate } else { 2920*0Sstevel@tonic-gate $list = $self->deparse($kid, 1); 2921*0Sstevel@tonic-gate } 2922*0Sstevel@tonic-gate return "\@" . $array . $left . $list . $right; 2923*0Sstevel@tonic-gate} 2924*0Sstevel@tonic-gate 2925*0Sstevel@tonic-gatesub pp_aslice { maybe_local(@_, slice(@_, "[", "]", "rv2av", "padav")) } 2926*0Sstevel@tonic-gatesub pp_hslice { maybe_local(@_, slice(@_, "{", "}", "rv2hv", "padhv")) } 2927*0Sstevel@tonic-gate 2928*0Sstevel@tonic-gatesub pp_lslice { 2929*0Sstevel@tonic-gate my $self = shift; 2930*0Sstevel@tonic-gate my($op, $cx) = @_; 2931*0Sstevel@tonic-gate my $idx = $op->first; 2932*0Sstevel@tonic-gate my $list = $op->last; 2933*0Sstevel@tonic-gate my(@elems, $kid); 2934*0Sstevel@tonic-gate $list = $self->deparse($list, 1); 2935*0Sstevel@tonic-gate $idx = $self->deparse($idx, 1); 2936*0Sstevel@tonic-gate return "($list)" . "[$idx]"; 2937*0Sstevel@tonic-gate} 2938*0Sstevel@tonic-gate 2939*0Sstevel@tonic-gatesub want_scalar { 2940*0Sstevel@tonic-gate my $op = shift; 2941*0Sstevel@tonic-gate return ($op->flags & OPf_WANT) == OPf_WANT_SCALAR; 2942*0Sstevel@tonic-gate} 2943*0Sstevel@tonic-gate 2944*0Sstevel@tonic-gatesub want_list { 2945*0Sstevel@tonic-gate my $op = shift; 2946*0Sstevel@tonic-gate return ($op->flags & OPf_WANT) == OPf_WANT_LIST; 2947*0Sstevel@tonic-gate} 2948*0Sstevel@tonic-gate 2949*0Sstevel@tonic-gatesub method { 2950*0Sstevel@tonic-gate my $self = shift; 2951*0Sstevel@tonic-gate my($op, $cx) = @_; 2952*0Sstevel@tonic-gate my $kid = $op->first->sibling; # skip pushmark 2953*0Sstevel@tonic-gate my($meth, $obj, @exprs); 2954*0Sstevel@tonic-gate if ($kid->name eq "list" and want_list $kid) { 2955*0Sstevel@tonic-gate # When an indirect object isn't a bareword but the args are in 2956*0Sstevel@tonic-gate # parens, the parens aren't part of the method syntax (the LLAFR 2957*0Sstevel@tonic-gate # doesn't apply), but they make a list with OPf_PARENS set that 2958*0Sstevel@tonic-gate # doesn't get flattened by the append_elem that adds the method, 2959*0Sstevel@tonic-gate # making a (object, arg1, arg2, ...) list where the object 2960*0Sstevel@tonic-gate # usually is. This can be distinguished from 2961*0Sstevel@tonic-gate # `($obj, $arg1, $arg2)->meth()' (which is legal if $arg2 is an 2962*0Sstevel@tonic-gate # object) because in the later the list is in scalar context 2963*0Sstevel@tonic-gate # as the left side of -> always is, while in the former 2964*0Sstevel@tonic-gate # the list is in list context as method arguments always are. 2965*0Sstevel@tonic-gate # (Good thing there aren't method prototypes!) 2966*0Sstevel@tonic-gate $meth = $kid->sibling; 2967*0Sstevel@tonic-gate $kid = $kid->first->sibling; # skip pushmark 2968*0Sstevel@tonic-gate $obj = $kid; 2969*0Sstevel@tonic-gate $kid = $kid->sibling; 2970*0Sstevel@tonic-gate for (; not null $kid; $kid = $kid->sibling) { 2971*0Sstevel@tonic-gate push @exprs, $self->deparse($kid, 6); 2972*0Sstevel@tonic-gate } 2973*0Sstevel@tonic-gate } else { 2974*0Sstevel@tonic-gate $obj = $kid; 2975*0Sstevel@tonic-gate $kid = $kid->sibling; 2976*0Sstevel@tonic-gate for (; !null ($kid->sibling) && $kid->name ne "method_named"; 2977*0Sstevel@tonic-gate $kid = $kid->sibling) { 2978*0Sstevel@tonic-gate push @exprs, $self->deparse($kid, 6); 2979*0Sstevel@tonic-gate } 2980*0Sstevel@tonic-gate $meth = $kid; 2981*0Sstevel@tonic-gate } 2982*0Sstevel@tonic-gate $obj = $self->deparse($obj, 24); 2983*0Sstevel@tonic-gate if ($meth->name eq "method_named") { 2984*0Sstevel@tonic-gate $meth = $self->const_sv($meth)->PV; 2985*0Sstevel@tonic-gate } else { 2986*0Sstevel@tonic-gate $meth = $meth->first; 2987*0Sstevel@tonic-gate if ($meth->name eq "const") { 2988*0Sstevel@tonic-gate # As of 5.005_58, this case is probably obsoleted by the 2989*0Sstevel@tonic-gate # method_named case above 2990*0Sstevel@tonic-gate $meth = $self->const_sv($meth)->PV; # needs to be bare 2991*0Sstevel@tonic-gate } else { 2992*0Sstevel@tonic-gate $meth = $self->deparse($meth, 1); 2993*0Sstevel@tonic-gate } 2994*0Sstevel@tonic-gate } 2995*0Sstevel@tonic-gate my $args = join(", ", @exprs); 2996*0Sstevel@tonic-gate $kid = $obj . "->" . $meth; 2997*0Sstevel@tonic-gate if (length $args) { 2998*0Sstevel@tonic-gate return $kid . "(" . $args . ")"; # parens mandatory 2999*0Sstevel@tonic-gate } else { 3000*0Sstevel@tonic-gate return $kid; 3001*0Sstevel@tonic-gate } 3002*0Sstevel@tonic-gate} 3003*0Sstevel@tonic-gate 3004*0Sstevel@tonic-gate# returns "&" if the prototype doesn't match the args, 3005*0Sstevel@tonic-gate# or ("", $args_after_prototype_demunging) if it does. 3006*0Sstevel@tonic-gatesub check_proto { 3007*0Sstevel@tonic-gate my $self = shift; 3008*0Sstevel@tonic-gate return "&" if $self->{'noproto'}; 3009*0Sstevel@tonic-gate my($proto, @args) = @_; 3010*0Sstevel@tonic-gate my($arg, $real); 3011*0Sstevel@tonic-gate my $doneok = 0; 3012*0Sstevel@tonic-gate my @reals; 3013*0Sstevel@tonic-gate # An unbackslashed @ or % gobbles up the rest of the args 3014*0Sstevel@tonic-gate 1 while $proto =~ s/(?<!\\)([@%])[^\]]+$/$1/; 3015*0Sstevel@tonic-gate while ($proto) { 3016*0Sstevel@tonic-gate $proto =~ s/^(\\?[\$\@&%*]|\\\[[\$\@&%*]+\]|;)//; 3017*0Sstevel@tonic-gate my $chr = $1; 3018*0Sstevel@tonic-gate if ($chr eq "") { 3019*0Sstevel@tonic-gate return "&" if @args; 3020*0Sstevel@tonic-gate } elsif ($chr eq ";") { 3021*0Sstevel@tonic-gate $doneok = 1; 3022*0Sstevel@tonic-gate } elsif ($chr eq "@" or $chr eq "%") { 3023*0Sstevel@tonic-gate push @reals, map($self->deparse($_, 6), @args); 3024*0Sstevel@tonic-gate @args = (); 3025*0Sstevel@tonic-gate } else { 3026*0Sstevel@tonic-gate $arg = shift @args; 3027*0Sstevel@tonic-gate last unless $arg; 3028*0Sstevel@tonic-gate if ($chr eq "\$") { 3029*0Sstevel@tonic-gate if (want_scalar $arg) { 3030*0Sstevel@tonic-gate push @reals, $self->deparse($arg, 6); 3031*0Sstevel@tonic-gate } else { 3032*0Sstevel@tonic-gate return "&"; 3033*0Sstevel@tonic-gate } 3034*0Sstevel@tonic-gate } elsif ($chr eq "&") { 3035*0Sstevel@tonic-gate if ($arg->name =~ /^(s?refgen|undef)$/) { 3036*0Sstevel@tonic-gate push @reals, $self->deparse($arg, 6); 3037*0Sstevel@tonic-gate } else { 3038*0Sstevel@tonic-gate return "&"; 3039*0Sstevel@tonic-gate } 3040*0Sstevel@tonic-gate } elsif ($chr eq "*") { 3041*0Sstevel@tonic-gate if ($arg->name =~ /^s?refgen$/ 3042*0Sstevel@tonic-gate and $arg->first->first->name eq "rv2gv") 3043*0Sstevel@tonic-gate { 3044*0Sstevel@tonic-gate $real = $arg->first->first; # skip refgen, null 3045*0Sstevel@tonic-gate if ($real->first->name eq "gv") { 3046*0Sstevel@tonic-gate push @reals, $self->deparse($real, 6); 3047*0Sstevel@tonic-gate } else { 3048*0Sstevel@tonic-gate push @reals, $self->deparse($real->first, 6); 3049*0Sstevel@tonic-gate } 3050*0Sstevel@tonic-gate } else { 3051*0Sstevel@tonic-gate return "&"; 3052*0Sstevel@tonic-gate } 3053*0Sstevel@tonic-gate } elsif (substr($chr, 0, 1) eq "\\") { 3054*0Sstevel@tonic-gate $chr =~ tr/\\[]//d; 3055*0Sstevel@tonic-gate if ($arg->name =~ /^s?refgen$/ and 3056*0Sstevel@tonic-gate !null($real = $arg->first) and 3057*0Sstevel@tonic-gate ($chr =~ /\$/ && is_scalar($real->first) 3058*0Sstevel@tonic-gate or ($chr =~ /@/ 3059*0Sstevel@tonic-gate && class($real->first->sibling) ne 'NULL' 3060*0Sstevel@tonic-gate && $real->first->sibling->name 3061*0Sstevel@tonic-gate =~ /^(rv2|pad)av$/) 3062*0Sstevel@tonic-gate or ($chr =~ /%/ 3063*0Sstevel@tonic-gate && class($real->first->sibling) ne 'NULL' 3064*0Sstevel@tonic-gate && $real->first->sibling->name 3065*0Sstevel@tonic-gate =~ /^(rv2|pad)hv$/) 3066*0Sstevel@tonic-gate #or ($chr =~ /&/ # This doesn't work 3067*0Sstevel@tonic-gate # && $real->first->name eq "rv2cv") 3068*0Sstevel@tonic-gate or ($chr =~ /\*/ 3069*0Sstevel@tonic-gate && $real->first->name eq "rv2gv"))) 3070*0Sstevel@tonic-gate { 3071*0Sstevel@tonic-gate push @reals, $self->deparse($real, 6); 3072*0Sstevel@tonic-gate } else { 3073*0Sstevel@tonic-gate return "&"; 3074*0Sstevel@tonic-gate } 3075*0Sstevel@tonic-gate } 3076*0Sstevel@tonic-gate } 3077*0Sstevel@tonic-gate } 3078*0Sstevel@tonic-gate return "&" if $proto and !$doneok; # too few args and no `;' 3079*0Sstevel@tonic-gate return "&" if @args; # too many args 3080*0Sstevel@tonic-gate return ("", join ", ", @reals); 3081*0Sstevel@tonic-gate} 3082*0Sstevel@tonic-gate 3083*0Sstevel@tonic-gatesub pp_entersub { 3084*0Sstevel@tonic-gate my $self = shift; 3085*0Sstevel@tonic-gate my($op, $cx) = @_; 3086*0Sstevel@tonic-gate return $self->method($op, $cx) unless null $op->first->sibling; 3087*0Sstevel@tonic-gate my $prefix = ""; 3088*0Sstevel@tonic-gate my $amper = ""; 3089*0Sstevel@tonic-gate my($kid, @exprs); 3090*0Sstevel@tonic-gate if ($op->flags & OPf_SPECIAL && !($op->flags & OPf_MOD)) { 3091*0Sstevel@tonic-gate $prefix = "do "; 3092*0Sstevel@tonic-gate } elsif ($op->private & OPpENTERSUB_AMPER) { 3093*0Sstevel@tonic-gate $amper = "&"; 3094*0Sstevel@tonic-gate } 3095*0Sstevel@tonic-gate $kid = $op->first; 3096*0Sstevel@tonic-gate $kid = $kid->first->sibling; # skip ex-list, pushmark 3097*0Sstevel@tonic-gate for (; not null $kid->sibling; $kid = $kid->sibling) { 3098*0Sstevel@tonic-gate push @exprs, $kid; 3099*0Sstevel@tonic-gate } 3100*0Sstevel@tonic-gate my $simple = 0; 3101*0Sstevel@tonic-gate my $proto = undef; 3102*0Sstevel@tonic-gate if (is_scope($kid)) { 3103*0Sstevel@tonic-gate $amper = "&"; 3104*0Sstevel@tonic-gate $kid = "{" . $self->deparse($kid, 0) . "}"; 3105*0Sstevel@tonic-gate } elsif ($kid->first->name eq "gv") { 3106*0Sstevel@tonic-gate my $gv = $self->gv_or_padgv($kid->first); 3107*0Sstevel@tonic-gate if (class($gv->CV) ne "SPECIAL") { 3108*0Sstevel@tonic-gate $proto = $gv->CV->PV if $gv->CV->FLAGS & SVf_POK; 3109*0Sstevel@tonic-gate } 3110*0Sstevel@tonic-gate $simple = 1; # only calls of named functions can be prototyped 3111*0Sstevel@tonic-gate $kid = $self->deparse($kid, 24); 3112*0Sstevel@tonic-gate } elsif (is_scalar ($kid->first) && $kid->first->name ne 'rv2cv') { 3113*0Sstevel@tonic-gate $amper = "&"; 3114*0Sstevel@tonic-gate $kid = $self->deparse($kid, 24); 3115*0Sstevel@tonic-gate } else { 3116*0Sstevel@tonic-gate $prefix = ""; 3117*0Sstevel@tonic-gate my $arrow = is_subscriptable($kid->first) ? "" : "->"; 3118*0Sstevel@tonic-gate $kid = $self->deparse($kid, 24) . $arrow; 3119*0Sstevel@tonic-gate } 3120*0Sstevel@tonic-gate 3121*0Sstevel@tonic-gate # Doesn't matter how many prototypes there are, if 3122*0Sstevel@tonic-gate # they haven't happened yet! 3123*0Sstevel@tonic-gate my $declared; 3124*0Sstevel@tonic-gate { 3125*0Sstevel@tonic-gate no strict 'refs'; 3126*0Sstevel@tonic-gate no warnings 'uninitialized'; 3127*0Sstevel@tonic-gate $declared = exists $self->{'subs_declared'}{$kid} 3128*0Sstevel@tonic-gate || ( 3129*0Sstevel@tonic-gate defined &{ %{$self->{'curstash'}."::"}->{$kid} } 3130*0Sstevel@tonic-gate && !exists 3131*0Sstevel@tonic-gate $self->{'subs_deparsed'}{$self->{'curstash'}."::".$kid} 3132*0Sstevel@tonic-gate && defined prototype $self->{'curstash'}."::".$kid 3133*0Sstevel@tonic-gate ); 3134*0Sstevel@tonic-gate if (!$declared && defined($proto)) { 3135*0Sstevel@tonic-gate # Avoid "too early to check prototype" warning 3136*0Sstevel@tonic-gate ($amper, $proto) = ('&'); 3137*0Sstevel@tonic-gate } 3138*0Sstevel@tonic-gate } 3139*0Sstevel@tonic-gate 3140*0Sstevel@tonic-gate my $args; 3141*0Sstevel@tonic-gate if ($declared and defined $proto and not $amper) { 3142*0Sstevel@tonic-gate ($amper, $args) = $self->check_proto($proto, @exprs); 3143*0Sstevel@tonic-gate if ($amper eq "&") { 3144*0Sstevel@tonic-gate $args = join(", ", map($self->deparse($_, 6), @exprs)); 3145*0Sstevel@tonic-gate } 3146*0Sstevel@tonic-gate } else { 3147*0Sstevel@tonic-gate $args = join(", ", map($self->deparse($_, 6), @exprs)); 3148*0Sstevel@tonic-gate } 3149*0Sstevel@tonic-gate if ($prefix or $amper) { 3150*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED) { 3151*0Sstevel@tonic-gate return $prefix . $amper . $kid . "(" . $args . ")"; 3152*0Sstevel@tonic-gate } else { 3153*0Sstevel@tonic-gate return $prefix . $amper. $kid; 3154*0Sstevel@tonic-gate } 3155*0Sstevel@tonic-gate } else { 3156*0Sstevel@tonic-gate # glob() invocations can be translated into calls of 3157*0Sstevel@tonic-gate # CORE::GLOBAL::glob with a second parameter, a number. 3158*0Sstevel@tonic-gate # Reverse this. 3159*0Sstevel@tonic-gate if ($kid eq "CORE::GLOBAL::glob") { 3160*0Sstevel@tonic-gate $kid = "glob"; 3161*0Sstevel@tonic-gate $args =~ s/\s*,[^,]+$//; 3162*0Sstevel@tonic-gate } 3163*0Sstevel@tonic-gate 3164*0Sstevel@tonic-gate # It's a syntax error to call CORE::GLOBAL::foo without a prefix, 3165*0Sstevel@tonic-gate # so it must have been translated from a keyword call. Translate 3166*0Sstevel@tonic-gate # it back. 3167*0Sstevel@tonic-gate $kid =~ s/^CORE::GLOBAL:://; 3168*0Sstevel@tonic-gate 3169*0Sstevel@tonic-gate my $dproto = defined($proto) ? $proto : "undefined"; 3170*0Sstevel@tonic-gate if (!$declared) { 3171*0Sstevel@tonic-gate return "$kid(" . $args . ")"; 3172*0Sstevel@tonic-gate } elsif ($dproto eq "") { 3173*0Sstevel@tonic-gate return $kid; 3174*0Sstevel@tonic-gate } elsif ($dproto eq "\$" and is_scalar($exprs[0])) { 3175*0Sstevel@tonic-gate # is_scalar is an excessively conservative test here: 3176*0Sstevel@tonic-gate # really, we should be comparing to the precedence of the 3177*0Sstevel@tonic-gate # top operator of $exprs[0] (ala unop()), but that would 3178*0Sstevel@tonic-gate # take some major code restructuring to do right. 3179*0Sstevel@tonic-gate return $self->maybe_parens_func($kid, $args, $cx, 16); 3180*0Sstevel@tonic-gate } elsif ($dproto ne '$' and defined($proto) || $simple) { #' 3181*0Sstevel@tonic-gate return $self->maybe_parens_func($kid, $args, $cx, 5); 3182*0Sstevel@tonic-gate } else { 3183*0Sstevel@tonic-gate return "$kid(" . $args . ")"; 3184*0Sstevel@tonic-gate } 3185*0Sstevel@tonic-gate } 3186*0Sstevel@tonic-gate} 3187*0Sstevel@tonic-gate 3188*0Sstevel@tonic-gatesub pp_enterwrite { unop(@_, "write") } 3189*0Sstevel@tonic-gate 3190*0Sstevel@tonic-gate# escape things that cause interpolation in double quotes, 3191*0Sstevel@tonic-gate# but not character escapes 3192*0Sstevel@tonic-gatesub uninterp { 3193*0Sstevel@tonic-gate my($str) = @_; 3194*0Sstevel@tonic-gate $str =~ s/(^|\G|[^\\])((?:\\\\)*)([\$\@]|\\[uUlLQE])/$1$2\\$3/g; 3195*0Sstevel@tonic-gate return $str; 3196*0Sstevel@tonic-gate} 3197*0Sstevel@tonic-gate 3198*0Sstevel@tonic-gate{ 3199*0Sstevel@tonic-gatemy $bal; 3200*0Sstevel@tonic-gateBEGIN { 3201*0Sstevel@tonic-gate use re "eval"; 3202*0Sstevel@tonic-gate # Matches any string which is balanced with respect to {braces} 3203*0Sstevel@tonic-gate $bal = qr( 3204*0Sstevel@tonic-gate (?: 3205*0Sstevel@tonic-gate [^\\{}] 3206*0Sstevel@tonic-gate | \\\\ 3207*0Sstevel@tonic-gate | \\[{}] 3208*0Sstevel@tonic-gate | \{(??{$bal})\} 3209*0Sstevel@tonic-gate )* 3210*0Sstevel@tonic-gate )x; 3211*0Sstevel@tonic-gate} 3212*0Sstevel@tonic-gate 3213*0Sstevel@tonic-gate# the same, but treat $|, $), $( and $ at the end of the string differently 3214*0Sstevel@tonic-gatesub re_uninterp { 3215*0Sstevel@tonic-gate my($str) = @_; 3216*0Sstevel@tonic-gate 3217*0Sstevel@tonic-gate $str =~ s/ 3218*0Sstevel@tonic-gate ( ^|\G # $1 3219*0Sstevel@tonic-gate | [^\\] 3220*0Sstevel@tonic-gate ) 3221*0Sstevel@tonic-gate 3222*0Sstevel@tonic-gate ( # $2 3223*0Sstevel@tonic-gate (?:\\\\)* 3224*0Sstevel@tonic-gate ) 3225*0Sstevel@tonic-gate 3226*0Sstevel@tonic-gate ( # $3 3227*0Sstevel@tonic-gate (\(\?\??\{$bal\}\)) # $4 3228*0Sstevel@tonic-gate | [\$\@] 3229*0Sstevel@tonic-gate (?!\||\)|\(|$) 3230*0Sstevel@tonic-gate | \\[uUlLQE] 3231*0Sstevel@tonic-gate ) 3232*0Sstevel@tonic-gate 3233*0Sstevel@tonic-gate /defined($4) && length($4) ? "$1$2$4" : "$1$2\\$3"/xeg; 3234*0Sstevel@tonic-gate 3235*0Sstevel@tonic-gate return $str; 3236*0Sstevel@tonic-gate} 3237*0Sstevel@tonic-gate 3238*0Sstevel@tonic-gate# This is for regular expressions with the /x modifier 3239*0Sstevel@tonic-gate# We have to leave comments unmangled. 3240*0Sstevel@tonic-gatesub re_uninterp_extended { 3241*0Sstevel@tonic-gate my($str) = @_; 3242*0Sstevel@tonic-gate 3243*0Sstevel@tonic-gate $str =~ s/ 3244*0Sstevel@tonic-gate ( ^|\G # $1 3245*0Sstevel@tonic-gate | [^\\] 3246*0Sstevel@tonic-gate ) 3247*0Sstevel@tonic-gate 3248*0Sstevel@tonic-gate ( # $2 3249*0Sstevel@tonic-gate (?:\\\\)* 3250*0Sstevel@tonic-gate ) 3251*0Sstevel@tonic-gate 3252*0Sstevel@tonic-gate ( # $3 3253*0Sstevel@tonic-gate ( \(\?\??\{$bal\}\) # $4 (skip over (?{}) and (??{}) blocks) 3254*0Sstevel@tonic-gate | \#[^\n]* # (skip over comments) 3255*0Sstevel@tonic-gate ) 3256*0Sstevel@tonic-gate | [\$\@] 3257*0Sstevel@tonic-gate (?!\||\)|\(|$|\s) 3258*0Sstevel@tonic-gate | \\[uUlLQE] 3259*0Sstevel@tonic-gate ) 3260*0Sstevel@tonic-gate 3261*0Sstevel@tonic-gate /defined($4) && length($4) ? "$1$2$4" : "$1$2\\$3"/xeg; 3262*0Sstevel@tonic-gate 3263*0Sstevel@tonic-gate return $str; 3264*0Sstevel@tonic-gate} 3265*0Sstevel@tonic-gate} 3266*0Sstevel@tonic-gate 3267*0Sstevel@tonic-gatemy %unctrl = # portable to to EBCDIC 3268*0Sstevel@tonic-gate ( 3269*0Sstevel@tonic-gate "\c@" => '\c@', # unused 3270*0Sstevel@tonic-gate "\cA" => '\cA', 3271*0Sstevel@tonic-gate "\cB" => '\cB', 3272*0Sstevel@tonic-gate "\cC" => '\cC', 3273*0Sstevel@tonic-gate "\cD" => '\cD', 3274*0Sstevel@tonic-gate "\cE" => '\cE', 3275*0Sstevel@tonic-gate "\cF" => '\cF', 3276*0Sstevel@tonic-gate "\cG" => '\cG', 3277*0Sstevel@tonic-gate "\cH" => '\cH', 3278*0Sstevel@tonic-gate "\cI" => '\cI', 3279*0Sstevel@tonic-gate "\cJ" => '\cJ', 3280*0Sstevel@tonic-gate "\cK" => '\cK', 3281*0Sstevel@tonic-gate "\cL" => '\cL', 3282*0Sstevel@tonic-gate "\cM" => '\cM', 3283*0Sstevel@tonic-gate "\cN" => '\cN', 3284*0Sstevel@tonic-gate "\cO" => '\cO', 3285*0Sstevel@tonic-gate "\cP" => '\cP', 3286*0Sstevel@tonic-gate "\cQ" => '\cQ', 3287*0Sstevel@tonic-gate "\cR" => '\cR', 3288*0Sstevel@tonic-gate "\cS" => '\cS', 3289*0Sstevel@tonic-gate "\cT" => '\cT', 3290*0Sstevel@tonic-gate "\cU" => '\cU', 3291*0Sstevel@tonic-gate "\cV" => '\cV', 3292*0Sstevel@tonic-gate "\cW" => '\cW', 3293*0Sstevel@tonic-gate "\cX" => '\cX', 3294*0Sstevel@tonic-gate "\cY" => '\cY', 3295*0Sstevel@tonic-gate "\cZ" => '\cZ', 3296*0Sstevel@tonic-gate "\c[" => '\c[', # unused 3297*0Sstevel@tonic-gate "\c\\" => '\c\\', # unused 3298*0Sstevel@tonic-gate "\c]" => '\c]', # unused 3299*0Sstevel@tonic-gate "\c_" => '\c_', # unused 3300*0Sstevel@tonic-gate ); 3301*0Sstevel@tonic-gate 3302*0Sstevel@tonic-gate# character escapes, but not delimiters that might need to be escaped 3303*0Sstevel@tonic-gatesub escape_str { # ASCII, UTF8 3304*0Sstevel@tonic-gate my($str) = @_; 3305*0Sstevel@tonic-gate $str =~ s/(.)/ord($1) > 255 ? sprintf("\\x{%x}", ord($1)) : $1/eg; 3306*0Sstevel@tonic-gate $str =~ s/\a/\\a/g; 3307*0Sstevel@tonic-gate# $str =~ s/\cH/\\b/g; # \b means something different in a regex 3308*0Sstevel@tonic-gate $str =~ s/\t/\\t/g; 3309*0Sstevel@tonic-gate $str =~ s/\n/\\n/g; 3310*0Sstevel@tonic-gate $str =~ s/\e/\\e/g; 3311*0Sstevel@tonic-gate $str =~ s/\f/\\f/g; 3312*0Sstevel@tonic-gate $str =~ s/\r/\\r/g; 3313*0Sstevel@tonic-gate $str =~ s/([\cA-\cZ])/$unctrl{$1}/ge; 3314*0Sstevel@tonic-gate $str =~ s/([[:^print:]])/sprintf("\\%03o", ord($1))/ge; 3315*0Sstevel@tonic-gate return $str; 3316*0Sstevel@tonic-gate} 3317*0Sstevel@tonic-gate 3318*0Sstevel@tonic-gate# For regexes with the /x modifier. 3319*0Sstevel@tonic-gate# Leave whitespace unmangled. 3320*0Sstevel@tonic-gatesub escape_extended_re { 3321*0Sstevel@tonic-gate my($str) = @_; 3322*0Sstevel@tonic-gate $str =~ s/(.)/ord($1) > 255 ? sprintf("\\x{%x}", ord($1)) : $1/eg; 3323*0Sstevel@tonic-gate $str =~ s/([[:^print:]])/ 3324*0Sstevel@tonic-gate ($1 =~ y! \t\n!!) ? $1 : sprintf("\\%03o", ord($1))/ge; 3325*0Sstevel@tonic-gate $str =~ s/\n/\n\f/g; 3326*0Sstevel@tonic-gate return $str; 3327*0Sstevel@tonic-gate} 3328*0Sstevel@tonic-gate 3329*0Sstevel@tonic-gate# Don't do this for regexen 3330*0Sstevel@tonic-gatesub unback { 3331*0Sstevel@tonic-gate my($str) = @_; 3332*0Sstevel@tonic-gate $str =~ s/\\/\\\\/g; 3333*0Sstevel@tonic-gate return $str; 3334*0Sstevel@tonic-gate} 3335*0Sstevel@tonic-gate 3336*0Sstevel@tonic-gate# Remove backslashes which precede literal control characters, 3337*0Sstevel@tonic-gate# to avoid creating ambiguity when we escape the latter. 3338*0Sstevel@tonic-gatesub re_unback { 3339*0Sstevel@tonic-gate my($str) = @_; 3340*0Sstevel@tonic-gate 3341*0Sstevel@tonic-gate # the insane complexity here is due to the behaviour of "\c\" 3342*0Sstevel@tonic-gate $str =~ s/(^|[^\\]|\\c\\)(?<!\\c)\\(\\\\)*(?=[[:^print:]])/$1$2/g; 3343*0Sstevel@tonic-gate return $str; 3344*0Sstevel@tonic-gate} 3345*0Sstevel@tonic-gate 3346*0Sstevel@tonic-gatesub balanced_delim { 3347*0Sstevel@tonic-gate my($str) = @_; 3348*0Sstevel@tonic-gate my @str = split //, $str; 3349*0Sstevel@tonic-gate my($ar, $open, $close, $fail, $c, $cnt); 3350*0Sstevel@tonic-gate for $ar (['[',']'], ['(',')'], ['<','>'], ['{','}']) { 3351*0Sstevel@tonic-gate ($open, $close) = @$ar; 3352*0Sstevel@tonic-gate $fail = 0; $cnt = 0; 3353*0Sstevel@tonic-gate for $c (@str) { 3354*0Sstevel@tonic-gate if ($c eq $open) { 3355*0Sstevel@tonic-gate $cnt++; 3356*0Sstevel@tonic-gate } elsif ($c eq $close) { 3357*0Sstevel@tonic-gate $cnt--; 3358*0Sstevel@tonic-gate if ($cnt < 0) { 3359*0Sstevel@tonic-gate # qq()() isn't ")(" 3360*0Sstevel@tonic-gate $fail = 1; 3361*0Sstevel@tonic-gate last; 3362*0Sstevel@tonic-gate } 3363*0Sstevel@tonic-gate } 3364*0Sstevel@tonic-gate } 3365*0Sstevel@tonic-gate $fail = 1 if $cnt != 0; 3366*0Sstevel@tonic-gate return ($open, "$open$str$close") if not $fail; 3367*0Sstevel@tonic-gate } 3368*0Sstevel@tonic-gate return ("", $str); 3369*0Sstevel@tonic-gate} 3370*0Sstevel@tonic-gate 3371*0Sstevel@tonic-gatesub single_delim { 3372*0Sstevel@tonic-gate my($q, $default, $str) = @_; 3373*0Sstevel@tonic-gate return "$default$str$default" if $default and index($str, $default) == -1; 3374*0Sstevel@tonic-gate if ($q ne 'qr') { 3375*0Sstevel@tonic-gate (my $succeed, $str) = balanced_delim($str); 3376*0Sstevel@tonic-gate return "$q$str" if $succeed; 3377*0Sstevel@tonic-gate } 3378*0Sstevel@tonic-gate for my $delim ('/', '"', '#') { 3379*0Sstevel@tonic-gate return "$q$delim" . $str . $delim if index($str, $delim) == -1; 3380*0Sstevel@tonic-gate } 3381*0Sstevel@tonic-gate if ($default) { 3382*0Sstevel@tonic-gate $str =~ s/$default/\\$default/g; 3383*0Sstevel@tonic-gate return "$default$str$default"; 3384*0Sstevel@tonic-gate } else { 3385*0Sstevel@tonic-gate $str =~ s[/][\\/]g; 3386*0Sstevel@tonic-gate return "$q/$str/"; 3387*0Sstevel@tonic-gate } 3388*0Sstevel@tonic-gate} 3389*0Sstevel@tonic-gate 3390*0Sstevel@tonic-gatemy $max_prec; 3391*0Sstevel@tonic-gateBEGIN { $max_prec = int(0.999 + 8*length(pack("F", 42))*log(2)/log(10)); } 3392*0Sstevel@tonic-gate 3393*0Sstevel@tonic-gate# Split a floating point number into an integer mantissa and a binary 3394*0Sstevel@tonic-gate# exponent. Assumes you've already made sure the number isn't zero or 3395*0Sstevel@tonic-gate# some weird infinity or NaN. 3396*0Sstevel@tonic-gatesub split_float { 3397*0Sstevel@tonic-gate my($f) = @_; 3398*0Sstevel@tonic-gate my $exponent = 0; 3399*0Sstevel@tonic-gate if ($f == int($f)) { 3400*0Sstevel@tonic-gate while ($f % 2 == 0) { 3401*0Sstevel@tonic-gate $f /= 2; 3402*0Sstevel@tonic-gate $exponent++; 3403*0Sstevel@tonic-gate } 3404*0Sstevel@tonic-gate } else { 3405*0Sstevel@tonic-gate while ($f != int($f)) { 3406*0Sstevel@tonic-gate $f *= 2; 3407*0Sstevel@tonic-gate $exponent--; 3408*0Sstevel@tonic-gate } 3409*0Sstevel@tonic-gate } 3410*0Sstevel@tonic-gate my $mantissa = sprintf("%.0f", $f); 3411*0Sstevel@tonic-gate return ($mantissa, $exponent); 3412*0Sstevel@tonic-gate} 3413*0Sstevel@tonic-gate 3414*0Sstevel@tonic-gatesub const { 3415*0Sstevel@tonic-gate my $self = shift; 3416*0Sstevel@tonic-gate my($sv, $cx) = @_; 3417*0Sstevel@tonic-gate if ($self->{'use_dumper'}) { 3418*0Sstevel@tonic-gate return $self->const_dumper($sv, $cx); 3419*0Sstevel@tonic-gate } 3420*0Sstevel@tonic-gate if (class($sv) eq "SPECIAL") { 3421*0Sstevel@tonic-gate # sv_undef, sv_yes, sv_no 3422*0Sstevel@tonic-gate return ('undef', '1', $self->maybe_parens("!1", $cx, 21))[$$sv-1]; 3423*0Sstevel@tonic-gate } elsif (class($sv) eq "NULL") { 3424*0Sstevel@tonic-gate return 'undef'; 3425*0Sstevel@tonic-gate } 3426*0Sstevel@tonic-gate # convert a version object into the "v1.2.3" string in its V magic 3427*0Sstevel@tonic-gate if ($sv->FLAGS & SVs_RMG) { 3428*0Sstevel@tonic-gate for (my $mg = $sv->MAGIC; $mg; $mg = $mg->MOREMAGIC) { 3429*0Sstevel@tonic-gate return $mg->PTR if $mg->TYPE eq 'V'; 3430*0Sstevel@tonic-gate } 3431*0Sstevel@tonic-gate } 3432*0Sstevel@tonic-gate 3433*0Sstevel@tonic-gate if ($sv->FLAGS & SVf_IOK) { 3434*0Sstevel@tonic-gate my $str = $sv->int_value; 3435*0Sstevel@tonic-gate $str = $self->maybe_parens($str, $cx, 21) if $str < 0; 3436*0Sstevel@tonic-gate return $str; 3437*0Sstevel@tonic-gate } elsif ($sv->FLAGS & SVf_NOK) { 3438*0Sstevel@tonic-gate my $nv = $sv->NV; 3439*0Sstevel@tonic-gate if ($nv == 0) { 3440*0Sstevel@tonic-gate if (pack("F", $nv) eq pack("F", 0)) { 3441*0Sstevel@tonic-gate # positive zero 3442*0Sstevel@tonic-gate return "0"; 3443*0Sstevel@tonic-gate } else { 3444*0Sstevel@tonic-gate # negative zero 3445*0Sstevel@tonic-gate return $self->maybe_parens("-.0", $cx, 21); 3446*0Sstevel@tonic-gate } 3447*0Sstevel@tonic-gate } elsif (1/$nv == 0) { 3448*0Sstevel@tonic-gate if ($nv > 0) { 3449*0Sstevel@tonic-gate # positive infinity 3450*0Sstevel@tonic-gate return $self->maybe_parens("9**9**9", $cx, 22); 3451*0Sstevel@tonic-gate } else { 3452*0Sstevel@tonic-gate # negative infinity 3453*0Sstevel@tonic-gate return $self->maybe_parens("-9**9**9", $cx, 21); 3454*0Sstevel@tonic-gate } 3455*0Sstevel@tonic-gate } elsif ($nv != $nv) { 3456*0Sstevel@tonic-gate # NaN 3457*0Sstevel@tonic-gate if (pack("F", $nv) eq pack("F", sin(9**9**9))) { 3458*0Sstevel@tonic-gate # the normal kind 3459*0Sstevel@tonic-gate return "sin(9**9**9)"; 3460*0Sstevel@tonic-gate } elsif (pack("F", $nv) eq pack("F", -sin(9**9**9))) { 3461*0Sstevel@tonic-gate # the inverted kind 3462*0Sstevel@tonic-gate return $self->maybe_parens("-sin(9**9**9)", $cx, 21); 3463*0Sstevel@tonic-gate } else { 3464*0Sstevel@tonic-gate # some other kind 3465*0Sstevel@tonic-gate my $hex = unpack("h*", pack("F", $nv)); 3466*0Sstevel@tonic-gate return qq'unpack("F", pack("h*", "$hex"))'; 3467*0Sstevel@tonic-gate } 3468*0Sstevel@tonic-gate } 3469*0Sstevel@tonic-gate # first, try the default stringification 3470*0Sstevel@tonic-gate my $str = "$nv"; 3471*0Sstevel@tonic-gate if ($str != $nv) { 3472*0Sstevel@tonic-gate # failing that, try using more precision 3473*0Sstevel@tonic-gate $str = sprintf("%.${max_prec}g", $nv); 3474*0Sstevel@tonic-gate# if (pack("F", $str) ne pack("F", $nv)) { 3475*0Sstevel@tonic-gate if ($str != $nv) { 3476*0Sstevel@tonic-gate # not representable in decimal with whatever sprintf() 3477*0Sstevel@tonic-gate # and atof() Perl is using here. 3478*0Sstevel@tonic-gate my($mant, $exp) = split_float($nv); 3479*0Sstevel@tonic-gate return $self->maybe_parens("$mant * 2**$exp", $cx, 19); 3480*0Sstevel@tonic-gate } 3481*0Sstevel@tonic-gate } 3482*0Sstevel@tonic-gate $str = $self->maybe_parens($str, $cx, 21) if $nv < 0; 3483*0Sstevel@tonic-gate return $str; 3484*0Sstevel@tonic-gate } elsif ($sv->FLAGS & SVf_ROK && $sv->can("RV")) { 3485*0Sstevel@tonic-gate my $ref = $sv->RV; 3486*0Sstevel@tonic-gate if (class($ref) eq "AV") { 3487*0Sstevel@tonic-gate return "[" . $self->list_const(2, $ref->ARRAY) . "]"; 3488*0Sstevel@tonic-gate } elsif (class($ref) eq "HV") { 3489*0Sstevel@tonic-gate my %hash = $ref->ARRAY; 3490*0Sstevel@tonic-gate my @elts; 3491*0Sstevel@tonic-gate for my $k (sort keys %hash) { 3492*0Sstevel@tonic-gate push @elts, "$k => " . $self->const($hash{$k}, 6); 3493*0Sstevel@tonic-gate } 3494*0Sstevel@tonic-gate return "{" . join(", ", @elts) . "}"; 3495*0Sstevel@tonic-gate } elsif (class($ref) eq "CV") { 3496*0Sstevel@tonic-gate return "sub " . $self->deparse_sub($ref); 3497*0Sstevel@tonic-gate } 3498*0Sstevel@tonic-gate if ($ref->FLAGS & SVs_SMG) { 3499*0Sstevel@tonic-gate for (my $mg = $ref->MAGIC; $mg; $mg = $mg->MOREMAGIC) { 3500*0Sstevel@tonic-gate if ($mg->TYPE eq 'r') { 3501*0Sstevel@tonic-gate my $re = re_uninterp(escape_str(re_unback($mg->precomp))); 3502*0Sstevel@tonic-gate return single_delim("qr", "", $re); 3503*0Sstevel@tonic-gate } 3504*0Sstevel@tonic-gate } 3505*0Sstevel@tonic-gate } 3506*0Sstevel@tonic-gate 3507*0Sstevel@tonic-gate return $self->maybe_parens("\\" . $self->const($ref, 20), $cx, 20); 3508*0Sstevel@tonic-gate } elsif ($sv->FLAGS & SVf_POK) { 3509*0Sstevel@tonic-gate my $str = $sv->PV; 3510*0Sstevel@tonic-gate if ($str =~ /[^ -~]/) { # ASCII for non-printing 3511*0Sstevel@tonic-gate return single_delim("qq", '"', uninterp escape_str unback $str); 3512*0Sstevel@tonic-gate } else { 3513*0Sstevel@tonic-gate return single_delim("q", "'", unback $str); 3514*0Sstevel@tonic-gate } 3515*0Sstevel@tonic-gate } else { 3516*0Sstevel@tonic-gate return "undef"; 3517*0Sstevel@tonic-gate } 3518*0Sstevel@tonic-gate} 3519*0Sstevel@tonic-gate 3520*0Sstevel@tonic-gatesub const_dumper { 3521*0Sstevel@tonic-gate my $self = shift; 3522*0Sstevel@tonic-gate my($sv, $cx) = @_; 3523*0Sstevel@tonic-gate my $ref = $sv->object_2svref(); 3524*0Sstevel@tonic-gate my $dumper = Data::Dumper->new([$$ref], ['$v']); 3525*0Sstevel@tonic-gate $dumper->Purity(1)->Terse(1)->Deparse(1)->Indent(0)->Useqq(1)->Sortkeys(1); 3526*0Sstevel@tonic-gate my $str = $dumper->Dump(); 3527*0Sstevel@tonic-gate if ($str =~ /^\$v/) { 3528*0Sstevel@tonic-gate return '${my ' . $str . ' \$v}'; 3529*0Sstevel@tonic-gate } else { 3530*0Sstevel@tonic-gate return $str; 3531*0Sstevel@tonic-gate } 3532*0Sstevel@tonic-gate} 3533*0Sstevel@tonic-gate 3534*0Sstevel@tonic-gatesub const_sv { 3535*0Sstevel@tonic-gate my $self = shift; 3536*0Sstevel@tonic-gate my $op = shift; 3537*0Sstevel@tonic-gate my $sv = $op->sv; 3538*0Sstevel@tonic-gate # the constant could be in the pad (under useithreads) 3539*0Sstevel@tonic-gate $sv = $self->padval($op->targ) unless $$sv; 3540*0Sstevel@tonic-gate return $sv; 3541*0Sstevel@tonic-gate} 3542*0Sstevel@tonic-gate 3543*0Sstevel@tonic-gatesub pp_const { 3544*0Sstevel@tonic-gate my $self = shift; 3545*0Sstevel@tonic-gate my($op, $cx) = @_; 3546*0Sstevel@tonic-gate if ($op->private & OPpCONST_ARYBASE) { 3547*0Sstevel@tonic-gate return '$['; 3548*0Sstevel@tonic-gate } 3549*0Sstevel@tonic-gate# if ($op->private & OPpCONST_BARE) { # trouble with `=>' autoquoting 3550*0Sstevel@tonic-gate# return $self->const_sv($op)->PV; 3551*0Sstevel@tonic-gate# } 3552*0Sstevel@tonic-gate my $sv = $self->const_sv($op); 3553*0Sstevel@tonic-gate return $self->const($sv, $cx); 3554*0Sstevel@tonic-gate} 3555*0Sstevel@tonic-gate 3556*0Sstevel@tonic-gatesub dq { 3557*0Sstevel@tonic-gate my $self = shift; 3558*0Sstevel@tonic-gate my $op = shift; 3559*0Sstevel@tonic-gate my $type = $op->name; 3560*0Sstevel@tonic-gate if ($type eq "const") { 3561*0Sstevel@tonic-gate return '$[' if $op->private & OPpCONST_ARYBASE; 3562*0Sstevel@tonic-gate return uninterp(escape_str(unback($self->const_sv($op)->as_string))); 3563*0Sstevel@tonic-gate } elsif ($type eq "concat") { 3564*0Sstevel@tonic-gate my $first = $self->dq($op->first); 3565*0Sstevel@tonic-gate my $last = $self->dq($op->last); 3566*0Sstevel@tonic-gate 3567*0Sstevel@tonic-gate # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]", "$foo\::bar" 3568*0Sstevel@tonic-gate ($last =~ /^[A-Z\\\^\[\]_?]/ && 3569*0Sstevel@tonic-gate $first =~ s/([\$@])\^$/${1}{^}/) # "${^}W" etc 3570*0Sstevel@tonic-gate || ($last =~ /^[:'{\[\w_]/ && #' 3571*0Sstevel@tonic-gate $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/); 3572*0Sstevel@tonic-gate 3573*0Sstevel@tonic-gate return $first . $last; 3574*0Sstevel@tonic-gate } elsif ($type eq "uc") { 3575*0Sstevel@tonic-gate return '\U' . $self->dq($op->first->sibling) . '\E'; 3576*0Sstevel@tonic-gate } elsif ($type eq "lc") { 3577*0Sstevel@tonic-gate return '\L' . $self->dq($op->first->sibling) . '\E'; 3578*0Sstevel@tonic-gate } elsif ($type eq "ucfirst") { 3579*0Sstevel@tonic-gate return '\u' . $self->dq($op->first->sibling); 3580*0Sstevel@tonic-gate } elsif ($type eq "lcfirst") { 3581*0Sstevel@tonic-gate return '\l' . $self->dq($op->first->sibling); 3582*0Sstevel@tonic-gate } elsif ($type eq "quotemeta") { 3583*0Sstevel@tonic-gate return '\Q' . $self->dq($op->first->sibling) . '\E'; 3584*0Sstevel@tonic-gate } elsif ($type eq "join") { 3585*0Sstevel@tonic-gate return $self->deparse($op->last, 26); # was join($", @ary) 3586*0Sstevel@tonic-gate } else { 3587*0Sstevel@tonic-gate return $self->deparse($op, 26); 3588*0Sstevel@tonic-gate } 3589*0Sstevel@tonic-gate} 3590*0Sstevel@tonic-gate 3591*0Sstevel@tonic-gatesub pp_backtick { 3592*0Sstevel@tonic-gate my $self = shift; 3593*0Sstevel@tonic-gate my($op, $cx) = @_; 3594*0Sstevel@tonic-gate # skip pushmark 3595*0Sstevel@tonic-gate return single_delim("qx", '`', $self->dq($op->first->sibling)); 3596*0Sstevel@tonic-gate} 3597*0Sstevel@tonic-gate 3598*0Sstevel@tonic-gatesub dquote { 3599*0Sstevel@tonic-gate my $self = shift; 3600*0Sstevel@tonic-gate my($op, $cx) = @_; 3601*0Sstevel@tonic-gate my $kid = $op->first->sibling; # skip ex-stringify, pushmark 3602*0Sstevel@tonic-gate return $self->deparse($kid, $cx) if $self->{'unquote'}; 3603*0Sstevel@tonic-gate $self->maybe_targmy($kid, $cx, 3604*0Sstevel@tonic-gate sub {single_delim("qq", '"', $self->dq($_[1]))}); 3605*0Sstevel@tonic-gate} 3606*0Sstevel@tonic-gate 3607*0Sstevel@tonic-gate# OP_STRINGIFY is a listop, but it only ever has one arg 3608*0Sstevel@tonic-gatesub pp_stringify { maybe_targmy(@_, \&dquote) } 3609*0Sstevel@tonic-gate 3610*0Sstevel@tonic-gate# tr/// and s/// (and tr[][], tr[]//, tr###, etc) 3611*0Sstevel@tonic-gate# note that tr(from)/to/ is OK, but not tr/from/(to) 3612*0Sstevel@tonic-gatesub double_delim { 3613*0Sstevel@tonic-gate my($from, $to) = @_; 3614*0Sstevel@tonic-gate my($succeed, $delim); 3615*0Sstevel@tonic-gate if ($from !~ m[/] and $to !~ m[/]) { 3616*0Sstevel@tonic-gate return "/$from/$to/"; 3617*0Sstevel@tonic-gate } elsif (($succeed, $from) = balanced_delim($from) and $succeed) { 3618*0Sstevel@tonic-gate if (($succeed, $to) = balanced_delim($to) and $succeed) { 3619*0Sstevel@tonic-gate return "$from$to"; 3620*0Sstevel@tonic-gate } else { 3621*0Sstevel@tonic-gate for $delim ('/', '"', '#') { # note no `'' -- s''' is special 3622*0Sstevel@tonic-gate return "$from$delim$to$delim" if index($to, $delim) == -1; 3623*0Sstevel@tonic-gate } 3624*0Sstevel@tonic-gate $to =~ s[/][\\/]g; 3625*0Sstevel@tonic-gate return "$from/$to/"; 3626*0Sstevel@tonic-gate } 3627*0Sstevel@tonic-gate } else { 3628*0Sstevel@tonic-gate for $delim ('/', '"', '#') { # note no ' 3629*0Sstevel@tonic-gate return "$delim$from$delim$to$delim" 3630*0Sstevel@tonic-gate if index($to . $from, $delim) == -1; 3631*0Sstevel@tonic-gate } 3632*0Sstevel@tonic-gate $from =~ s[/][\\/]g; 3633*0Sstevel@tonic-gate $to =~ s[/][\\/]g; 3634*0Sstevel@tonic-gate return "/$from/$to/"; 3635*0Sstevel@tonic-gate } 3636*0Sstevel@tonic-gate} 3637*0Sstevel@tonic-gate 3638*0Sstevel@tonic-gate# Only used by tr///, so backslashes hyphens 3639*0Sstevel@tonic-gatesub pchr { # ASCII 3640*0Sstevel@tonic-gate my($n) = @_; 3641*0Sstevel@tonic-gate if ($n == ord '\\') { 3642*0Sstevel@tonic-gate return '\\\\'; 3643*0Sstevel@tonic-gate } elsif ($n == ord "-") { 3644*0Sstevel@tonic-gate return "\\-"; 3645*0Sstevel@tonic-gate } elsif ($n >= ord(' ') and $n <= ord('~')) { 3646*0Sstevel@tonic-gate return chr($n); 3647*0Sstevel@tonic-gate } elsif ($n == ord "\a") { 3648*0Sstevel@tonic-gate return '\\a'; 3649*0Sstevel@tonic-gate } elsif ($n == ord "\b") { 3650*0Sstevel@tonic-gate return '\\b'; 3651*0Sstevel@tonic-gate } elsif ($n == ord "\t") { 3652*0Sstevel@tonic-gate return '\\t'; 3653*0Sstevel@tonic-gate } elsif ($n == ord "\n") { 3654*0Sstevel@tonic-gate return '\\n'; 3655*0Sstevel@tonic-gate } elsif ($n == ord "\e") { 3656*0Sstevel@tonic-gate return '\\e'; 3657*0Sstevel@tonic-gate } elsif ($n == ord "\f") { 3658*0Sstevel@tonic-gate return '\\f'; 3659*0Sstevel@tonic-gate } elsif ($n == ord "\r") { 3660*0Sstevel@tonic-gate return '\\r'; 3661*0Sstevel@tonic-gate } elsif ($n >= ord("\cA") and $n <= ord("\cZ")) { 3662*0Sstevel@tonic-gate return '\\c' . chr(ord("@") + $n); 3663*0Sstevel@tonic-gate } else { 3664*0Sstevel@tonic-gate# return '\x' . sprintf("%02x", $n); 3665*0Sstevel@tonic-gate return '\\' . sprintf("%03o", $n); 3666*0Sstevel@tonic-gate } 3667*0Sstevel@tonic-gate} 3668*0Sstevel@tonic-gate 3669*0Sstevel@tonic-gatesub collapse { 3670*0Sstevel@tonic-gate my(@chars) = @_; 3671*0Sstevel@tonic-gate my($str, $c, $tr) = (""); 3672*0Sstevel@tonic-gate for ($c = 0; $c < @chars; $c++) { 3673*0Sstevel@tonic-gate $tr = $chars[$c]; 3674*0Sstevel@tonic-gate $str .= pchr($tr); 3675*0Sstevel@tonic-gate if ($c <= $#chars - 2 and $chars[$c + 1] == $tr + 1 and 3676*0Sstevel@tonic-gate $chars[$c + 2] == $tr + 2) 3677*0Sstevel@tonic-gate { 3678*0Sstevel@tonic-gate for (; $c <= $#chars-1 and $chars[$c + 1] == $chars[$c] + 1; $c++) 3679*0Sstevel@tonic-gate {} 3680*0Sstevel@tonic-gate $str .= "-"; 3681*0Sstevel@tonic-gate $str .= pchr($chars[$c]); 3682*0Sstevel@tonic-gate } 3683*0Sstevel@tonic-gate } 3684*0Sstevel@tonic-gate return $str; 3685*0Sstevel@tonic-gate} 3686*0Sstevel@tonic-gate 3687*0Sstevel@tonic-gatesub tr_decode_byte { 3688*0Sstevel@tonic-gate my($table, $flags) = @_; 3689*0Sstevel@tonic-gate my(@table) = unpack("s*", $table); 3690*0Sstevel@tonic-gate splice @table, 0x100, 1; # Number of subsequent elements 3691*0Sstevel@tonic-gate my($c, $tr, @from, @to, @delfrom, $delhyphen); 3692*0Sstevel@tonic-gate if ($table[ord "-"] != -1 and 3693*0Sstevel@tonic-gate $table[ord("-") - 1] == -1 || $table[ord("-") + 1] == -1) 3694*0Sstevel@tonic-gate { 3695*0Sstevel@tonic-gate $tr = $table[ord "-"]; 3696*0Sstevel@tonic-gate $table[ord "-"] = -1; 3697*0Sstevel@tonic-gate if ($tr >= 0) { 3698*0Sstevel@tonic-gate @from = ord("-"); 3699*0Sstevel@tonic-gate @to = $tr; 3700*0Sstevel@tonic-gate } else { # -2 ==> delete 3701*0Sstevel@tonic-gate $delhyphen = 1; 3702*0Sstevel@tonic-gate } 3703*0Sstevel@tonic-gate } 3704*0Sstevel@tonic-gate for ($c = 0; $c < @table; $c++) { 3705*0Sstevel@tonic-gate $tr = $table[$c]; 3706*0Sstevel@tonic-gate if ($tr >= 0) { 3707*0Sstevel@tonic-gate push @from, $c; push @to, $tr; 3708*0Sstevel@tonic-gate } elsif ($tr == -2) { 3709*0Sstevel@tonic-gate push @delfrom, $c; 3710*0Sstevel@tonic-gate } 3711*0Sstevel@tonic-gate } 3712*0Sstevel@tonic-gate @from = (@from, @delfrom); 3713*0Sstevel@tonic-gate if ($flags & OPpTRANS_COMPLEMENT) { 3714*0Sstevel@tonic-gate my @newfrom = (); 3715*0Sstevel@tonic-gate my %from; 3716*0Sstevel@tonic-gate @from{@from} = (1) x @from; 3717*0Sstevel@tonic-gate for ($c = 0; $c < 256; $c++) { 3718*0Sstevel@tonic-gate push @newfrom, $c unless $from{$c}; 3719*0Sstevel@tonic-gate } 3720*0Sstevel@tonic-gate @from = @newfrom; 3721*0Sstevel@tonic-gate } 3722*0Sstevel@tonic-gate unless ($flags & OPpTRANS_DELETE || !@to) { 3723*0Sstevel@tonic-gate pop @to while $#to and $to[$#to] == $to[$#to -1]; 3724*0Sstevel@tonic-gate } 3725*0Sstevel@tonic-gate my($from, $to); 3726*0Sstevel@tonic-gate $from = collapse(@from); 3727*0Sstevel@tonic-gate $to = collapse(@to); 3728*0Sstevel@tonic-gate $from .= "-" if $delhyphen; 3729*0Sstevel@tonic-gate return ($from, $to); 3730*0Sstevel@tonic-gate} 3731*0Sstevel@tonic-gate 3732*0Sstevel@tonic-gatesub tr_chr { 3733*0Sstevel@tonic-gate my $x = shift; 3734*0Sstevel@tonic-gate if ($x == ord "-") { 3735*0Sstevel@tonic-gate return "\\-"; 3736*0Sstevel@tonic-gate } elsif ($x == ord "\\") { 3737*0Sstevel@tonic-gate return "\\\\"; 3738*0Sstevel@tonic-gate } else { 3739*0Sstevel@tonic-gate return chr $x; 3740*0Sstevel@tonic-gate } 3741*0Sstevel@tonic-gate} 3742*0Sstevel@tonic-gate 3743*0Sstevel@tonic-gate# XXX This doesn't yet handle all cases correctly either 3744*0Sstevel@tonic-gate 3745*0Sstevel@tonic-gatesub tr_decode_utf8 { 3746*0Sstevel@tonic-gate my($swash_hv, $flags) = @_; 3747*0Sstevel@tonic-gate my %swash = $swash_hv->ARRAY; 3748*0Sstevel@tonic-gate my $final = undef; 3749*0Sstevel@tonic-gate $final = $swash{'FINAL'}->IV if exists $swash{'FINAL'}; 3750*0Sstevel@tonic-gate my $none = $swash{"NONE"}->IV; 3751*0Sstevel@tonic-gate my $extra = $none + 1; 3752*0Sstevel@tonic-gate my(@from, @delfrom, @to); 3753*0Sstevel@tonic-gate my $line; 3754*0Sstevel@tonic-gate foreach $line (split /\n/, $swash{'LIST'}->PV) { 3755*0Sstevel@tonic-gate my($min, $max, $result) = split(/\t/, $line); 3756*0Sstevel@tonic-gate $min = hex $min; 3757*0Sstevel@tonic-gate if (length $max) { 3758*0Sstevel@tonic-gate $max = hex $max; 3759*0Sstevel@tonic-gate } else { 3760*0Sstevel@tonic-gate $max = $min; 3761*0Sstevel@tonic-gate } 3762*0Sstevel@tonic-gate $result = hex $result; 3763*0Sstevel@tonic-gate if ($result == $extra) { 3764*0Sstevel@tonic-gate push @delfrom, [$min, $max]; 3765*0Sstevel@tonic-gate } else { 3766*0Sstevel@tonic-gate push @from, [$min, $max]; 3767*0Sstevel@tonic-gate push @to, [$result, $result + $max - $min]; 3768*0Sstevel@tonic-gate } 3769*0Sstevel@tonic-gate } 3770*0Sstevel@tonic-gate for my $i (0 .. $#from) { 3771*0Sstevel@tonic-gate if ($from[$i][0] == ord '-') { 3772*0Sstevel@tonic-gate unshift @from, splice(@from, $i, 1); 3773*0Sstevel@tonic-gate unshift @to, splice(@to, $i, 1); 3774*0Sstevel@tonic-gate last; 3775*0Sstevel@tonic-gate } elsif ($from[$i][1] == ord '-') { 3776*0Sstevel@tonic-gate $from[$i][1]--; 3777*0Sstevel@tonic-gate $to[$i][1]--; 3778*0Sstevel@tonic-gate unshift @from, ord '-'; 3779*0Sstevel@tonic-gate unshift @to, ord '-'; 3780*0Sstevel@tonic-gate last; 3781*0Sstevel@tonic-gate } 3782*0Sstevel@tonic-gate } 3783*0Sstevel@tonic-gate for my $i (0 .. $#delfrom) { 3784*0Sstevel@tonic-gate if ($delfrom[$i][0] == ord '-') { 3785*0Sstevel@tonic-gate push @delfrom, splice(@delfrom, $i, 1); 3786*0Sstevel@tonic-gate last; 3787*0Sstevel@tonic-gate } elsif ($delfrom[$i][1] == ord '-') { 3788*0Sstevel@tonic-gate $delfrom[$i][1]--; 3789*0Sstevel@tonic-gate push @delfrom, ord '-'; 3790*0Sstevel@tonic-gate last; 3791*0Sstevel@tonic-gate } 3792*0Sstevel@tonic-gate } 3793*0Sstevel@tonic-gate if (defined $final and $to[$#to][1] != $final) { 3794*0Sstevel@tonic-gate push @to, [$final, $final]; 3795*0Sstevel@tonic-gate } 3796*0Sstevel@tonic-gate push @from, @delfrom; 3797*0Sstevel@tonic-gate if ($flags & OPpTRANS_COMPLEMENT) { 3798*0Sstevel@tonic-gate my @newfrom; 3799*0Sstevel@tonic-gate my $next = 0; 3800*0Sstevel@tonic-gate for my $i (0 .. $#from) { 3801*0Sstevel@tonic-gate push @newfrom, [$next, $from[$i][0] - 1]; 3802*0Sstevel@tonic-gate $next = $from[$i][1] + 1; 3803*0Sstevel@tonic-gate } 3804*0Sstevel@tonic-gate @from = (); 3805*0Sstevel@tonic-gate for my $range (@newfrom) { 3806*0Sstevel@tonic-gate if ($range->[0] <= $range->[1]) { 3807*0Sstevel@tonic-gate push @from, $range; 3808*0Sstevel@tonic-gate } 3809*0Sstevel@tonic-gate } 3810*0Sstevel@tonic-gate } 3811*0Sstevel@tonic-gate my($from, $to, $diff); 3812*0Sstevel@tonic-gate for my $chunk (@from) { 3813*0Sstevel@tonic-gate $diff = $chunk->[1] - $chunk->[0]; 3814*0Sstevel@tonic-gate if ($diff > 1) { 3815*0Sstevel@tonic-gate $from .= tr_chr($chunk->[0]) . "-" . tr_chr($chunk->[1]); 3816*0Sstevel@tonic-gate } elsif ($diff == 1) { 3817*0Sstevel@tonic-gate $from .= tr_chr($chunk->[0]) . tr_chr($chunk->[1]); 3818*0Sstevel@tonic-gate } else { 3819*0Sstevel@tonic-gate $from .= tr_chr($chunk->[0]); 3820*0Sstevel@tonic-gate } 3821*0Sstevel@tonic-gate } 3822*0Sstevel@tonic-gate for my $chunk (@to) { 3823*0Sstevel@tonic-gate $diff = $chunk->[1] - $chunk->[0]; 3824*0Sstevel@tonic-gate if ($diff > 1) { 3825*0Sstevel@tonic-gate $to .= tr_chr($chunk->[0]) . "-" . tr_chr($chunk->[1]); 3826*0Sstevel@tonic-gate } elsif ($diff == 1) { 3827*0Sstevel@tonic-gate $to .= tr_chr($chunk->[0]) . tr_chr($chunk->[1]); 3828*0Sstevel@tonic-gate } else { 3829*0Sstevel@tonic-gate $to .= tr_chr($chunk->[0]); 3830*0Sstevel@tonic-gate } 3831*0Sstevel@tonic-gate } 3832*0Sstevel@tonic-gate #$final = sprintf("%04x", $final) if defined $final; 3833*0Sstevel@tonic-gate #$none = sprintf("%04x", $none) if defined $none; 3834*0Sstevel@tonic-gate #$extra = sprintf("%04x", $extra) if defined $extra; 3835*0Sstevel@tonic-gate #print STDERR "final: $final\n none: $none\nextra: $extra\n"; 3836*0Sstevel@tonic-gate #print STDERR $swash{'LIST'}->PV; 3837*0Sstevel@tonic-gate return (escape_str($from), escape_str($to)); 3838*0Sstevel@tonic-gate} 3839*0Sstevel@tonic-gate 3840*0Sstevel@tonic-gatesub pp_trans { 3841*0Sstevel@tonic-gate my $self = shift; 3842*0Sstevel@tonic-gate my($op, $cx) = @_; 3843*0Sstevel@tonic-gate my($from, $to); 3844*0Sstevel@tonic-gate if (class($op) eq "PVOP") { 3845*0Sstevel@tonic-gate ($from, $to) = tr_decode_byte($op->pv, $op->private); 3846*0Sstevel@tonic-gate } else { # class($op) eq "SVOP" 3847*0Sstevel@tonic-gate ($from, $to) = tr_decode_utf8($op->sv->RV, $op->private); 3848*0Sstevel@tonic-gate } 3849*0Sstevel@tonic-gate my $flags = ""; 3850*0Sstevel@tonic-gate $flags .= "c" if $op->private & OPpTRANS_COMPLEMENT; 3851*0Sstevel@tonic-gate $flags .= "d" if $op->private & OPpTRANS_DELETE; 3852*0Sstevel@tonic-gate $to = "" if $from eq $to and $flags eq ""; 3853*0Sstevel@tonic-gate $flags .= "s" if $op->private & OPpTRANS_SQUASH; 3854*0Sstevel@tonic-gate return "tr" . double_delim($from, $to) . $flags; 3855*0Sstevel@tonic-gate} 3856*0Sstevel@tonic-gate 3857*0Sstevel@tonic-gate# Like dq(), but different 3858*0Sstevel@tonic-gatesub re_dq { 3859*0Sstevel@tonic-gate my $self = shift; 3860*0Sstevel@tonic-gate my ($op, $extended) = @_; 3861*0Sstevel@tonic-gate 3862*0Sstevel@tonic-gate my $type = $op->name; 3863*0Sstevel@tonic-gate if ($type eq "const") { 3864*0Sstevel@tonic-gate return '$[' if $op->private & OPpCONST_ARYBASE; 3865*0Sstevel@tonic-gate my $unbacked = re_unback($self->const_sv($op)->as_string); 3866*0Sstevel@tonic-gate return re_uninterp_extended(escape_extended_re($unbacked)) 3867*0Sstevel@tonic-gate if $extended; 3868*0Sstevel@tonic-gate return re_uninterp(escape_str($unbacked)); 3869*0Sstevel@tonic-gate } elsif ($type eq "concat") { 3870*0Sstevel@tonic-gate my $first = $self->re_dq($op->first, $extended); 3871*0Sstevel@tonic-gate my $last = $self->re_dq($op->last, $extended); 3872*0Sstevel@tonic-gate 3873*0Sstevel@tonic-gate # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]" 3874*0Sstevel@tonic-gate ($last =~ /^[A-Z\\\^\[\]_?]/ && 3875*0Sstevel@tonic-gate $first =~ s/([\$@])\^$/${1}{^}/) # "${^}W" etc 3876*0Sstevel@tonic-gate || ($last =~ /^[{\[\w_]/ && 3877*0Sstevel@tonic-gate $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/); 3878*0Sstevel@tonic-gate 3879*0Sstevel@tonic-gate return $first . $last; 3880*0Sstevel@tonic-gate } elsif ($type eq "uc") { 3881*0Sstevel@tonic-gate return '\U' . $self->re_dq($op->first->sibling, $extended) . '\E'; 3882*0Sstevel@tonic-gate } elsif ($type eq "lc") { 3883*0Sstevel@tonic-gate return '\L' . $self->re_dq($op->first->sibling, $extended) . '\E'; 3884*0Sstevel@tonic-gate } elsif ($type eq "ucfirst") { 3885*0Sstevel@tonic-gate return '\u' . $self->re_dq($op->first->sibling, $extended); 3886*0Sstevel@tonic-gate } elsif ($type eq "lcfirst") { 3887*0Sstevel@tonic-gate return '\l' . $self->re_dq($op->first->sibling, $extended); 3888*0Sstevel@tonic-gate } elsif ($type eq "quotemeta") { 3889*0Sstevel@tonic-gate return '\Q' . $self->re_dq($op->first->sibling, $extended) . '\E'; 3890*0Sstevel@tonic-gate } elsif ($type eq "join") { 3891*0Sstevel@tonic-gate return $self->deparse($op->last, 26); # was join($", @ary) 3892*0Sstevel@tonic-gate } else { 3893*0Sstevel@tonic-gate return $self->deparse($op, 26); 3894*0Sstevel@tonic-gate } 3895*0Sstevel@tonic-gate} 3896*0Sstevel@tonic-gate 3897*0Sstevel@tonic-gatesub pure_string { 3898*0Sstevel@tonic-gate my ($self, $op) = @_; 3899*0Sstevel@tonic-gate return 0 if null $op; 3900*0Sstevel@tonic-gate my $type = $op->name; 3901*0Sstevel@tonic-gate 3902*0Sstevel@tonic-gate if ($type eq 'const') { 3903*0Sstevel@tonic-gate return 1; 3904*0Sstevel@tonic-gate } 3905*0Sstevel@tonic-gate elsif ($type =~ /^[ul]c(first)?$/ || $type eq 'quotemeta') { 3906*0Sstevel@tonic-gate return $self->pure_string($op->first->sibling); 3907*0Sstevel@tonic-gate } 3908*0Sstevel@tonic-gate elsif ($type eq 'join') { 3909*0Sstevel@tonic-gate my $join_op = $op->first->sibling; # Skip pushmark 3910*0Sstevel@tonic-gate return 0 unless $join_op->name eq 'null' && $join_op->targ eq OP_RV2SV; 3911*0Sstevel@tonic-gate 3912*0Sstevel@tonic-gate my $gvop = $join_op->first; 3913*0Sstevel@tonic-gate return 0 unless $gvop->name eq 'gvsv'; 3914*0Sstevel@tonic-gate return 0 unless '"' eq $self->gv_name($self->gv_or_padgv($gvop)); 3915*0Sstevel@tonic-gate 3916*0Sstevel@tonic-gate return 0 unless ${$join_op->sibling} eq ${$op->last}; 3917*0Sstevel@tonic-gate return 0 unless $op->last->name =~ /^(rv2|pad)av$/; 3918*0Sstevel@tonic-gate } 3919*0Sstevel@tonic-gate elsif ($type eq 'concat') { 3920*0Sstevel@tonic-gate return $self->pure_string($op->first) 3921*0Sstevel@tonic-gate && $self->pure_string($op->last); 3922*0Sstevel@tonic-gate } 3923*0Sstevel@tonic-gate elsif (is_scalar($op) || $type =~ /^[ah]elem$/) { 3924*0Sstevel@tonic-gate return 1; 3925*0Sstevel@tonic-gate } 3926*0Sstevel@tonic-gate elsif ($type eq "null" and $op->can('first') and not null $op->first and 3927*0Sstevel@tonic-gate $op->first->name eq "null" and $op->first->can('first') 3928*0Sstevel@tonic-gate and not null $op->first->first and 3929*0Sstevel@tonic-gate $op->first->first->name eq "aelemfast") { 3930*0Sstevel@tonic-gate return 1; 3931*0Sstevel@tonic-gate } 3932*0Sstevel@tonic-gate else { 3933*0Sstevel@tonic-gate return 0; 3934*0Sstevel@tonic-gate } 3935*0Sstevel@tonic-gate 3936*0Sstevel@tonic-gate return 1; 3937*0Sstevel@tonic-gate} 3938*0Sstevel@tonic-gate 3939*0Sstevel@tonic-gatesub regcomp { 3940*0Sstevel@tonic-gate my $self = shift; 3941*0Sstevel@tonic-gate my($op, $cx, $extended) = @_; 3942*0Sstevel@tonic-gate my $kid = $op->first; 3943*0Sstevel@tonic-gate $kid = $kid->first if $kid->name eq "regcmaybe"; 3944*0Sstevel@tonic-gate $kid = $kid->first if $kid->name eq "regcreset"; 3945*0Sstevel@tonic-gate return ($self->re_dq($kid, $extended), 1) if $self->pure_string($kid); 3946*0Sstevel@tonic-gate return ($self->deparse($kid, $cx), 0); 3947*0Sstevel@tonic-gate} 3948*0Sstevel@tonic-gate 3949*0Sstevel@tonic-gatesub pp_regcomp { 3950*0Sstevel@tonic-gate my ($self, $op, $cx) = @_; 3951*0Sstevel@tonic-gate return (($self->regcomp($op, $cx, 0))[0]); 3952*0Sstevel@tonic-gate} 3953*0Sstevel@tonic-gate 3954*0Sstevel@tonic-gate# osmic acid -- see osmium tetroxide 3955*0Sstevel@tonic-gate 3956*0Sstevel@tonic-gatemy %matchwords; 3957*0Sstevel@tonic-gatemap($matchwords{join "", sort split //, $_} = $_, 'cig', 'cog', 'cos', 'cogs', 3958*0Sstevel@tonic-gate 'cox', 'go', 'is', 'ism', 'iso', 'mig', 'mix', 'osmic', 'ox', 'sic', 3959*0Sstevel@tonic-gate 'sig', 'six', 'smog', 'so', 'soc', 'sog', 'xi'); 3960*0Sstevel@tonic-gate 3961*0Sstevel@tonic-gatesub matchop { 3962*0Sstevel@tonic-gate my $self = shift; 3963*0Sstevel@tonic-gate my($op, $cx, $name, $delim) = @_; 3964*0Sstevel@tonic-gate my $kid = $op->first; 3965*0Sstevel@tonic-gate my ($binop, $var, $re) = ("", "", ""); 3966*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED) { 3967*0Sstevel@tonic-gate $binop = 1; 3968*0Sstevel@tonic-gate $var = $self->deparse($kid, 20); 3969*0Sstevel@tonic-gate $kid = $kid->sibling; 3970*0Sstevel@tonic-gate } 3971*0Sstevel@tonic-gate my $quote = 1; 3972*0Sstevel@tonic-gate my $extended = ($op->pmflags & PMf_EXTENDED); 3973*0Sstevel@tonic-gate if (null $kid) { 3974*0Sstevel@tonic-gate my $unbacked = re_unback($op->precomp); 3975*0Sstevel@tonic-gate if ($extended) { 3976*0Sstevel@tonic-gate $re = re_uninterp_extended(escape_extended_re($unbacked)); 3977*0Sstevel@tonic-gate } else { 3978*0Sstevel@tonic-gate $re = re_uninterp(escape_str(re_unback($op->precomp))); 3979*0Sstevel@tonic-gate } 3980*0Sstevel@tonic-gate } elsif ($kid->name ne 'regcomp') { 3981*0Sstevel@tonic-gate carp("found ".$kid->name." where regcomp expected"); 3982*0Sstevel@tonic-gate } else { 3983*0Sstevel@tonic-gate ($re, $quote) = $self->regcomp($kid, 21, $extended); 3984*0Sstevel@tonic-gate } 3985*0Sstevel@tonic-gate my $flags = ""; 3986*0Sstevel@tonic-gate $flags .= "c" if $op->pmflags & PMf_CONTINUE; 3987*0Sstevel@tonic-gate $flags .= "g" if $op->pmflags & PMf_GLOBAL; 3988*0Sstevel@tonic-gate $flags .= "i" if $op->pmflags & PMf_FOLD; 3989*0Sstevel@tonic-gate $flags .= "m" if $op->pmflags & PMf_MULTILINE; 3990*0Sstevel@tonic-gate $flags .= "o" if $op->pmflags & PMf_KEEP; 3991*0Sstevel@tonic-gate $flags .= "s" if $op->pmflags & PMf_SINGLELINE; 3992*0Sstevel@tonic-gate $flags .= "x" if $op->pmflags & PMf_EXTENDED; 3993*0Sstevel@tonic-gate $flags = $matchwords{$flags} if $matchwords{$flags}; 3994*0Sstevel@tonic-gate if ($op->pmflags & PMf_ONCE) { # only one kind of delimiter works here 3995*0Sstevel@tonic-gate $re =~ s/\?/\\?/g; 3996*0Sstevel@tonic-gate $re = "?$re?"; 3997*0Sstevel@tonic-gate } elsif ($quote) { 3998*0Sstevel@tonic-gate $re = single_delim($name, $delim, $re); 3999*0Sstevel@tonic-gate } 4000*0Sstevel@tonic-gate $re = $re . $flags if $quote; 4001*0Sstevel@tonic-gate if ($binop) { 4002*0Sstevel@tonic-gate return $self->maybe_parens("$var =~ $re", $cx, 20); 4003*0Sstevel@tonic-gate } else { 4004*0Sstevel@tonic-gate return $re; 4005*0Sstevel@tonic-gate } 4006*0Sstevel@tonic-gate} 4007*0Sstevel@tonic-gate 4008*0Sstevel@tonic-gatesub pp_match { matchop(@_, "m", "/") } 4009*0Sstevel@tonic-gatesub pp_pushre { matchop(@_, "m", "/") } 4010*0Sstevel@tonic-gatesub pp_qr { matchop(@_, "qr", "") } 4011*0Sstevel@tonic-gate 4012*0Sstevel@tonic-gatesub pp_split { 4013*0Sstevel@tonic-gate my $self = shift; 4014*0Sstevel@tonic-gate my($op, $cx) = @_; 4015*0Sstevel@tonic-gate my($kid, @exprs, $ary, $expr); 4016*0Sstevel@tonic-gate $kid = $op->first; 4017*0Sstevel@tonic-gate 4018*0Sstevel@tonic-gate # For our kid (an OP_PUSHRE), pmreplroot is never actually the 4019*0Sstevel@tonic-gate # root of a replacement; it's either empty, or abused to point to 4020*0Sstevel@tonic-gate # the GV for an array we split into (an optimization to save 4021*0Sstevel@tonic-gate # assignment overhead). Depending on whether we're using ithreads, 4022*0Sstevel@tonic-gate # this OP* holds either a GV* or a PADOFFSET. Luckily, B.xs 4023*0Sstevel@tonic-gate # figures out for us which it is. 4024*0Sstevel@tonic-gate my $replroot = $kid->pmreplroot; 4025*0Sstevel@tonic-gate my $gv = 0; 4026*0Sstevel@tonic-gate if (ref($replroot) eq "B::GV") { 4027*0Sstevel@tonic-gate $gv = $replroot; 4028*0Sstevel@tonic-gate } elsif (!ref($replroot) and $replroot > 0) { 4029*0Sstevel@tonic-gate $gv = $self->padval($replroot); 4030*0Sstevel@tonic-gate } 4031*0Sstevel@tonic-gate $ary = $self->stash_variable('@', $self->gv_name($gv)) if $gv; 4032*0Sstevel@tonic-gate 4033*0Sstevel@tonic-gate for (; !null($kid); $kid = $kid->sibling) { 4034*0Sstevel@tonic-gate push @exprs, $self->deparse($kid, 6); 4035*0Sstevel@tonic-gate } 4036*0Sstevel@tonic-gate 4037*0Sstevel@tonic-gate # handle special case of split(), and split(" ") that compiles to /\s+/ 4038*0Sstevel@tonic-gate $kid = $op->first; 4039*0Sstevel@tonic-gate if ($kid->flags & OPf_SPECIAL 4040*0Sstevel@tonic-gate && $exprs[0] eq '/\\s+/' 4041*0Sstevel@tonic-gate && $kid->pmflags & PMf_SKIPWHITE ) { 4042*0Sstevel@tonic-gate $exprs[0] = '" "'; 4043*0Sstevel@tonic-gate } 4044*0Sstevel@tonic-gate 4045*0Sstevel@tonic-gate $expr = "split(" . join(", ", @exprs) . ")"; 4046*0Sstevel@tonic-gate if ($ary) { 4047*0Sstevel@tonic-gate return $self->maybe_parens("$ary = $expr", $cx, 7); 4048*0Sstevel@tonic-gate } else { 4049*0Sstevel@tonic-gate return $expr; 4050*0Sstevel@tonic-gate } 4051*0Sstevel@tonic-gate} 4052*0Sstevel@tonic-gate 4053*0Sstevel@tonic-gate# oxime -- any of various compounds obtained chiefly by the action of 4054*0Sstevel@tonic-gate# hydroxylamine on aldehydes and ketones and characterized by the 4055*0Sstevel@tonic-gate# bivalent grouping C=NOH [Webster's Tenth] 4056*0Sstevel@tonic-gate 4057*0Sstevel@tonic-gatemy %substwords; 4058*0Sstevel@tonic-gatemap($substwords{join "", sort split //, $_} = $_, 'ego', 'egoism', 'em', 4059*0Sstevel@tonic-gate 'es', 'ex', 'exes', 'gee', 'go', 'goes', 'ie', 'ism', 'iso', 'me', 4060*0Sstevel@tonic-gate 'meese', 'meso', 'mig', 'mix', 'os', 'ox', 'oxime', 'see', 'seem', 4061*0Sstevel@tonic-gate 'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi'); 4062*0Sstevel@tonic-gate 4063*0Sstevel@tonic-gatesub pp_subst { 4064*0Sstevel@tonic-gate my $self = shift; 4065*0Sstevel@tonic-gate my($op, $cx) = @_; 4066*0Sstevel@tonic-gate my $kid = $op->first; 4067*0Sstevel@tonic-gate my($binop, $var, $re, $repl) = ("", "", "", ""); 4068*0Sstevel@tonic-gate if ($op->flags & OPf_STACKED) { 4069*0Sstevel@tonic-gate $binop = 1; 4070*0Sstevel@tonic-gate $var = $self->deparse($kid, 20); 4071*0Sstevel@tonic-gate $kid = $kid->sibling; 4072*0Sstevel@tonic-gate } 4073*0Sstevel@tonic-gate my $flags = ""; 4074*0Sstevel@tonic-gate if (null($op->pmreplroot)) { 4075*0Sstevel@tonic-gate $repl = $self->dq($kid); 4076*0Sstevel@tonic-gate $kid = $kid->sibling; 4077*0Sstevel@tonic-gate } else { 4078*0Sstevel@tonic-gate $repl = $op->pmreplroot->first; # skip substcont 4079*0Sstevel@tonic-gate while ($repl->name eq "entereval") { 4080*0Sstevel@tonic-gate $repl = $repl->first; 4081*0Sstevel@tonic-gate $flags .= "e"; 4082*0Sstevel@tonic-gate } 4083*0Sstevel@tonic-gate if ($op->pmflags & PMf_EVAL) { 4084*0Sstevel@tonic-gate $repl = $self->deparse($repl->first, 0); 4085*0Sstevel@tonic-gate } else { 4086*0Sstevel@tonic-gate $repl = $self->dq($repl); 4087*0Sstevel@tonic-gate } 4088*0Sstevel@tonic-gate } 4089*0Sstevel@tonic-gate my $extended = ($op->pmflags & PMf_EXTENDED); 4090*0Sstevel@tonic-gate if (null $kid) { 4091*0Sstevel@tonic-gate my $unbacked = re_unback($op->precomp); 4092*0Sstevel@tonic-gate if ($extended) { 4093*0Sstevel@tonic-gate $re = re_uninterp_extended(escape_extended_re($unbacked)); 4094*0Sstevel@tonic-gate } 4095*0Sstevel@tonic-gate else { 4096*0Sstevel@tonic-gate $re = re_uninterp(escape_str($unbacked)); 4097*0Sstevel@tonic-gate } 4098*0Sstevel@tonic-gate } else { 4099*0Sstevel@tonic-gate ($re) = $self->regcomp($kid, 1, $extended); 4100*0Sstevel@tonic-gate } 4101*0Sstevel@tonic-gate $flags .= "e" if $op->pmflags & PMf_EVAL; 4102*0Sstevel@tonic-gate $flags .= "g" if $op->pmflags & PMf_GLOBAL; 4103*0Sstevel@tonic-gate $flags .= "i" if $op->pmflags & PMf_FOLD; 4104*0Sstevel@tonic-gate $flags .= "m" if $op->pmflags & PMf_MULTILINE; 4105*0Sstevel@tonic-gate $flags .= "o" if $op->pmflags & PMf_KEEP; 4106*0Sstevel@tonic-gate $flags .= "s" if $op->pmflags & PMf_SINGLELINE; 4107*0Sstevel@tonic-gate $flags .= "x" if $extended; 4108*0Sstevel@tonic-gate $flags = $substwords{$flags} if $substwords{$flags}; 4109*0Sstevel@tonic-gate if ($binop) { 4110*0Sstevel@tonic-gate return $self->maybe_parens("$var =~ s" 4111*0Sstevel@tonic-gate . double_delim($re, $repl) . $flags, 4112*0Sstevel@tonic-gate $cx, 20); 4113*0Sstevel@tonic-gate } else { 4114*0Sstevel@tonic-gate return "s". double_delim($re, $repl) . $flags; 4115*0Sstevel@tonic-gate } 4116*0Sstevel@tonic-gate} 4117*0Sstevel@tonic-gate 4118*0Sstevel@tonic-gate1; 4119*0Sstevel@tonic-gate__END__ 4120*0Sstevel@tonic-gate 4121*0Sstevel@tonic-gate=head1 NAME 4122*0Sstevel@tonic-gate 4123*0Sstevel@tonic-gateB::Deparse - Perl compiler backend to produce perl code 4124*0Sstevel@tonic-gate 4125*0Sstevel@tonic-gate=head1 SYNOPSIS 4126*0Sstevel@tonic-gate 4127*0Sstevel@tonic-gateB<perl> B<-MO=Deparse>[B<,-d>][B<,-f>I<FILE>][B<,-p>][B<,-q>][B<,-l>] 4128*0Sstevel@tonic-gate [B<,-s>I<LETTERS>][B<,-x>I<LEVEL>] I<prog.pl> 4129*0Sstevel@tonic-gate 4130*0Sstevel@tonic-gate=head1 DESCRIPTION 4131*0Sstevel@tonic-gate 4132*0Sstevel@tonic-gateB::Deparse is a backend module for the Perl compiler that generates 4133*0Sstevel@tonic-gateperl source code, based on the internal compiled structure that perl 4134*0Sstevel@tonic-gateitself creates after parsing a program. The output of B::Deparse won't 4135*0Sstevel@tonic-gatebe exactly the same as the original source, since perl doesn't keep 4136*0Sstevel@tonic-gatetrack of comments or whitespace, and there isn't a one-to-one 4137*0Sstevel@tonic-gatecorrespondence between perl's syntactical constructions and their 4138*0Sstevel@tonic-gatecompiled form, but it will often be close. When you use the B<-p> 4139*0Sstevel@tonic-gateoption, the output also includes parentheses even when they are not 4140*0Sstevel@tonic-gaterequired by precedence, which can make it easy to see if perl is 4141*0Sstevel@tonic-gateparsing your expressions the way you intended. 4142*0Sstevel@tonic-gate 4143*0Sstevel@tonic-gateWhile B::Deparse goes to some lengths to try to figure out what your 4144*0Sstevel@tonic-gateoriginal program was doing, some parts of the language can still trip 4145*0Sstevel@tonic-gateit up; it still fails even on some parts of Perl's own test suite. If 4146*0Sstevel@tonic-gateyou encounter a failure other than the most common ones described in 4147*0Sstevel@tonic-gatethe BUGS section below, you can help contribute to B::Deparse's 4148*0Sstevel@tonic-gateongoing development by submitting a bug report with a small 4149*0Sstevel@tonic-gateexample. 4150*0Sstevel@tonic-gate 4151*0Sstevel@tonic-gate=head1 OPTIONS 4152*0Sstevel@tonic-gate 4153*0Sstevel@tonic-gateAs with all compiler backend options, these must follow directly after 4154*0Sstevel@tonic-gatethe '-MO=Deparse', separated by a comma but not any white space. 4155*0Sstevel@tonic-gate 4156*0Sstevel@tonic-gate=over 4 4157*0Sstevel@tonic-gate 4158*0Sstevel@tonic-gate=item B<-d> 4159*0Sstevel@tonic-gate 4160*0Sstevel@tonic-gateOutput data values (when they appear as constants) using Data::Dumper. 4161*0Sstevel@tonic-gateWithout this option, B::Deparse will use some simple routines of its 4162*0Sstevel@tonic-gateown for the same purpose. Currently, Data::Dumper is better for some 4163*0Sstevel@tonic-gatekinds of data (such as complex structures with sharing and 4164*0Sstevel@tonic-gateself-reference) while the built-in routines are better for others 4165*0Sstevel@tonic-gate(such as odd floating-point values). 4166*0Sstevel@tonic-gate 4167*0Sstevel@tonic-gate=item B<-f>I<FILE> 4168*0Sstevel@tonic-gate 4169*0Sstevel@tonic-gateNormally, B::Deparse deparses the main code of a program, and all the subs 4170*0Sstevel@tonic-gatedefined in the same file. To include subs defined in other files, pass the 4171*0Sstevel@tonic-gateB<-f> option with the filename. You can pass the B<-f> option several times, to 4172*0Sstevel@tonic-gateinclude more than one secondary file. (Most of the time you don't want to 4173*0Sstevel@tonic-gateuse it at all.) You can also use this option to include subs which are 4174*0Sstevel@tonic-gatedefined in the scope of a B<#line> directive with two parameters. 4175*0Sstevel@tonic-gate 4176*0Sstevel@tonic-gate=item B<-l> 4177*0Sstevel@tonic-gate 4178*0Sstevel@tonic-gateAdd '#line' declarations to the output based on the line and file 4179*0Sstevel@tonic-gatelocations of the original code. 4180*0Sstevel@tonic-gate 4181*0Sstevel@tonic-gate=item B<-p> 4182*0Sstevel@tonic-gate 4183*0Sstevel@tonic-gatePrint extra parentheses. Without this option, B::Deparse includes 4184*0Sstevel@tonic-gateparentheses in its output only when they are needed, based on the 4185*0Sstevel@tonic-gatestructure of your program. With B<-p>, it uses parentheses (almost) 4186*0Sstevel@tonic-gatewhenever they would be legal. This can be useful if you are used to 4187*0Sstevel@tonic-gateLISP, or if you want to see how perl parses your input. If you say 4188*0Sstevel@tonic-gate 4189*0Sstevel@tonic-gate if ($var & 0x7f == 65) {print "Gimme an A!"} 4190*0Sstevel@tonic-gate print ($which ? $a : $b), "\n"; 4191*0Sstevel@tonic-gate $name = $ENV{USER} or "Bob"; 4192*0Sstevel@tonic-gate 4193*0Sstevel@tonic-gateC<B::Deparse,-p> will print 4194*0Sstevel@tonic-gate 4195*0Sstevel@tonic-gate if (($var & 0)) { 4196*0Sstevel@tonic-gate print('Gimme an A!') 4197*0Sstevel@tonic-gate }; 4198*0Sstevel@tonic-gate (print(($which ? $a : $b)), '???'); 4199*0Sstevel@tonic-gate (($name = $ENV{'USER'}) or '???') 4200*0Sstevel@tonic-gate 4201*0Sstevel@tonic-gatewhich probably isn't what you intended (the C<'???'> is a sign that 4202*0Sstevel@tonic-gateperl optimized away a constant value). 4203*0Sstevel@tonic-gate 4204*0Sstevel@tonic-gate=item B<-P> 4205*0Sstevel@tonic-gate 4206*0Sstevel@tonic-gateDisable prototype checking. With this option, all function calls are 4207*0Sstevel@tonic-gatedeparsed as if no prototype was defined for them. In other words, 4208*0Sstevel@tonic-gate 4209*0Sstevel@tonic-gate perl -MO=Deparse,-P -e 'sub foo (\@) { 1 } foo @x' 4210*0Sstevel@tonic-gate 4211*0Sstevel@tonic-gatewill print 4212*0Sstevel@tonic-gate 4213*0Sstevel@tonic-gate sub foo (\@) { 4214*0Sstevel@tonic-gate 1; 4215*0Sstevel@tonic-gate } 4216*0Sstevel@tonic-gate &foo(\@x); 4217*0Sstevel@tonic-gate 4218*0Sstevel@tonic-gatemaking clear how the parameters are actually passed to C<foo>. 4219*0Sstevel@tonic-gate 4220*0Sstevel@tonic-gate=item B<-q> 4221*0Sstevel@tonic-gate 4222*0Sstevel@tonic-gateExpand double-quoted strings into the corresponding combinations of 4223*0Sstevel@tonic-gateconcatenation, uc, ucfirst, lc, lcfirst, quotemeta, and join. For 4224*0Sstevel@tonic-gateinstance, print 4225*0Sstevel@tonic-gate 4226*0Sstevel@tonic-gate print "Hello, $world, @ladies, \u$gentlemen\E, \u\L$me!"; 4227*0Sstevel@tonic-gate 4228*0Sstevel@tonic-gateas 4229*0Sstevel@tonic-gate 4230*0Sstevel@tonic-gate print 'Hello, ' . $world . ', ' . join($", @ladies) . ', ' 4231*0Sstevel@tonic-gate . ucfirst($gentlemen) . ', ' . ucfirst(lc $me . '!'); 4232*0Sstevel@tonic-gate 4233*0Sstevel@tonic-gateNote that the expanded form represents the way perl handles such 4234*0Sstevel@tonic-gateconstructions internally -- this option actually turns off the reverse 4235*0Sstevel@tonic-gatetranslation that B::Deparse usually does. On the other hand, note that 4236*0Sstevel@tonic-gateC<$x = "$y"> is not the same as C<$x = $y>: the former makes the value 4237*0Sstevel@tonic-gateof $y into a string before doing the assignment. 4238*0Sstevel@tonic-gate 4239*0Sstevel@tonic-gate=item B<-s>I<LETTERS> 4240*0Sstevel@tonic-gate 4241*0Sstevel@tonic-gateTweak the style of B::Deparse's output. The letters should follow 4242*0Sstevel@tonic-gatedirectly after the 's', with no space or punctuation. The following 4243*0Sstevel@tonic-gateoptions are available: 4244*0Sstevel@tonic-gate 4245*0Sstevel@tonic-gate=over 4 4246*0Sstevel@tonic-gate 4247*0Sstevel@tonic-gate=item B<C> 4248*0Sstevel@tonic-gate 4249*0Sstevel@tonic-gateCuddle C<elsif>, C<else>, and C<continue> blocks. For example, print 4250*0Sstevel@tonic-gate 4251*0Sstevel@tonic-gate if (...) { 4252*0Sstevel@tonic-gate ... 4253*0Sstevel@tonic-gate } else { 4254*0Sstevel@tonic-gate ... 4255*0Sstevel@tonic-gate } 4256*0Sstevel@tonic-gate 4257*0Sstevel@tonic-gateinstead of 4258*0Sstevel@tonic-gate 4259*0Sstevel@tonic-gate if (...) { 4260*0Sstevel@tonic-gate ... 4261*0Sstevel@tonic-gate } 4262*0Sstevel@tonic-gate else { 4263*0Sstevel@tonic-gate ... 4264*0Sstevel@tonic-gate } 4265*0Sstevel@tonic-gate 4266*0Sstevel@tonic-gateThe default is not to cuddle. 4267*0Sstevel@tonic-gate 4268*0Sstevel@tonic-gate=item B<i>I<NUMBER> 4269*0Sstevel@tonic-gate 4270*0Sstevel@tonic-gateIndent lines by multiples of I<NUMBER> columns. The default is 4 columns. 4271*0Sstevel@tonic-gate 4272*0Sstevel@tonic-gate=item B<T> 4273*0Sstevel@tonic-gate 4274*0Sstevel@tonic-gateUse tabs for each 8 columns of indent. The default is to use only spaces. 4275*0Sstevel@tonic-gateFor instance, if the style options are B<-si4T>, a line that's indented 4276*0Sstevel@tonic-gate3 times will be preceded by one tab and four spaces; if the options were 4277*0Sstevel@tonic-gateB<-si8T>, the same line would be preceded by three tabs. 4278*0Sstevel@tonic-gate 4279*0Sstevel@tonic-gate=item B<v>I<STRING>B<.> 4280*0Sstevel@tonic-gate 4281*0Sstevel@tonic-gatePrint I<STRING> for the value of a constant that can't be determined 4282*0Sstevel@tonic-gatebecause it was optimized away (mnemonic: this happens when a constant 4283*0Sstevel@tonic-gateis used in B<v>oid context). The end of the string is marked by a period. 4284*0Sstevel@tonic-gateThe string should be a valid perl expression, generally a constant. 4285*0Sstevel@tonic-gateNote that unless it's a number, it probably needs to be quoted, and on 4286*0Sstevel@tonic-gatea command line quotes need to be protected from the shell. Some 4287*0Sstevel@tonic-gateconventional values include 0, 1, 42, '', 'foo', and 4288*0Sstevel@tonic-gate'Useless use of constant omitted' (which may need to be 4289*0Sstevel@tonic-gateB<-sv"'Useless use of constant omitted'."> 4290*0Sstevel@tonic-gateor something similar depending on your shell). The default is '???'. 4291*0Sstevel@tonic-gateIf you're using B::Deparse on a module or other file that's require'd, 4292*0Sstevel@tonic-gateyou shouldn't use a value that evaluates to false, since the customary 4293*0Sstevel@tonic-gatetrue constant at the end of a module will be in void context when the 4294*0Sstevel@tonic-gatefile is compiled as a main program. 4295*0Sstevel@tonic-gate 4296*0Sstevel@tonic-gate=back 4297*0Sstevel@tonic-gate 4298*0Sstevel@tonic-gate=item B<-x>I<LEVEL> 4299*0Sstevel@tonic-gate 4300*0Sstevel@tonic-gateExpand conventional syntax constructions into equivalent ones that expose 4301*0Sstevel@tonic-gatetheir internal operation. I<LEVEL> should be a digit, with higher values 4302*0Sstevel@tonic-gatemeaning more expansion. As with B<-q>, this actually involves turning off 4303*0Sstevel@tonic-gatespecial cases in B::Deparse's normal operations. 4304*0Sstevel@tonic-gate 4305*0Sstevel@tonic-gateIf I<LEVEL> is at least 3, C<for> loops will be translated into equivalent 4306*0Sstevel@tonic-gatewhile loops with continue blocks; for instance 4307*0Sstevel@tonic-gate 4308*0Sstevel@tonic-gate for ($i = 0; $i < 10; ++$i) { 4309*0Sstevel@tonic-gate print $i; 4310*0Sstevel@tonic-gate } 4311*0Sstevel@tonic-gate 4312*0Sstevel@tonic-gateturns into 4313*0Sstevel@tonic-gate 4314*0Sstevel@tonic-gate $i = 0; 4315*0Sstevel@tonic-gate while ($i < 10) { 4316*0Sstevel@tonic-gate print $i; 4317*0Sstevel@tonic-gate } continue { 4318*0Sstevel@tonic-gate ++$i 4319*0Sstevel@tonic-gate } 4320*0Sstevel@tonic-gate 4321*0Sstevel@tonic-gateNote that in a few cases this translation can't be perfectly carried back 4322*0Sstevel@tonic-gateinto the source code -- if the loop's initializer declares a my variable, 4323*0Sstevel@tonic-gatefor instance, it won't have the correct scope outside of the loop. 4324*0Sstevel@tonic-gate 4325*0Sstevel@tonic-gateIf I<LEVEL> is at least 5, C<use> declarations will be translated into 4326*0Sstevel@tonic-gateC<BEGIN> blocks containing calls to C<require> and C<import>; for 4327*0Sstevel@tonic-gateinstance, 4328*0Sstevel@tonic-gate 4329*0Sstevel@tonic-gate use strict 'refs'; 4330*0Sstevel@tonic-gate 4331*0Sstevel@tonic-gateturns into 4332*0Sstevel@tonic-gate 4333*0Sstevel@tonic-gate sub BEGIN { 4334*0Sstevel@tonic-gate require strict; 4335*0Sstevel@tonic-gate do { 4336*0Sstevel@tonic-gate 'strict'->import('refs') 4337*0Sstevel@tonic-gate }; 4338*0Sstevel@tonic-gate } 4339*0Sstevel@tonic-gate 4340*0Sstevel@tonic-gateIf I<LEVEL> is at least 7, C<if> statements will be translated into 4341*0Sstevel@tonic-gateequivalent expressions using C<&&>, C<?:> and C<do {}>; for instance 4342*0Sstevel@tonic-gate 4343*0Sstevel@tonic-gate print 'hi' if $nice; 4344*0Sstevel@tonic-gate if ($nice) { 4345*0Sstevel@tonic-gate print 'hi'; 4346*0Sstevel@tonic-gate } 4347*0Sstevel@tonic-gate if ($nice) { 4348*0Sstevel@tonic-gate print 'hi'; 4349*0Sstevel@tonic-gate } else { 4350*0Sstevel@tonic-gate print 'bye'; 4351*0Sstevel@tonic-gate } 4352*0Sstevel@tonic-gate 4353*0Sstevel@tonic-gateturns into 4354*0Sstevel@tonic-gate 4355*0Sstevel@tonic-gate $nice and print 'hi'; 4356*0Sstevel@tonic-gate $nice and do { print 'hi' }; 4357*0Sstevel@tonic-gate $nice ? do { print 'hi' } : do { print 'bye' }; 4358*0Sstevel@tonic-gate 4359*0Sstevel@tonic-gateLong sequences of elsifs will turn into nested ternary operators, which 4360*0Sstevel@tonic-gateB::Deparse doesn't know how to indent nicely. 4361*0Sstevel@tonic-gate 4362*0Sstevel@tonic-gate=back 4363*0Sstevel@tonic-gate 4364*0Sstevel@tonic-gate=head1 USING B::Deparse AS A MODULE 4365*0Sstevel@tonic-gate 4366*0Sstevel@tonic-gate=head2 Synopsis 4367*0Sstevel@tonic-gate 4368*0Sstevel@tonic-gate use B::Deparse; 4369*0Sstevel@tonic-gate $deparse = B::Deparse->new("-p", "-sC"); 4370*0Sstevel@tonic-gate $body = $deparse->coderef2text(\&func); 4371*0Sstevel@tonic-gate eval "sub func $body"; # the inverse operation 4372*0Sstevel@tonic-gate 4373*0Sstevel@tonic-gate=head2 Description 4374*0Sstevel@tonic-gate 4375*0Sstevel@tonic-gateB::Deparse can also be used on a sub-by-sub basis from other perl 4376*0Sstevel@tonic-gateprograms. 4377*0Sstevel@tonic-gate 4378*0Sstevel@tonic-gate=head2 new 4379*0Sstevel@tonic-gate 4380*0Sstevel@tonic-gate $deparse = B::Deparse->new(OPTIONS) 4381*0Sstevel@tonic-gate 4382*0Sstevel@tonic-gateCreate an object to store the state of a deparsing operation and any 4383*0Sstevel@tonic-gateoptions. The options are the same as those that can be given on the 4384*0Sstevel@tonic-gatecommand line (see L</OPTIONS>); options that are separated by commas 4385*0Sstevel@tonic-gateafter B<-MO=Deparse> should be given as separate strings. Some 4386*0Sstevel@tonic-gateoptions, like B<-u>, don't make sense for a single subroutine, so 4387*0Sstevel@tonic-gatedon't pass them. 4388*0Sstevel@tonic-gate 4389*0Sstevel@tonic-gate=head2 ambient_pragmas 4390*0Sstevel@tonic-gate 4391*0Sstevel@tonic-gate $deparse->ambient_pragmas(strict => 'all', '$[' => $[); 4392*0Sstevel@tonic-gate 4393*0Sstevel@tonic-gateThe compilation of a subroutine can be affected by a few compiler 4394*0Sstevel@tonic-gatedirectives, B<pragmas>. These are: 4395*0Sstevel@tonic-gate 4396*0Sstevel@tonic-gate=over 4 4397*0Sstevel@tonic-gate 4398*0Sstevel@tonic-gate=item * 4399*0Sstevel@tonic-gate 4400*0Sstevel@tonic-gateuse strict; 4401*0Sstevel@tonic-gate 4402*0Sstevel@tonic-gate=item * 4403*0Sstevel@tonic-gate 4404*0Sstevel@tonic-gateuse warnings; 4405*0Sstevel@tonic-gate 4406*0Sstevel@tonic-gate=item * 4407*0Sstevel@tonic-gate 4408*0Sstevel@tonic-gateAssigning to the special variable $[ 4409*0Sstevel@tonic-gate 4410*0Sstevel@tonic-gate=item * 4411*0Sstevel@tonic-gate 4412*0Sstevel@tonic-gateuse integer; 4413*0Sstevel@tonic-gate 4414*0Sstevel@tonic-gate=item * 4415*0Sstevel@tonic-gate 4416*0Sstevel@tonic-gateuse bytes; 4417*0Sstevel@tonic-gate 4418*0Sstevel@tonic-gate=item * 4419*0Sstevel@tonic-gate 4420*0Sstevel@tonic-gateuse utf8; 4421*0Sstevel@tonic-gate 4422*0Sstevel@tonic-gate=item * 4423*0Sstevel@tonic-gate 4424*0Sstevel@tonic-gateuse re; 4425*0Sstevel@tonic-gate 4426*0Sstevel@tonic-gate=back 4427*0Sstevel@tonic-gate 4428*0Sstevel@tonic-gateOrdinarily, if you use B::Deparse on a subroutine which has 4429*0Sstevel@tonic-gatebeen compiled in the presence of one or more of these pragmas, 4430*0Sstevel@tonic-gatethe output will include statements to turn on the appropriate 4431*0Sstevel@tonic-gatedirectives. So if you then compile the code returned by coderef2text, 4432*0Sstevel@tonic-gateit will behave the same way as the subroutine which you deparsed. 4433*0Sstevel@tonic-gate 4434*0Sstevel@tonic-gateHowever, you may know that you intend to use the results in a 4435*0Sstevel@tonic-gateparticular context, where some pragmas are already in scope. In 4436*0Sstevel@tonic-gatethis case, you use the B<ambient_pragmas> method to describe the 4437*0Sstevel@tonic-gateassumptions you wish to make. 4438*0Sstevel@tonic-gate 4439*0Sstevel@tonic-gateNot all of the options currently have any useful effect. See 4440*0Sstevel@tonic-gateL</BUGS> for more details. 4441*0Sstevel@tonic-gate 4442*0Sstevel@tonic-gateThe parameters it accepts are: 4443*0Sstevel@tonic-gate 4444*0Sstevel@tonic-gate=over 4 4445*0Sstevel@tonic-gate 4446*0Sstevel@tonic-gate=item strict 4447*0Sstevel@tonic-gate 4448*0Sstevel@tonic-gateTakes a string, possibly containing several values separated 4449*0Sstevel@tonic-gateby whitespace. The special values "all" and "none" mean what you'd 4450*0Sstevel@tonic-gateexpect. 4451*0Sstevel@tonic-gate 4452*0Sstevel@tonic-gate $deparse->ambient_pragmas(strict => 'subs refs'); 4453*0Sstevel@tonic-gate 4454*0Sstevel@tonic-gate=item $[ 4455*0Sstevel@tonic-gate 4456*0Sstevel@tonic-gateTakes a number, the value of the array base $[. 4457*0Sstevel@tonic-gate 4458*0Sstevel@tonic-gate=item bytes 4459*0Sstevel@tonic-gate 4460*0Sstevel@tonic-gate=item utf8 4461*0Sstevel@tonic-gate 4462*0Sstevel@tonic-gate=item integer 4463*0Sstevel@tonic-gate 4464*0Sstevel@tonic-gateIf the value is true, then the appropriate pragma is assumed to 4465*0Sstevel@tonic-gatebe in the ambient scope, otherwise not. 4466*0Sstevel@tonic-gate 4467*0Sstevel@tonic-gate=item re 4468*0Sstevel@tonic-gate 4469*0Sstevel@tonic-gateTakes a string, possibly containing a whitespace-separated list of 4470*0Sstevel@tonic-gatevalues. The values "all" and "none" are special. It's also permissible 4471*0Sstevel@tonic-gateto pass an array reference here. 4472*0Sstevel@tonic-gate 4473*0Sstevel@tonic-gate $deparser->ambient_pragmas(re => 'eval'); 4474*0Sstevel@tonic-gate 4475*0Sstevel@tonic-gate 4476*0Sstevel@tonic-gate=item warnings 4477*0Sstevel@tonic-gate 4478*0Sstevel@tonic-gateTakes a string, possibly containing a whitespace-separated list of 4479*0Sstevel@tonic-gatevalues. The values "all" and "none" are special, again. It's also 4480*0Sstevel@tonic-gatepermissible to pass an array reference here. 4481*0Sstevel@tonic-gate 4482*0Sstevel@tonic-gate $deparser->ambient_pragmas(warnings => [qw[void io]]); 4483*0Sstevel@tonic-gate 4484*0Sstevel@tonic-gateIf one of the values is the string "FATAL", then all the warnings 4485*0Sstevel@tonic-gatein that list will be considered fatal, just as with the B<warnings> 4486*0Sstevel@tonic-gatepragma itself. Should you need to specify that some warnings are 4487*0Sstevel@tonic-gatefatal, and others are merely enabled, you can pass the B<warnings> 4488*0Sstevel@tonic-gateparameter twice: 4489*0Sstevel@tonic-gate 4490*0Sstevel@tonic-gate $deparser->ambient_pragmas( 4491*0Sstevel@tonic-gate warnings => 'all', 4492*0Sstevel@tonic-gate warnings => [FATAL => qw/void io/], 4493*0Sstevel@tonic-gate ); 4494*0Sstevel@tonic-gate 4495*0Sstevel@tonic-gateSee L<perllexwarn> for more information about lexical warnings. 4496*0Sstevel@tonic-gate 4497*0Sstevel@tonic-gate=item hint_bits 4498*0Sstevel@tonic-gate 4499*0Sstevel@tonic-gate=item warning_bits 4500*0Sstevel@tonic-gate 4501*0Sstevel@tonic-gateThese two parameters are used to specify the ambient pragmas in 4502*0Sstevel@tonic-gatethe format used by the special variables $^H and ${^WARNING_BITS}. 4503*0Sstevel@tonic-gate 4504*0Sstevel@tonic-gateThey exist principally so that you can write code like: 4505*0Sstevel@tonic-gate 4506*0Sstevel@tonic-gate { my ($hint_bits, $warning_bits); 4507*0Sstevel@tonic-gate BEGIN {($hint_bits, $warning_bits) = ($^H, ${^WARNING_BITS})} 4508*0Sstevel@tonic-gate $deparser->ambient_pragmas ( 4509*0Sstevel@tonic-gate hint_bits => $hint_bits, 4510*0Sstevel@tonic-gate warning_bits => $warning_bits, 4511*0Sstevel@tonic-gate '$[' => 0 + $[ 4512*0Sstevel@tonic-gate ); } 4513*0Sstevel@tonic-gate 4514*0Sstevel@tonic-gatewhich specifies that the ambient pragmas are exactly those which 4515*0Sstevel@tonic-gateare in scope at the point of calling. 4516*0Sstevel@tonic-gate 4517*0Sstevel@tonic-gate=back 4518*0Sstevel@tonic-gate 4519*0Sstevel@tonic-gate=head2 coderef2text 4520*0Sstevel@tonic-gate 4521*0Sstevel@tonic-gate $body = $deparse->coderef2text(\&func) 4522*0Sstevel@tonic-gate $body = $deparse->coderef2text(sub ($$) { ... }) 4523*0Sstevel@tonic-gate 4524*0Sstevel@tonic-gateReturn source code for the body of a subroutine (a block, optionally 4525*0Sstevel@tonic-gatepreceded by a prototype in parens), given a reference to the 4526*0Sstevel@tonic-gatesub. Because a subroutine can have no names, or more than one name, 4527*0Sstevel@tonic-gatethis method doesn't return a complete subroutine definition -- if you 4528*0Sstevel@tonic-gatewant to eval the result, you should prepend "sub subname ", or "sub " 4529*0Sstevel@tonic-gatefor an anonymous function constructor. Unless the sub was defined in 4530*0Sstevel@tonic-gatethe main:: package, the code will include a package declaration. 4531*0Sstevel@tonic-gate 4532*0Sstevel@tonic-gate=head1 BUGS 4533*0Sstevel@tonic-gate 4534*0Sstevel@tonic-gate=over 4 4535*0Sstevel@tonic-gate 4536*0Sstevel@tonic-gate=item * 4537*0Sstevel@tonic-gate 4538*0Sstevel@tonic-gateThe only pragmas to be completely supported are: C<use warnings>, 4539*0Sstevel@tonic-gateC<use strict 'refs'>, C<use bytes>, and C<use integer>. (C<$[>, which 4540*0Sstevel@tonic-gatebehaves like a pragma, is also supported.) 4541*0Sstevel@tonic-gate 4542*0Sstevel@tonic-gateExcepting those listed above, we're currently unable to guarantee that 4543*0Sstevel@tonic-gateB::Deparse will produce a pragma at the correct point in the program. 4544*0Sstevel@tonic-gate(Specifically, pragmas at the beginning of a block often appear right 4545*0Sstevel@tonic-gatebefore the start of the block instead.) 4546*0Sstevel@tonic-gateSince the effects of pragmas are often lexically scoped, this can mean 4547*0Sstevel@tonic-gatethat the pragma holds sway over a different portion of the program 4548*0Sstevel@tonic-gatethan in the input file. 4549*0Sstevel@tonic-gate 4550*0Sstevel@tonic-gate=item * 4551*0Sstevel@tonic-gate 4552*0Sstevel@tonic-gateIn fact, the above is a specific instance of a more general problem: 4553*0Sstevel@tonic-gatewe can't guarantee to produce BEGIN blocks or C<use> declarations in 4554*0Sstevel@tonic-gateexactly the right place. So if you use a module which affects compilation 4555*0Sstevel@tonic-gate(such as by over-riding keywords, overloading constants or whatever) 4556*0Sstevel@tonic-gatethen the output code might not work as intended. 4557*0Sstevel@tonic-gate 4558*0Sstevel@tonic-gateThis is the most serious outstanding problem, and will require some help 4559*0Sstevel@tonic-gatefrom the Perl core to fix. 4560*0Sstevel@tonic-gate 4561*0Sstevel@tonic-gate=item * 4562*0Sstevel@tonic-gate 4563*0Sstevel@tonic-gateIf a keyword is over-ridden, and your program explicitly calls 4564*0Sstevel@tonic-gatethe built-in version by using CORE::keyword, the output of B::Deparse 4565*0Sstevel@tonic-gatewill not reflect this. If you run the resulting code, it will call 4566*0Sstevel@tonic-gatethe over-ridden version rather than the built-in one. (Maybe there 4567*0Sstevel@tonic-gateshould be an option to B<always> print keyword calls as C<CORE::name>.) 4568*0Sstevel@tonic-gate 4569*0Sstevel@tonic-gate=item * 4570*0Sstevel@tonic-gate 4571*0Sstevel@tonic-gateSome constants don't print correctly either with or without B<-d>. 4572*0Sstevel@tonic-gateFor instance, neither B::Deparse nor Data::Dumper know how to print 4573*0Sstevel@tonic-gatedual-valued scalars correctly, as in: 4574*0Sstevel@tonic-gate 4575*0Sstevel@tonic-gate use constant E2BIG => ($!=7); $y = E2BIG; print $y, 0+$y; 4576*0Sstevel@tonic-gate 4577*0Sstevel@tonic-gate=item * 4578*0Sstevel@tonic-gate 4579*0Sstevel@tonic-gateAn input file that uses source filtering probably won't be deparsed into 4580*0Sstevel@tonic-gaterunnable code, because it will still include the B<use> declaration 4581*0Sstevel@tonic-gatefor the source filtering module, even though the code that is 4582*0Sstevel@tonic-gateproduced is already ordinary Perl which shouldn't be filtered again. 4583*0Sstevel@tonic-gate 4584*0Sstevel@tonic-gate=item * 4585*0Sstevel@tonic-gate 4586*0Sstevel@tonic-gateThere are probably many more bugs on non-ASCII platforms (EBCDIC). 4587*0Sstevel@tonic-gate 4588*0Sstevel@tonic-gate=back 4589*0Sstevel@tonic-gate 4590*0Sstevel@tonic-gate=head1 AUTHOR 4591*0Sstevel@tonic-gate 4592*0Sstevel@tonic-gateStephen McCamant <smcc@CSUA.Berkeley.EDU>, based on an earlier version 4593*0Sstevel@tonic-gateby Malcolm Beattie <mbeattie@sable.ox.ac.uk>, with contributions from 4594*0Sstevel@tonic-gateGisle Aas, James Duncan, Albert Dvornik, Robin Houston, Dave Mitchell, 4595*0Sstevel@tonic-gateHugo van der Sanden, Gurusamy Sarathy, Nick Ing-Simmons, and Rafael 4596*0Sstevel@tonic-gateGarcia-Suarez. 4597*0Sstevel@tonic-gate 4598*0Sstevel@tonic-gate=cut 4599