File Coverage

lib/B/DeparseTree/PPfns.pm
Criterion Covered Total %
statement 653 1336 48.8
branch 263 598 43.9
condition 187 364 51.3
subroutine 60 83 72.2
pod 0 56 0.0
total 1163 2437 47.7


line stmt bran cond sub pod time code
1             # Common routines used by PP Functions
2             # Copyright (c) 2015-2018 Rocky Bernstein
3             # Copyright (c) 1998-2000, 2002, 2003, 2004, 2005, 2006 Stephen McCamant.
4              
5             # All rights reserved.
6             # This module is free software; you can redistribute and/or modify
7             # it under the same terms as Perl itself.
8              
9             # This is based on the module B::Deparse by Stephen McCamant.
10             # It has been extended save tree structure, and is addressible
11             # by opcode address.
12              
13             # B::Parse in turn is based on the module of the same name by Malcolm Beattie,
14             # but essentially none of his code remains.
15 3     3   22 use strict; use warnings;
  3     3   7  
  3         85  
  3         16  
  3         6  
  3         89  
16              
17             package B::DeparseTree::PPfns;
18 3     3   11 use Carp;
  3         6  
  3         144  
19 3         164 use B qw(
20             OPf_STACKED
21             OPf_SPECIAL
22             OPpCONST_BARE
23             OPpLVAL_INTRO
24             OPpREPEAT_DOLIST
25             OPpSORT_INTEGER
26             OPpSORT_NUMERIC
27             OPpSORT_REVERSE
28             opnumber
29 3     3   15 );
  3         5  
30              
31 3     3   17 use B::Deparse;
  3         4  
  3         212  
32              
33             # Copy unchanged functions from B::Deparse
34             *balanced_delim = *B::Deparse::balanced_delim;
35             *double_delim = *B::Deparse::double_delim;
36             *escape_extended_re = *B::Deparse::escape_extended_re;
37             *escape_re = *B::Deparse::escape_re;
38             *lex_in_scope = *B::Deparse::lex_in_scope;
39             *rv2gv_or_string = *B::Deparse::rv2gv_or_string;
40              
41 3     3   14 use B::DeparseTree::SyntaxTree;
  3         3  
  3         307  
42              
43             # Various operator flag bits
44 3     3   16 use constant POSTFIX => 1; # operator can be used as postfix operator
  3         4  
  3         169  
45 3     3   16 use constant SWAP_CHILDREN => 1; # children of op should be reversed
  3         12  
  3         124  
46 3     3   13 use constant ASSIGN => 2; # has OP= variant
  3         5  
  3         117  
47 3     3   15 use constant LIST_CONTEXT => 4; # Assignment is in list context
  3         3  
  3         452  
48              
49              
50              
51             our($VERSION, @EXPORT, @ISA);
52             $VERSION = '3.2.0';
53             @ISA = qw(Exporter);
54             @EXPORT = qw(
55             %strict_bits
56             ASSIGN
57             LIST_CONTEXT
58             POSTFIX
59             SWAP_CHILDREN
60             ambient_pragmas
61             anon_hash_or_list
62             baseop
63             binop
64             code_list
65             concat
66             cops
67             dedup_parens_func
68             deparse_binop_left
69             deparse_binop_right
70             deparse_format
71             deparse_op_siblings
72             double_delim
73             dq
74             dq_unop
75             dquote
76             e_anoncode
77             elem
78             filetest
79             func_needs_parens
80             givwhen
81             indirop
82             is_list_newer
83             is_list_older
84             listop
85             logassignop
86             logop
87             loop_common
88             loopex
89             map_texts
90             mapop
91             matchop
92             maybe_local
93             maybe_local_str
94             maybe_my
95             maybe_parens
96             maybe_parens_func
97             maybe_parens_unop
98             maybe_qualify
99             maybe_targmy
100             null_newer
101             null_older
102             pfixop
103             range
104             repeat
105             rv2x
106             scopeop
107             single_delim
108             slice
109             subst_newer
110             subst_older
111             unop
112             );
113              
114             # The BEGIN {} is used here because otherwise this code isn't executed
115             # when you run B::Deparse on itself.
116             my %globalnames;
117 3     3   188 BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
118             "ENV", "ARGV", "ARGVOUT", "_"); }
119              
120             BEGIN {
121             # List version-specific constants here.
122             # Easiest way to keep this code portable between version looks to
123             # be to fake up a dummy constant that will never actually be true.
124 3     3   11 foreach (qw(
125             CVf_LOCKED
126             OPpCONST_ARYBASE
127             OPpCONST_NOVER
128             OPpEVAL_BYTES
129             OPpITER_REVERSED
130             OPpOUR_INTRO
131             OPpPAD_STATE
132             OPpREVERSE_INPLACE
133             OPpSORT_DESCEND
134             OPpSORT_INPLACE
135             OPpTARGET_MY
136             OPpSUBSTR_REPL_FIRST
137             PMf_EVAL PMf_EXTENDED
138             PMf_NONDESTRUCT
139             PMf_SKIPWHITE
140             RXf_PMf_CHARSET
141             RXf_PMf_KEEPCOPY
142             RXf_SKIPWHITE
143             )) {
144 57         71 eval { import B $_ };
  57         3030  
145 3     3   15 no strict 'refs';
  3         6  
  3         178  
146 57 100       164 *{$_} = sub () {0} unless *{$_}{CODE};
  9         28  
  57         554  
147             }
148             }
149              
150             my %strict_bits = do {
151             local $^H;
152             map +($_ => strict::bits($_)), qw/refs subs vars/
153             };
154              
155 3     3   12 BEGIN { for (qw[ pushmark ]) {
156 3         231 eval "sub OP_\U$_ () { " . opnumber($_) . "}"
157             }}
158              
159             {
160             # Mask out the bits that L uses
161             my $WARN_MASK;
162             BEGIN {
163 3     3   3516 $WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all};
164             }
165             sub WARN_MASK () {
166 169     169 0 446 return $WARN_MASK;
167             }
168             }
169              
170             my(%left, %right);
171              
172             sub ambient_pragmas {
173 56     56 0 82514 my $self = shift;
174 56         162 my ($arybase, $hint_bits, $warning_bits, $hinthash) = (0, 0);
175              
176 56         221 while (@_ > 1) {
177 168         259 my $name = shift();
178 168         214 my $val = shift();
179              
180 168 50 33     1241 if ($name eq 'strict') {
    50 33        
    50          
    50          
    50          
    100          
    100          
    50          
181 0         0 require strict;
182              
183 0 0       0 if ($val eq 'none') {
184 0         0 $hint_bits &= $strict_bits{$_} for qw/refs subs vars/;
185 0         0 next();
186             }
187              
188 0         0 my @names;
189 0 0       0 if ($val eq "all") {
    0          
190 0         0 @names = qw/refs subs vars/;
191             }
192             elsif (ref $val) {
193 0         0 @names = @$val;
194             }
195             else {
196 0         0 @names = split' ', $val;
197             }
198 0         0 $hint_bits |= $strict_bits{$_} for @names;
199             }
200              
201             elsif ($name eq '$[') {
202 0         0 if (OPpCONST_ARYBASE) {
203             $arybase = $val;
204             } else {
205 0 0       0 croak "\$[ can't be non-zero on this perl" unless $val == 0;
206             }
207             }
208              
209             elsif ($name eq 'integer'
210             || $name eq 'bytes'
211             || $name eq 'utf8') {
212 0         0 require "$name.pm";
213 0 0       0 if ($val) {
214 0         0 $hint_bits |= ${$::{"${name}::"}{"hint_bits"}};
  0         0  
215             }
216             else {
217 0         0 $hint_bits &= ~${$::{"${name}::"}{"hint_bits"}};
  0         0  
218             }
219             }
220              
221             elsif ($name eq 're') {
222 0         0 require re;
223 0 0       0 if ($val eq 'none') {
224 0         0 $hint_bits &= ~re::bits(qw/taint eval/);
225 0         0 next();
226             }
227              
228 0         0 my @names;
229 0 0       0 if ($val eq 'all') {
    0          
230 0         0 @names = qw/taint eval/;
231             }
232             elsif (ref $val) {
233 0         0 @names = @$val;
234             }
235             else {
236 0         0 @names = split' ',$val;
237             }
238 0         0 $hint_bits |= re::bits(@names);
239             }
240              
241             elsif ($name eq 'warnings') {
242 0 0       0 if ($val eq 'none') {
243 0         0 $warning_bits = $warnings::NONE;
244 0         0 next();
245             }
246              
247 0         0 my @names;
248 0 0       0 if (ref $val) {
249 0         0 @names = @$val;
250             }
251             else {
252 0         0 @names = split/\s+/, $val;
253             }
254              
255 0 0       0 $warning_bits = $warnings::NONE if !defined ($warning_bits);
256 0         0 $warning_bits |= warnings::bits(@names);
257             }
258              
259             elsif ($name eq 'warning_bits') {
260 56         127 $warning_bits = $val;
261             }
262              
263             elsif ($name eq 'hint_bits') {
264 56         152 $hint_bits = $val;
265             }
266              
267             elsif ($name eq '%^H') {
268 56         151 $hinthash = $val;
269             }
270              
271             else {
272 0         0 croak "Unknown pragma type: $name";
273             }
274             }
275 56 50       158 if (@_) {
276 0         0 croak "The ambient_pragmas method expects an even number of args";
277             }
278              
279 56         147 $self->{'ambient_arybase'} = $arybase;
280 56         124 $self->{'ambient_warnings'} = $warning_bits;
281 56         86 $self->{'ambient_hints'} = $hint_bits;
282 56         1015 $self->{'ambient_hinthash'} = $hinthash;
283             }
284              
285             sub anon_hash_or_list($$$)
286             {
287 0     0 0 0 my ($self, $op, $cx) = @_;
288 0         0 my $name = $op->name;
289 0         0 my($pre, $post) = @{{"anonlist" => ["[","]"],
290 0         0 "anonhash" => ["{","}"]}->{$name}};
291 0         0 my($expr, @exprs);
292 0         0 my $other_ops = [$op->first];
293 0         0 $op = $op->first->sibling; # skip pushmark
294 0         0 for (; !B::Deparse::null($op); $op = $op->sibling) {
295 0         0 $expr = $self->deparse($op, 6, $op);
296 0         0 push @exprs, [$expr, $op];
297             }
298 0 0 0     0 if ($pre eq "{" and $cx < 1) {
299             # Disambiguate that it's not a block
300 0         0 $pre = "+{";
301             }
302 0         0 my $texts = [$pre, $self->combine(", ", \@exprs), $post];
303 0         0 return info_from_list($op, $self, $texts, '', $name,
304             {body => \@exprs,
305             other_ops => $other_ops
306             });
307             }
308              
309             sub assoc_class {
310 4445     4445 0 5270 my $op = shift;
311 4445         13418 my $name = $op->name;
312 4445 100 100     9138 if ($name eq "concat" and $op->first->name eq "concat") {
313             # avoid spurious '=' -- see comment in pp_concat
314 4         25 return "concat";
315             }
316 4441 100 66     23537 if ($name eq "null" and B::class($op) eq "UNOP"
      100        
      66        
317             and $op->first->name =~ /^(and|x?or)$/
318             and B::Deparse::null $op->first->sibling)
319             {
320             # Like all conditional constructs, OP_ANDs and OP_ORs are topped
321             # with a null that's used as the common end point of the two
322             # flows of control. For precedence purposes, ignore it.
323             # (COND_EXPRs have these too, but we don't bother with
324             # their associativity).
325 26         99 return assoc_class($op->first);
326             }
327 4415 100       24395 return $name . ($op->flags & B::OPf_STACKED ? "=" : "");
328             }
329              
330             # routines implementing classes of ops
331              
332             sub baseop
333             {
334 42     42 0 107 my($self, $op, $cx, $name) = @_;
335 42         1477 return $self->info_from_string("baseop $name", $op, $self->keyword($name));
336             }
337              
338             # Handle binary operators like +, and assignment
339             sub binop
340             {
341              
342 1396     1396 0 3037 my ($self, $op, $cx, $opname, $prec) = @_;
343 1396         2895 my ($flags, $type) = (0, '');
344 1396 100       3193 if (scalar(@_) > 5) {
345 1338         1894 $flags = $_[5];
346 1338 100       3224 $type = $_[6] if (scalar(@_) > 6);
347             }
348 1396         4737 my $left = $op->first;
349 1396         3878 my $right = $op->last;
350 1396         2094 my $eq = "";
351 1396 100 100     6837 if ($op->flags & B::OPf_STACKED && $flags & B::Deparse::ASSIGN) {
352 5         14 $eq = "=";
353 5         10 $prec = 7;
354             }
355 1396 100       2753 if ($flags & SWAP_CHILDREN) {
356 1322         2440 ($left, $right) = ($right, $left);
357             }
358 1396         3738 my $lhs = $self->deparse_binop_left($op, $left, $prec);
359 1396 50 66     7921 if ($flags & B::Deparse::LIST_CONTEXT
360             && $lhs->{text} !~ /^(my|our|local|)[\@\(]/) {
361 0   0     0 $lhs->{maybe_parens} ||= {};
362 0         0 $lhs->{maybe_parens}{force} = 'true';
363 0         0 $lhs->{text} = "($lhs->{text})";
364             }
365              
366 1396         4538 my $rhs = $self->deparse_binop_right($op, $right, $prec);
367 1396 100       3299 if ($flags & SWAP_CHILDREN) {
368             # Not sure why this is right
369 1322         2444 $lhs->{prev_expr} = $rhs;
370             } else {
371 74         237 $rhs->{prev_expr} = $lhs;
372             }
373              
374 1396   100     3022 $type = $type || 'binary operator';
375 1396         3039 $type .= " $opname$eq";
376 1396         9892 my $node = $self->info_from_template($type, $op, "%c $opname$eq %c",
377             undef, [$lhs, $rhs],
378             {maybe_parens => [$self, $cx, $prec]});
379 1396         3568 $node->{prev_expr} = $rhs;
380 1396         4892 return $node;
381             }
382              
383             # Left associative operators, like '+', for which
384             # $a + $b + $c is equivalent to ($a + $b) + $c
385              
386             BEGIN {
387 3     3   3451 %left = ('multiply' => 19, 'i_multiply' => 19,
388             'divide' => 19, 'i_divide' => 19,
389             'modulo' => 19, 'i_modulo' => 19,
390             'repeat' => 19,
391             'add' => 18, 'i_add' => 18,
392             'subtract' => 18, 'i_subtract' => 18,
393             'concat' => 18,
394             'left_shift' => 17, 'right_shift' => 17,
395             'bit_and' => 13,
396             'bit_or' => 12, 'bit_xor' => 12,
397             'and' => 3,
398             'or' => 2, 'xor' => 2,
399             );
400             }
401              
402             sub code_list {
403 0     0 0 0 my ($self, $op, $cv) = @_;
404              
405             # localise stuff relating to the current sub
406             $cv and
407             local($self->{'curcv'}) = $cv,
408             local($self->{'curcvlex'}),
409             local(@$self{qw'curstash warnings hints hinthash curcop'})
410 0 0       0 = @$self{qw'curstash warnings hints hinthash curcop'};
411              
412 0         0 my $re;
413 0         0 for ($op = $op->first->sibling; !B::Deparse::null($op); $op = $op->sibling) {
414 0 0 0     0 if ($op->name eq 'null' and $op->flags & OPf_SPECIAL) {
415 0         0 my $scope = $op->first;
416             # 0 context (last arg to scopeop) means statement context, so
417             # the contents of the block will not be wrapped in do{...}.
418 0         0 my $block = scopeop($scope->first->name eq "enter", $self,
419             $scope, 0);
420             # next op is the source code of the block
421 0         0 $op = $op->sibling;
422 0         0 $re .= ($self->const_sv($op)->PV =~ m|^(\(\?\??\{)|)[0];
423 0         0 my $multiline = $block =~ /\n/;
424 0 0       0 $re .= $multiline ? "\n\t" : ' ';
425 0         0 $re .= $block;
426 0 0       0 $re .= $multiline ? "\n\b})" : " })";
427             } else {
428 0         0 $re = B::Deparse::re_dq_disambiguate($re, $self->re_dq($op));
429             }
430             }
431 0         0 $re;
432             }
433              
434             # Concatenation or '.' is special because concats-of-concats are
435             # optimized to save copying by making all but the first concat
436             # stacked. The effect is as if the programmer had written:
437             # ($a . $b) .= $c'
438             # but the above is illegal.
439              
440             sub concat {
441 6     6 0 12 my $self = shift;
442 6         12 my($op, $cx) = @_;
443 6         21 my $left = $op->first;
444 6         23 my $right = $op->last;
445 6         14 my $eq = "";
446 6         10 my $prec = 18;
447 6 100 100     36 if ($op->flags & OPf_STACKED and $op->first->name ne "concat") {
448 1         2 $eq = "=";
449 1         3 $prec = 7;
450             }
451 6         19 my $lhs = $self->deparse_binop_left($op, $left, $prec);
452 6         22 my $rhs = $self->deparse_binop_right($op, $right, $prec);
453 6         34 return $self->bin_info_join_maybe_parens($op, $lhs, $rhs, ".$eq", " ", $cx, $prec,
454             'concat');
455             }
456              
457             # Handle pp_dbstate, and pp_nextstate and COP ops.
458             #
459             # Notice how subs and formats are inserted between statements here;
460             # also $[ assignments and pragmas.
461             sub cops
462             {
463 2089     2089 0 4132 my ($self, $op, $cx, $name) = @_;
464 2089         3588 $self->{'curcop'} = $op;
465 2089         2607 my @texts;
466 2089         3002 my $opts = {};
467 2089         3317 my @args_spec = ();
468 2089         2782 my $fmt = '%;';
469              
470 2089         15409 push @texts, $self->B::Deparse::cop_subs($op);
471 2089 50       3796 if (@texts) {
472             # Special marker to swallow up the semicolon
473 0         0 $opts->{'omit_next_semicolon'} = 1;
474             }
475              
476 2089         6388 my $stash = $op->stashpv;
477 2089 100       5259 if ($stash ne $self->{'curstash'}) {
478 1286         512903 push @texts, $self->keyword("package") . " $stash;";
479 1286         4178 $self->{'curstash'} = $stash;
480             }
481              
482 2089         2548 if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) {
483             push @texts, '$[ = '. $op->arybase .";";
484             $self->{'arybase'} = $op->arybase;
485             }
486              
487 2089         6678 my $warnings = $op->warnings;
488 2089         2836 my $warning_bits;
489 2089 100 66     13692 if ($warnings->isa("B::SPECIAL") && $$warnings == 4) {
    50 33        
    0          
490 169         444 $warning_bits = $warnings::Bits{"all"} & WARN_MASK;
491             }
492             elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) {
493 1920         3249 $warning_bits = $warnings::NONE;
494             }
495             elsif ($warnings->isa("B::SPECIAL")) {
496 0         0 $warning_bits = undef;
497             }
498             else {
499 0         0 $warning_bits = $warnings->PV & WARN_MASK;
500             }
501              
502 2089 100 66     8703 if (defined ($warning_bits) and
      33        
503             !defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) {
504 1288         5696 my @warnings = $self->declare_warnings($self->{'warnings'}, $warning_bits);
505 1288         2516 foreach my $warning (@warnings) {
506 1288         2240 push @texts, $warning;
507             }
508 1288         2318 $self->{'warnings'} = $warning_bits;
509             }
510              
511 2089 50       8183 my $hints = $] < 5.008009 ? $op->private : $op->hints;
512 2089         3859 my $old_hints = $self->{'hints'};
513 2089 100       3941 if ($self->{'hints'} != $hints) {
514 1337         4215 my @hints = $self->declare_hints($self->{'hints'}, $hints);
515 1337         2488 foreach my $hint (@hints) {
516 1288         2424 push @texts, $hint;
517             }
518 1337         2282 $self->{'hints'} = $hints;
519             }
520              
521 2089         2495 my $newhh;
522 2089 50       3718 if ($] > 5.009) {
523 2089         10567 $newhh = $op->hints_hash->HASH;
524             }
525              
526 2089 50       4860 if ($] >= 5.015006) {
527             # feature bundle hints
528 2089         2874 my $from = $old_hints & $feature::hint_mask;
529 2089         2506 my $to = $ hints & $feature::hint_mask;
530 2089 100       4153 if ($from != $to) {
531 8 100       17 if ($to == $feature::hint_mask) {
532 4 50       11 if ($self->{'hinthash'}) {
533             delete $self->{'hinthash'}{$_}
534 4         7 for grep /^feature_/, keys %{$self->{'hinthash'}};
  4         58  
535             }
536 0         0 else { $self->{'hinthash'} = {} }
537             $self->{'hinthash'}
538             = B::Deparse::_features_from_bundle($from,
539 4         45 $self->{'hinthash'});
540             }
541             else {
542 4         9 my $bundle =
543             $feature::hint_bundles[$to >> $feature::hint_shift];
544 4         18 $bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12
  2         9  
545 4         1849 push @texts,
546             $self->keyword("no") . " feature ':all'",
547             $self->keyword("use") . " feature ':$bundle'";
548             }
549             }
550             }
551              
552 2089 50       3663 if ($] > 5.009) {
553             # FIXME use format specifiers
554             my @hints = $self->declare_hinthash(
555 2089         6242 $self->{'hinthash'}, $newhh, 0, $self->{hints});
556 2089         3597 foreach my $hint (@hints) {
557 3         7 push @texts, $hint;
558             }
559 2089         3659 $self->{'hinthash'} = $newhh;
560             }
561              
562              
563             # This should go after of any branches that add statements, to
564             # increase the chances that it refers to the same line it did in
565             # the original program.
566 2089 50 33     4799 if ($self->{'linenums'} && $cx != .5) { # $cx == .5 means in a format
567 0         0 my $line = sprintf("\n# line %s '%s'", $op->line, $op->file);
568 0 0       0 $line .= sprintf(" 0x%x", $$op) if $self->{'opaddr'};
569 0         0 $opts->{'omit_next_semicolon'} = 1;
570 0         0 push @texts, $line;
571             }
572              
573 2089 50       8000 if ($op->label) {
574 0         0 $fmt .= "%c\n";
575 0         0 push @args_spec, scalar(@args_spec);
576 0         0 push @texts, $op->label . ": " ;
577             }
578              
579 2089         6406 my $node = $self->info_from_template($name, $op, $fmt,
580             \@args_spec, \@texts, $opts);
581 2089         8008 return $node;
582             }
583              
584             sub deparse_binop_left {
585 1483     1483 0 2136 my $self = shift;
586 1483         2700 my($op, $left, $prec) = @_;
587 1483 100 100     3603 if ($left{assoc_class($op)} && $left{assoc_class($left)}
      66        
588             and $left{assoc_class($op)} == $left{assoc_class($left)})
589             {
590 14         60 return $self->deparse($left, $prec - .00001, $op);
591             } else {
592 1469         3915 return $self->deparse($left, $prec, $op);
593             }
594             }
595              
596             # Right associative operators, like '=', for which
597             # $a = $b = $c is equivalent to $a = ($b = $c)
598              
599             BEGIN {
600 3     3   36065 %right = ('pow' => 22,
601             'sassign=' => 7, 'aassign=' => 7,
602             'multiply=' => 7, 'i_multiply=' => 7,
603             'divide=' => 7, 'i_divide=' => 7,
604             'modulo=' => 7, 'i_modulo=' => 7,
605             'repeat=' => 7,
606             'add=' => 7, 'i_add=' => 7,
607             'subtract=' => 7, 'i_subtract=' => 7,
608             'concat=' => 7,
609             'left_shift=' => 7, 'right_shift=' => 7,
610             'bit_and=' => 7,
611             'bit_or=' => 7, 'bit_xor=' => 7,
612             'andassign' => 7,
613             'orassign' => 7,
614             );
615             }
616              
617             sub deparse_format($$$)
618             {
619 0     0 0 0 my ($self, $form, $parent) = @_;
620 0         0 my @texts;
621 0         0 local($self->{'curcv'}) = $form;
622 0         0 local($self->{'curcvlex'});
623 0         0 local($self->{'in_format'}) = 1;
624             local(@$self{qw'curstash warnings hints hinthash'})
625 0         0 = @$self{qw'curstash warnings hints hinthash'};
626 0         0 my $op = $form->ROOT;
627 0         0 local $B::overlay = {};
628 0         0 $self->pessimise($op, $form->START);
629             my $info = {
630             op => $op,
631             parent => $parent,
632 0         0 cop => $self->{'curcop'}
633             };
634 0         0 $self->{optree}{$$op} = $info;
635              
636 0 0 0     0 if ($op->first->name eq 'stub' || $op->first->name eq 'nextstate') {
637 0         0 my $info->{text} = "\f.";
638 0         0 return $info;
639             }
640              
641 0         0 $op->{other_ops} = [$op->first];
642 0         0 $op = $op->first->first; # skip leavewrite, lineseq
643 0         0 my $kid;
644 0         0 while (not B::Deparse::null $op) {
645 0         0 push @{$op->{other_ops}}, $op;
  0         0  
646 0         0 $op = $op->sibling; # skip nextstate
647 0         0 my @body;
648 0         0 push @{$op->{other_ops}}, $op->first;
  0         0  
649 0         0 $kid = $op->first->sibling; # skip a pushmark
650 0         0 push @texts, "\f".$self->const_sv($kid)->PV;
651 0         0 push @{$op->{other_ops}}, $kid;
  0         0  
652 0         0 $kid = $kid->sibling;
653 0         0 for (; not B::Deparse::null $kid; $kid = $kid->sibling) {
654 0         0 push @body, $self->deparse($kid, -1, $op);
655 0         0 $body[-1] =~ s/;\z//;
656             }
657 0 0       0 push @texts, "\f".$self->combine2str("\n", \@body) if @body;
658 0         0 $op = $op->sibling;
659             }
660              
661 0         0 $info->{text} = $self->combine2str(\@texts) . "\f.";
662 0         0 $info->{texts} = \@texts;
663 0         0 return $info;
664             }
665              
666             sub dedup_parens_func($$$)
667             {
668 593     593 0 1110 my $self = shift;
669 593         952 my $sub_info = shift;
670 593         1211 my ($args_ref) = @_;
671 593         1245 my @args = @$args_ref;
672 593 50 66     2607 if (scalar @args == 1 && substr($args[0], 0, 1) eq '(' &&
      33        
673             substr($args[0], -1, 1) eq ')') {
674 0         0 return ($sub_info, $self->combine(', ', \@args), );
675             } else {
676 593         2515 return ($sub_info, '(', $self->combine(', ', \@args), ')', );
677             }
678             }
679              
680             sub deparse_binop_right {
681 1483     1483 0 2697 my $self = shift;
682 1483         2710 my($op, $right, $prec) = @_;
683 1483 50 66     2968 if ($right{assoc_class($op)} && $right{assoc_class($right)}
      33        
684             and $right{assoc_class($op)} == $right{assoc_class($right)})
685             {
686 0         0 return $self->deparse($right, $prec - .00001, $op);
687             } else {
688 1483         4140 return $self->deparse($right, $prec, $op);
689             }
690             }
691              
692             # Iterate via sibling links a list of OP nodes starting with
693             # $first. Each OP is deparsed, with $op and $precedence each to get a
694             # node. Then the "prev" field in the node is set, and finally it is
695             # pushed onto the end of the $exprs reference ARRAY.
696             sub deparse_op_siblings($$$$$)
697             {
698 277     277 0 687 my ($self, $exprs, $kid, $op, $precedence) = @_;
699 277         392 my $prev_expr = undef;
700 277 50       408 $prev_expr = $exprs->[-1] if scalar @{$exprs};
  277         813  
701 277         2344 for ( ; !B::Deparse::null($kid); $kid = $kid->sibling) {
702 333         933 my $expr = $self->deparse($kid, $precedence, $op);
703 333 50       716 if (defined $expr) {
704 333         825 $expr->{prev_expr} = $prev_expr;
705 333         427 $prev_expr = $expr;
706 333         3565 push @$exprs, $expr;
707             }
708             }
709             }
710              
711              
712             # tr/// and s/// (and tr[][], tr[]//, tr###, etc)
713             # note that tr(from)/to/ is OK, but not tr/from/(to)
714             sub double_delim {
715             my($from, $to) = @_;
716             my($succeed, $delim);
717             if ($from !~ m[/] and $to !~ m[/]) {
718             return "/$from/$to/";
719             } elsif (($succeed, $from) = B::Deparse::balanced_delim($from) and $succeed) {
720             if (($succeed, $to) = B::Deparse::balanced_delim($to) and $succeed) {
721             return "$from$to";
722             } else {
723             for $delim ('/', '"', '#') { # note no "'" -- s''' is special
724             return "$from$delim$to$delim" if index($to, $delim) == -1;
725             }
726             $to =~ s[/][\\/]g;
727             return "$from/$to/";
728             }
729             } else {
730             for $delim ('/', '"', '#') { # note no '
731             return "$delim$from$delim$to$delim"
732             if index($to . $from, $delim) == -1;
733             }
734             $from =~ s[/][\\/]g;
735             $to =~ s[/][\\/]g;
736             return "/$from/$to/";
737             }
738             }
739              
740             sub dq($$$)
741             {
742 24     24 0 61 my ($self, $op, $parent) = @_;
743 24         73 my $type = $op->name;
744 24         44 my $info;
745 24 100       97 if ($type eq "const") {
    50          
    50          
746 14 50       50 return info_from_text($op, $self, '$[', 'dq constant ary', {}) if $op->private & OPpCONST_ARYBASE;
747 14         172 return info_from_text($op, $self,
748             B::Deparse::uninterp(B::Deparse::escape_str(B::Deparse::unback($self->const_sv($op)->as_string))),
749             'dq constant', {});
750             } elsif ($type eq "concat") {
751 0         0 my $first = $self->dq($op->first, $op);
752 0         0 my $last = $self->dq($op->last, $op);
753              
754             # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]", "$foo\::bar"
755 0 0 0     0 ($last =~ /^[A-Z\\\^\[\]_?]/ &&
      0        
756             $first =~ s/([\$@])\^$/${1}{^}/) # "${^}W" etc
757             || ($last =~ /^[:'{\[\w_]/ && #'
758             $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/);
759              
760 0         0 return info_from_list($op, $self, [$first->{text}, $last->{text}], '', 'dq_concat',
761             {body => [$first, $last]});
762             } elsif ($type eq "join") {
763 0         0 return $self->deparse($op->last, 26, $op); # was join($", @ary)
764             } else {
765 10         36 return $self->deparse($op, 26, $parent);
766             }
767 0         0 my $kid = $self->dq($op->first->sibling, $op);
768 0         0 my $kid_text = $kid->{text};
769 0 0       0 if ($type eq "uc") {
    0          
    0          
    0          
    0          
    0          
770 0         0 $info = info_from_lists(['\U', $kid, '\E'], '', 'dq_uc', {});
771             } elsif ($type eq "lc") {
772 0         0 $info = info_from_lists(['\L', $kid, '\E'], '', 'dq_lc', {});
773             } elsif ($type eq "ucfirst") {
774 0         0 $info = info_from_lists(['\u', $kid, '\E'], '', 'dq_ucfirst', {});
775             } elsif ($type eq "lcfirst") {
776 0         0 $info = info_from_lists(['\l', $kid, '\E'], '', 'dq_lcfirst', {});
777             } elsif ($type eq "quotemeta") {
778 0         0 $info = info_from_lists(['\Q', $kid, '\E'], '', 'dq_quotemeta', {});
779             } elsif ($type eq "fc") {
780 0         0 $info = info_from_lists(['\F', $kid, '\E'], '', 'dq_fc', {});
781             }
782 0         0 $info->{body} = [$kid];
783 0         0 return $info;
784             }
785              
786             # Handle unary operators that can occur as pseudo-listops inside
787             # double quotes
788             sub dq_unop
789             {
790 20     20 0 58 my($self, $op, $cx, $name, $prec, $flags) = (@_, 0, 0);
791 20         33 my $kid;
792 20 50       72 if ($op->flags & B::OPf_KIDS) {
793 20         29 my $pushmark_op = undef;
794 20         54 $kid = $op->first;
795 20 50       153 if (not B::Deparse::null $kid->sibling) {
796             # If there's more than one kid, the first is an ex-pushmark.
797 0         0 $pushmark_op = $kid;
798 0         0 $kid = $kid->sibling;
799             }
800 20         83 my $info = $self->maybe_parens_unop($name, $kid, $cx, $op);
801 20 50       54 if ($pushmark_op) {
802             # For the pushmark opc we'll consider it the "name" portion
803             # of info. We examine that to get the text.
804 0         0 my $text = $info->{text};
805 0         0 my $word_end = index($text, ' ');
806 0 0       0 $word_end = length($text) unless $word_end > 0;
807 0         0 my $pushmark_info =
808             $self->info_from_string("dq $name", $op, $text,
809             {position => [0, $word_end]});
810 0         0 $info->{other_ops} = [$pushmark_info];
811             # $info->{other_ops} = [$pushmark_op];
812             }
813 20         50 return $info;
814             } else {
815 0 0       0 $name .= '()' if $op->flags & B::OPf_SPECIAL;
816 0         0 return $self->info_from_string("dq $name", $op, $name)
817             }
818 0         0 Carp::confess("unhandled condition in dq_unop");
819             }
820              
821             sub dquote
822             {
823 0     0 0 0 my($self, $op, $cx) = @_;
824             # FIXME figure out how to use this
825 0         0 my $skipped_ops = [$op->first];
826 0         0 my $kid = $op->first->sibling; # skip ex-stringify, pushmark
827 0 0       0 return $self->deparse($kid, $cx, $op) if $self->{'unquote'};
828             $self->maybe_targmy($kid, $cx,
829 0     0   0 sub {$self->single_delim($kid, "qq", '"',
830             $self->info2str($self->dq($_[1], $op))
831 0         0 )});
832             }
833              
834             sub elem
835             {
836 1     1 0 4 my ($self, $op, $cx, $left, $right, $padname) = @_;
837 1         9 my($array, $idx) = ($op->first, $op->first->sibling);
838              
839 1         8 my $idx_info = $self->elem_or_slice_single_index($idx, $op);
840 1         4 my $opts = {body => [$idx_info]};
841              
842 1 50       7 unless ($array->name eq $padname) { # Maybe this has been fixed
843 0         0 $opts->{other_ops} = [$array];
844 0         0 $array = $array->first; # skip rv2av (or ex-rv2av in _53+)
845             }
846 1         3 my @texts = ();
847 1         8 my $info;
848 1         10 my $array_name=$self->elem_or_slice_array_name($array, $left, $padname, 1);
849 1 50       3 if ($array_name) {
850 1 50       4 if ($array_name !~ /->\z/) {
851 1 50       3 if ($array_name eq '#') {
852 0         0 $array_name = '${#}';
853             } else {
854 1         3 $array_name = '$' . $array_name ;
855             }
856             }
857 1         2 push @texts, $array_name;
858 1 50       3 push @texts, $left if $left;
859 1         3 push @texts, $idx_info->{text}, $right;
860 1         5 return info_from_list($op, $self, \@texts, '', 'elem', $opts)
861             } else {
862             # $x[20][3]{hi} or expr->[20]
863 0         0 my $type;
864 0         0 my $array_info = $self->deparse($array, 24, $op);
865 0         0 push @{$info->{body}}, $array_info;
  0         0  
866 0         0 @texts = ($array_info->{text});
867 0 0       0 if (is_subscriptable($array)) {
868 0         0 push @texts, $left, $idx_info->{text}, $right;
869 0         0 $type = 'elem_no_arrow';
870             } else {
871 0         0 push @texts, '->', $left, $idx_info->{text}, $right;
872 0         0 $type = 'elem_arrow';
873             }
874 0         0 return info_from_list($op, $self, \@texts, '', $type, $opts);
875             }
876 0         0 Carp::confess("unhandled condition in elem");
877             }
878              
879             sub e_anoncode($$)
880             {
881 0     0 0 0 my ($self, $info) = @_;
882 0         0 my $sub_info = $self->deparse_sub($info->{code});
883             return $self->info_from_template('sub anonymous', $sub_info->{op},
884 0         0 'sub %c', [0], [$sub_info]);
885             }
886              
887             # Handle filetest operators -r, stat, etc.
888             sub filetest
889             {
890 8     8 0 17 my($self, $op, $cx, $name) = @_;
891 8 50       46 if (B::class($op) eq "UNOP") {
    0          
892             # Genuine '-X' filetests are exempt from the LLAFR, but not
893             # l?stat()
894 8 50       23 if ($name =~ /^-/) {
895 0         0 my $kid = $self->deparse($op->first, 16, $op);
896 0         0 return $self->info_from_template("filetest $name", $op,
897             "$name %c", undef, [$kid],
898             {maybe_parens => [$self, $cx, 16]});
899             }
900 8         47 return $self->maybe_parens_unop($name, $op->first, $cx, $op);
901             } elsif (B::class($op) =~ /^(SV|PAD)OP$/) {
902             # FIXME redo after maybe_parens_func returns a string.
903 0         0 my @list = $self->maybe_parens_func($name, $self->pp_gv($op, 1), $cx, 16);
904 0         0 return info_from_list($op, $self, \@list, ' ', "filetest list $name", {});
905             } else {
906             # I don't think baseop filetests ever survive ck_filetest, but...
907 0         0 return info_from_text($op, $self, $name, 'unop', {});
908             }
909             }
910              
911             sub func_needs_parens($$$$)
912             {
913 9     9 0 25 my($self, $first_param, $cx, $prec) = @_;
914 9   33     95 return ($prec <= $cx and substr($first_param, 0, 1) ne "(") || $self->{'parens'};
915             }
916              
917             sub givwhen
918             {
919 0     0 0 0 my($self, $op, $cx, $give_when) = @_;
920              
921 0         0 my @arg_spec = ();
922 0         0 my @nodes = ();
923 0         0 my $enterop = $op->first;
924 0         0 my $fmt;
925 0         0 my ($head, $block);
926 0 0       0 if ($enterop->flags & B::OPf_SPECIAL) {
927 0         0 $head = $self->keyword("default");
928 0         0 $fmt = "$give_when ($head)\n\%+%c\n%-}\n";
929 0         0 $block = $self->deparse($enterop->first, 0, $enterop, $op);
930             }
931             else {
932 0         0 my $cond = $enterop->first;
933 0         0 my $cond_node = $self->deparse($cond, 1, $enterop, $op);
934 0         0 push @nodes, $cond_node;
935 0         0 $fmt = "$give_when (%c)\n\%+%c\n%-}\n";
936 0         0 $block = $self->deparse($cond->sibling, 0, $enterop, $op);
937             }
938 0         0 push @nodes, $block;
939              
940 0         0 return $self->info_from_template("{} $give_when",
941             "%c\n\%+%c\n%-}\n", [0, 1],
942             \@nodes);
943             }
944              
945             # Handles the indirect operators, print, say(), sort()
946             sub indirop
947             {
948 8     8 0 21 my($self, $op, $cx, $name) = @_;
949 8         12 my($expr, @exprs);
950 8         39 my $firstkid = my $kid = $op->first->sibling;
951 8         10 my $indir_info;
952 8         12 my $type = $name;
953 8         22 my $first_op = $op->first;
954 8         16 my @skipped_ops = ($first_op);
955 8         11 my @indir = ();
956 8         13 my @args_spec = ();
957 8         15 my $fmt = '';
958              
959 8 50       31 if ($op->flags & OPf_STACKED) {
960 0         0 push @skipped_ops, $kid;
961 0         0 my $indir_op = $kid->first; # skip rv2gv
962 0 0 0     0 if (B::Deparse::is_scope($indir_op)) {
    0          
963 0         0 $indir_info = $self->deparse($indir_op, 0, $op);
964 0 0       0 if ($indir_info->{text} eq '') {
965 0         0 $fmt = '{;}';
966             } else {
967 0         0 $fmt = '{%c}';
968 0         0 push @args_spec, $indir_info;
969             }
970             } elsif ($indir_op->name eq "const" && $indir_op->private & OPpCONST_BARE) {
971 0         0 $fmt = $self->const_sv($indir_op)->PV;
972             } else {
973 0         0 $indir_info = $self->deparse($indir_op, 24, $op);
974 0         0 $fmt = '%c';
975 0         0 push @args_spec, $indir_info;
976             }
977 0         0 $fmt .= ' ';
978 0         0 $kid = $kid->sibling;
979             }
980              
981 8 50 66     55 if ($name eq "sort" && $op->private & (OPpSORT_NUMERIC | OPpSORT_INTEGER)) {
    50 66        
982 0         0 $type = 'sort numeric or integer';
983 0 0       0 $fmt = ($op->private & OPpSORT_DESCEND)
984             ? '{$b <=> $a} ': '{$a <=> $b} ';
985             } elsif ($name eq "sort" && $op->private & OPpSORT_DESCEND) {
986 0         0 $type = 'sort_descend';
987 0         0 $fmt = '{$b cmp $a} ';
988             }
989              
990             # FIXME: turn into a function;
991 8         15 my $prev_expr = $exprs[-1];
992 8         55 for (; !B::Deparse::null($kid); $kid = $kid->sibling) {
993             # This prevents us from using deparse_op_siblings
994 8         12 my $operator_context;
995 8 100 33     56 if (!$fmt && $kid == $firstkid
      66        
      66        
996             && $name eq "sort"
997             && $firstkid->name =~ /^enter(xs)?sub/) {
998 1         2 $operator_context = 16;
999             } else {
1000 7         10 $operator_context = 6;
1001             }
1002 8         24 $expr = $self->deparse($kid, $operator_context, $op);
1003 8 50       18 if (defined $expr) {
1004 8         16 $expr->{prev_expr} = $prev_expr;
1005 8         11 $prev_expr = $expr;
1006 8         104 push @exprs, $expr;
1007             }
1008             }
1009              
1010             # Extend $name possibly by adding "reverse".
1011 8         15 my $name2;
1012 8 50 66     28 if ($name eq "sort" && $op->private & OPpSORT_REVERSE) {
1013 0         0 $name2 = $self->keyword('reverse') . ' ' . $self->keyword('sort');
1014             } else {
1015 8         650 $name2 = $self->keyword($name)
1016             }
1017              
1018 8 50 66     40 if ($name eq "sort" && ($op->private & OPpSORT_INPLACE)) {
1019 0         0 $fmt = "%c = $name2 $fmt %c";
1020             # FIXME: do better with skipped ops
1021 0         0 return $self->info_from_template($name2, $op,
1022             [0, 0], \@exprs, {other_ops => \@skipped_ops});
1023             }
1024              
1025              
1026 8         12 my $node;
1027 8 50 33     71 if ($fmt ne "" && $name eq "sort") {
    100 66        
      66        
      66        
1028             # We don't want to say "sort(f 1, 2, 3)", since perl -w will
1029             # give bareword warnings in that case. Therefore if context
1030             # requires, we'll put parens around the outside "(sort f 1, 2,
1031             # 3)". Unfortunately, we'll currently think the parens are
1032             # necessary more often that they really are, because we don't
1033             # distinguish which side of an assignment we're on.
1034 0         0 $node = $self->info_from_template($name2, $op,
1035             "$name2 %C",
1036             [[0, $#exprs, ', ']],
1037             \@exprs,
1038             {
1039             other_ops => \@skipped_ops,
1040             maybe_parens => {
1041             context => $cx,
1042             precedence => 5}});
1043              
1044             } elsif (!$fmt && $name eq "sort"
1045             && !B::Deparse::null($op->first->sibling)
1046             && $op->first->sibling->name eq 'entersub' ) {
1047             # We cannot say sort foo(bar), as foo will be interpreted as a
1048             # comparison routine. We have to say sort(...) in that case.
1049 1         9 $node = $self->info_from_template("$name2()", $op,
1050             "$name2(%C)",
1051             [[0, $#exprs, ', ']],
1052             \@exprs,
1053             {other_ops => \@skipped_ops});
1054              
1055             } else {
1056 7 50       17 if (@exprs) {
1057 7         9 my $fmt;
1058 7 50       34 if ($self->func_needs_parens($exprs[0]->{text}, $cx, 5)) {
1059 0         0 $fmt = "$name2(%C)"
1060             } else {
1061 7         16 $fmt = "$name2 %C"
1062             }
1063 7         68 $node = $self->info_from_template($name2, $first_op, $fmt,
1064             [[0, $#exprs, ', ']],
1065             \@exprs,
1066             {other_ops => \@skipped_ops,
1067             maybe_parens => [$self, $cx, 5]});
1068              
1069             } else {
1070 0         0 $type="indirect $name2";
1071 0 0       0 $type .= '()' if (7 < $cx); # FIXME - do with format specifier
1072 0         0 $node = $self->info_from_string($first_op, $name2,
1073             {other_ops => \@skipped_ops})
1074             }
1075             }
1076              
1077             # Handle skipped ops
1078 8         23 my @new_ops;
1079 8         20 my $position = [0, length($name2)];
1080 8         13 my $str = $node->{text};
1081 8         20 foreach my $skipped_op (@skipped_ops) {
1082 8         64 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
1083             {position => $position});
1084 8         32 push @new_ops, $new_op;
1085             }
1086 8         16 $node->{other_ops} = \@new_ops;
1087 8         43 return $node;
1088             }
1089              
1090             # The version of null_op_list after 5.22
1091             # Note: this uses "op" not "kid"
1092             sub is_list_newer($$) {
1093 4391     4391 0 6659 my ($self, $op) = @_;
1094 4391         10843 my $kid = $op->first;
1095 4391 100       16846 return 1 if $kid->name eq 'pushmark';
1096 1768   66     56721 return ($kid->name eq 'null'
1097             && $kid->targ == OP_PUSHMARK
1098             && B::Deparse::_op_is_or_was($op, B::Deparse::OP_LIST));
1099             }
1100              
1101              
1102             # The version of null_op_list before 5.22
1103             # Note: this uses "kid", not "op"
1104             sub is_list_older($) {
1105 0     0 0 0 my ($self, $kid) = @_;
1106             # Something may be funky where without the convesion we are getting ""
1107             # as a return
1108 0 0       0 return ($kid->name eq 'pushmark') ? 1 : 0;
1109             }
1110              
1111             # This handle logical ops: "if"/"until", "&&", "and", ...
1112             # The one-line "while"/"until" is handled in pp_leave.
1113             sub logop
1114             {
1115 107     107 0 265 my ($self, $op, $cx, $lowop, $lowprec, $highop,
1116             $highprec, $blockname) = @_;
1117 107         375 my $left = $op->first;
1118 107         482 my $right = $op->first->sibling;
1119 107         180 my ($lhs, $rhs, $type, $opname);
1120 107         159 my $opts = {};
1121 107 50 66     1059 if ($cx < 1 and B::Deparse::is_scope($right) and $blockname
    100 33        
    100 33        
      66        
      66        
      33        
      100        
1122             and $self->{'expand'} < 7) {
1123             # Is this branch used in 5.26 and above?
1124             # ($a) {$b}
1125 0         0 my $if_cond_info = $self->deparse($left, 1, $op);
1126 0         0 my $if_body_info = $self->deparse($right, 0, $op);
1127 0         0 return $self->info_from_template("$blockname () {}", $op,
1128             "$blockname (%c) {\n%+%c\n%-}",
1129             [0, 1],
1130             [$if_cond_info, $if_body_info], $opts);
1131             } elsif ($cx < 1 and $blockname and not $self->{'parens'}
1132             and $self->{'expand'} < 7) { # $b if $a
1133             # Note: order of lhs and rhs is reversed
1134 35         116 $lhs = $self->deparse($right, 1, $op);
1135 35         110 $rhs = $self->deparse($left, 1, $op);
1136 35         68 $opname = $blockname;
1137 35         67 $type = "suffix $opname"
1138             } elsif ($cx > $lowprec and $highop) {
1139             # low-precedence operator like $a && $b
1140 24         69 $lhs = $self->deparse_binop_left($op, $left, $highprec);
1141 24         81 $rhs = $self->deparse_binop_right($op, $right, $highprec);
1142 24         48 $opname = $highop;
1143 24         74 $opts = {maybe_parens => [$self, $cx, $highprec]};
1144             } else {
1145             # high-precedence operator like $a and $b
1146 48         138 $lhs = $self->deparse_binop_left($op, $left, $lowprec);
1147 48         139 $rhs = $self->deparse_binop_right($op, $right, $lowprec);
1148 48         85 $opname = $lowop;
1149 48         163 $opts = {maybe_parens => [$self, $cx, $lowprec]};
1150             }
1151 107   66     379 $type ||= $opname;
1152 107         459 return $self->info_from_template($type, $op, "%c $opname %c",
1153             [0, 1], [$lhs, $rhs], $opts);
1154             }
1155              
1156             # This handle list ops: "open", "pack", "return" ...
1157             sub listop
1158             {
1159 301     301 0 965 my($self, $op, $cx, $name, $kid, $nollafr) = @_;
1160 301         472 my(@exprs, @new_nodes, @skipped_ops);
1161 301   66     851 my $parens = ($cx >= 5) || $self->{'parens'};
1162              
1163 301 100       668 unless ($kid) {
1164 274         988 push @skipped_ops, $op->first;
1165 274         1235 $kid = $op->first->sibling;
1166             }
1167              
1168             # If there are no arguments, add final parentheses (or parenthesize the
1169             # whole thing if the llafr does not apply) to account for cases like
1170             # (return)+1 or setpgrp()+1. When the llafr does not apply, we use a
1171             # precedence of 6 (< comma), as "return, 1" does not need parentheses.
1172 301 100       2041 if (B::Deparse::null $kid) {
1173 24         1024 my $fullname = $self->keyword($name);
1174 24 100       115 my $text = $nollafr
1175             ? $self->maybe_parens($fullname, $cx, 7)
1176             : $fullname . '()' x (7 < $cx);
1177 24         84 return $self->info_from_string("listop $name", $op, $text);
1178             }
1179 277         456 my $first;
1180 277         7388 my $fullname = $self->keyword($name);
1181 277         1776 my $proto = prototype("CORE::$name");
1182 277 100 100     2909 if (
      100        
      100        
1183             ( (defined $proto && $proto =~ /^;?\*/)
1184             || $name eq 'select' # select(F) doesn't have a proto
1185             )
1186             && $kid->name eq "rv2gv"
1187             && !($kid->private & B::OPpLVAL_INTRO)
1188             ) {
1189 74         774 $first = $self->rv2gv_or_string($kid->first, $op);
1190             }
1191             else {
1192 203         704 $first = $self->deparse($kid, 6, $op);
1193             }
1194 277 50 66     957 if ($name eq "chmod" && $first->{text} =~ /^\d+$/) {
1195 0     0   0 my $transform_fn = sub {sprintf("%#o", $self->info2str(shift))};
  0         0  
1196 0         0 $first = $self->info_from_template("chmod octal", undef,
1197             "%F", [[0, $transform_fn]],
1198             [$first], {'relink_children' => [0]});
1199 0         0 push @new_nodes, $first;
1200             }
1201              
1202             # FIXME: fold this into a template
1203             $first->{text} = "+" + $first->{text}
1204 277 50 66     998 if not $parens and not $nollafr and substr($first->{text}, 0, 1) eq "(";
      66        
1205              
1206 277         686 push @exprs, $first;
1207 277         1139 $kid = $kid->sibling;
1208 277 100 100     1721 if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv"
      66        
      100        
1209             && !($kid->private & B::OPpLVAL_INTRO)) {
1210 6         45 $first = $self->rv2gv_or_string($kid->first, $op);
1211 6         12 push @exprs, $first;
1212 6         25 $kid = $kid->sibling;
1213             }
1214              
1215 277         1132 $self->deparse_op_siblings(\@exprs, $kid, $op, 6);
1216              
1217 277 50 66     894 if ($name eq "reverse" && ($op->private & B::OPpREVERSE_INPLACE)) {
1218 0 0       0 my $texts = [$exprs[0->{text}], '=',
1219             $fullname . ($parens ? "($exprs[0]->{text})" : " $exprs[0]->{text}")];
1220 0         0 return info_from_list($op, $self, $texts, ' ', 'listop_reverse', {});
1221             }
1222              
1223 277         491 my $opts = {};
1224 277         572 my $type;
1225             my $fmt;
1226              
1227 277 100 100     1123 if ($name =~ /^(system|exec)$/
      66        
1228             && ($op->flags & B::OPf_STACKED)
1229             && @exprs > 1)
1230             {
1231             # handle the "system(prog a1, a2, ...)" form
1232             # where there is no ', ' between the first two arguments.
1233 4 50 33     19 if ($parens && $nollafr) {
    50          
1234 0         0 $fmt = "($fullname %c %C)";
1235 0         0 $type = "listop ($fullname)";
1236             } elsif ($parens) {
1237 4         19 $fmt = "$fullname(%c %C)";
1238 4         11 $type = "listop $fullname()";
1239             } else {
1240 0         0 $fmt = "$fullname %c %C";
1241 0         0 $type = "listop $fullname";
1242             }
1243 4         17 return $self->info_from_template($type, $op, $fmt,
1244             [0, [1, $#exprs, ', ']], \@exprs);
1245              
1246             }
1247              
1248 273         492 $fmt = "%c %C";
1249 273 50 66     1063 if ($parens && $nollafr) {
    100          
1250             # FIXME: do with parens mechanism
1251 0         0 $fmt = "($fullname %C)";
1252 0         0 $type = "listop ($fullname)";
1253             } elsif ($parens) {
1254 244         471 $fmt = "$fullname(%C)";
1255 244         553 $type = "listop $fullname()";
1256             } else {
1257 29         56 $fmt = "$fullname %C";
1258 29         45 $type = "listop $fullname";
1259             }
1260 273 50       638 $opts->{synthesized_nodes} = \@new_nodes if @new_nodes;
1261 273         1283 my $node = $self->info_from_template($type, $op, $fmt,
1262             [[0, $#exprs, ', ']], \@exprs,
1263             $opts);
1264 273 100       774 if (@skipped_ops) {
1265             # if we have skipped ops like pushmark, we will use $full name
1266             # as the part it represents.
1267             ## FIXME
1268 246         319 my @new_ops;
1269 246         593 my $position = [0, length($fullname)];
1270 246         450 my $str = $node->{text};
1271 246         311 my @skipped_nodes;
1272 246         493 for my $skipped_op (@skipped_ops) {
1273 246         1510 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
1274             {position => $position});
1275 246         770 push @new_ops, $new_op;
1276             }
1277 246         634 $node->{other_ops} = \@new_ops;
1278             }
1279 273         985 return $node;
1280             }
1281              
1282             sub loop_common
1283             {
1284 3     3 0 7 my $self = shift;
1285 3         6 my($op, $cx, $init) = @_;
1286 3         22 my $enter = $op->first;
1287 3         102 my $kid = $enter->sibling;
1288              
1289 3         10 my @skipped_ops = ($enter);
1290             local(@$self{qw'curstash warnings hints hinthash'})
1291 3         72 = @$self{qw'curstash warnings hints hinthash'};
1292              
1293 3         9 my ($body, @body);
1294 3         7 my @nodes = ();
1295 3         7 my ($bare, $cond_info) = (0, undef);
1296 3         8 my $fmt = '';
1297 3         4 my $var_fmt;
1298 3         6 my @args_spec = ();
1299 3         8 my $opts = {};
1300 3         7 my $type = 'loop';
1301              
1302 3 50       18 if ($kid->name eq "lineseq") {
    0          
    0          
    0          
1303             # bare or infinite loop
1304 3         9 $type .= ' while (1)';
1305              
1306 3 100       17 if ($kid->last->name eq "unstack") { # infinite
1307 1         3 $fmt .= 'while (1)';
1308             } else {
1309 2         4 $bare = 1;
1310             }
1311 3         6 $body = $kid;
1312             } elsif ($enter->name eq "enteriter") {
1313             # foreach
1314 0         0 $type .= ' foreach';
1315              
1316 0         0 my $ary = $enter->first->sibling; # first was pushmark
1317 0         0 push @skipped_ops, $enter->first, $ary->first->sibling;
1318 0         0 my ($ary_fmt, $var_info);
1319 0         0 my $var = $ary->sibling;
1320 0 0       0 if (B::Deparse::null $var) {
    0          
    0          
1321 0 0 0     0 if (($enter->flags & B::OPf_SPECIAL) && ($] < 5.009)) {
1322             # thread special var, under 5005threads
1323 0         0 $var_fmt = $self->pp_threadsv($enter, 1);
1324             } else { # regular my() variable
1325 0         0 $var_info = $self->pp_padsv($enter, 1, 1);
1326 0         0 push @nodes, $var_info;
1327 0         0 $var_fmt = '%c';
1328 0         0 push @args_spec, $#nodes;
1329             }
1330             } elsif ($var->name eq "rv2gv") {
1331 0         0 $var_info = $self->pp_rv2sv($var, 1);
1332 0         0 push @nodes, $var_info;
1333 0 0       0 if ($enter->private & B::OPpOUR_INTRO) {
1334             # "our" declarations don't have package names
1335 0     0   0 my $transform_fn = sub {$_[0] =~ s/^(.).*::/$1/};
  0         0  
1336 0         0 $var_fmt = "our %F";
1337 0         0 push @args_spec, [$#nodes, $transform_fn];
1338             } else {
1339 0         0 $var_fmt = '%c';
1340 0         0 push @args_spec, $#nodes;
1341             }
1342             } elsif ($var->name eq "gv") {
1343 0         0 $var_info = $self->deparse($var, 1, $op);
1344 0         0 push @nodes, $var_info;
1345 0         0 $var_fmt = '$%c';
1346 0         0 push @args_spec, $#nodes;
1347             }
1348              
1349 0 0 0     0 if ($ary->name eq 'null' and $enter->private & B::OPpITER_REVERSED) {
    0 0        
1350             # "reverse" was optimised away
1351 0         0 push @nodes, listop($self, $ary->first->sibling, 1, 'reverse');
1352 0         0 $ary_fmt = "%c";
1353 0         0 push @args_spec, $#nodes;
1354             } elsif ($enter->flags & B::OPf_STACKED
1355             and not B::Deparse::null $ary->first->sibling->sibling) {
1356 0         0 push @args_spec, scalar(@nodes), scalar(@nodes+1);
1357 0         0 push @nodes, ($self->deparse($ary->first->sibling, 9, $op),
1358             $self->deparse($ary->first->sibling->sibling, 9, $op));
1359 0         0 $ary_fmt = '(%c .. %c)';
1360              
1361             } else {
1362 0         0 push @nodes, $self->deparse($ary, 1, $op);
1363 0         0 $ary_fmt = "%c";
1364 0         0 push @args_spec, $#nodes;
1365             }
1366              
1367             # skip OP_AND and OP_ITER
1368 0         0 push @skipped_ops, $kid->first, $kid->first->first;
1369 0         0 $body = $kid->first->first->sibling;
1370              
1371 0 0 0     0 if (!B::Deparse::is_state $body->first
1372             and $body->first->name !~ /^(?:stub|leave|scope)$/) {
1373             # FIXME:
1374             # Carp::confess("var ne \$_") unless join('', @var_text) eq '$_';
1375 0         0 push @skipped_ops, $body->first;
1376 0         0 $body = $body->first;
1377 0         0 my $body_info = $self->deparse($body, 2, $op);
1378 0         0 push @nodes, $body_info;
1379 0         0 return $self->info_from_template("foreach", $op,
1380             "$var_fmt foreach ($ary_fmt)",
1381             \@args_spec, \@nodes,
1382             {other_ops => \@skipped_ops});
1383             }
1384 0         0 $fmt = "foreach $var_fmt $ary_fmt";
1385             } elsif ($kid->name eq "null") {
1386             # while/until
1387              
1388 0         0 $kid = $kid->first;
1389 0         0 my $name = {"and" => "while", "or" => "until"}->{$kid->name};
1390 0         0 $type .= " $name";
1391 0         0 $cond_info = $self->deparse($kid->first, 1, $op);
1392 0         0 $fmt = "$name (%c) ";
1393 0         0 push @nodes, $cond_info;
1394 0         0 $body = $kid->first->sibling;
1395 0         0 @args_spec = (0);
1396             } elsif ($kid->name eq "stub") {
1397             # bare and empty
1398 0         0 return info_from_text($op, $self, '{;}', 'empty loop', {});
1399             }
1400              
1401             # If there isn't a continue block, then the next pointer for the loop
1402             # will point to the unstack, which is kid's last child, except
1403             # in a bare loop, when it will point to the leaveloop. When neither of
1404             # these conditions hold, then the second-to-last child is the continue
1405             # block (or the last in a bare loop).
1406 3         11 my $cont_start = $enter->nextop;
1407 3         6 my ($cont, @cont_text, $body_info);
1408 3         5 my @cont = ();
1409 3 50 66     14 if ($$cont_start != $$op && ${$cont_start} != ${$body->last}) {
  1         2  
  1         6  
1410 0         0 $type .= ' continue';
1411              
1412 0 0       0 if ($bare) {
1413 0         0 $cont = $body->last;
1414             } else {
1415 0         0 $cont = $body->first;
1416 0         0 while (!B::Deparse::null($cont->sibling->sibling)) {
1417 0         0 $cont = $cont->sibling;
1418             }
1419             }
1420 0         0 my $state = $body->first;
1421 0         0 my $cuddle = " ";
1422 0         0 my @states;
1423 0         0 for (; $$state != $$cont; $state = $state->sibling) {
1424 0         0 push @states, $state;
1425             }
1426 0         0 $body_info = $self->lineseq(undef, 0, @states);
1427 0 0 0     0 if (defined $cond_info
      0        
1428             and not B::Deparse::is_scope($cont)
1429             and $self->{'expand'} < 3) {
1430 0         0 my $cont_info = $self->deparse($cont, 1, $op);
1431 0 0       0 my $init = defined($init) ? $init : ' ';
1432 0         0 @nodes = ($init, $cond_info, $cont_info);
1433             # @nodes_text = ('for', '(', "$init_text;", $cont_info->{text}, ')');
1434 0         0 $fmt = 'for (%c; %c; %c) ';
1435 0         0 @args_spec = (0, 1, 2);
1436 0         0 $opts->{'omit_next_semicolon'} = 1;
1437             } else {
1438 0         0 my $cont_info = $self->deparse($cont, 0, $op);
1439 0         0 @nodes = ($init, $cont_info);
1440 0         0 @args_spec = (0, 1);
1441 0         0 $opts->{'omit_next_semicolon'} = 1;
1442             @cont_text = ($cuddle, 'continue', "{\n\t",
1443 0         0 $cont_info->{text} , "\n\b}");
1444             }
1445             } else {
1446 3 50       9 return info_from_text($op, $self, '', 'loop_no_body', {})
1447             if !defined $body;
1448 3 50       7 if (defined $init) {
1449 0         0 @nodes = ($init, $cond_info);
1450 0         0 $fmt = 'for (%c; %c;) ';
1451 0         0 @args_spec = (0, 1);
1452             }
1453 3         7 $opts->{'omit_next_semicolon'} = 1;
1454 3         11 $body_info = $self->deparse($body, 0, $op);
1455             }
1456              
1457             # (my $body_text = $body_info->{text}) =~ s/;?$/;\n/;
1458             # my @texts = (@nodes_text, "{\n\t", $body_text, "\b}", @cont_text);
1459              
1460 3         8 push @nodes, $body_info;
1461 3         6 push @args_spec, $#nodes;
1462 3         7 $fmt .= " {\n%+%c%-\n}";
1463 3 50       9 if (@cont_text) {
1464 0         0 push @nodes, @cont_text;
1465 0         0 push @args_spec, $#nodes;
1466 0         0 $type .= ' cont';
1467 0         0 $fmt .= '%c';
1468             }
1469 3         11 return $self->info_from_template($type, $op, $fmt, \@args_spec, \@nodes, $opts)
1470             }
1471              
1472             # loop expressions
1473             sub loopex
1474             {
1475 0     0 0 0 my ($self, $op, $cx, $name) = @_;
1476 0         0 my $opts = {maybe_parens => [$self, $cx, 7]};
1477 0 0       0 if (B::class($op) eq "PVOP") {
    0          
    0          
1478 0         0 return info_from_list($op, $self, [$name, $op->pv], ' ',
1479             "loop $name $op->pv", $opts);
1480             } elsif (B::class($op) eq "OP") {
1481             # no-op
1482 0         0 return info_from_text($op, $self, $name, "loopex $name", $opts);
1483             } elsif (B::class($op) eq "UNOP") {
1484 0         0 (my $kid_info = $self->deparse($op->first, 7)) =~ s/^\cS//;
1485             # last foo() is a syntax error. So we might surround it with parens.
1486             my $transform_fn = sub {
1487 0     0   0 my $text = shift->{text};
1488 0 0       0 $text = "($text)" if $text =~ /^(?!\d)\w/;
1489 0         0 return $text;
1490 0         0 };
1491 0         0 return $self->info_from_template("loop $name", $op, "$name %F",
1492             undef, [$kid_info], $opts);
1493             } else {
1494 0         0 return info_from_text($op, $self, $name, "loop $name", $opts);
1495             }
1496 0         0 Carp::confess("unhandled condition in lopex");
1497             }
1498              
1499             # Logical assignment operations, e.g. ||= &&=, //=
1500             sub logassignop
1501             {
1502 0     0 0 0 my ($self, $op, $cx, $opname) = @_;
1503 0         0 my $left_op = $op->first;
1504              
1505 0         0 my $sassign_op = $left_op->sibling;
1506 0         0 my $right_op = $sassign_op->first; # skip sassign
1507 0         0 my $left_node = $self->deparse($left_op, 7, $op);
1508 0         0 my $right_node = $self->deparse($right_op, 7, $op);
1509 0         0 my $node = $self->info_from_template(
1510             "logical assign $opname", $op,
1511             "%c $opname %c", undef, [$left_node, $right_node],
1512             {other_ops => [$op->first->sibling],
1513             maybe_parens => [$self, $cx, 7]});
1514              
1515             # Handle skipped sassign
1516 0         0 my $str = $node->{text};
1517 0         0 my $position = [length($left_node->{text})+1, length($opname)];
1518 0         0 my $new_op = $self->info_from_string($sassign_op->name, $sassign_op, $str,
1519             {position => $position});
1520 0         0 $node->{other_ops} = [$new_op];
1521 0         0 return $node;
1522              
1523             }
1524              
1525             sub mapop
1526             {
1527 0     0 0 0 my($self, $op, $cx, $name) = @_;
1528 0         0 my $kid = $op->first; # this is the (map|grep)start
1529              
1530 0         0 my @skipped_ops = ($kid, $kid->first);
1531 0         0 $kid = $kid->first->sibling; # skip a pushmark
1532              
1533 0         0 my $code_block = $kid->first; # skip a null
1534              
1535 0         0 my ($code_block_node, @nodes);
1536 0         0 my ($fmt, $first_arg_fmt, $is_block);
1537 0         0 my $type = "map $name";
1538 0         0 my @args_spec = ();
1539              
1540 0 0       0 if (B::Deparse::is_scope $code_block) {
1541 0         0 $code_block_node = $self->deparse($code_block, 0, $op);
1542             my $transform_fn = sub {
1543             # remove first \n in block.
1544 0     0   0 ($_[0]->{text})=~ s/^\n\s*//;
1545 0         0 return $_[0]->{text};
1546 0         0 };
1547 0         0 push @args_spec, [0, $transform_fn];
1548 0         0 $first_arg_fmt = '{ %F }';
1549              
1550             ## Alternate simpler form:
1551             # push @args_spec, 0;
1552             # $first_arg_fmt = '{ %c }';
1553 0         0 $type .= " block";
1554 0         0 $is_block = 1;
1555              
1556             } else {
1557 0         0 $code_block_node = $self->deparse($code_block, 24, $op);
1558 0         0 push @args_spec, 0;
1559 0         0 $first_arg_fmt = '%c';
1560 0         0 $type .= " expr";
1561 0         0 $is_block = 0;
1562             }
1563 0         0 push @nodes, $code_block_node;
1564              
1565              
1566 0         0 push @skipped_ops, $kid;
1567 0         0 $kid = $kid->sibling;
1568 0         0 $self->deparse_op_siblings(\@nodes, $kid, $op, 6);
1569 0         0 push @args_spec, [1, $#nodes, ', '];
1570              
1571 0 0       0 if ($self->func_needs_parens($nodes[1]->{text}, $cx, 5)) {
1572 0         0 $fmt = "$name $first_arg_fmt (%C)";
1573             } else {
1574 0         0 $fmt = "$name $first_arg_fmt %C";
1575             }
1576 0         0 my $node = $self->info_from_template($type, $op, $fmt,
1577             \@args_spec, \@nodes,
1578             {other_ops => \@skipped_ops});
1579              
1580             # Handle skipped ops
1581 0         0 my @new_ops;
1582 0         0 my $str = $node->{text};
1583 0         0 my $position;
1584 0 0       0 if ($is_block) {
1585             # Make the position be the position of the "{".
1586 0         0 $position = [length($name)+1, 1];
1587             } else {
1588             # Make the position be the name portion
1589 0         0 $position = [0, length($name)];
1590             }
1591 0         0 my @skipped_nodes;
1592 0         0 for my $skipped_op (@skipped_ops) {
1593 0         0 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
1594             {position => $position});
1595 0         0 push @new_ops, $new_op;
1596             }
1597 0         0 $node->{other_ops} = \@new_ops;
1598 0         0 return $node;
1599             }
1600              
1601              
1602             # osmic acid -- see osmium tetroxide
1603              
1604             my %matchwords;
1605             map($matchwords{join "", sort split //, $_} = $_, 'cig', 'cog', 'cos', 'cogs',
1606             'cox', 'go', 'is', 'ism', 'iso', 'mig', 'mix', 'osmic', 'ox', 'sic',
1607             'sig', 'six', 'smog', 'so', 'soc', 'sog', 'xi');
1608              
1609             sub matchop
1610             {
1611 6 50   6 0 29 $] < 5.022 ? matchop_older(@_) : matchop_newer(@_);
1612             }
1613              
1614             # matchop for Perl 5.22 and later
1615             sub matchop_newer
1616             {
1617 6     6 0 15 my($self, $op, $cx, $name, $delim) = @_;
1618 6         25 my $kid = $op->first;
1619 6         12 my $info = {};
1620 6         9 my @body = ();
1621 6         11 my ($binop, $var_str, $re_str) = ("", "", "");
1622 6         10 my $var_node;
1623             my $re;
1624 6 100 33     37 if ($op->flags & B::OPf_STACKED) {
    50          
1625 4         7 $binop = 1;
1626 4         12 $var_node = $self->deparse($kid, 20, $op);
1627 4         8 $var_str = $var_node->{text};
1628 4         8 push @body, $var_node;
1629 4         21 $kid = $kid->sibling;
1630             }
1631             # not $name; $name will be 'm' for both match and split
1632             elsif ($op->name eq 'match' and my $targ = $op->targ) {
1633 0         0 $binop = 1;
1634 0         0 $var_str = $self->padname($targ);
1635             }
1636 6         10 my $quote = 1;
1637 6         15 my $pmflags = $op->pmflags;
1638 6         9 my $rhs_bound_to_defsv;
1639 6         9 my ($cv, $bregexp);
1640 6         51 my $have_kid = !B::Deparse::null $kid;
1641             # Check for code blocks first
1642 6 50 66     62 if (not B::Deparse::null my $code_list = $op->code_list) {
    50          
    100          
    50          
1643 0 0       0 $re = $self->code_list($code_list,
1644             $op->name eq 'qr'
1645             ? $self->padval(
1646             $kid->first # ex-list
1647             ->first # pushmark
1648             ->sibling # entersub
1649             ->first # ex-list
1650             ->first # pushmark
1651             ->sibling # srefgen
1652             ->first # ex-list
1653             ->first # anoncode
1654             ->targ
1655             )
1656             : undef);
1657 6         79 } elsif (${$bregexp = $op->pmregexp} && ${$cv = $bregexp->qr_anoncv}) {
  1         24  
1658 0         0 my $patop = $cv->ROOT # leavesub
1659             ->first # qr
1660             ->code_list;# list
1661 0         0 $re = $self->code_list($patop, $cv);
1662             } elsif (!$have_kid) {
1663 1         110 $re_str = B::Deparse::re_uninterp(B::Deparse::escape_str(B::Deparse::re_unback($op->precomp)));
1664             } elsif ($kid->name ne 'regcomp') {
1665 0 0       0 if ($op->name eq 'split') {
1666             # split has other kids, not just regcomp
1667 0         0 $re = re_uninterp(escape_re(re_unback($op->precomp)));
1668             } else {
1669 0         0 carp("found ".$kid->name." where regcomp expected");
1670             }
1671             } else {
1672 5         24 ($re, $quote) = $self->regcomp($kid, 21);
1673 5         11 push @body, $re;
1674 5         9 $re_str = $re->{text};
1675 5         27 my $matchop = $kid->first;
1676 5 50       24 if ($matchop->name eq 'regcrest') {
1677 0         0 $matchop = $matchop->first;
1678             }
1679 5 100 66     49 if ($matchop->name =~ /^(?:match|transr?|subst)\z/
1680             && $matchop->flags & B::OPf_SPECIAL) {
1681 4         9 $rhs_bound_to_defsv = 1;
1682             }
1683             }
1684 6         14 my $flags = '';
1685 6 50       12 $flags .= "c" if $pmflags & B::PMf_CONTINUE;
1686 6         65 $flags .= $self->re_flags($op);
1687 6         22 $flags = join '', sort split //, $flags;
1688 6 50       16 $flags = $matchwords{$flags} if $matchwords{$flags};
1689              
1690 6 50       21 if ($pmflags & B::PMf_ONCE) {
    100          
1691             # only one kind of delimiter works here
1692 0         0 $re_str =~ s/\?/\\?/g;
1693             # explicit 'm' is required
1694 0         0 $re_str = $self->keyword("m") . "?$re_str?";
1695             } elsif ($quote) {
1696 2         7 my $re = $self->single_delim($kid, $name, $delim, $re_str);
1697 2         5 push @body, $re;
1698 2         5 $re_str = $re->{text};
1699             }
1700 6         12 my $opts = {};
1701 6         9 my @texts;
1702 6 100       22 $re_str .= $flags if $quote;
1703 6         9 my $type;
1704 6 100       12 if ($binop) {
1705             # FIXME: use template string
1706 4 50       8 if ($rhs_bound_to_defsv) {
1707 4         24 @texts = ($var_str, ' =~ ($_ =~ ', $re_str, ')');
1708             } else {
1709 0         0 @texts = ($var_str, ' =~ ', $re_str);
1710             }
1711 4         17 $opts->{maybe_parens} = [$self, $cx, 20];
1712 4         8 $type = 'binary match ~=';
1713             } else {
1714 2         6 @texts = ($re_str);
1715 2         4 $type = 'unary ($_) match';
1716             }
1717 6         21 return info_from_list($op, $self, \@texts, '', $type, $opts);
1718             }
1719              
1720             # matchop for Perl before 5.22
1721             sub matchop_older
1722             {
1723 0     0 0 0 my($self, $op, $cx, $name, $delim) = @_;
1724 0         0 my $kid = $op->first;
1725 0         0 my $info = {};
1726 0         0 my @body = ();
1727 0         0 my ($binop, $var, $re_str) = ("", "", "");
1728 0         0 my $re;
1729 0 0       0 if ($op->flags & B::OPf_STACKED) {
1730 0         0 $binop = 1;
1731 0         0 $var = $self->deparse($kid, 20, $op);
1732 0         0 push @body, $var;
1733 0         0 $kid = $kid->sibling;
1734             }
1735 0         0 my $quote = 1;
1736 0         0 my $pmflags = $op->pmflags;
1737 0         0 my $extended = ($pmflags & B::PMf_EXTENDED);
1738 0         0 my $rhs_bound_to_defsv;
1739 0 0       0 if (B::Deparse::null $kid) {
    0          
1740 0         0 my $unbacked = B::Deparse::re_unback($op->precomp);
1741 0 0       0 if ($extended) {
1742 0         0 $re_str = B::Deparse::re_uninterp_extended(B::Deparse::escape_extended_re($unbacked));
1743             } else {
1744 0         0 $re_str = B::Deparse::re_uninterp(B::Deparse::escape_str(B::Deparse::re_unback($op->precomp)));
1745             }
1746             } elsif ($kid->name ne 'regcomp') {
1747 0         0 carp("found ".$kid->name." where regcomp expected");
1748             } else {
1749 0         0 ($re, $quote) = $self->regcomp($kid, 21, $extended);
1750 0         0 push @body, $re;
1751 0         0 $re_str = $re->{text};
1752 0         0 my $matchop = $kid->first;
1753 0 0       0 if ($matchop->name eq 'regcrest') {
1754 0         0 $matchop = $matchop->first;
1755             }
1756 0 0 0     0 if ($matchop->name =~ /^(?:match|transr?|subst)\z/
1757             && $matchop->flags & B::OPf_SPECIAL) {
1758 0         0 $rhs_bound_to_defsv = 1;
1759             }
1760             }
1761 0         0 my $flags = '';
1762 0 0       0 $flags .= "c" if $pmflags & B::PMf_CONTINUE;
1763 0         0 $flags .= $self->re_flags($op);
1764 0         0 $flags = join '', sort split //, $flags;
1765 0 0       0 $flags = $matchwords{$flags} if $matchwords{$flags};
1766              
1767 0 0       0 if ($pmflags & B::PMf_ONCE) { # only one kind of delimiter works here
    0          
1768 0         0 $re_str =~ s/\?/\\?/g;
1769 0         0 $re_str = "?$re_str?";
1770             } elsif ($quote) {
1771 0         0 my $re = $self->single_delim($kid, $name, $delim, $re_str);
1772 0         0 push @body, $re;
1773 0         0 $re_str = $re->{text};
1774             }
1775 0         0 my $opts = {body => \@body};
1776 0         0 my @texts;
1777 0 0       0 $re_str .= $flags if $quote;
1778 0         0 my $type;
1779 0 0       0 if ($binop) {
1780 0 0       0 if ($rhs_bound_to_defsv) {
1781 0         0 @texts = ($var->{text}, ' =~ ', "(", '$_', ' =~ ', $re_str, ')');
1782             } else {
1783 0         0 @texts = ($var->{text}, ' =~ ', $re_str);
1784             }
1785 0         0 $opts->{maybe_parens} = [$self, $cx, 20];
1786 0         0 $type = 'matchop_binop';
1787             } else {
1788 0         0 @texts = ($re_str);
1789 0         0 $type = 'matchop_unnop';
1790             }
1791 0         0 return info_from_list($op, $self, \@texts, '', $type, $opts);
1792             }
1793              
1794             # FIXME: remove this
1795             sub map_texts($$)
1796             {
1797 0     0 0 0 my ($self, $args) = @_;
1798 0         0 my @result ;
1799 0         0 foreach my $expr (@$args) {
1800 0 0 0     0 if (ref $expr eq 'ARRAY' and scalar(@$expr) == 2) {
1801             # First item is hash and second item is op address.
1802 0         0 push @result, [$expr->[0]{text}, $expr->[1]];
1803             } else {
1804 0         0 push @result, [$expr->{text}, $expr->{addr}];
1805             }
1806             }
1807 0         0 return @result;
1808             }
1809              
1810             # FIXME: This is weird. Regularize var_info
1811             sub maybe_local {
1812 19     19 0 56 my($self, $op, $cx, $var_info) = @_;
1813 19         47 $var_info->{parent} = $$op;
1814 19         51 return maybe_local_str($self, $op, $cx, $var_info->{text});
1815             }
1816              
1817             # Handles "our", "local", "my" variables (and possibly no
1818             # declaration of these) in scalar and array contexts.
1819             # The complications include stripping a package name on
1820             # "our" variables, and not including parenthesis when
1821             # not needed, unless there's a setting to always include
1822             # parenthesis.
1823              
1824             sub maybe_local_str
1825             {
1826 1110     1110 0 2383 my($self, $op, $cx, $info) = @_;
1827 1110         1615 my ($text, $is_node);
1828 1110 100 66     2824 if (ref $info && $info->isa("B::DeparseTree::Node")) {
1829 78         189 $text = $self->info2str($info);
1830 78         120 $is_node = 1;
1831             } else {
1832 1032         1453 $text = $info;
1833 1032         1353 $is_node = 0;
1834             }
1835              
1836 1110 100       5747 my $our_intro = ($op->name =~ /^(gv|rv2)[ash]v$/) ? OPpOUR_INTRO : 0;
1837 1110         1765 my ($fmt, $type);
1838 1110 100 100     4459 if ($op->private & (OPpLVAL_INTRO|$our_intro)
1839             and not $self->{'avoid_local'}{$$op}) {
1840 6 100       30 my $our_local = ($op->private & OPpLVAL_INTRO) ? "local" : "our";
1841 6 100       23 if( $our_local eq 'our' ) {
1842             # "our" variables needs to strip off package the prefix
1843              
1844 3 0 0     30 if ( $text !~ /^\W(\w+::)*\w+\z/
      33        
1845             and !utf8::decode($text) || $text !~ /^\W(\w+::)*\w+\z/
1846             ) {
1847 0         0 Carp::confess("Unexpected our text $text");
1848             }
1849              
1850 3 50       11 if ($] >= 5.024) {
1851 3 50       52 if ($type = $self->B::Deparse::find_our_type($text)) {
1852 0         0 $our_local .= ' ' . $type;
1853             }
1854             }
1855              
1856 3 50 66     42 if (!B::Deparse::want_scalar($op)
1857             && $self->func_needs_parens($text, $cx, 16)) {
1858 0         0 $type = "$our_local ()";
1859 0         0 $fmt = "$our_local(%F)";
1860             } else {
1861 3         7 $type = "$our_local";
1862 3         19 $fmt = "$our_local %F";
1863             }
1864             my $transform_fn = sub {
1865 23 100   23   50 my $text = $is_node ? $_[0]->{text} : $_[0];
1866             # Strip possible package prefix
1867 23         139 $text =~ s/(\w+::)+//;
1868 23         90 return $text;
1869 3         21 };
1870             # $info could be either a string or a node, %c covers both.
1871 3         19 return $self->info_from_template($type, $op, $fmt,
1872             [[0, $transform_fn]], [$info]);
1873             }
1874              
1875             # Not an "our" declaration.
1876 3 50       14 if (B::Deparse::want_scalar($op)) {
1877             # $info could be either a string or a node, %c covers both
1878 3         27 return $self->info_from_template("scalar $our_local", $op, "$our_local %c", undef, [$info]);
1879             } else {
1880 0 0 0     0 if (!B::Deparse::want_scalar($op)
1881             && $self->func_needs_parens($text, $cx, 16)) {
1882 0         0 $fmt = "$our_local(%F)";
1883 0         0 $type = "$our_local()";
1884             } else {
1885 0         0 $fmt = "$our_local %F";
1886 0         0 $type = "$our_local";
1887             }
1888 0         0 return $self->info_from_template($type, $op, $fmt, undef, [$info]);
1889             }
1890             } else {
1891 1104 100 66     2875 if (ref $info && $info->isa("B::DeparseTree::Node")) {
1892 73         299 return $info;
1893             } else {
1894 1031         3114 return $self->info_from_string('not local', $op, $text);
1895             }
1896             }
1897             }
1898              
1899             sub maybe_my {
1900 4120     4120 0 6122 my $self = shift;
1901 4120         6767 my($op, $cx, $text, $forbid_parens) = @_;
1902 4120 100 100     18871 if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
1903 23 100       122 my $my_str = $op->private & OPpPAD_STATE
1904             ? $self->keyword("state")
1905             : "my";
1906 23 100 100     175 if ($forbid_parens || B::Deparse::want_scalar($op)) {
1907 16         92 return $self->info_from_string('my', $op, "$my_str $text");
1908             } else {
1909 7         49 return $self->info_from_string('my (maybe with parens)', $op,
1910             "$my_str $text",
1911             {maybe_parens => [$self, $cx, 16]});
1912             }
1913             } else {
1914 4097         9780 return $self->info_from_string('not my', $op, $text);
1915             }
1916             }
1917              
1918             # Possibly add () around $text depending on precedence $prec and
1919             # context $cx. We return a string.
1920             sub maybe_parens($$$$)
1921             {
1922 8     8 0 20 my($self, $text, $cx, $prec) = @_;
1923 8 100       24 if (B::DeparseTree::Node::parens_test($self, $cx, $prec)) {
1924 1         4 $text = "($text)";
1925             # In a unop, let parent reuse our parens; see maybe_parens_unop
1926             # FIXME:
1927 1 50       4 $text = "\cS" . $text if $cx == 16;
1928 1         3 return $text;
1929             } else {
1930 7         15 return $text;
1931             }
1932             }
1933              
1934             # FIXME: go back to default B::Deparse routine and return a string.
1935             sub maybe_parens_func($$$$$)
1936             {
1937 1     1 0 9 my($self, $func, $params, $cx, $prec) = @_;
1938 1 50 33     20 if ($prec <= $cx or substr($params, 0, 1) eq "(" or $self->{'parens'}) {
      33        
1939 0         0 return ($func, '(', $params, ')');
1940             } else {
1941 1         7 return ($func, ' ', $params);
1942             }
1943             }
1944              
1945             # Sort of like maybe_parens in that we may possibly add (). However we take
1946             # an op rather than text, and return a tree node. Also, we get around
1947             # the 'if it looks like a function' rule.
1948             sub maybe_parens_unop($$$$$)
1949             {
1950 260     260 0 408 my $self = shift;
1951 260         572 my($name, $op, $cx, $parent) = @_;
1952 260         721 my $info = $self->deparse($op, 1, $parent);
1953 260         426 my $fmt;
1954 260         653 my @exprs = ($info);
1955 260 50 66     705 if ($name eq "umask" && $info->{text} =~ /^\d+$/) {
1956             # Display umask numbers in octal.
1957             # FIXME: add as a info_node option to run a transformation function
1958             # such as the below
1959 0         0 $info->{text} = sprintf("%#o", $info->{text});
1960 0         0 $exprs[0] = $info;
1961             }
1962 260         6159 $name = $self->keyword($name);
1963 260 100 66     1368 if ($cx > 16 or $self->{'parens'}) {
1964 3         33 return $self->info_from_template("$name()", $op,
1965             "$name(%c)",[0], \@exprs);
1966             } else {
1967             # FIXME: we don't do \cS
1968             # if (substr($text, 0, 1) eq "\cS") {
1969             # # use op's parens
1970             # return info_from_list($op, $self,[$name, substr($text, 1)],
1971             # '', 'maybe_parens_unop_cS', {body => [$info]});
1972             # } else
1973 257 50       954 if (substr($info->{text}, 0, 1) eq "(") {
1974             # avoid looks-like-a-function trap with extra parens
1975             # ('+' can lead to ambiguities)
1976 0         0 return $self->info_from_template("$name(())", $op,
1977             "$name(%c)", [0], \@exprs);
1978             } else {
1979 257         1396 return $self->info_from_template("$name ", $op,
1980             "$name %c", [0], \@exprs);
1981             }
1982             }
1983 0         0 Carp::confess("unhandled condition in maybe_parens_unop");
1984             }
1985              
1986             sub maybe_qualify {
1987 1521     1521 0 3586 my ($self,$prefix,$name) = @_;
1988 1521 100       3435 my $v = ($prefix eq '$#' ? '@' : $prefix) . $name;
1989 1521 100 66     5177 return $name if !$prefix || $name =~ /::/;
1990             return $self->{'curstash'}.'::'. $name
1991             if
1992             $name =~ /^(?!\d)\w/ # alphabetic
1993             && $v !~ /^\$[ab]\z/ # not $a or $b
1994             && !$globalnames{$name} # not a global name
1995             && $self->{hints} & $strict_bits{vars} # strict vars
1996 1520 100 100     25475 && !$self->lex_in_scope($v,1) # no "our"
      100        
      100        
      100        
      66        
1997             or $self->lex_in_scope($v); # conflicts with "my" variable
1998 1513         6393 return $name;
1999             }
2000              
2001             # FIXME: need a way to pass in skipped_ops
2002             sub maybe_targmy
2003             {
2004 159     159 0 485 my($self, $op, $cx, $func, @args) = @_;
2005 159 50       729 if ($op->private & OPpTARGET_MY) {
2006 0         0 my $var = $self->padname($op->targ);
2007 0         0 my $val = $func->($self, $op, 7, @args);
2008 0         0 my @texts = ($var, '=', $val);
2009 0         0 return $self->info_from_template("my", $op,
2010             "%c = %c", [0, 1],
2011             [$var, $val],
2012             {maybe_parens => [$self, $cx, 7]});
2013             } else {
2014 159         529 return $self->$func($op, $cx, @args);
2015             }
2016             }
2017              
2018             sub null_older
2019             {
2020 0     0 0 0 my($self, $op, $cx) = @_;
2021 0         0 my $info;
2022 0 0       0 if (B::class($op) eq "OP") {
    0          
2023 0 0       0 if ($op->targ == B::Deparse::OP_CONST) {
2024             # The Perl source constant value can't be recovered.
2025             # We'll use the 'ex_const' value as a substitute
2026 0         0 return $self->info_from_string('constant unrecoverable', $op, $self->{'ex_const'});
2027             } else {
2028             # FIXME: look over. Is this right?
2029 0         0 return $self->info_from_string('constant ""', $op, '');
2030             }
2031             } elsif (B::class ($op) eq "COP") {
2032 0         0 return $self->cops($op, $cx, $op->name);
2033             }
2034 0         0 my $kid = $op->first;
2035 0 0 0     0 if ($self->is_list_older($kid)) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
2036 0         0 my $node = $self->pp_list($op, $cx);
2037 0         0 $node->update_other_ops($kid);
2038 0         0 return $node;
2039             } elsif ($kid->name eq "enter") {
2040 0         0 return $self->pp_leave($op, $cx);
2041             } elsif ($kid->name eq "leave") {
2042 0         0 return $self->pp_leave($kid, $cx);
2043             } elsif ($kid->name eq "scope") {
2044 0         0 return $self->pp_scope($kid, $cx);
2045             } elsif ($op->targ == B::Deparse::OP_STRINGIFY) {
2046 0         0 return $self->dquote($op, $cx);
2047             } elsif ($op->targ == B::Deparse::OP_GLOB) {
2048 0         0 my @other_ops = ($kid, $kid->first, $kid->first->first);
2049 0         0 my $info = $self->pp_glob(
2050             $kid # entersub
2051             ->first # ex-list
2052             ->first # pushmark
2053             ->sibling, # glob
2054             $cx
2055             );
2056 0         0 push @{$info->{other_ops}}, @other_ops;
  0         0  
2057 0         0 return $info;
2058             } elsif (!B::Deparse::null($kid->sibling) and
2059             $kid->sibling->name eq "readline" and
2060             $kid->sibling->flags & OPf_STACKED) {
2061 0         0 my $lhs = $self->deparse($kid, 7, $op);
2062 0         0 my $rhs = $self->deparse($kid->sibling, 7, $kid);
2063 0         0 return $self->info_from_template("readline = ", $op,
2064             "%c = %c", undef, [$lhs, $rhs],
2065             {maybe_parens => [$self, $cx, 7],
2066             prev_expr => $rhs});
2067             } elsif (!B::Deparse::null($kid->sibling) and
2068             $kid->sibling->name eq "trans" and
2069             $kid->sibling->flags & OPf_STACKED) {
2070 0         0 my $lhs = $self->deparse($kid, 20, $op);
2071 0         0 my $rhs = $self->deparse($kid->sibling, 20, $op);
2072 0         0 return $self->info_from_template("trans =~",$op,
2073             "%c =~ %c", undef, [$lhs, $rhs],
2074             { maybe_parens => [$self, $cx, 7],
2075             prev_expr => $rhs });
2076             } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) {
2077 0         0 my $kid_info = $self->deparse($kid, $cx, $op);
2078 0         0 return $self->info_from_template("do { }", $op,
2079             "do {\n%+%c\n%-}", undef, [$kid_info]);
2080             } elsif (!B::Deparse::null($kid->sibling) and
2081             $kid->sibling->name eq "null" and
2082             B::class($kid->sibling) eq "UNOP" and
2083             $kid->sibling->first->flags & OPf_STACKED and
2084             $kid->sibling->first->name eq "rcatline") {
2085 0         0 my $lhs = $self->deparse($kid, 18, $op);
2086 0         0 my $rhs = $self->deparse($kid->sibling, 18, $op);
2087 0         0 return $self->info_from_template("rcatline =",$op,
2088             "%c = %c", undef, [$lhs, $rhs],
2089             { maybe_parens => [$self, $cx, 20],
2090             prev_expr => $rhs });
2091             } else {
2092 0         0 return $self->deparse($kid, $cx, $op);
2093             }
2094 0         0 Carp::confess("unhandled condition in null");
2095             }
2096              
2097             sub pushmark_position($) {
2098 2627     2627 0 3881 my ($node) = @_;
2099 2627         3446 my $l = undef;
2100 2627 50       5758 if ($node->{parens}) {
    100          
2101 0         0 return [0, 1];
2102             } elsif (exists $node->{fmt}) {
2103             # Match up to %c, %C, or %F after ( or {
2104 672 100       3759 if ($node->{fmt} =~ /^(.*)%[cCF]/) {
2105 627         1745 $l = length($1);
2106             }
2107             } else {
2108             # Match up to first ( or {
2109 1955 100       8360 if ($node->{text} =~ /^(.*)\W/) {
2110 1951         4785 $l = length($1);
2111             }
2112             }
2113 2627 100       4718 if (defined($l)) {
2114 2578 100       4894 $l = $l > 0 ? $l-1 : 0;
2115 2578         6073 return [$l, 1]
2116             }
2117 49         70 return undef;
2118             }
2119              
2120              
2121             # Note 5.26 and up
2122             sub null_newer
2123             {
2124 4392     4392 0 7328 my($self, $op, $cx) = @_;
2125 4392         5036 my $node;
2126 4392 100       33644 if (B::class($op) eq "OP") {
    50          
2127             # If the Perl source constant value can't be recovered.
2128             # We'll use the 'ex_const' value as a substitute
2129 1 50       8 return $self->info_from_string("constant_unrecoverable",$op, $self->{'ex_const'})
2130             if $op->targ == B::Deparse::OP_CONST;
2131 0 0       0 return $self->dquote($op, $cx) if $op->targ == B::Deparse::OP_STRINGIFY;
2132             } elsif (B::class($op) eq "COP") {
2133 0         0 return $self->cops($op, $cx, $op->name);
2134             } else {
2135             # All of these use $kid
2136 4391         14745 my $kid = $op->first;
2137 4391         5800 my $update_node = $kid;
2138 4391 100 66     9060 if ($self->is_list_newer($op)) {
    50 33        
    50 66        
    50 33        
    50 100        
    100 66        
    50 66        
    50 66        
    50 33        
    50 33        
2139 2627         6414 $node = $self->pp_list($op, $cx);
2140             } elsif ($kid->name eq "enter") {
2141 0         0 $node = $self->pp_leave($op, $cx);
2142             } elsif ($kid->name eq "leave") {
2143 0         0 $node = $self->pp_leave($kid, $cx);
2144             } elsif ($kid->name eq "scope") {
2145 0         0 $node = $self->pp_scope($kid, $cx);
2146             } elsif ($op->targ == B::Deparse::OP_STRINGIFY) {
2147             # This case is duplicated the below "else". Can it ever happen?
2148 0         0 $node = $self->dquote($op, $cx);
2149             } elsif ($op->targ == B::Deparse::OP_GLOB) {
2150 4         29 my @other_ops = ($kid, $kid->first, $kid->first->first);
2151 4         44 my $info = $self->pp_glob(
2152             $kid # entersub
2153             ->first # ex-list
2154             ->first # pushmark
2155             ->sibling, # glob
2156             $cx
2157             );
2158             # FIXME: mark text.
2159 4         17 push @{$info->{other_ops}}, @other_ops;
  4         17  
2160 4         15 return $info;
2161             } elsif (!B::Deparse::null($kid->sibling) and
2162             $kid->sibling->name eq "readline" and
2163             $kid->sibling->flags & OPf_STACKED) {
2164 0         0 my $lhs = $self->deparse($kid, 7, $op);
2165 0         0 my $rhs = $self->deparse($kid->sibling, 7, $kid);
2166 0         0 $node = $self->info_from_template("readline = ", $op,
2167             "%c = %c", undef, [$lhs, $rhs],
2168             {maybe_parens => [$self, $cx, 7],
2169             prev_expr => $rhs});
2170             } elsif (!B::Deparse::null($kid->sibling) and
2171             $kid->sibling->name =~ /^transr?\z/ and
2172             $kid->sibling->flags & OPf_STACKED) {
2173 0         0 my $lhs = $self->deparse($kid, 20, $op);
2174 0         0 my $rhs = $self->deparse($kid->sibling, 20, $op);
2175 0         0 $node = $self->info_from_template("trans =~",$op,
2176             "%c =~ %c", undef, [$lhs, $rhs],
2177             { maybe_parens => [$self, $cx, 7],
2178             prev_expr => $rhs });
2179             } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) {
2180 0         0 my $kid_info = $self->deparse($kid, $cx, $op);
2181 0         0 $node = $self->info_from_template("do { }", $op,
2182             "do {\n%+%c\n%-}", undef, [$kid_info]);
2183             } elsif (!B::Deparse::null($kid->sibling) and
2184             $kid->sibling->name eq "null" and
2185             B::class($kid->sibling) eq "UNOP" and
2186             $kid->sibling->first->flags & OPf_STACKED and
2187             $kid->sibling->first->name eq "rcatline") {
2188 0         0 my $lhs = $self->deparse($kid, 18, $op);
2189 0         0 my $rhs = $self->deparse($kid->sibling, 18, $op);
2190 0         0 $node = $self->info_from_template("rcatline =",$op,
2191             "%c = %c", undef, [$lhs, $rhs],
2192             { maybe_parens => [$self, $cx, 20],
2193             prev_expr => $rhs });
2194             } else {
2195 1760         5306 my $node = $self->deparse($kid, $cx, $op);
2196 1760         9247 return $self->info_from_template($op->name, $op,
2197             "%c", undef, [$node]);
2198             }
2199 2627         6009 my $position = pushmark_position($node);
2200 2627 100       4756 if ($position) {
2201             $update_node =
2202             $self->info_from_string($kid->name, $kid,
2203             $node->{text},
2204 2578         15049 {position => $position});
2205             }
2206 2627         8168 $node->update_other_ops($update_node);
2207 2627         6404 return $node;
2208             }
2209 0         0 Carp::confess("unhandled condition in null");
2210             }
2211              
2212             # This is the 5.26 version. It is different from earlier versions.
2213             # Is it compatable/
2214             #
2215             # 'x' is weird when the left arg is a list
2216             sub repeat {
2217 9     9 0 14 my $self = shift;
2218 9         20 my($op, $cx) = @_;
2219 9         27 my $left = $op->first;
2220 9         27 my $right = $op->last;
2221 9         12 my $eq = "";
2222 9         15 my $prec = 19;
2223 9         14 my @skipped_ops = ();
2224 9         11 my $left_fmt;
2225 9         13 my $type = "repeat";
2226 9         12 my @args_spec = ();
2227 9         14 my @exprs = ();
2228 9 50       28 if ($op->flags & OPf_STACKED) {
2229 0         0 $eq = "=";
2230 0         0 $prec = 7;
2231             }
2232              
2233 9 50       53 if (B::Deparse::null($right)) {
2234             # This branch occurs in 5.21.5 and earlier.
2235             # A list repeat; count is inside left-side ex-list
2236 0         0 $type = 'list repeat';
2237              
2238 0         0 my $kid = $left->first->sibling; # skip pushmark
2239 0         0 push @skipped_ops, $left->first, $kid;
2240 0         0 $self->deparse_op_siblings(\@exprs, $kid, $op, 6);
2241 0         0 $left_fmt = '(%C)';
2242 0         0 @args_spec = ([0, $#exprs, ', '], scalar(@exprs));
2243             } else {
2244 9         17 $type = 'repeat';
2245 9         26 my $dolist = $op->private & OPpREPEAT_DOLIST;
2246 9 100       35 push @exprs, $self->deparse_binop_left($op, $left, $dolist ? 1 : $prec);
2247 9         15 $left_fmt = '%c';
2248 9 100       20 if ($dolist) {
2249 1         1 $left_fmt = "(%c)";
2250             }
2251 9         21 @args_spec = (0, 1);
2252             }
2253 9         28 push @exprs, $self->deparse_binop_right($op, $right, $prec);
2254 9         18 my $opname = "x$eq";
2255 9         54 my $node = $self->info_from_template("$type $opname",
2256             $op, "$left_fmt $opname %c",
2257             \@args_spec,
2258             \@exprs,
2259             {maybe_parens => [$self, $cx, $prec],
2260             other_ops => \@skipped_ops});
2261              
2262 9 50       31 if (@skipped_ops) {
2263             # if we have skipped ops like pushmark, we will use the position
2264             # of the "x" as the part it represents.
2265 0         0 my @new_ops;
2266 0         0 my $str = $node->{text};
2267 0         0 my $right_text = "$opname " . $exprs[-1]->{text};
2268 0         0 my $start = rindex($str, $right_text);
2269 0         0 my $position;
2270 0 0       0 if ($start >= 0) {
2271 0         0 $position = [$start, length($opname)];
2272             } else {
2273 0         0 $position = [0, length($str)];
2274             }
2275 0         0 my @skipped_nodes;
2276 0         0 for my $skipped_op (@skipped_ops) {
2277 0         0 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
2278             {position => $position});
2279 0         0 push @new_ops, $new_op;
2280             }
2281 0         0 $node->{other_ops} = \@new_ops;
2282             }
2283              
2284 9         29 return $node;
2285             }
2286              
2287             # Kind of silly, but we prefer, subst regexp flags joined together to
2288             # make words. For example: s/a/b/xo => s/a/b/ox
2289              
2290             # oxime -- any of various compounds obtained chiefly by the action of
2291             # hydroxylamine on aldehydes and ketones and characterized by the
2292             # bivalent grouping C=NOH [Webster's Tenth]
2293              
2294             my %substwords;
2295             map($substwords{join "", sort split //, $_} = $_, 'ego', 'egoism', 'em',
2296             'es', 'ex', 'exes', 'gee', 'go', 'goes', 'ie', 'ism', 'iso', 'me',
2297             'meese', 'meso', 'mig', 'mix', 'os', 'ox', 'oxime', 'see', 'seem',
2298             'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi', 'rogue',
2299             'sir', 'rise', 'smore', 'more', 'seer', 'rome', 'gore', 'grim', 'grime',
2300             'or', 'rose', 'rosie');
2301              
2302             # FIXME 522 and 526 could probably be combined or common parts pulled out.
2303             sub subst_older
2304             {
2305 0     0 0 0 my($self, $op, $cx) = @_;
2306 0         0 my $kid = $op->first;
2307 0         0 my($binop, $var, $re, @other_ops) = ("", "", "", ());
2308 0         0 my ($repl, $repl_info);
2309              
2310 0 0       0 if ($op->flags & OPf_STACKED) {
2311 0         0 $binop = 1;
2312 0         0 $var = $self->deparse($kid, 20, $op);
2313 0         0 $kid = $kid->sibling;
2314             }
2315 0         0 my $flags = "";
2316 0         0 my $pmflags = $op->pmflags;
2317 0 0       0 if (B::Deparse::null($op->pmreplroot)) {
2318 0         0 $repl = $kid;
2319 0         0 $kid = $kid->sibling;
2320             } else {
2321 0         0 push @other_ops, $op->pmreplroot;
2322 0         0 $repl = $op->pmreplroot->first; # skip substcont
2323             }
2324 0         0 while ($repl->name eq "entereval") {
2325 0         0 push @other_ops, $repl;
2326 0         0 $repl = $repl->first;
2327 0         0 $flags .= "e";
2328             }
2329             {
2330 0         0 local $self->{in_subst_repl} = 1;
  0         0  
2331 0 0       0 if ($pmflags & PMf_EVAL) {
2332 0         0 $repl_info = $self->deparse($repl->first, 0, $repl);
2333             } else {
2334 0         0 $repl_info = $self->dq($repl);
2335             }
2336             }
2337 0         0 my $extended = ($pmflags & PMf_EXTENDED);
2338 0 0       0 if (B::Deparse::null $kid) {
2339 0         0 my $unbacked = B::Deparse::re_unback($op->precomp);
2340 0 0       0 if ($extended) {
2341 0         0 $re = B::Deparse::re_uninterp_extended(escape_extended_re($unbacked));
2342             }
2343             else {
2344 0         0 $re = B::Deparse::re_uninterp(B::Deparse::escape_str($unbacked));
2345             }
2346             } else {
2347 0         0 my ($re_info, $junk) = $self->regcomp($kid, 1, $extended);
2348 0         0 $re = $re_info->{text};
2349             }
2350 0 0       0 $flags .= "r" if $pmflags & PMf_NONDESTRUCT;
2351 0 0       0 $flags .= "e" if $pmflags & PMf_EVAL;
2352 0         0 $flags .= $self->re_flags($op);
2353 0         0 $flags = join '', sort split //, $flags;
2354 0 0       0 $flags = $substwords{$flags} if $substwords{$flags};
2355 0         0 my $core_s = $self->keyword("s"); # maybe CORE::s
2356              
2357             # FIXME: we need to attach the $repl_info someplace.
2358 0         0 my $repl_text = $repl_info->{text};
2359 0         0 my $find_replace_re = double_delim($re, $repl_text);
2360 0         0 my $opts = {};
2361 0 0       0 $opts->{other_ops} = \@other_ops if @other_ops;
2362 0 0       0 if ($binop) {
2363 0         0 return $self->info_from_template("=~ s///", $op,
2364             "%c =~ ${core_s}%c$flags",
2365             undef,
2366             [$var, $find_replace_re],
2367             {maybe_parens => [$self, $cx, 20]});
2368             } else {
2369 0         0 return $self->info_from_string("s///", $op, "${core_s}${find_replace_re}$flags");
2370             }
2371 0         0 Carp::confess("unhandled condition in pp_subst");
2372             }
2373              
2374             sub slice
2375             {
2376 2     2 0 6 my ($self, $op, $cx, $left, $right, $regname, $padname) = @_;
2377 2         4 my $last;
2378 2         3 my(@elems, $kid, $array);
2379 2 50       11 if (B::class($op) eq "LISTOP") {
2380 2         9 $last = $op->last;
2381             } else {
2382             # ex-hslice inside delete()
2383 0         0 for ($kid = $op->first; !B::Deparse::null $kid->sibling; $kid = $kid->sibling) {
2384 0         0 $last = $kid;
2385             }
2386             }
2387 2         4 $array = $last;
2388 2 50 33     27 $array = $array->first
2389             if $array->name eq $regname or $array->name eq "null";
2390 2         9 my $array_info = $self->elem_or_slice_array_name($array, $left, $padname, 0);
2391 2         13 $kid = $op->first->sibling; # skip pushmark
2392              
2393 2 50       9 if ($kid->name eq "list") {
2394             # FIXME:
2395             # skip list, pushmark
2396 0         0 $kid = $kid->first->sibling;
2397 0         0 for (; !B::Deparse::null $kid; $kid = $kid->sibling) {
2398 0         0 push @elems, $self->deparse($kid, 6, $op);
2399             }
2400             } else {
2401 2         6 @elems = ($self->elem_or_slice_single_index($kid, $op));
2402             }
2403 2         6 my $lead = '@';
2404 2 50       16 $lead = '%' if $op->name =~ /^kv/i;
2405 2         6 my ($fmt, $args_spec);
2406 2         0 my (@texts, $type);
2407 2 50       7 if ($array_info) {
2408 2         5 unshift @elems, $array_info;
2409 2         5 $fmt = "${lead}%c$left%C$right";
2410 2         18 $args_spec = [0, [1, $#elems, ', ']];
2411 2         8 $type = "$lead$left .. $right";
2412             } else {
2413 0         0 $fmt = "${lead}$left%C$right";
2414 0         0 $args_spec = [0, $#elems, ', '];
2415 0         0 $type = "${lead}$left .. $right";
2416             }
2417 2         9 return $self->info_from_template($type, $op, $fmt, $args_spec,
2418             \@elems),
2419             }
2420              
2421             sub subst_newer
2422             {
2423 18     18 0 37 my($self, $op, $cx) = @_;
2424 18         57 my $kid = $op->first;
2425 18         42 my($binop, $var, $re, @other_ops) = ("", "", "", ());
2426 18         31 my ($repl, $repl_info);
2427              
2428 18 50       84 if ($op->flags & OPf_STACKED) {
    50          
2429 0         0 $binop = 1;
2430 0         0 $var = $self->deparse($kid, 20, $op);
2431 0         0 $kid = $kid->sibling;
2432             }
2433             elsif (my $targ = $op->targ) {
2434 0         0 $binop = 1;
2435 0         0 $var = $self->padname($targ);
2436             }
2437 18         30 my $flags = "";
2438 18         43 my $pmflags = $op->pmflags;
2439 18 100       125 if (B::Deparse::null($op->pmreplroot)) {
2440 14         21 $repl = $kid;
2441 14         43 $kid = $kid->sibling;
2442             } else {
2443 4         22 push @other_ops, $op->pmreplroot;
2444 4         17 $repl = $op->pmreplroot->first; # skip substcont
2445             }
2446 18         67 while ($repl->name eq "entereval") {
2447 0         0 push @other_ops, $repl;
2448 0         0 $repl = $repl->first;
2449 0         0 $flags .= "e";
2450             }
2451             {
2452 18         29 local $self->{in_subst_repl} = 1;
  18         41  
2453 18 100       33 if ($pmflags & PMf_EVAL) {
2454 4         32 $repl_info = $self->deparse($repl->first, 0, $repl);
2455             } else {
2456 14         39 $repl_info = $self->dq($repl);
2457             }
2458             }
2459 18 50       212 if (not B::Deparse::null my $code_list = $op->code_list) {
    50          
2460 0         0 $re = $self->code_list($code_list);
2461             } elsif (B::Deparse::null $kid) {
2462 18         1500 $re = B::Deparse::re_uninterp(escape_re(B::Deparse::re_unback($op->precomp)));
2463             } else {
2464 0         0 my ($re_info, $junk) = $self->regcomp($kid, 1);
2465 0         0 $re = $re_info->{text};
2466             }
2467 18 100       72 $flags .= "r" if $pmflags & PMf_NONDESTRUCT;
2468 18 100       36 $flags .= "e" if $pmflags & PMf_EVAL;
2469 18         165 $flags .= $self->re_flags($op);
2470 18         62 $flags = join '', sort split //, $flags;
2471 18 50       50 $flags = $substwords{$flags} if $substwords{$flags};
2472 18         2241 my $core_s = $self->keyword("s"); # maybe CORE::s
2473              
2474             # FIXME: we need to attach the $repl_info someplace.
2475 18         43 my $repl_text = $repl_info->{text};
2476 18 100       41 my $opts->{other_ops} = \@other_ops if @other_ops;
2477 18         121 my $find_replace_re = double_delim($re, $repl_text);
2478              
2479 18 50       40 if ($binop) {
2480 0         0 return $self->info_from_template("=~ s///", $op,
2481             "%c =~ ${core_s}%c$flags",
2482             undef,
2483             [$var, $find_replace_re],
2484             {maybe_parens => [$self, $cx, 20]});
2485             } else {
2486 18         68 return $self->info_from_string("s///", $op, "${core_s}${find_replace_re}$flags");
2487             }
2488 0         0 Carp::confess("unhandled condition in pp_subst");
2489             }
2490              
2491             # This handles the category of unary operators, e.g. alarm(), caller(),
2492             # close()..
2493             sub unop
2494             {
2495 291     291 0 745 my($self, $op, $cx, $name, $nollafr) = @_;
2496 291         427 my $kid;
2497 291 100       1070 if ($op->flags & B::OPf_KIDS) {
2498 233         709 $kid = $op->first;
2499 233 50       604 if (not $name) {
2500             # this deals with 'boolkeys' right now
2501 0         0 return $self->deparse($kid, $cx, $op);
2502             }
2503 233         383 my $builtinname = $name;
2504 233 50       622 $builtinname =~ /^CORE::/ or $builtinname = "CORE::$name";
2505 233 100 100     4843 if (defined prototype($builtinname)
      100        
      66        
2506             && $builtinname ne 'CORE::readline'
2507             && prototype($builtinname) =~ /^;?\*/
2508             && $kid->name eq "rv2gv") {
2509 24         83 $kid = $kid->first;
2510             }
2511              
2512 233 100       550 if ($nollafr) {
2513 1         5 $kid = $self->deparse($kid, 16, $op);
2514 1         3 my $opts = {
2515             maybe_parens => [$self, $cx, 16],
2516             };
2517 1         18 my $fullname = $self->keyword($name);
2518 1         6 return $self->info_from_template("unary operator $name noallafr", $op,
2519             "$fullname %c", undef, [$kid], $opts);
2520             }
2521 232         806 return $self->maybe_parens_unop($name, $kid, $cx, $op);
2522             } else {
2523 58         233 my $opts = {maybe_parens => [$self, $cx, 16]};
2524 58         3818 my $fullname = ($self->keyword($name));
2525 58         186 my $fmt = "$fullname";
2526 58 100       252 $fmt .= '()' if $op->flags & B::OPf_SPECIAL;
2527 58         309 return $self->info_from_template("unary operator $name", $op, $fmt,
2528             undef, [], $opts);
2529             }
2530             }
2531              
2532             # This handles category of symbolic prefix and postfix unary operators,
2533             # e.g $x++, -r, +$x.
2534             sub pfixop
2535             {
2536 6     6 0 12 my $self = shift;
2537 6         20 my($op, $cx, $operator, $prec, $flags) = (@_, 0);
2538 6         30 my $operand = $self->deparse($op->first, $prec, $op);
2539 6         21 my ($type, $fmt);
2540 6         0 my @nodes;
2541 6 50 66     23 if ($flags & POSTFIX) {
    50          
2542 0         0 @nodes = ($operand, $operator);
2543 0         0 $type = "prefix $operator";
2544 0         0 $fmt = "%c%c";
2545             } elsif ($operator eq '-' && $operand->{text} =~ /^[a-zA-Z](?!\w)/) {
2546             # Add () around operator to disambiguate with filetest operator
2547 0         0 @nodes = ($operator, $operand);
2548 0         0 $type = "prefix non-filetest $operator";
2549 0         0 $fmt = "%c(%c)";
2550             } else {
2551 6         15 @nodes = ($operator, $operand);
2552 6         12 $type = "postfix $operator";
2553 6         12 $fmt = "%c%c";
2554             }
2555              
2556 6         30 return $self->info_from_template($type, $op, $fmt, [0, 1],
2557             \@nodes,
2558             {maybe_parens => [$self, $cx, $prec]}) ;
2559             }
2560              
2561             # Produce an node for a range (".." or "..." op)
2562             sub range {
2563 0     0 0 0 my $self = shift;
2564 0         0 my ($op, $cx, $type) = @_;
2565 0         0 my $left = $op->first;
2566 0         0 my $right = $left->sibling;
2567 0         0 $left = $self->deparse($left, 9, $op);
2568 0         0 $right = $self->deparse($right, 9, $op);
2569 0         0 return $self->info_from_template("range $type", $op, "%c${type}%c",
2570             undef, [$left, $right],
2571             {maybe_parens => [$self, $cx, 9]});
2572             }
2573              
2574             sub rv2x
2575             {
2576 78     78 0 181 my($self, $op, $cx, $type) = @_;
2577 78 50 33     733 if (B::class($op) eq 'NULL' || !$op->can("first")) {
2578 0         0 carp("Unexpected op in pp_rv2x");
2579 0         0 return info_from_text($op, $self, 'XXX', 'bad_rv2x', {});
2580             }
2581 78         164 my ($info, $kid_info);
2582 78         259 my $kid = $op->first;
2583 78         229 $kid_info = $self->deparse($kid, 0, $op);
2584 78 50       351 if ($kid->name eq "gv") {
    0          
2585 78     878   459 my $transform_fn = sub {$self->stash_variable($type, $self->info2str(shift), $cx)};
  878         1995  
2586 78         462 return $self->info_from_template("rv2x $type", undef, "%F", [[0, $transform_fn]], [$kid_info])
2587             } elsif (B::Deparse::is_scalar $kid) {
2588 0         0 my $str = $self->info2str($kid_info);
2589 0         0 my $fmt = '%c';
2590 0         0 my @args_spec = (0);
2591 0 0       0 if ($str =~ /^\$([^\w\d])\z/) {
2592             # "$$+" isn't a legal way to write the scalar dereference
2593             # of $+, since the lexer can't tell you aren't trying to
2594             # do something like "$$ + 1" to get one more than your
2595             # PID. Either "${$+}" or "$${+}" are workable
2596             # disambiguations, but if the programmer did the former,
2597             # they'd be in the "else" clause below rather than here.
2598             # It's not clear if this should somehow be unified with
2599             # the code in dq and re_dq that also adds lexer
2600             # disambiguation braces.
2601 0     0   0 my $transform = sub { $_[0] =~ /^\$([^\w\d])\z/; '$' . "{$1}"};
  0         0  
  0         0  
2602 0         0 $fmt = '%F';
2603 0         0 @args_spec = (0, $transform);
2604             }
2605 0         0 return $self->info_from_template("scalar $str", $op, $fmt, \@args_spec, {})
2606             } else {
2607 0         0 my $str = "$type" . '{}';
2608 0         0 return info_from_text($op, $self, $str, $str, {other_ops => [$kid_info]});
2609             }
2610 0         0 Carp::confess("unhandled condition in rv2x");
2611             }
2612              
2613             sub scopeop
2614             {
2615 7     7 0 16 my($real_block, $self, $op, $cx) = @_;
2616 7         14 my $kid;
2617             my @kids;
2618              
2619             local(@$self{qw'curstash warnings hints hinthash'})
2620 7 100       31 = @$self{qw'curstash warnings hints hinthash'} if $real_block;
2621 7 100       16 if ($real_block) {
2622 4         16 $kid = $op->first->sibling; # skip enter
2623 4 50       47 if (B::Deparse::is_miniwhile($kid)) {
2624 0         0 my $top = $kid->first;
2625 0         0 my $name = $top->name;
2626 0 0       0 if ($name eq "and") {
    0          
2627 0         0 $name = $self->keyword("while");
2628             } elsif ($name eq "or") {
2629 0         0 $name = $self->keyword("until");
2630             } else { # no conditional -> while 1 or until 0
2631 0         0 my $body = $self->deparse($top->first, 1, $top);
2632 0         0 return info_from_list $op, $self, [$body, 'while', '1'],
2633             ' ', "$name 1", {};
2634             }
2635 0         0 my $cond = $top->first;
2636 0         0 my $skipped_ops = [$cond->sibling];
2637 0         0 my $body = $cond->sibling->first; # skip lineseq
2638 0         0 my $cond_info = $self->deparse($cond, 1, $top);
2639 0         0 my $body_info = $self->deparse($body, 1, $top);
2640 0         0 return info_from_list($op, $self,
2641             [$body_info, $name, $cond_info], ' ',
2642             "$name",
2643             {other_ops => $skipped_ops});
2644             }
2645             } else {
2646 3         12 $kid = $op->first;
2647             }
2648 7         48 for (; !B::Deparse::null($kid); $kid = $kid->sibling) {
2649 17         103 push @kids, $kid;
2650             }
2651 7 50       18 if ($cx > 0) {
2652             # inside an expression, (a do {} while for lineseq)
2653 0         0 my $body = $self->lineseq($op, 0, @kids);
2654 0         0 my $text;
2655 0 0       0 if (B::Deparse::is_lexical_subs(@kids)) {
2656 0         0 return $self->info_from_template("scoped do", $op,
2657             'do {\n%+%c\n%-}',
2658             [0], [$body]);
2659              
2660             } else {
2661 0         0 return $self->info_from_template("scoped expression", $op,
2662             '%c',[0], [$body]);
2663             }
2664             } else {
2665 7         24 return $self->lineseq($op, $cx, @kids);
2666             }
2667             }
2668              
2669             sub single_delim($$$$$) {
2670 25     25 0 70 my($self, $op, $q, $default, $str) = @_;
2671              
2672 25 50 33     245 return $self->info_from_template("string $default .. $default (default)", $op,
2673             "$default%c$default", [0],
2674             [$str])
2675             if $default and index($str, $default) == -1;
2676 0           my $coreq = $self->keyword($q); # maybe CORE::q
2677 0 0         if ($q ne 'qr') {
2678 0           (my $succeed, $str) = balanced_delim($str);
2679 0 0         return $self->info_from_string("string $q", $op, "$coreq$str")
2680             if $succeed;
2681             }
2682 0           for my $delim ('/', '"', '#') {
2683 0 0         $self->info_from_string("string $q $delim$delim", $op, "qr$delim$str$delim")
2684             if index($str, $delim) == -1;
2685             }
2686 0 0         if ($default) {
2687             my $transform_fn = sub {
2688 0     0     s/$_[0]/\\$_[0]/g;
2689 0           return $_[0];
2690 0           };
2691              
2692 0           return $self->info_from_template("string $q $default$default",
2693             $op, "$default%F$default",
2694             [[0, $transform_fn]], [$str]);
2695             } else {
2696             my $transform_fn = sub {
2697 0     0     $_[0] =~ s[/][\\/]g;
2698 0           return $_[0];
2699 0           };
2700 0           return $self->info_from_template("string $q //",
2701             $op, "$coreq/%F/",
2702             [[0, $transform_fn]], [$str]);
2703             }
2704             }
2705              
2706             # Demo code
2707             unless(caller) {
2708             ;
2709             }
2710              
2711             1;