File Coverage

lib/B/DeparseTree/PPfns.pm
Criterion Covered Total %
statement 803 1650 48.6
branch 301 748 40.2
condition 203 427 47.5
subroutine 68 99 68.6
pod 0 70 0.0
total 1375 2994 45.9


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 8     8   48 use strict; use warnings;
  8     8   17  
  8         223  
  8         31  
  8         157  
  8         291  
16              
17             package B::DeparseTree::PPfns;
18 8     8   34 use Carp;
  8         13  
  8         457  
19 8         404 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 8     8   42 );
  8         12  
30              
31 8     8   35 use B::Deparse;
  8         10  
  8         129  
32 8     8   27 use B::DeparseTree::OPflags;
  8         47  
  8         458  
33              
34             # Copied from B/const-xs.inc. Perl 5.16 doesn't have this
35 8     8   37 use constant SVpad_STATE => 11;
  8         11  
  8         670  
36 8     8   43 use constant SVpad_TYPED => 8;
  8         13  
  8         715  
37              
38             # FIXME: DRY $is_cperl
39             # Version specific modification are next...
40 8     8   44 use Config;
  8         14  
  8         670  
41             my $is_cperl = $Config::Config{usecperl};
42              
43             # Copy unchanged functions from B::Deparse
44             *balanced_delim = *B::Deparse::balanced_delim;
45             *double_delim = *B::Deparse::double_delim;
46             *escape_extended_re = *B::Deparse::escape_extended_re;
47              
48 8     8   42 use B::DeparseTree::SyntaxTree;
  8         13  
  8         1535  
49              
50             our($VERSION, @EXPORT, @ISA);
51             $VERSION = '3.2.0';
52             @ISA = qw(Exporter);
53             @EXPORT = qw(
54             %strict_bits
55             ambient_pragmas
56             anon_hash_or_list
57             baseop
58             binop
59             code_list
60             concat
61             cops
62             dedup_func_parens
63             dedup_parens_func
64             deparse_binop_left
65             deparse_binop_right
66             deparse_format
67             deparse_op_siblings
68             double_delim
69             dq
70             dq_unop
71             dquote
72             e_anoncode
73             e_method
74             elem
75             filetest
76             for_loop
77             func_needs_parens
78             givwhen
79             indirop
80             is_lexical_subs
81             is_list_newer
82             is_list_older
83             list_const
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             _method
101             null_newer
102             null_older
103             pfixop
104             pp_padsv
105             range
106             repeat
107             rv2x
108             scopeop
109             single_delim
110             slice
111             split
112             stringify_newer
113             stringify_older
114             subst_newer
115             subst_older
116             unop
117             );
118              
119              
120             # The BEGIN {} is used here because otherwise this code isn't executed
121             # when you run B::Deparse on itself.
122             my %globalnames;
123 8     8   525 BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
124             "ENV", "ARGV", "ARGVOUT", "_"); }
125              
126             BEGIN {
127             # List version-specific constants here.
128             # Easiest way to keep this code portable between version looks to
129             # be to fake up a dummy constant that will never actually be true.
130 8     8   39 foreach (qw(
131             CVf_LOCKED
132             OPpCONST_ARYBASE
133             OPpCONST_NOVER
134             OPpEVAL_BYTES
135             OPpITER_REVERSED
136             OPpOUR_INTRO
137             OPpPAD_STATE
138             OPpREVERSE_INPLACE
139             OPpSORT_DESCEND
140             OPpSORT_INPLACE
141             OPpTARGET_MY
142             OPpSUBSTR_REPL_FIRST
143             PMf_EVAL PMf_EXTENDED
144             PMf_NONDESTRUCT
145             PMf_SKIPWHITE
146             RXf_PMf_CHARSET
147             RXf_PMf_KEEPCOPY
148             RXf_SKIPWHITE
149             )) {
150 152         206 eval { import B $_ };
  152         7623  
151 8     8   39 no strict 'refs';
  8         12  
  8         495  
152 152 100       222 *{$_} = sub () {0} unless *{$_}{CODE};
  24         64  
  152         1264  
153             }
154             }
155              
156             my %strict_bits = do {
157             local $^H;
158             map +($_ => strict::bits($_)), qw/refs subs vars/
159             };
160              
161 8     8   28 BEGIN { for (qw[ pushmark ]) {
162 8         674 eval "sub OP_\U$_ () { " . opnumber($_) . "}"
163             }}
164              
165             {
166             # Mask out the bits that L uses
167             my $WARN_MASK;
168             BEGIN {
169 8     8   9433 $WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all};
170             }
171             sub WARN_MASK () {
172 200     200 0 471 return $WARN_MASK;
173             }
174             }
175              
176             my(%left, %right);
177              
178             sub ambient_pragmas {
179 61     61 0 85283 my $self = shift;
180 61         204 my ($arybase, $hint_bits, $warning_bits, $hinthash) = (0, 0);
181              
182 61         219 while (@_ > 1) {
183 183         224 my $name = shift();
184 183         220 my $val = shift();
185              
186 183 50 33     1202 if ($name eq 'strict') {
    50 33        
    50          
    50          
    50          
    100          
    100          
    50          
187 0         0 require strict;
188              
189 0 0       0 if ($val eq 'none') {
190 0         0 $hint_bits &= $strict_bits{$_} for qw/refs subs vars/;
191 0         0 next();
192             }
193              
194 0         0 my @names;
195 0 0       0 if ($val eq "all") {
    0          
196 0         0 @names = qw/refs subs vars/;
197             }
198             elsif (ref $val) {
199 0         0 @names = @$val;
200             }
201             else {
202 0         0 @names = split' ', $val;
203             }
204 0         0 $hint_bits |= $strict_bits{$_} for @names;
205             }
206              
207             elsif ($name eq '$[') {
208 0         0 if (OPpCONST_ARYBASE) {
209             $arybase = $val;
210             } else {
211 0 0       0 croak "\$[ can't be non-zero on this perl" unless $val == 0;
212             }
213             }
214              
215             elsif ($name eq 'integer'
216             || $name eq 'bytes'
217             || $name eq 'utf8') {
218 0         0 require "$name.pm";
219 0 0       0 if ($val) {
220 0         0 $hint_bits |= ${$::{"${name}::"}{"hint_bits"}};
  0         0  
221             }
222             else {
223 0         0 $hint_bits &= ~${$::{"${name}::"}{"hint_bits"}};
  0         0  
224             }
225             }
226              
227             elsif ($name eq 're') {
228 0         0 require re;
229 0 0       0 if ($val eq 'none') {
230 0         0 $hint_bits &= ~re::bits(qw/taint eval/);
231 0         0 next();
232             }
233              
234 0         0 my @names;
235 0 0       0 if ($val eq 'all') {
    0          
236 0         0 @names = qw/taint eval/;
237             }
238             elsif (ref $val) {
239 0         0 @names = @$val;
240             }
241             else {
242 0         0 @names = split' ',$val;
243             }
244 0         0 $hint_bits |= re::bits(@names);
245             }
246              
247             elsif ($name eq 'warnings') {
248 0 0       0 if ($val eq 'none') {
249 0         0 $warning_bits = $warnings::NONE;
250 0         0 next();
251             }
252              
253 0         0 my @names;
254 0 0       0 if (ref $val) {
255 0         0 @names = @$val;
256             }
257             else {
258 0         0 @names = split/\s+/, $val;
259             }
260              
261 0 0       0 $warning_bits = $warnings::NONE if !defined ($warning_bits);
262 0         0 $warning_bits |= warnings::bits(@names);
263             }
264              
265             elsif ($name eq 'warning_bits') {
266 61         140 $warning_bits = $val;
267             }
268              
269             elsif ($name eq 'hint_bits') {
270 61         173 $hint_bits = $val;
271             }
272              
273             elsif ($name eq '%^H') {
274 61         140 $hinthash = $val;
275             }
276              
277             else {
278 0         0 croak "Unknown pragma type: $name";
279             }
280             }
281 61 50       145 if (@_) {
282 0         0 croak "The ambient_pragmas method expects an even number of args";
283             }
284              
285 61         130 $self->{'ambient_arybase'} = $arybase;
286 61         153 $self->{'ambient_warnings'} = $warning_bits;
287 61         90 $self->{'ambient_hints'} = $hint_bits;
288 61         884 $self->{'ambient_hinthash'} = $hinthash;
289             }
290              
291             sub anon_hash_or_list($$$)
292             {
293 0     0 0 0 my ($self, $op, $cx) = @_;
294 0         0 my $name = $op->name;
295 0         0 my($pre, $post) = @{{"anonlist" => ["[","]"],
296 0         0 "anonhash" => ["{","}"]}->{$name}};
297 0         0 my($expr, @exprs);
298 0         0 my $first_op = $op->first;
299 0         0 $op = $first_op->sibling; # skip pushmark
300 0         0 for (; !B::Deparse::null($op); $op = $op->sibling) {
301 0         0 $expr = $self->deparse($op, 6, $op);
302 0         0 push @exprs, $expr;
303             }
304             # if ($pre eq "{" and $cx < 1) {
305             # # Disambiguate that it's not a block
306             # $pre = "+{";
307             # }
308              
309 0         0 my $node = $self->info_from_template("$name $pre $post", $op,
310             "$pre%C$post",
311             [[0, $#exprs, ', ']], \@exprs);
312              
313             # Set the skipped op as the opener of the list.
314 0         0 my $position = [0, 1];
315             my $first_node = $self->info_from_string($first_op->name, $first_op,
316             $node->{text},
317 0         0 {position => $position});
318 0         0 $node->update_other_ops($first_node);
319 0         0 return $node;
320              
321             }
322              
323             sub assoc_class {
324 4381     4381 0 5464 my $op = shift;
325 4381         13019 my $name = $op->name;
326 4381 100 100     9145 if ($name eq "concat" and $op->first->name eq "concat") {
327             # avoid spurious '=' -- see comment in pp_concat
328 4         15 return "concat";
329             }
330 4377 100 66     24750 if ($name eq "null" and B::class($op) eq "UNOP"
      100        
      66        
331             and $op->first->name =~ /^(and|x?or)$/
332             and B::Deparse::null $op->first->sibling)
333             {
334             # Like all conditional constructs, OP_ANDs and OP_ORs are topped
335             # with a null that's used as the common end point of the two
336             # flows of control. For precedence purposes, ignore it.
337             # (COND_EXPRs have these too, but we don't bother with
338             # their associativity).
339 26         133 return assoc_class($op->first);
340             }
341 4351 100       26091 return $name . ($op->flags & B::OPf_STACKED ? "=" : "");
342             }
343              
344             # routines implementing classes of ops
345              
346             sub baseop
347             {
348 48     48 0 119 my($self, $op, $cx, $name) = @_;
349 48         1712 return $self->info_from_string("baseop $name", $op, $self->keyword($name));
350             }
351              
352             # Handle binary operators like +, and assignment
353             sub binop
354             {
355              
356 1378     1378 0 3699 my ($self, $op, $cx, $opname, $prec) = @_;
357 1378         3015 my ($flags, $type) = (0, '');
358 1378 100       3255 if (scalar(@_) > 5) {
359 1348         2010 $flags = $_[5];
360 1348 100       2909 $type = $_[6] if (scalar(@_) > 6);
361             }
362 1378         4964 my $left = $op->first;
363 1378         4526 my $right = $op->last;
364 1378         2337 my $eq = "";
365 1378 100 100     7786 if ($op->flags & B::OPf_STACKED && $flags & B::Deparse::ASSIGN) {
366 5         8 $eq = "=";
367 5         7 $prec = 7;
368             }
369 1378 100       3463 if ($flags & SWAP_CHILDREN) {
370 1315         2681 ($left, $right) = ($right, $left);
371             }
372 1378         4414 my $lhs = $self->deparse_binop_left($op, $left, $prec);
373 1378 50 66     8855 if ($flags & LIST_CONTEXT
374             && $lhs->{text} !~ /^(my|our|local|)[\@\(]/) {
375 0   0     0 $lhs->{maybe_parens} ||= {};
376 0         0 $lhs->{maybe_parens}{force} = 'true';
377 0         0 $lhs->{text} = "($lhs->{text})";
378             }
379              
380 1378         4886 my $rhs = $self->deparse_binop_right($op, $right, $prec);
381 1378 100       3312 if ($flags & SWAP_CHILDREN) {
382             # Not sure why this is right
383 1315         2606 $lhs->{prev_expr} = $rhs;
384             } else {
385 63         137 $rhs->{prev_expr} = $lhs;
386             }
387              
388 1378   100     2959 $type = $type || 'binary operator';
389 1378         2936 $type .= " $opname$eq";
390 1378         8998 my $node = $self->info_from_template($type, $op, "%c $opname$eq %c",
391             undef, [$lhs, $rhs],
392             {maybe_parens => [$self, $cx, $prec]});
393 1378         3566 $node->{prev_expr} = $rhs;
394 1378         4831 return $node;
395             }
396              
397             # Left associative operators, like '+', for which
398             # $a + $b + $c is equivalent to ($a + $b) + $c
399              
400             BEGIN {
401 8     8   8526 %left = ('multiply' => 19, 'i_multiply' => 19,
402             'divide' => 19, 'i_divide' => 19,
403             'modulo' => 19, 'i_modulo' => 19,
404             'repeat' => 19,
405             'add' => 18, 'i_add' => 18,
406             'subtract' => 18, 'i_subtract' => 18,
407             'concat' => 18,
408             'left_shift' => 17, 'right_shift' => 17,
409             'bit_and' => 13, 'nbit_and' => 13, 'sbit_and' => 13,
410             'bit_or' => 12, 'bit_xor' => 12,
411             'sbit_or' => 12, 'sbit_xor' => 12,
412             'nbit_or' => 12, 'nbit_xor' => 12,
413             'and' => 3,
414             'or' => 2, 'xor' => 2,
415             );
416             }
417              
418             sub code_list {
419 0     0 0 0 my ($self, $op, $cv) = @_;
420              
421             # localise stuff relating to the current sub
422             $cv and
423             local($self->{'curcv'}) = $cv,
424             local($self->{'curcvlex'}),
425             local(@$self{qw'curstash warnings hints hinthash curcop'})
426 0 0       0 = @$self{qw'curstash warnings hints hinthash curcop'};
427              
428 0         0 my $re;
429 0         0 for ($op = $op->first->sibling; !B::Deparse::null($op); $op = $op->sibling) {
430 0 0 0     0 if ($op->name eq 'null' and $op->flags & OPf_SPECIAL) {
431 0         0 my $scope = $op->first;
432             # 0 context (last arg to scopeop) means statement context, so
433             # the contents of the block will not be wrapped in do{...}.
434 0         0 my $block = scopeop($scope->first->name eq "enter", $self,
435             $scope, 0);
436             # next op is the source code of the block
437 0         0 $op = $op->sibling;
438 0         0 $re .= ($self->const_sv($op)->PV =~ m|^(\(\?\??\{)|)[0];
439 0         0 my $multiline = $block =~ /\n/;
440 0 0       0 $re .= $multiline ? "\n\t" : ' ';
441 0         0 $re .= $block;
442 0 0       0 $re .= $multiline ? "\n\b})" : " })";
443             } else {
444 0         0 $re = B::Deparse::re_dq_disambiguate($re, $self->re_dq($op));
445             }
446             }
447 0         0 $re;
448             }
449              
450             # Concatenation or '.' is special because concats-of-concats are
451             # optimized to save copying by making all but the first concat
452             # stacked. The effect is as if the programmer had written:
453             # ($a . $b) .= $c'
454             # but the above is illegal.
455              
456             sub concat {
457 6     6 0 12 my $self = shift;
458 6         11 my($op, $cx) = @_;
459 6         19 my $left = $op->first;
460 6         19 my $right = $op->last;
461 6         16 my $eq = "";
462 6         9 my $prec = 18;
463 6 100 100     41 if ($op->flags & OPf_STACKED and $op->first->name ne "concat") {
464 1         3 $eq = "=";
465 1         2 $prec = 7;
466             }
467 6         18 my $lhs = $self->deparse_binop_left($op, $left, $prec);
468 6         20 my $rhs = $self->deparse_binop_right($op, $right, $prec);
469 6         53 return $self->info_from_template(".$eq", $op,
470             "%c .$eq %c", undef, [$lhs, $rhs],
471             {maybe_parens => [$self, $cx, $prec]});
472             }
473              
474             # Handle pp_dbstate, and pp_nextstate and COP ops.
475             #
476             # Notice how subs and formats are inserted between statements here;
477             # also $[ assignments and pragmas.
478              
479             sub cops
480             {
481 2087     2087 0 4702 my ($self, $op, $cx, $name) = @_;
482 2087         3962 $self->{'curcop'} = $op;
483 2087         3187 my @texts = ();
484 2087         3220 my $opts = {};
485 2087         2998 my @args_spec = ();
486 2087         3146 my $fmt = '%;';
487              
488 2087         16533 push @texts, $self->B::Deparse::cop_subs($op);
489              
490 2087 50       4404 if (@texts) {
491             # Special marker to swallow up the semicolon
492 0         0 $opts->{'omit_next_semicolon'} = 1;
493             }
494              
495 2087         7274 my $stash = $op->stashpv;
496 2087 100       5402 if ($stash ne $self->{'curstash'}) {
497 1264         552392 push @texts, $self->keyword("package") . " $stash;";
498 1264         4763 $self->{'curstash'} = $stash;
499             }
500              
501 2087         2597 if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) {
502             push @texts, '$[ = '. $op->arybase .";";
503             $self->{'arybase'} = $op->arybase;
504             }
505              
506 2087         7462 my $warnings = $op->warnings;
507 2087         3054 my $warning_bits;
508 2087 100 66     15571 if ($warnings->isa("B::SPECIAL") && $$warnings == 4) {
    50 33        
    0          
509 200         558 $warning_bits = $warnings::Bits{"all"} & WARN_MASK;
510             }
511             elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) {
512 1887         3364 $warning_bits = $warnings::NONE;
513             }
514             elsif ($warnings->isa("B::SPECIAL")) {
515 0         0 $warning_bits = undef;
516             }
517             else {
518 0         0 $warning_bits = $warnings->PV & WARN_MASK;
519             }
520              
521 2087 100 66     9486 if (defined ($warning_bits) and
      33        
522             !defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) {
523 1266         5271 my @warnings = $self->declare_warnings($self->{'warnings'}, $warning_bits);
524 1266         2449 foreach my $warning (@warnings) {
525 1266         2813 push @texts, $warning;
526             }
527 1266         2663 $self->{'warnings'} = $warning_bits;
528             }
529              
530 2087 50       8781 my $hints = $] < 5.008009 ? $op->private : $op->hints;
531 2087         3646 my $old_hints = $self->{'hints'};
532 2087 100       4646 if ($self->{'hints'} != $hints) {
533 1321         5135 my @hints = $self->declare_hints($self->{'hints'}, $hints);
534 1321         2533 foreach my $hint (@hints) {
535 1266         2171 push @texts, $hint;
536             }
537 1321         2312 $self->{'hints'} = $hints;
538             }
539              
540 2087         2486 my $newhh;
541 2087 50       4993 if ($] > 5.009) {
542 2087         10554 $newhh = $op->hints_hash->HASH;
543             }
544              
545 2087 50       5306 if ($] >= 5.015006) {
546             # feature bundle hints
547 2087         2936 my $from = $old_hints & $feature::hint_mask;
548 2087         2762 my $to = $ hints & $feature::hint_mask;
549 2087 100       4085 if ($from != $to) {
550 9 100       17 if ($to == $feature::hint_mask) {
551 5 50       13 if ($self->{'hinthash'}) {
552             delete $self->{'hinthash'}{$_}
553 5         10 for grep /^feature_/, keys %{$self->{'hinthash'}};
  5         60  
554             }
555 0         0 else { $self->{'hinthash'} = {} }
556             $self->{'hinthash'}
557             = B::Deparse::_features_from_bundle($from,
558 5         46 $self->{'hinthash'});
559             }
560             else {
561 4         11 my $bundle =
562             $feature::hint_bundles[$to >> $feature::hint_shift];
563 4         17 $bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12
  2         9  
564 4         1602 push @texts,
565             $self->keyword("no") . " feature ':all'",
566             $self->keyword("use") . " feature ':$bundle'";
567             }
568             }
569             }
570              
571 2087 50       4209 if ($] > 5.009) {
572             # FIXME use format specifiers
573             my @hints = $self->declare_hinthash(
574 2087         7594 $self->{'hinthash'}, $newhh, 0, $self->{hints});
575 2087         3514 foreach my $hint (@hints) {
576 3         8 push @texts, $hint;
577             }
578 2087         3894 $self->{'hinthash'} = $newhh;
579             }
580              
581              
582             # This should go after of any branches that add statements, to
583             # increase the chances that it refers to the same line it did in
584             # the original program.
585 2087 50 33     5135 if ($self->{'linenums'} && $cx != .5) { # $cx == .5 means in a format
586 0         0 my $line = sprintf("\n# line %s '%s'", $op->line, $op->file);
587 0 0       0 $line .= sprintf(" 0x%x", $$op) if $self->{'opaddr'};
588 0         0 $opts->{'omit_next_semicolon'} = 1;
589 0         0 push @texts, $line;
590             }
591              
592 2087 50       8141 if ($op->label) {
593 0         0 $fmt .= "%c\n";
594 0         0 push @args_spec, scalar(@args_spec);
595 0         0 push @texts, $op->label . ": " ;
596             }
597              
598 2087         6592 my $node = $self->info_from_template($name, $op, $fmt,
599             \@args_spec, \@texts, $opts);
600 2087         7917 return $node;
601             }
602              
603             sub deparse_binop_left {
604 1451     1451 0 2713 my $self = shift;
605 1451         2904 my($op, $left, $prec) = @_;
606 1451 100 100     3809 if ($left{assoc_class($op)} && $left{assoc_class($left)}
      100        
607             and $left{assoc_class($op)} == $left{assoc_class($left)})
608             {
609 14         87 return $self->deparse($left, $prec - .00001, $op);
610             } else {
611 1437         4091 return $self->deparse($left, $prec, $op);
612             }
613             }
614              
615             # Right associative operators, like '=', for which
616             # $a = $b = $c is equivalent to $a = ($b = $c)
617              
618             BEGIN {
619 8     8   78258 %right = ('pow' => 22,
620             'sassign=' => 7, 'aassign=' => 7,
621             'multiply=' => 7, 'i_multiply=' => 7,
622             'divide=' => 7, 'i_divide=' => 7,
623             'modulo=' => 7, 'i_modulo=' => 7,
624             'repeat=' => 7,
625             'add=' => 7, 'i_add=' => 7,
626             'subtract=' => 7, 'i_subtract=' => 7,
627             'concat=' => 7,
628             'left_shift=' => 7, 'right_shift=' => 7,
629             'bit_and=' => 7,
630             'bit_or=' => 7, 'bit_xor=' => 7,
631             'andassign' => 7,
632             'orassign' => 7,
633             );
634             }
635              
636             sub deparse_format($$$)
637             {
638 0     0 0 0 my ($self, $form, $parent) = @_;
639 0         0 my @texts;
640 0         0 local($self->{'curcv'}) = $form;
641 0         0 local($self->{'curcvlex'});
642 0         0 local($self->{'in_format'}) = 1;
643             local(@$self{qw'curstash warnings hints hinthash'})
644 0         0 = @$self{qw'curstash warnings hints hinthash'};
645 0         0 my $op = $form->ROOT;
646 0         0 local $B::overlay = {};
647 0         0 $self->pessimise($op, $form->START);
648             my $info = {
649             op => $op,
650             parent => $parent,
651 0         0 cop => $self->{'curcop'}
652             };
653 0         0 $self->{optree}{$$op} = $info;
654              
655 0 0 0     0 if ($op->first->name eq 'stub' || $op->first->name eq 'nextstate') {
656 0         0 my $info->{text} = "\f.";
657 0         0 return $info;
658             }
659              
660 0         0 $op->{other_ops} = [$op->first];
661 0         0 $op = $op->first->first; # skip leavewrite, lineseq
662 0         0 my $kid;
663 0         0 while (not B::Deparse::null $op) {
664 0         0 push @{$op->{other_ops}}, $op;
  0         0  
665 0         0 $op = $op->sibling; # skip nextstate
666 0         0 my @body;
667 0         0 push @{$op->{other_ops}}, $op->first;
  0         0  
668 0         0 $kid = $op->first->sibling; # skip a pushmark
669 0         0 push @texts, "\f".$self->const_sv($kid)->PV;
670 0         0 push @{$op->{other_ops}}, $kid;
  0         0  
671 0         0 $kid = $kid->sibling;
672 0         0 for (; not B::Deparse::null $kid; $kid = $kid->sibling) {
673 0         0 push @body, $self->deparse($kid, -1, $op);
674 0         0 $body[-1] =~ s/;\z//;
675             }
676 0 0       0 push @texts, "\f".$self->combine2str("\n", \@body) if @body;
677 0         0 $op = $op->sibling;
678             }
679              
680 0         0 $info->{text} = $self->combine2str(\@texts) . "\f.";
681 0         0 $info->{texts} = \@texts;
682 0         0 return $info;
683             }
684              
685             sub dedup_func_parens($$)
686             {
687 573     573 0 984 my $self = shift;
688 573         1081 my ($args_ref) = @_;
689 573         1146 my @args = @$args_ref;
690             return (
691             scalar @args == 1 &&
692             substr($args[0]->{text}, 0, 1) eq '(' &&
693 573   33     3094 substr($args[0]->{text}, 0, 1) eq ')');
694             }
695              
696             sub dedup_parens_func($$$)
697             {
698 0     0 0 0 my $self = shift;
699 0         0 my $sub_info = shift;
700 0         0 my ($args_ref) = @_;
701 0         0 my @args = @$args_ref;
702 0 0 0     0 if (scalar @args == 1 && substr($args[0], 0, 1) eq '(' &&
      0        
703             substr($args[0], -1, 1) eq ')') {
704 0         0 return ($sub_info, $self->combine(', ', \@args), );
705             } else {
706 0         0 return ($sub_info, '(', $self->combine(', ', \@args), ')', );
707             }
708             }
709              
710             sub deparse_binop_right {
711 1451     1451 0 2555 my $self = shift;
712 1451         3138 my($op, $right, $prec) = @_;
713 1451 50 66     2890 if ($right{assoc_class($op)} && $right{assoc_class($right)}
      33        
714             and $right{assoc_class($op)} == $right{assoc_class($right)})
715             {
716 0         0 return $self->deparse($right, $prec - .00001, $op);
717             } else {
718 1451         4288 return $self->deparse($right, $prec, $op);
719             }
720             }
721              
722             # Iterate via sibling links a list of OP nodes starting with
723             # $first. Each OP is deparsed, with $op and $precedence each to get a
724             # node. Then the "prev" field in the node is set, and finally it is
725             # pushed onto the end of the $exprs reference ARRAY.
726             sub deparse_op_siblings($$$$$)
727             {
728 871     871 0 2144 my ($self, $exprs, $kid, $op, $precedence) = @_;
729 871         1369 my $prev_expr = undef;
730 871 100       1143 $prev_expr = $exprs->[-1] if scalar @{$exprs};
  871         2114  
731 871         6808 for ( ; !B::Deparse::null($kid); $kid = $kid->sibling) {
732 1642         4522 my $expr = $self->deparse($kid, $precedence, $op);
733 1642 50       3329 if (defined $expr) {
734 1642         3335 $expr->{prev_expr} = $prev_expr;
735 1642         1969 $prev_expr = $expr;
736 1642         18440 push @$exprs, $expr;
737             }
738             }
739             }
740              
741              
742             # tr/// and s/// (and tr[][], tr[]//, tr###, etc)
743             # note that tr(from)/to/ is OK, but not tr/from/(to)
744             sub double_delim {
745             my($from, $to) = @_;
746             my($succeed, $delim);
747             if ($from !~ m[/] and $to !~ m[/]) {
748             return "/$from/$to/";
749             } elsif (($succeed, $from) = B::Deparse::balanced_delim($from) and $succeed) {
750             if (($succeed, $to) = B::Deparse::balanced_delim($to) and $succeed) {
751             return "$from$to";
752             } else {
753             for $delim ('/', '"', '#') { # note no "'" -- s''' is special
754             return "$from$delim$to$delim" if index($to, $delim) == -1;
755             }
756             $to =~ s[/][\\/]g;
757             return "$from/$to/";
758             }
759             } else {
760             for $delim ('/', '"', '#') { # note no '
761             return "$delim$from$delim$to$delim"
762             if index($to . $from, $delim) == -1;
763             }
764             $from =~ s[/][\\/]g;
765             $to =~ s[/][\\/]g;
766             return "/$from/$to/";
767             }
768             }
769              
770             sub dq($$$)
771             {
772 16     16 0 30 my ($self, $op, $parent) = @_;
773 16         42 my $type = $op->name;
774 16         21 my $info;
775 16 100       32 if ($type eq "const") {
    50          
    50          
776 14 50       41 return info_from_text($op, $self, '$[', 'dq constant ary', {}) if $op->private & OPpCONST_ARYBASE;
777 14         153 return info_from_text($op, $self,
778             B::Deparse::uninterp(B::Deparse::escape_str(B::Deparse::unback($self->const_sv($op)->as_string))),
779             'dq constant', {});
780             } elsif ($type eq "concat") {
781 0         0 my $first = $self->dq($op->first, $op);
782 0         0 my $last = $self->dq($op->last, $op);
783              
784             # FIXME: convert to newer conventions
785             # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]", "$foo\::bar"
786             ($last->{text} =~ /^[A-Z\\\^\[\]_?]/ &&
787             $first->{text} =~ s/([\$@])\^$/${1}{^}/) # "${^}W" etc
788             || ($last->{text} =~ /^[:'{\[\w_]/ && #'
789 0 0 0     0 $first->{text} =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/);
      0        
790              
791 0         0 return info_from_list($op, $self, [$first->{text}, $last->{text}], '', 'dq_concat',
792             {body => [$first, $last]});
793             } elsif ($type eq "join") {
794 0         0 return $self->deparse($op->last, 26, $op); # was join($", @ary)
795             } else {
796 2         5 return $self->deparse($op, 26, $parent);
797             }
798 0         0 my $kid = $self->dq($op->first->sibling, $op);
799 0         0 my $kid_text = $kid->{text};
800 0 0       0 if ($type eq "uc") {
    0          
    0          
    0          
    0          
    0          
801 0         0 $info = info_from_lists(['\U', $kid, '\E'], '', 'dq_uc', {});
802             } elsif ($type eq "lc") {
803 0         0 $info = info_from_lists(['\L', $kid, '\E'], '', 'dq_lc', {});
804             } elsif ($type eq "ucfirst") {
805 0         0 $info = info_from_lists(['\u', $kid, '\E'], '', 'dq_ucfirst', {});
806             } elsif ($type eq "lcfirst") {
807 0         0 $info = info_from_lists(['\l', $kid, '\E'], '', 'dq_lcfirst', {});
808             } elsif ($type eq "quotemeta") {
809 0         0 $info = info_from_lists(['\Q', $kid, '\E'], '', 'dq_quotemeta', {});
810             } elsif ($type eq "fc") {
811 0         0 $info = info_from_lists(['\F', $kid, '\E'], '', 'dq_fc', {});
812             }
813 0         0 $info->{body} = [$kid];
814 0         0 return $info;
815             }
816              
817             # Handle unary operators that can occur as pseudo-listops inside
818             # double quotes
819             sub dq_unop
820             {
821 20     20 0 72 my($self, $op, $cx, $name, $prec, $flags) = (@_, 0, 0);
822 20         39 my $kid;
823 20 50       82 if ($op->flags & B::OPf_KIDS) {
824 20         33 my $pushmark_op = undef;
825 20         68 $kid = $op->first;
826 20 50       155 if (not B::Deparse::null $kid->sibling) {
827             # If there's more than one kid, the first is an ex-pushmark.
828 0         0 $pushmark_op = $kid;
829 0         0 $kid = $kid->sibling;
830             }
831 20         93 my $info = $self->maybe_parens_unop($name, $kid, $cx, $op);
832 20 50       47 if ($pushmark_op) {
833             # For the pushmark opc we'll consider it the "name" portion
834             # of info. We examine that to get the text.
835 0         0 my $text = $info->{text};
836 0         0 my $word_end = index($text, ' ');
837 0 0       0 $word_end = length($text) unless $word_end > 0;
838 0         0 my $pushmark_info =
839             $self->info_from_string("dq $name", $op, $text,
840             {position => [0, $word_end]});
841 0         0 $info->{other_ops} = [$pushmark_info];
842             # $info->{other_ops} = [$pushmark_op];
843             }
844 20         48 return $info;
845             } else {
846 0 0       0 $name .= '()' if $op->flags & B::OPf_SPECIAL;
847 0         0 return $self->info_from_string("dq $name", $op, $name)
848             }
849 0         0 Carp::confess("unhandled condition in dq_unop");
850             }
851              
852             sub dquote
853             {
854 0     0 0 0 my($self, $op, $cx) = @_;
855             # FIXME figure out how to use this
856 0         0 my $skipped_ops = [$op->first];
857 0         0 my $kid = $op->first->sibling; # skip ex-stringify, pushmark
858 0 0       0 return $self->deparse($kid, $cx, $op) if $self->{'unquote'};
859             $self->maybe_targmy($kid, $cx,
860 0     0   0 sub {$self->single_delim($kid, "qq", '"',
861             $self->info2str($self->dq($_[1], $op))
862 0         0 )});
863             }
864              
865             sub elem
866             {
867 1     1 0 3 my ($self, $op, $cx, $left, $right, $padname) = @_;
868 1         9 my($array, $idx) = ($op->first, $op->first->sibling);
869              
870 1         15 my $idx_info = $self->elem_or_slice_single_index($idx, $op);
871 1         3 my $opts = {body => [$idx_info]};
872              
873 1 50       8 unless ($array->name eq $padname) { # Maybe this has been fixed
874 0         0 $opts->{other_ops} = [$array];
875 0         0 $array = $array->first; # skip rv2av (or ex-rv2av in _53+)
876             }
877 1         2 my @texts = ();
878 1         2 my $info;
879 1         9 my $array_name=$self->elem_or_slice_array_name($array, $left, $padname, 1);
880 1 50       3 if ($array_name) {
881 1 50       4 if ($array_name !~ /->\z/) {
882 1 50       3 if ($array_name eq '#') {
883 0         0 $array_name = '${#}';
884             } else {
885 1         3 $array_name = '$' . $array_name ;
886             }
887             }
888 1         2 push @texts, $array_name;
889 1 50       4 push @texts, $left if $left;
890 1         3 push @texts, $idx_info->{text}, $right;
891 1         11 return info_from_list($op, $self, \@texts, '', 'elem', $opts)
892             } else {
893             # $x[20][3]{hi} or expr->[20]
894 0         0 my $type;
895 0         0 my $array_info = $self->deparse($array, 24, $op);
896 0         0 push @{$info->{body}}, $array_info;
  0         0  
897 0         0 @texts = ($array_info->{text});
898 0 0       0 if (is_subscriptable($array)) {
899 0         0 push @texts, $left, $idx_info->{text}, $right;
900 0         0 $type = 'elem_no_arrow';
901             } else {
902 0         0 push @texts, '->', $left, $idx_info->{text}, $right;
903 0         0 $type = 'elem_arrow';
904             }
905 0         0 return info_from_list($op, $self, \@texts, '', $type, $opts);
906             }
907 0         0 Carp::confess("unhandled condition in elem");
908             }
909              
910             sub e_anoncode($$)
911             {
912 2     2 0 4 my ($self, $info) = @_;
913 2         10 my $sub_info = $self->deparse_sub($info->{code});
914             return $self->info_from_template('sub anonymous', $sub_info->{op},
915 2         7 'sub %c', [0], [$sub_info]);
916             }
917              
918             # Handle filetest operators -r, stat, etc.
919             sub filetest
920             {
921 14     14 0 36 my($self, $op, $cx, $name) = @_;
922 14 50       90 if (B::class($op) eq "UNOP") {
    0          
923             # Genuine '-X' filetests are exempt from the LLAFR, but not
924             # l?stat()
925 14 100       60 if ($name =~ /^-/) {
926 6         43 my $kid = $self->deparse($op->first, 16, $op);
927 6         41 return $self->info_from_template("filetest $name", $op,
928             "$name %c", undef, [$kid],
929             {maybe_parens => [$self, $cx, 16]});
930             }
931 8         49 return $self->maybe_parens_unop($name, $op->first, $cx, $op);
932             } elsif (B::class($op) =~ /^(SV|PAD)OP$/) {
933 0         0 my ($fmt, $type);
934 0         0 my $gv_node = $self->pp_gv($op, 1);
935 0 0       0 if ($self->func_needs_parens($gv_node->{text}, $cx, 16)) {
936 0         0 $fmt = "$name(%c)";
937 0         0 $type = "filetest $name()";
938             } else {
939 0         0 $fmt = "$name %c";
940 0         0 $type = "filetest $name";
941             }
942 0         0 return $self->info_from_template($type, $op, $fmt, undef, [$gv_node]);
943             } else {
944             # I don't think baseop filetests ever survive ck_filetest, but...
945 0         0 return $self->info_from_string("filetest $name", $op, $name);
946             }
947             }
948              
949             sub for_loop($$$$) {
950 0     0 0 0 my ($self, $op, $cx, $parent) = @_;
951 0         0 my $init = $self->deparse($op, 1, $parent);
952 0         0 my $s = $op->sibling;
953 0 0       0 my $ll = $s->name eq "unstack" ? $s->sibling : $s->first->sibling;
954 0         0 return $self->loop_common($ll, $cx, $init);
955             }
956              
957             # Returns in function (whose name is not passed as a parameter) will
958             # need to surround its argements (the first argument is $first_param)
959             # in parenthesis. To determine this, we also pass in the operator
960             # precedence, $prec, and the current expression context value, $cx
961             sub func_needs_parens($$$$)
962             {
963 77     77 0 195 my($self, $first_param, $cx, $prec) = @_;
964 77   66     364 return ($prec <= $cx) || (substr($first_param, 0, 1) eq "(") || $self->{'parens'};
965             }
966              
967             sub givwhen
968             {
969 0     0 0 0 my($self, $op, $cx, $give_when) = @_;
970              
971 0         0 my @arg_spec = ();
972 0         0 my @nodes = ();
973 0         0 my $enterop = $op->first;
974 0         0 my $fmt;
975 0         0 my ($head, $block);
976 0 0       0 if ($enterop->flags & B::OPf_SPECIAL) {
977 0         0 $head = $self->keyword("default");
978 0         0 $fmt = "$give_when ($head)\n\%+%c\n%-}\n";
979 0         0 $block = $self->deparse($enterop->first, 0, $enterop, $op);
980             }
981             else {
982 0         0 my $cond = $enterop->first;
983 0         0 my $cond_node = $self->deparse($cond, 1, $enterop, $op);
984 0         0 push @nodes, $cond_node;
985 0         0 $fmt = "$give_when (%c)\n\%+%c\n%-}\n";
986 0         0 $block = $self->deparse($cond->sibling, 0, $enterop, $op);
987             }
988 0         0 push @nodes, $block;
989              
990 0         0 return $self->info_from_template("{} $give_when",
991             "%c\n\%+%c\n%-}\n", [0, 1],
992             \@nodes);
993             }
994              
995             # Handles the indirect operators, print, say(), sort()
996             sub indirop
997             {
998 49     49 0 93 my($self, $op, $cx, $name) = @_;
999 49         64 my($expr, @exprs);
1000 49         206 my $firstkid = my $kid = $op->first->sibling;
1001 49         80 my $indir_info = undef;
1002 49         67 my $type = $name;
1003 49         113 my $first_op = $op->first;
1004 49         77 my @skipped_ops = ($first_op);
1005 49         60 my @indir = ();
1006 49         59 my @args_spec;
1007              
1008 49         62 my $fmt = '';
1009              
1010 49 100       140 if ($op->flags & OPf_STACKED) {
1011 3         5 push @skipped_ops, $kid;
1012 3         10 my $indir_op = $kid->first; # skip rv2gv
1013 3 50 0     15 if (B::Deparse::is_scope($indir_op)) {
    0          
1014 3         7 $indir_info = $self->deparse($indir_op, 0, $op);
1015 3 50       8 if ($indir_info->{text} eq '') {
1016 0         0 $fmt = '{;}';
1017             } else {
1018 3         6 $fmt = '{%c}';
1019             }
1020             } elsif ($indir_op->name eq "const" && $indir_op->private & OPpCONST_BARE) {
1021 0         0 $fmt = $self->const_sv($indir_op)->PV;
1022             } else {
1023 0         0 $indir_info = $self->deparse($indir_op, 24, $op);
1024 0         0 $fmt = '%c';
1025             }
1026 3         4 $fmt .= ' ';
1027 3         14 $kid = $kid->sibling;
1028             }
1029              
1030 49 50 66     267 if ($name eq "sort" && $op->private & (OPpSORT_NUMERIC | OPpSORT_INTEGER)) {
    50 66        
1031 0         0 $type = 'indirop sort numeric or integer';
1032 0 0       0 $fmt = ($op->private & OPpSORT_DESCEND)
1033             ? '{$b <=> $a} ': '{$a <=> $b} ';
1034             } elsif ($name eq "sort" && $op->private & OPpSORT_DESCEND) {
1035 0         0 $type = 'indirop sort descend';
1036 0         0 $fmt = '{$b cmp $a} ';
1037             }
1038              
1039             # FIXME: turn into a function;
1040 49         73 my $prev_expr = $exprs[-1];
1041 49         292 for (; !B::Deparse::null($kid); $kid = $kid->sibling) {
1042             # This prevents us from using deparse_op_siblings
1043 57         98 my $operator_context;
1044 57 100 100     303 if (!$fmt && $kid == $firstkid
      100        
      100        
1045             && $name eq "sort"
1046             && $firstkid->name =~ /^enter(xs)?sub/) {
1047 1         2 $operator_context = 16;
1048             } else {
1049 56         80 $operator_context = 6;
1050             }
1051 57         131 $expr = $self->deparse($kid, $operator_context, $op);
1052 57 50       110 if (defined $expr) {
1053 57         100 $expr->{prev_expr} = $prev_expr;
1054 57         63 $prev_expr = $expr;
1055 57         568 push @exprs, $expr;
1056             }
1057             }
1058              
1059             # Extend $name possibly by adding "reverse".
1060 49         78 my $name2;
1061 49 50 66     158 if ($name eq "sort" && $op->private & OPpSORT_REVERSE) {
1062 0         0 $name2 = $self->keyword('reverse') . ' ' . $self->keyword('sort');
1063             } else {
1064 49         1041 $name2 = $self->keyword($name)
1065             }
1066              
1067 49 100 100     168 if ($name eq "sort" && ($op->private & OPpSORT_INPLACE)) {
1068 2         5 $fmt = "%c = $name2 $fmt %c";
1069             # FIXME: do better with skipped ops
1070 2         9 return $self->info_from_template("indirop sort inplace", $op, $fmt,
1071             [0, 0], \@exprs,
1072             {prev_expr => $prev_expr});
1073             }
1074              
1075              
1076 47         56 my $node;
1077 47         57 $prev_expr = $exprs[-1];
1078 47 50 66     339 if ($fmt ne "" && $name eq "sort") {
    100 100        
      100        
      100        
1079             # We don't want to say "sort(f 1, 2, 3)", since perl -w will
1080             # give bareword warnings in that case. Therefore if context
1081             # requires, we'll put parens around the outside "(sort f 1, 2,
1082             # 3)". Unfortunately, we'll currently think the parens are
1083             # necessary more often that they really are, because we don't
1084             # distinguish which side of an assignment we're on.
1085 0         0 $node = $self->info_from_template($name2, $op,
1086             "$name2 %C",
1087             [[0, $#exprs, ', ']],
1088             \@exprs,
1089             {
1090             other_ops => \@skipped_ops,
1091             maybe_parens => {
1092             context => $cx,
1093             precedence => 5},
1094             prev_expr => $prev_expr
1095             });
1096              
1097             } elsif (!$fmt && $name eq "sort"
1098             && !B::Deparse::null($op->first->sibling)
1099             && $op->first->sibling->name eq 'entersub' ) {
1100             # We cannot say sort foo(bar), as foo will be interpreted as a
1101             # comparison routine. We have to say sort(...) in that case.
1102 1         16 $node = $self->info_from_template("indirop $name2()", $op,
1103             "$name2(%C)",
1104             [[0, $#exprs, ', ']],
1105             \@exprs,
1106             {other_ops => \@skipped_ops,
1107             prev_expr => $prev_expr});
1108              
1109             } else {
1110 46 100       90 if (@exprs) {
1111 42         54 my $type = "indirop";
1112 42         45 my $args_fmt;
1113 42 100       106 if ($self->func_needs_parens($exprs[0]->{text}, $cx, 5)) {
1114 32         58 $type = "indirop $name2()";
1115 32         37 $args_fmt = "(%C)";
1116             } else {
1117 10         21 $type = "indirop $name2";
1118 10         13 $args_fmt = "%C";
1119             }
1120 42         107 @args_spec = ([0, $#exprs, ', ']);
1121 42 100       81 if ($fmt) {
1122 3         8 $fmt = "${name2} ${fmt}${args_fmt}";
1123 3 50       6 if ($indir_info) {
1124 3         7 unshift @exprs, $indir_info;
1125 3         7 @args_spec = (0, [1, $#exprs, ', ']);
1126             }
1127             } else {
1128 39 100       97 if (substr($args_fmt, 0, 1) eq '(') {
1129 32         46 $fmt = "${name2}$args_fmt";
1130             } else {
1131 7         19 $fmt = "${name2} $args_fmt";
1132             }
1133 39         95 @args_spec = [0, $#exprs, ', '];
1134             }
1135              
1136 42         196 $node = $self->info_from_template($type, $op, $fmt,
1137             \@args_spec, \@exprs,
1138             {prev_expr => $prev_expr});
1139             } else {
1140 4         6 $type="indirop $name2";
1141             # Should this be maybe_parens()?
1142 4 50       8 $type .= '()' if (7 < $cx); # FIXME - do with format specifier
1143 4         10 $node = $self->info_from_string($type, $op, $name2);
1144             }
1145             }
1146              
1147             # Handle skipped ops
1148 47         99 my @new_ops;
1149 47         86 my $position = [0, length($name2)];
1150 47         73 my $str = $node->{text};
1151 47         83 foreach my $skipped_op (@skipped_ops) {
1152 50         314 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
1153             {position => $position});
1154 50         136 push @new_ops, $new_op;
1155             }
1156 47         73 $node->{other_ops} = \@new_ops;
1157 47         148 return $node;
1158             }
1159              
1160             # 5.16 doesn't have this so we include it, even though it's not
1161             # going to get used?
1162             sub is_lexical_subs {
1163 0     0 0 0 my (@ops) = shift;
1164 0         0 for my $op (@ops) {
1165 0 0       0 return 0 if $op->name !~ /\A(?:introcv|clonecv)\z/;
1166             }
1167 0         0 return 1;
1168             }
1169              
1170             # The version of null_op_list after 5.22
1171             # Note: this uses "op" not "kid"
1172             sub is_list_newer($$) {
1173 5254     5254 0 8270 my ($self, $op) = @_;
1174 5254         13337 my $kid = $op->first;
1175 5254 100       19868 return 1 if $kid->name eq 'pushmark';
1176 2647   66     82452 return ($kid->name eq 'null'
1177             && $kid->targ == OP_PUSHMARK
1178             && B::Deparse::_op_is_or_was($op, B::Deparse::OP_LIST));
1179             }
1180              
1181              
1182             # The version of null_op_list before 5.22
1183             # Note: this uses "kid", not "op"
1184             sub is_list_older($) {
1185 0     0 0 0 my ($self, $kid) = @_;
1186             # Something may be funky where without the convesion we are getting ""
1187             # as a return
1188 0 0       0 return ($kid->name eq 'pushmark') ? 1 : 0;
1189             }
1190              
1191             # This handle logical ops: "if"/"until", "&&", "and", ...
1192             # The one-line "while"/"until" is handled in pp_leave.
1193             sub logop
1194             {
1195 97     97 0 244 my ($self, $op, $cx, $lowop, $lowprec, $highop,
1196             $highprec, $blockname) = @_;
1197 97         349 my $left = $op->first;
1198 97         439 my $right = $op->first->sibling;
1199 97         189 my ($lhs, $rhs, $type, $opname);
1200 97         195 my $opts = {};
1201 97 50 66     1066 if ($cx < 1 and B::Deparse::is_scope($right) and $blockname
    100 33        
    100 33        
      66        
      66        
      33        
      100        
1202             and $self->{'expand'} < 7) {
1203             # Is this branch used in 5.26 and above?
1204             # ($a) {$b}
1205 0         0 my $if_cond_info = $self->deparse($left, 1, $op);
1206 0         0 my $if_body_info = $self->deparse($right, 0, $op);
1207 0         0 return $self->info_from_template("$blockname () {}", $op,
1208             "$blockname (%c) {\n%+%c\n%-}",
1209             [0, 1],
1210             [$if_cond_info, $if_body_info], $opts);
1211             } elsif ($cx < 1 and $blockname and not $self->{'parens'}
1212             and $self->{'expand'} < 7) { # $b if $a
1213             # Note: order of lhs and rhs is reversed
1214 35         124 $lhs = $self->deparse($right, 1, $op);
1215 35         118 $rhs = $self->deparse($left, 1, $op);
1216 35         72 $opname = $blockname;
1217 35         57 $type = "suffix $opname"
1218             } elsif ($cx > $lowprec and $highop) {
1219             # low-precedence operator like $a && $b
1220 16         48 $lhs = $self->deparse_binop_left($op, $left, $highprec);
1221 16         49 $rhs = $self->deparse_binop_right($op, $right, $highprec);
1222 16         48 $opname = $highop;
1223 16         46 $opts = {maybe_parens => [$self, $cx, $highprec]};
1224             } else {
1225             # high-precedence operator like $a and $b
1226 46         142 $lhs = $self->deparse_binop_left($op, $left, $lowprec);
1227 46         133 $rhs = $self->deparse_binop_right($op, $right, $lowprec);
1228 46         73 $opname = $lowop;
1229 46         140 $opts = {maybe_parens => [$self, $cx, $lowprec]};
1230             }
1231 97   66     317 $type ||= $opname;
1232 97         429 return $self->info_from_template($type, $op, "%c $opname %c",
1233             [0, 1], [$lhs, $rhs], $opts);
1234             }
1235              
1236             sub list_const
1237             {
1238 0     0 0 0 my $self = shift;
1239 0         0 my($op, $cx, @list) = @_;
1240 0         0 my @a = map $self->const($_, 6), @list;
1241 0         0 my $prec = 6;
1242 0 0       0 if (@a == 0) {
1243 0         0 return $self->info_from_string('list const ()', $op, '()');
1244             }
1245 0 0       0 if (@a == 1) {
1246 0         0 return $self->info_from_template('list const: one item',
1247             $op, "(%c)", undef, [$a[0]]);
1248             }
1249              
1250 0         0 my @texts = map $_->{text}, @a;
1251 0 0 0     0 if ( @a > 2 and !grep(!/^-?\d+$/, @texts)) {
1252             # collapse a consecutive sequence like (-1,0,1,2) into a range like (-1..2)
1253 0         0 my $first = $texts[0];
1254 0         0 my $i = $first;
1255 0 0       0 return $self->info_from_template('list const ..', $op,
1256             "%c..%c", undef,
1257             [$a[0], $a[-1]],
1258             {maybe_parens => [$self, $cx, 9]})
1259             unless grep $i++ != $_, @texts;
1260             }
1261 0         0 return $self->info_from_template('list const, more than one item',
1262             $op, "%C", [[0, $#a, ', ']], \@a,
1263             {maybe_parens => [$self, $cx, $prec]});
1264             }
1265              
1266             # This handle list ops: "open", "pack", "return" ...
1267             sub listop
1268             {
1269 298     298 0 924 my($self, $op, $cx, $name, $kid, $nollafr) = @_;
1270 298         541 my(@exprs, @new_nodes, @skipped_ops);
1271 298   66     807 my $parens = ($cx >= 5) || $self->{'parens'};
1272              
1273 298 100       603 unless ($kid) {
1274 271         985 push @skipped_ops, $op->first;
1275 271         1453 $kid = $op->first->sibling;
1276             }
1277              
1278             # If there are no arguments, add final parentheses (or parenthesize the
1279             # whole thing if the llafr does not apply) to account for cases like
1280             # (return)+1 or setpgrp()+1. When the llafr does not apply, we use a
1281             # precedence of 6 (< comma), as "return, 1" does not need parentheses.
1282 298 100       1999 if (B::Deparse::null $kid) {
1283 24         569 my $fullname = $self->keyword($name);
1284 24 100       103 my $text = $nollafr
1285             ? $self->maybe_parens($fullname, $cx, 7)
1286             : $fullname . '()' x (7 < $cx);
1287 24         87 return $self->info_from_string("listop $name", $op, $text);
1288             }
1289 274         468 my $first;
1290 274         8603 my $fullname = $self->keyword($name);
1291 274         1946 my $proto = prototype("CORE::$name");
1292 274 100 100     2899 if (
      100        
      100        
1293             ( (defined $proto && $proto =~ /^;?\*/)
1294             || $name eq 'select' # select(F) doesn't have a proto
1295             )
1296             && $kid->name eq "rv2gv"
1297             && !($kid->private & B::OPpLVAL_INTRO)
1298             ) {
1299 74         921 $first = $self->rv2gv_or_string($kid->first, $op);
1300             }
1301             else {
1302 200         804 $first = $self->deparse($kid, 6, $op);
1303             }
1304 274 50 66     1042 if ($name eq "chmod" && $first->{text} =~ /^\d+$/) {
1305 0     0   0 my $transform_fn = sub {sprintf("%#o", $self->info2str(shift))};
  0         0  
1306 0         0 $first = $self->info_from_template("chmod octal", undef,
1307             "%F", [[0, $transform_fn]],
1308             [$first], {'relink_children' => [0]});
1309 0         0 push @new_nodes, $first;
1310             }
1311              
1312             # FIXME: fold this into a template
1313             $first->{text} = "+" + $first->{text}
1314 274 50 66     1288 if not $parens and not $nollafr and substr($first->{text}, 0, 1) eq "(";
      66        
1315              
1316 274         524 push @exprs, $first;
1317 274         1155 $kid = $kid->sibling;
1318 274 100 100     1467 if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv"
      66        
      100        
1319             && !($kid->private & B::OPpLVAL_INTRO)) {
1320 6         42 $first = $self->rv2gv_or_string($kid->first, $op);
1321 6         16 push @exprs, $first;
1322 6         24 $kid = $kid->sibling;
1323             }
1324              
1325 274         1261 $self->deparse_op_siblings(\@exprs, $kid, $op, 6);
1326              
1327 274 50 66     1009 if ($name eq "reverse" && ($op->private & B::OPpREVERSE_INPLACE)) {
1328 0         0 my $fmt;
1329             my $type;
1330 0 0       0 if ($parens) {
1331 0         0 $fmt = "%c = $fullname(%c)";
1332 0         0 $type = "listop reverse ()"
1333             } else {
1334 0         0 $fmt = "%c = $fullname(%c)";
1335 0         0 $type = "listop reverse"
1336             }
1337 0         0 my @nodes = ($exprs[0], $exprs[0]);
1338 0         0 return $self->info_from_template($type, $op, $fmt, undef,
1339             [$exprs[0], $exprs[0]]);
1340             }
1341              
1342 274         529 my $opts = {};
1343 274         481 my $type;
1344             my $fmt;
1345              
1346 274 50 66     1159 if ($name =~ /^(system|exec)$/
      33        
1347             && ($op->flags & B::OPf_STACKED)
1348             && @exprs > 1)
1349             {
1350             # handle the "system(prog a1, a2, ...)" form
1351             # where there is no ', ' between the first two arguments.
1352 0 0 0     0 if ($parens && $nollafr) {
    0          
1353 0         0 $fmt = "($fullname %c %C)";
1354 0         0 $type = "listop ($fullname)";
1355             } elsif ($parens) {
1356 0         0 $fmt = "$fullname(%c %C)";
1357 0         0 $type = "listop $fullname()";
1358             } else {
1359 0         0 $fmt = "$fullname %c %C";
1360 0         0 $type = "listop $fullname";
1361             }
1362 0         0 return $self->info_from_template($type, $op, $fmt,
1363             [0, [1, $#exprs, ', ']], \@exprs);
1364              
1365             }
1366              
1367 274         473 $fmt = "%c %C";
1368 274 100 100     1044 if ($parens && $nollafr) {
    100          
1369             # FIXME: do with parens mechanism
1370 3         9 $fmt = "($fullname %C)";
1371 3         7 $type = "listop ($fullname)";
1372             } elsif ($parens) {
1373 242         460 $fmt = "$fullname(%C)";
1374 242         542 $type = "listop $fullname()";
1375             } else {
1376 29         64 $fmt = "$fullname %C";
1377 29         44 $type = "listop $fullname";
1378             }
1379 274 50       611 $opts->{synthesized_nodes} = \@new_nodes if @new_nodes;
1380 274         1439 my $node = $self->info_from_template($type, $op, $fmt,
1381             [[0, $#exprs, ', ']], \@exprs,
1382             $opts);
1383 274         674 $node->{prev_expr} = $exprs[-1];
1384 274 100       640 if (@skipped_ops) {
1385             # if we have skipped ops like pushmark, we will use $full name
1386             # as the part it represents.
1387             ## FIXME
1388 247         347 my @new_ops;
1389 247         516 my $position = [0, length($fullname)];
1390 247         399 my $str = $node->{text};
1391 247         405 my @skipped_nodes;
1392 247         449 for my $skipped_op (@skipped_ops) {
1393 247         1581 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
1394             {position => $position});
1395 247         830 push @new_ops, $new_op;
1396             }
1397 247         756 $node->{other_ops} = \@new_ops;
1398             }
1399 274         957 return $node;
1400             }
1401              
1402             sub loop_common
1403             {
1404 5     5 0 11 my $self = shift;
1405 5         11 my($op, $cx, $init) = @_;
1406 5         16 my $enter = $op->first;
1407 5         21 my $kid = $enter->sibling;
1408              
1409 5         11 my @skipped_ops = ($enter);
1410             local(@$self{qw'curstash warnings hints hinthash'})
1411 5         28 = @$self{qw'curstash warnings hints hinthash'};
1412              
1413 5         9 my ($body, @body);
1414 5         9 my @nodes = ();
1415 5         8 my ($bare, $cond_info) = (0, undef);
1416 5         9 my $fmt = '';
1417 5         5 my $var_fmt;
1418 5         6 my @args_spec = ();
1419 5         10 my $opts = {};
1420 5         8 my $type = 'loop';
1421              
1422 5 50       20 if ($kid->name eq "lineseq") {
    0          
    0          
    0          
1423             # bare or infinite loop
1424 5         12 $type .= ' while (1)';
1425              
1426 5 100       36 if ($kid->last->name eq "unstack") { # infinite
1427 1         4 $fmt .= 'while (1)';
1428             } else {
1429 4         7 $bare = 1;
1430             }
1431 5         7 $body = $kid;
1432             } elsif ($enter->name eq "enteriter") {
1433             # foreach
1434 0         0 $type .= ' foreach';
1435              
1436 0         0 my $ary = $enter->first->sibling; # first was pushmark
1437 0         0 push @skipped_ops, $enter->first, $ary->first->sibling;
1438 0         0 my ($ary_fmt, $var_info);
1439 0         0 my $var = $ary->sibling;
1440 0 0       0 if (B::Deparse::null $var) {
    0          
    0          
1441 0 0 0     0 if (($enter->flags & B::OPf_SPECIAL) && ($] < 5.009)) {
1442             # thread special var, under 5005threads
1443 0         0 $var_fmt = $self->pp_threadsv($enter, 1);
1444             } else { # regular my() variable
1445 0         0 $var_info = $self->pp_padsv($enter, 1, 1);
1446 0         0 push @nodes, $var_info;
1447 0         0 $var_fmt = '%c';
1448 0         0 push @args_spec, $#nodes;
1449             }
1450             } elsif ($var->name eq "rv2gv") {
1451 0         0 $var_info = $self->pp_rv2sv($var, 1);
1452 0         0 push @nodes, $var_info;
1453 0 0       0 if ($enter->private & B::OPpOUR_INTRO) {
1454             # "our" declarations don't have package names
1455 0     0   0 my $transform_fn = sub {$_[0] =~ s/^(.).*::/$1/};
  0         0  
1456 0         0 $var_fmt = "our %F";
1457 0         0 push @args_spec, [$#nodes, $transform_fn];
1458             } else {
1459 0         0 $var_fmt = '%c';
1460 0         0 push @args_spec, $#nodes;
1461             }
1462             } elsif ($var->name eq "gv") {
1463 0         0 $var_info = $self->deparse($var, 1, $op);
1464 0         0 push @nodes, $var_info;
1465 0         0 $var_fmt = '$%c';
1466 0         0 push @args_spec, $#nodes;
1467             }
1468              
1469 0 0 0     0 if ($ary->name eq 'null' and $enter->private & B::OPpITER_REVERSED) {
    0 0        
1470             # "reverse" was optimised away
1471 0         0 push @nodes, listop($self, $ary->first->sibling, 1, 'reverse');
1472 0         0 $ary_fmt = "%c";
1473 0         0 push @args_spec, $#nodes;
1474             } elsif ($enter->flags & B::OPf_STACKED
1475             and not B::Deparse::null $ary->first->sibling->sibling) {
1476 0         0 push @args_spec, scalar(@nodes), scalar(@nodes+1);
1477 0         0 push @nodes, ($self->deparse($ary->first->sibling, 9, $op),
1478             $self->deparse($ary->first->sibling->sibling, 9, $op));
1479 0         0 $ary_fmt = '(%c..%c)';
1480              
1481             } else {
1482 0         0 push @nodes, $self->deparse($ary, 1, $op);
1483 0         0 $ary_fmt = "(%c)";
1484 0         0 push @args_spec, $#nodes;
1485             }
1486              
1487             # skip OP_AND and OP_ITER
1488 0         0 push @skipped_ops, $kid->first, $kid->first->first;
1489 0         0 $body = $kid->first->first->sibling;
1490              
1491 0 0 0     0 if (!B::Deparse::is_state $body->first
1492             and $body->first->name !~ /^(?:stub|leave|scope)$/) {
1493             # Loop of body should be over "$_".
1494 0 0       0 Carp::confess('var ne $_') unless $var_info->{text} eq '_';
1495 0         0 push @skipped_ops, $body->first;
1496 0         0 push @skipped_ops, $nodes[0];
1497 0         0 $var_fmt = '%c';
1498 0         0 $body = $body->first;
1499 0         0 my $body_info = $self->deparse($body, 2, $op);
1500 0         0 $nodes[0] = $body_info;
1501 0         0 return $self->info_from_template("foreach", $op,
1502             "$var_fmt foreach $ary_fmt",
1503             \@args_spec, \@nodes,
1504             {other_ops => \@skipped_ops});
1505             }
1506 0         0 $fmt = "foreach $var_fmt $ary_fmt";
1507             } elsif ($kid->name eq "null") {
1508             # while/until
1509              
1510 0         0 $kid = $kid->first;
1511 0         0 my $name = {"and" => "while", "or" => "until"}->{$kid->name};
1512 0         0 $type .= " $name";
1513 0         0 $cond_info = $self->deparse($kid->first, 1, $op);
1514 0         0 $fmt = "$name (%c) ";
1515 0         0 push @nodes, $cond_info;
1516 0         0 $body = $kid->first->sibling;
1517 0         0 @args_spec = (0);
1518             } elsif ($kid->name eq "stub") {
1519             # bare and empty
1520 0         0 return $self->info_from_string('loop_common {;}', $op, '{;}');
1521             }
1522              
1523             # If there isn't a continue block, then the next pointer for the loop
1524             # will point to the unstack, which is kid's last child, except
1525             # in a bare loop, when it will point to the leaveloop. When neither of
1526             # these conditions hold, then the second-to-last child is the continue
1527             # block (or the last in a bare loop).
1528 5         16 my $cont_start = $enter->nextop;
1529 5         18 my ($cont, @cont_text, $body_info);
1530 5         12 my @cont = ();
1531 5 50 66     19 if ($$cont_start != $$op && ${$cont_start} != ${$body->last}) {
  1         3  
  1         5  
1532 0         0 $type .= ' continue';
1533              
1534 0 0       0 if ($bare) {
1535 0         0 $cont = $body->last;
1536             } else {
1537 0         0 $cont = $body->first;
1538 0         0 while (!B::Deparse::null($cont->sibling->sibling)) {
1539 0         0 $cont = $cont->sibling;
1540             }
1541             }
1542 0         0 my $state = $body->first;
1543 0         0 my $cuddle = " ";
1544 0         0 my @states;
1545 0         0 for (; $$state != $$cont; $state = $state->sibling) {
1546 0         0 push @states, $state;
1547             }
1548 0         0 $body_info = $self->lineseq(undef, 0, @states);
1549 0 0 0     0 if (defined $cond_info
      0        
1550             and not B::Deparse::is_scope($cont)
1551             and $self->{'expand'} < 3) {
1552 0         0 my $cont_info = $self->deparse($cont, 1, $op);
1553 0 0       0 if ($body_info->{type} eq 'statements') {
1554             Carp::confess('expecting statements to have only 1')
1555 0 0       0 unless scalar @{$body_info->{texts}} == 1;
  0         0  
1556              
1557             # Use the last entry the lineseq for prev_expr
1558 0         0 my $last_stmts_node = $body_info->{texts}[0]{texts}[-1];
1559 0         0 $cont_info->{prev_expr} = $last_stmts_node;
1560             }
1561 0 0       0 my $init = defined($init) ? $init : ' ';
1562 0         0 @nodes = ($init, $cond_info, $cont_info);
1563             # @nodes_text = ('for', '(', "$init_text;", $cont_info->{text}, ')');
1564 0         0 $fmt = 'for (%c; %c; %c) ';
1565 0         0 @args_spec = (0, 1, 2);
1566 0         0 $opts->{'omit_next_semicolon'} = 1;
1567             } else {
1568 0         0 my $cont_info = $self->deparse($cont, 0, $op);
1569 0         0 @nodes = ($init, $cont_info);
1570 0         0 @args_spec = (0, 1);
1571 0         0 $opts->{'omit_next_semicolon'} = 1;
1572             @cont_text = ($cuddle, 'continue', "{\n\t",
1573 0         0 $cont_info->{text} , "\n\b}");
1574             }
1575             } else {
1576 5 50       13 return $self->info_from_string('loop no body', $op, '')
1577             if !defined $body;
1578 5 50       12 if (defined $init) {
1579 0         0 @nodes = ($init, $cond_info);
1580 0         0 $fmt = 'for (%c; %c;) ';
1581 0         0 @args_spec = (0, 1);
1582             }
1583 5         12 $opts->{'omit_next_semicolon'} = 1;
1584 5         14 $body_info = $self->deparse($body, 0, $op);
1585             }
1586              
1587             # (my $body_text = $body_info->{text}) =~ s/;?$/;\n/;
1588             # my @texts = (@nodes_text, "{\n\t", $body_text, "\b}", @cont_text);
1589              
1590 5         12 push @nodes, $body_info;
1591 5         9 push @args_spec, $#nodes;
1592 5         13 $fmt .= " {\n%+%c%-\n}";
1593 5 50       15 if (@cont_text) {
1594 0         0 push @nodes, @cont_text;
1595 0         0 push @args_spec, $#nodes;
1596 0         0 $type .= ' cont';
1597 0         0 $fmt .= '%c';
1598             }
1599 5         19 return $self->info_from_template($type, $op, $fmt, \@args_spec, \@nodes, $opts)
1600             }
1601              
1602             # loop expressions
1603             sub loopex
1604             {
1605 0     0 0 0 my ($self, $op, $cx, $name) = @_;
1606 0         0 my $opts = {maybe_parens => [$self, $cx, 7]};
1607 0 0       0 if (B::class($op) eq "PVOP") {
    0          
    0          
1608 0         0 return info_from_list($op, $self, [$name, $op->pv], ' ',
1609             "loop $name $op->pv", $opts);
1610             } elsif (B::class($op) eq "OP") {
1611             # no-op
1612 0         0 return $self->info_from_string("loopex op $name",
1613             $op, $name, $opts);
1614             } elsif (B::class($op) eq "UNOP") {
1615 0         0 (my $kid_info = $self->deparse($op->first, 7)) =~ s/^\cS//;
1616             # last foo() is a syntax error. So we might surround it with parens.
1617             my $transform_fn = sub {
1618 0     0   0 my $text = shift->{text};
1619 0 0       0 $text = "($text)" if $text =~ /^(?!\d)\w/;
1620 0         0 return $text;
1621 0         0 };
1622 0         0 return $self->info_from_template("loopex unop $name",
1623             $op, "$name %F",
1624             undef, [$kid_info], $opts);
1625             } else {
1626 0         0 return $self->info_from_string("loop $name",
1627             $op, $name, "loop $name", $opts);
1628             }
1629 0         0 Carp::confess("unhandled condition in lopex");
1630             }
1631              
1632             # Logical assignment operations, e.g. ||= &&=, //=
1633             sub logassignop
1634             {
1635 0     0 0 0 my ($self, $op, $cx, $opname) = @_;
1636 0         0 my $left_op = $op->first;
1637              
1638 0         0 my $sassign_op = $left_op->sibling;
1639 0         0 my $right_op = $sassign_op->first; # skip sassign
1640 0         0 my $left_node = $self->deparse($left_op, 7, $op);
1641 0         0 my $right_node = $self->deparse($right_op, 7, $op);
1642 0         0 my $node = $self->info_from_template(
1643             "logical assign $opname", $op,
1644             "%c $opname %c", undef, [$left_node, $right_node],
1645             {other_ops => [$op->first->sibling],
1646             maybe_parens => [$self, $cx, 7]});
1647              
1648             # Handle skipped sassign
1649 0         0 my $str = $node->{text};
1650 0         0 my $position = [length($left_node->{text})+1, length($opname)];
1651 0         0 my $new_op = $self->info_from_string($sassign_op->name, $sassign_op, $str,
1652             {position => $position});
1653 0         0 $node->{other_ops} = [$new_op];
1654 0         0 return $node;
1655              
1656             }
1657              
1658             sub mapop
1659             {
1660 24     24 0 252 my($self, $op, $cx, $name) = @_;
1661 24         99 my $kid = $op->first; # this is the (map|grep)start
1662              
1663 24         96 my @skipped_ops = ($kid, $kid->first);
1664 24         97 $kid = $kid->first->sibling; # skip a pushmark
1665              
1666 24         72 my $code_block = $kid->first; # skip a null
1667              
1668 24         151 my ($code_block_node, @nodes);
1669 24         0 my ($fmt, $first_arg_fmt, $is_block);
1670 24         45 my $type = "map $name";
1671 24         43 my @args_spec = ();
1672              
1673 24 50       420 if (B::Deparse::is_scope $code_block) {
1674 0         0 $code_block_node = $self->deparse($code_block, 0, $op);
1675             my $transform_fn = sub {
1676             # remove first \n in block.
1677 0     0   0 ($_[0]->{text})=~ s/^\n\s*//;
1678 0         0 return $_[0]->{text};
1679 0         0 };
1680 0         0 push @args_spec, [0, $transform_fn];
1681 0         0 $first_arg_fmt = '{ %F }';
1682              
1683             ## Alternate simpler form:
1684             # push @args_spec, 0;
1685             # $first_arg_fmt = '{ %c }';
1686 0         0 $type .= " block";
1687 0         0 $is_block = 1;
1688              
1689             } else {
1690 24         104 $code_block_node = $self->deparse($code_block, 24, $op);
1691 24         61 push @args_spec, 0;
1692 24         43 $first_arg_fmt = '%c';
1693 24         38 $type .= " expr";
1694 24         33 $is_block = 0;
1695             }
1696 24         55 push @nodes, $code_block_node;
1697 24         55 $self->{optree}{$code_block_node->{addr}} = $code_block_node;
1698              
1699 24         32 push @skipped_ops, $kid;
1700 24         103 $kid = $kid->sibling;
1701 24         97 $self->deparse_op_siblings(\@nodes, $kid, $op, 6);
1702 24         103 push @args_spec, [1, $#nodes, ', '];
1703              
1704 24         48 my $suffix = '';
1705 24 50       93 if ($self->func_needs_parens($nodes[0]->{text}, $cx, 5)) {
1706 24         46 $fmt = "$name($first_arg_fmt";
1707 24         53 $suffix = ')';
1708             } else {
1709 0         0 $fmt = "$name $first_arg_fmt";
1710             }
1711 24 100       59 if (@nodes > 1) {
1712 16 50       28 if ($is_block) {
1713 0         0 $fmt .= " ";
1714             } else {
1715 16         22 $fmt .= ", ";
1716             }
1717 16         21 $fmt .= "%C";
1718             }
1719 24         41 $fmt .= $suffix;
1720 24         120 my $node = $self->info_from_template($type, $op, $fmt,
1721             \@args_spec, \@nodes,
1722             {other_ops => \@skipped_ops});
1723 24         59 $code_block_node->{parent} = $node->{addr};
1724              
1725             # Handle skipped ops
1726 24         32 my @new_ops;
1727 24         34 my $str = $node->{text};
1728 24         36 my $position;
1729 24 50       49 if ($is_block) {
1730             # Make the position be the position of the "{".
1731 0         0 $position = [length($name)+1, 1];
1732             } else {
1733             # Make the position be the name portion
1734 24         51 $position = [0, length($name)];
1735             }
1736 24         29 my @skipped_nodes;
1737 24         47 for my $skipped_op (@skipped_ops) {
1738 72         285 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
1739             {position => $position});
1740 72         156 push @new_ops, $new_op;
1741             }
1742 24         38 $node->{other_ops} = \@new_ops;
1743 24         77 return $node;
1744             }
1745              
1746              
1747             # osmic acid -- see osmium tetroxide
1748              
1749             my %matchwords;
1750             map($matchwords{join "", sort split //, $_} = $_, 'cig', 'cog', 'cos', 'cogs',
1751             'cox', 'go', 'is', 'ism', 'iso', 'mig', 'mix', 'osmic', 'ox', 'sic',
1752             'sig', 'six', 'smog', 'so', 'soc', 'sog', 'xi');
1753              
1754             sub matchop
1755             {
1756 6 50   6 0 23 $] < 5.022 ? matchop_older(@_) : matchop_newer(@_);
1757             }
1758              
1759             # matchop for Perl 5.22 and later
1760             sub matchop_newer
1761             {
1762 6     6 0 13 my($self, $op, $cx, $name, $delim) = @_;
1763 6         21 my $kid = $op->first;
1764 6         10 my $info = {};
1765 6         7 my @body = ();
1766 6         11 my ($binop, $var_str, $re_str) = ("", "", "");
1767 6         10 my $var_node;
1768             my $re;
1769 6 100 33     29 if ($op->flags & B::OPf_STACKED) {
    50          
1770 4         5 $binop = 1;
1771 4         11 $var_node = $self->deparse($kid, 20, $op);
1772 4         10 $var_str = $var_node->{text};
1773 4         6 push @body, $var_node;
1774 4         17 $kid = $kid->sibling;
1775             }
1776             # not $name; $name will be 'm' for both match and split
1777             elsif ($op->name eq 'match' and my $targ = $op->targ) {
1778 0         0 $binop = 1;
1779 0         0 $var_str = $self->padname($targ);
1780             }
1781 6         9 my $quote = 1;
1782 6         15 my $pmflags = $op->pmflags;
1783 6         7 my $rhs_bound_to_defsv;
1784 6         8 my ($cv, $bregexp);
1785 6         48 my $have_kid = !B::Deparse::null $kid;
1786             # Check for code blocks first
1787 6 50 66     38 if (not B::Deparse::null my $code_list = $op->code_list) {
    50          
    100          
    50          
1788 0 0       0 $re = $self->code_list($code_list,
1789             $op->name eq 'qr'
1790             ? $self->padval(
1791             $kid->first # ex-list
1792             ->first # pushmark
1793             ->sibling # entersub
1794             ->first # ex-list
1795             ->first # pushmark
1796             ->sibling # srefgen
1797             ->first # ex-list
1798             ->first # anoncode
1799             ->targ
1800             )
1801             : undef);
1802 6         42 } elsif (${$bregexp = $op->pmregexp} && ${$cv = $bregexp->qr_anoncv}) {
  1         6  
1803 0         0 my $patop = $cv->ROOT # leavesub
1804             ->first # qr
1805             ->code_list;# list
1806 0         0 $re = $self->code_list($patop, $cv);
1807             } elsif (!$have_kid) {
1808 1         102 $re_str = B::Deparse::re_uninterp(B::Deparse::escape_str(B::Deparse::re_unback($op->precomp)));
1809             } elsif ($kid->name ne 'regcomp') {
1810 0 0       0 if ($op->name eq 'split') {
1811             # split has other kids, not just regcomp
1812 0         0 $re = B::Deparse::re_uninterp(B::Deparse::escape_re(B::Deparse::re_unback($op->precomp)));
1813             } else {
1814 0         0 carp("found ".$kid->name." where regcomp expected");
1815             }
1816             } else {
1817 5         20 ($re, $quote) = $self->regcomp($kid, 21);
1818 5         10 push @body, $re;
1819 5         8 $re_str = $re->{text};
1820 5         21 my $matchop = $kid->first;
1821 5 50       18 if ($matchop->name eq 'regcrest') {
1822 0         0 $matchop = $matchop->first;
1823             }
1824 5 100 66     39 if ($matchop->name =~ /^(?:match|transr?|subst)\z/
1825             && $matchop->flags & B::OPf_SPECIAL) {
1826 4         6 $rhs_bound_to_defsv = 1;
1827             }
1828             }
1829 6         13 my $flags = '';
1830 6 50       13 $flags .= "c" if $pmflags & B::PMf_CONTINUE;
1831 6         56 $flags .= $self->re_flags($op);
1832 6         16 $flags = join '', sort split //, $flags;
1833 6 50       17 $flags = $matchwords{$flags} if $matchwords{$flags};
1834              
1835 6 50       17 if ($pmflags & B::PMf_ONCE) {
    100          
1836             # only one kind of delimiter works here
1837 0         0 $re_str =~ s/\?/\\?/g;
1838             # explicit 'm' is required
1839 0         0 $re_str = $self->keyword("m") . "?$re_str?";
1840             } elsif ($quote) {
1841 2         7 my $re = $self->single_delim($kid, $name, $delim, $re_str);
1842 2         4 push @body, $re;
1843 2         5 $re_str = $re->{text};
1844             }
1845 6         7 my $opts = {};
1846 6         8 my @texts;
1847 6 100       11 $re_str .= $flags if $quote;
1848 6         7 my $type;
1849 6 100       11 if ($binop) {
1850             # FIXME: use template string
1851 4 50       7 if ($rhs_bound_to_defsv) {
1852 4         9 @texts = ($var_str, ' =~ ($_ =~ ', $re_str, ')');
1853             } else {
1854 0         0 @texts = ($var_str, ' =~ ', $re_str);
1855             }
1856 4         8 $opts->{maybe_parens} = [$self, $cx, 20];
1857 4         7 $type = 'binary match ~=';
1858             } else {
1859 2         5 @texts = ($re_str);
1860 2         4 $type = 'unary ($_) match';
1861             }
1862 6         16 return info_from_list($op, $self, \@texts, '', $type, $opts);
1863             }
1864              
1865             # matchop for Perl before 5.22
1866             sub matchop_older
1867             {
1868 0     0 0 0 my($self, $op, $cx, $name, $delim) = @_;
1869 0         0 my $kid = $op->first;
1870 0         0 my $info = {};
1871 0         0 my @body = ();
1872 0         0 my ($binop, $var, $re_str) = ("", "", "");
1873 0         0 my $re;
1874 0 0       0 if ($op->flags & B::OPf_STACKED) {
1875 0         0 $binop = 1;
1876 0         0 $var = $self->deparse($kid, 20, $op);
1877 0         0 push @body, $var;
1878 0         0 $kid = $kid->sibling;
1879             }
1880 0         0 my $quote = 1;
1881 0         0 my $pmflags = $op->pmflags;
1882 0         0 my $extended = ($pmflags & B::PMf_EXTENDED);
1883 0         0 my $rhs_bound_to_defsv;
1884 0 0       0 if (B::Deparse::null $kid) {
    0          
1885 0         0 my $unbacked = B::Deparse::re_unback($op->precomp);
1886 0 0       0 if ($extended) {
1887 0         0 $re_str = B::Deparse::re_uninterp_extended(B::Deparse::escape_extended_re($unbacked));
1888             } else {
1889 0         0 $re_str = B::Deparse::re_uninterp(B::Deparse::escape_str(B::Deparse::re_unback($op->precomp)));
1890             }
1891             } elsif ($kid->name ne 'regcomp') {
1892 0         0 carp("found ".$kid->name." where regcomp expected");
1893             } else {
1894 0         0 ($re, $quote) = $self->regcomp($kid, 21, $extended);
1895 0         0 push @body, $re;
1896 0         0 $re_str = $re->{text};
1897 0         0 my $matchop = $kid->first;
1898 0 0       0 if ($matchop->name eq 'regcrest') {
1899 0         0 $matchop = $matchop->first;
1900             }
1901 0 0 0     0 if ($matchop->name =~ /^(?:match|transr?|subst)\z/
1902             && $matchop->flags & B::OPf_SPECIAL) {
1903 0         0 $rhs_bound_to_defsv = 1;
1904             }
1905             }
1906 0         0 my $flags = '';
1907 0 0       0 $flags .= "c" if $pmflags & B::PMf_CONTINUE;
1908 0         0 $flags .= $self->re_flags($op);
1909 0         0 $flags = join '', sort split //, $flags;
1910 0 0       0 $flags = $matchwords{$flags} if $matchwords{$flags};
1911              
1912 0 0       0 if ($pmflags & B::PMf_ONCE) { # only one kind of delimiter works here
    0          
1913 0         0 $re_str =~ s/\?/\\?/g;
1914 0         0 $re_str = "?$re_str?";
1915             } elsif ($quote) {
1916 0         0 my $re = $self->single_delim($kid, $name, $delim, $re_str);
1917 0         0 push @body, $re;
1918 0         0 $re_str = $re->{text};
1919             }
1920 0         0 my $opts = {body => \@body};
1921 0         0 my @texts;
1922 0 0       0 $re_str .= $flags if $quote;
1923 0         0 my $type;
1924 0 0       0 if ($binop) {
1925 0 0       0 if ($rhs_bound_to_defsv) {
1926 0         0 @texts = ($var->{text}, ' =~ ', "(", '$_', ' =~ ', $re_str, ')');
1927             } else {
1928 0         0 @texts = ($var->{text}, ' =~ ', $re_str);
1929             }
1930 0         0 $opts->{maybe_parens} = [$self, $cx, 20];
1931 0         0 $type = 'matchop_binop';
1932             } else {
1933 0         0 @texts = ($re_str);
1934 0         0 $type = 'matchop_unnop';
1935             }
1936 0         0 return info_from_list($op, $self, \@texts, '', $type, $opts);
1937             }
1938              
1939             # FIXME: remove this
1940             sub map_texts($$)
1941             {
1942 0     0 0 0 my ($self, $args) = @_;
1943 0         0 my @result ;
1944 0         0 foreach my $expr (@$args) {
1945 0 0 0     0 if (ref $expr eq 'ARRAY' and scalar(@$expr) == 2) {
1946             # First item is hash and second item is op address.
1947 0         0 push @result, [$expr->[0]{text}, $expr->[1]];
1948             } else {
1949 0         0 push @result, [$expr->{text}, $expr->{addr}];
1950             }
1951             }
1952 0         0 return @result;
1953             }
1954              
1955             # FIXME: This is weird. Regularize var_info
1956             sub maybe_local {
1957 19     19 0 53 my($self, $op, $cx, $var_info) = @_;
1958 19         43 $var_info->{parent} = $$op;
1959 19         56 return maybe_local_str($self, $op, $cx, $var_info);
1960             }
1961              
1962             # Handles "our", "local", "my" variables (and possibly no
1963             # declaration of these) in scalar and array contexts.
1964             # The complications include stripping a package name on
1965             # "our" variables, and not including parenthesis when
1966             # not needed, unless there's a setting to always include
1967             # parenthesis.
1968              
1969             sub maybe_local_str
1970             {
1971 1447     1447 0 3255 my($self, $op, $cx, $info) = @_;
1972 1447         1953 my ($text, $is_node);
1973 1447 100 66     3906 if (ref $info && $info->isa("B::DeparseTree::TreeNode")) {
1974 94         225 $text = $self->info2str($info);
1975 94         124 $is_node = 1;
1976             } else {
1977 1353         1751 $text = $info;
1978 1353         1773 $is_node = 0;
1979             }
1980              
1981 1447 100       7953 my $our_intro = ($op->name =~ /^(gv|rv2)[ash]v$/) ? OPpOUR_INTRO : 0;
1982 1447         2519 my ($fmt, $type);
1983 1447 100 100     5817 if ($op->private & (OPpLVAL_INTRO|$our_intro)
1984             and not $self->{'avoid_local'}{$$op}) {
1985 7 100       43 my $our_local = ($op->private & OPpLVAL_INTRO) ? "local" : "our";
1986 7 100       21 if( $our_local eq 'our' ) {
1987             # "our" variables needs to strip off package the prefix
1988              
1989 4 0 0     42 if ( $text !~ /^\W(\w+::)*\w+\z/
      33        
1990             and !utf8::decode($text) || $text !~ /^\W(\w+::)*\w+\z/
1991             ) {
1992 0         0 Carp::confess("Unexpected our text $text");
1993             }
1994              
1995 4 50       14 if ($] >= 5.024) {
1996 4 50       52 if ($type = $self->B::Deparse::find_our_type($text)) {
1997 0         0 $our_local .= ' ' . $type;
1998             }
1999             }
2000              
2001 4 50 66     48 if (!B::Deparse::want_scalar($op)
2002             && $self->func_needs_parens($text, $cx, 16)) {
2003 0         0 $type = "$our_local ()";
2004 0         0 $fmt = "$our_local(%F)";
2005             } else {
2006 4         7 $type = "$our_local";
2007 4         7 $fmt = "$our_local %F";
2008             }
2009             my $transform_fn = sub {
2010 30 100   30   70 my $text = $is_node ? $_[0]->{text} : $_[0];
2011             # Strip possible package prefix
2012 30         150 $text =~ s/(\w+::)+//;
2013 30         105 return $text;
2014 4         36 };
2015             # $info could be either a string or a node, %c covers both.
2016 4         23 return $self->info_from_template($type, $op, $fmt,
2017             [[0, $transform_fn]], [$info]);
2018             }
2019              
2020             # Not an "our" declaration.
2021 3 50       14 if (B::Deparse::want_scalar($op)) {
2022             # $info could be either a string or a node, %c covers both
2023 3         13 return $self->info_from_template("scalar $our_local", $op, "$our_local %c", undef, [$info]);
2024             } else {
2025 0 0 0     0 if (!B::Deparse::want_scalar($op)
2026             && $self->func_needs_parens($text, $cx, 16)) {
2027 0         0 $fmt = "$our_local(%F)";
2028 0         0 $type = "$our_local()";
2029             } else {
2030 0         0 $fmt = "$our_local %F";
2031 0         0 $type = "$our_local";
2032             }
2033 0         0 return $self->info_from_template($type, $op, $fmt, undef, [$info]);
2034             }
2035             } else {
2036 1440 100 66     3520 if (ref $info && $info->isa("B::DeparseTree::TreeNode")) {
2037 88         295 return $info;
2038             } else {
2039 1352         3437 return $self->info_from_string('not local', $op, $text);
2040             }
2041             }
2042             }
2043              
2044             sub maybe_my
2045             {
2046 4400 50   4400 0 12972 $] >= 5.026 ? goto &maybe_my_newer : goto &maybe_my_older;
2047             }
2048              
2049             sub maybe_my_newer
2050             {
2051 4400     4400 0 5889 my $self = shift;
2052 4400         7506 my($op, $cx, $text, $padname, $forbid_parens) = @_;
2053             # The @a in \(@a) isn't in ref context, but only when the
2054             # parens are there.
2055 4400   33     15548 my $need_parens = !$forbid_parens && $self->{'in_refgen'}
2056             && $op->name =~ /[ah]v\z/
2057             && ($op->flags & (B::OPf_PARENS|B::OPf_REF)) == B::OPf_PARENS;
2058             # The @a in \my @a must not have parens.
2059 4400 50 33     11268 if (!$need_parens && $self->{'in_refgen'}) {
2060 0         0 $forbid_parens = 1;
2061             }
2062 4400 100 100     19247 if ($op->private & B::OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
2063             # Check $padname->FLAGS for statehood, rather than $op->private,
2064             # because enteriter ops do not carry the flag.
2065 29 50       74 unless (defined($padname)) {
2066 0         0 Carp::confess("undefine padname $padname");
2067             }
2068              
2069 29 100       9182 my $my =
2070             $self->keyword($padname->FLAGS & SVpad_STATE ? "state" : "my");
2071 29 50       126 if ($padname->FLAGS & SVpad_TYPED) {
2072 0         0 $my .= ' ' . $padname->SvSTASH->NAME;
2073             }
2074 29 50 100     224 if ($need_parens) {
    100          
    50          
2075 0         0 return $self->info_from_string("$my()", $op, "$my($text)");
2076             } elsif ($forbid_parens || B::Deparse::want_scalar($op)) {
2077 21         99 return $self->info_from_string("$my", $op, "$my $text");
2078             } elsif ($self->func_needs_parens($text, $cx, 16)) {
2079 0         0 return $self->info_from_string("$my()", $op, "$my($text)");
2080             } else {
2081 8         57 return $self->info_from_string("$my", $op, "$my $text");
2082             }
2083             } else {
2084 4371 50       12336 return $self->info_from_string("not my", $op, $need_parens ? "($text)" : $text);
2085             }
2086             }
2087              
2088             sub maybe_my_older
2089             {
2090 0     0 0 0 my $self = shift;
2091 0         0 my($op, $cx, $text, $forbid_parens) = @_;
2092 0 0 0     0 if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
2093 0 0       0 my $my_str = $op->private & OPpPAD_STATE
2094             ? $self->keyword("state")
2095             : "my";
2096 0 0 0     0 if ($forbid_parens || B::Deparse::want_scalar($op)) {
2097 0         0 return $self->info_from_string('my', $op, "$my_str $text");
2098             } else {
2099 0         0 return $self->info_from_string('my (maybe with parens)', $op,
2100             "$my_str $text",
2101             {maybe_parens => [$self, $cx, 16]});
2102             }
2103             } else {
2104 0         0 return $self->info_from_string('not my', $op, $text);
2105             }
2106             }
2107              
2108             # Possibly add () around $text depending on precedence $prec and
2109             # context $cx. We return a string.
2110             sub maybe_parens($$$$)
2111             {
2112 2     2 0 7 my($self, $text, $cx, $prec) = @_;
2113 2 100       13 if (B::DeparseTree::TreeNode::parens_test($self, $cx, $prec)) {
2114 1         9 $text = "($text)";
2115             # In a unop, let parent reuse our parens; see maybe_parens_unop
2116             # FIXME:
2117 1 50       6 $text = "\cS" . $text if $cx == 16;
2118 1         3 return $text;
2119             } else {
2120 1         2 return $text;
2121             }
2122             }
2123              
2124             # FIXME: go back to default B::Deparse routine and return a string.
2125             sub maybe_parens_func($$$$$)
2126             {
2127 1     1 0 3 my($self, $func, $params, $cx, $prec) = @_;
2128 1 50 33     16 if ($prec <= $cx or substr($params, 0, 1) eq "(" or $self->{'parens'}) {
      33        
2129 0         0 return ($func, '(', $params, ')');
2130             } else {
2131 1         11 return ($func, ' ', $params);
2132             }
2133             }
2134              
2135             # Sort of like maybe_parens in that we may possibly add (). However we take
2136             # an op rather than text, and return a tree node. Also, we get around
2137             # the 'if it looks like a function' rule.
2138             sub maybe_parens_unop($$$$$)
2139             {
2140 254     254 0 742 my ($self, $name, $op, $cx, $parent, $opts) = @_;
2141 254 100       552 $opts = {} unless $opts;
2142 254         684 my $info = $self->deparse($op, 1, $parent);
2143 254         494 my $fmt;
2144 254         622 my @exprs = ($info);
2145 254 50 66     683 if ($name eq "umask" && $info->{text} =~ /^\d+$/) {
2146             # Display umask numbers in octal.
2147             # FIXME: add as a info_node option to run a transformation function
2148             # such as the below
2149 0         0 $info->{text} = sprintf("%#o", $info->{text});
2150 0         0 $exprs[0] = $info;
2151             }
2152 254         6013 $name = $self->keyword($name);
2153 254 100 66     1511 if ($cx > 16 or $self->{'parens'}) {
2154 3         12 my $node = $self->info_from_template(
2155             "$name()", $parent, "$name(%c)",[0], \@exprs, $opts);
2156 3         4 $node->{prev_expr} = $exprs[0];
2157 3         11 return $node;
2158             } else {
2159             # FIXME: we don't do \cS
2160             # if (substr($text, 0, 1) eq "\cS") {
2161             # # use op's parens
2162             # return info_from_list($op, $self,[$name, substr($text, 1)],
2163             # '', 'maybe_parens_unop_cS', {body => [$info]});
2164             # } else
2165 251         351 my $node;
2166 251 50       750 if (substr($info->{text}, 0, 1) eq "(") {
2167             # avoid looks-like-a-function trap with extra parens
2168             # ('+' can lead to ambiguities)
2169 0         0 $node = $self->info_from_template(
2170             "$name(()) dup remove", $parent, "$name(%c)", [0], \@exprs, $opts);
2171             } else {
2172 251         1554 $node = $self->info_from_template(
2173             "$name ", $parent, "$name %c", [0], \@exprs, $opts);
2174             }
2175 251         606 $node->{prev_expr} = $exprs[0];
2176 251         1053 return $node;
2177             }
2178 0         0 Carp::confess("unhandled condition in maybe_parens_unop");
2179             }
2180              
2181             sub maybe_qualify {
2182 1797     1797 0 3898 my ($self,$prefix,$name) = @_;
2183 1797 100       4197 my $v = ($prefix eq '$#' ? '@' : $prefix) . $name;
2184 1797 100 66     5907 return $name if !$prefix || $name =~ /::/;
2185             return $self->{'curstash'}.'::'. $name
2186             if
2187             $name =~ /^(?!\d)\w/ # alphabetic
2188             && $v !~ /^\$[ab]\z/ # not $a or $b
2189             && !$globalnames{$name} # not a global name
2190             && $self->{hints} & $strict_bits{vars} # strict vars
2191 1796 100 100     27512 && !$self->B::Deparse::lex_in_scope($v,1) # no "our"
      100        
      100        
      100        
      66        
2192             or $self->B::Deparse::lex_in_scope($v); # conflicts with "my" variable
2193 1783         7099 return $name;
2194             }
2195              
2196             # FIXME: need a way to pass in skipped_ops
2197             # FIXME: see if we can move to some 5.xx-specific module
2198             sub maybe_targmy
2199             {
2200 10     10 0 33 my($self, $op, $cx, $func, @args) = @_;
2201 10 50       46 if ($op->private & OPpTARGET_MY) {
2202 0         0 my $var = $self->padname($op->targ);
2203 0         0 my $val = $func->($self, $op, 7, @args);
2204 0         0 my @texts = ($var, '=', $val);
2205 0         0 return $self->info_from_template("my", $op,
2206             "%c = %c", [0, 1],
2207             [$var, $val],
2208             {maybe_parens => [$self, $cx, 7]});
2209             } else {
2210 10         38 return $self->$func($op, $cx, @args);
2211             }
2212             }
2213              
2214             # Note: this is used in 5.28 and later versions only.
2215             # FIXME: see if we can move to some 5.xx-specific module
2216             sub maybe_var_attr {
2217 0     0 0 0 my ($self, $op, $cx) = @_;
2218              
2219 0         0 my @skipped_ops = ($op->first);
2220 0         0 my $kid = $op->first->sibling; # skip pushmark
2221 0 0       0 return if B::class($kid) eq 'NULL';
2222              
2223 0         0 my $lop;
2224             my $type;
2225              
2226             # Extract out all the pad ops and entersub ops into
2227             # @padops and @entersubops. Return if anything else seen.
2228             # Also determine what class (if any) all the pad vars belong to
2229 0         0 my $class;
2230 0         0 my $decl; # 'my' or 'state'
2231 0         0 my (@padops, @entersubops);
2232 0         0 for ($lop = $kid; !B::Deparse::null($lop); $lop = $lop->sibling) {
2233 0         0 my $lopname = $lop->name;
2234 0         0 my $loppriv = $lop->private;
2235 0 0       0 if ($lopname =~ /^pad[sah]v$/) {
    0          
2236 0 0       0 return unless $loppriv & B::Deparse::OPpLVAL_INTRO;
2237              
2238 0         0 my $padname = $self->padname_sv($lop->targ);
2239 0 0       0 my $thisclass = ($padname->FLAGS & SVpad_TYPED)
2240             ? $padname->B::Deparse::SvSTASH->NAME : 'main';
2241              
2242             # all pad vars must be in the same class
2243 0   0     0 $class //= $thisclass;
2244 0 0       0 return unless $thisclass eq $class;
2245              
2246             # all pad vars must be the same sort of declaration
2247             # (all my, all state, etc)
2248 0 0       0 my $this = ($loppriv & B::Deparse::OPpPAD_STATE) ? 'state' : 'my';
2249 0 0       0 if (defined $decl) {
2250 0 0       0 return unless $this eq $decl;
2251             }
2252 0         0 $decl = $this;
2253              
2254 0         0 push @padops, $lop;
2255             }
2256             elsif ($lopname eq 'entersub') {
2257 0         0 push @entersubops, $lop;
2258             }
2259             else {
2260 0         0 return;
2261             }
2262             }
2263              
2264 0 0 0     0 return unless @padops && @padops == @entersubops;
2265              
2266             # there should be a balance: each padop has a corresponding
2267             # 'attributes'->import() method call, in the same order.
2268              
2269 0         0 my @varnames;
2270             my $attr_text;
2271              
2272 0         0 for my $i (0..$#padops) {
2273 0         0 my $padop = $padops[$i];
2274 0         0 my $esop = $entersubops[$i];
2275              
2276 0         0 push @varnames, $self->padname($padop->targ);
2277              
2278 0 0       0 return unless ($esop->flags & B::Deparse::OPf_KIDS);
2279              
2280 0         0 push @skipped_ops, $esop;
2281 0         0 my $kid = $esop->first;
2282 0 0       0 return unless $kid->type == OP_PUSHMARK;
2283              
2284 0         0 push @skipped_ops, $kid;
2285 0         0 $kid = $kid->sibling;
2286 0 0 0     0 return unless $$kid && $kid->type == B::Deparse::OP_CONST;
2287 0 0       0 return unless $self->const_sv($kid)->PV eq 'attributes';
2288              
2289 0         0 push @skipped_ops, $kid;
2290 0         0 $kid = $kid->sibling;
2291 0 0 0     0 return unless $$kid && $kid->type == B::Deparse::OP_CONST; # __PACKAGE__
2292              
2293 0         0 push @skipped_ops, $kid;
2294 0         0 $kid = $kid->sibling;
2295 0 0 0     0 return unless $$kid
      0        
      0        
      0        
      0        
2296             && $kid->name eq "srefgen"
2297             && ($kid->flags & B::Deparse::OPf_KIDS)
2298             && ($kid->first->flags & B::Deparse::OPf_KIDS)
2299             && $kid->first->first->name =~ /^pad[sah]v$/
2300             && $kid->first->first->targ == $padop->targ;
2301              
2302 0         0 $kid = $kid->sibling;
2303 0         0 my @attr;
2304 0         0 my @nodes = ();
2305 0         0 while ($$kid) {
2306 0 0       0 last if ($kid->type != B::Deparse::OP_CONST);
2307 0         0 push @nodes, $kid;
2308 0         0 push @attr, $self->const_sv($kid)->PV;
2309 0         0 $kid = $kid->sibling;
2310             }
2311 0 0       0 return unless @attr;
2312              
2313 0         0 my $thisattr_node = $self->info_from_template("maybe var attr", $op,
2314             ":%C", [[0, $#nodes, ', ']],
2315             \@nodes);
2316 0         0 my $thisattr = ":" . join(' ', @attr);
2317 0   0     0 $attr_text //= $thisattr;
2318             # all import calls must have the same list of attributes
2319 0 0       0 return unless $attr_text eq $thisattr;
2320              
2321 0 0       0 return unless $kid->name eq 'method_named';
2322 0 0       0 return unless $self->meth_sv($kid)->PV eq 'import';
2323              
2324 0         0 $kid = $kid->sibling;
2325 0 0       0 return if $$kid;
2326             }
2327              
2328 0         0 my $fmt = $decl;
2329 0 0       0 $fmt .= " $class " if $class ne 'main';
2330 0 0       0 $fmt .=
2331             (@varnames > 1)
2332             ? "(" . join(', ', @varnames) . ')'
2333             : " $varnames[0]";
2334              
2335 0         0 $self->info_from_string('maybe_var_attr', $op,
2336             "$fmt $attr_text",
2337             {other_ops => @skipped_ops});
2338             }
2339              
2340             sub _method
2341             {
2342 2     2   7 my($self, $op, $cx) = @_;
2343 2         11 my @other_ops = ($op->first);
2344 2         8 my $kid = $op->first->sibling; # skip pushmark
2345 2         4 my($meth, $obj, @exprs);
2346 2 50 33     11 if ($kid->name eq "list" and B::Deparse::want_list $kid) {
2347             # When an indirect object isn't a bareword but the args are in
2348             # parens, the parens aren't part of the method syntax (the LLAFR
2349             # doesn't apply), but they make a list with OPf_PARENS set that
2350             # doesn't get flattened by the append_elem that adds the method,
2351             # making a (object, arg1, arg2, ...) list where the object
2352             # usually is. This can be distinguished from
2353             # '($obj, $arg1, $arg2)->meth()' (which is legal if $arg2 is an
2354             # object) because in the later the list is in scalar context
2355             # as the left side of -> always is, while in the former
2356             # the list is in list context as method arguments always are.
2357             # (Good thing there aren't method prototypes!)
2358 0         0 $meth = $kid->sibling;
2359 0         0 push @other_ops, $kid->first;
2360 0         0 $kid = $kid->first->sibling; # skip pushmark
2361 0         0 $obj = $kid;
2362 0         0 $kid = $kid->sibling;
2363 0         0 for (; not B::Deparse::null $kid; $kid = $kid->sibling) {
2364 0         0 push @exprs, $kid;
2365             }
2366             } else {
2367 2         4 $obj = $kid;
2368 2         5 $kid = $kid->sibling;
2369 2   66     21 for (; !B::Deparse::null ($kid->sibling) && $kid->name!~/^method(?:_named)?\z/;
2370             $kid = $kid->sibling) {
2371 1         9 push @exprs, $kid
2372             }
2373 2         3 $meth = $kid;
2374             }
2375              
2376 2         4 my $method_name = undef;
2377 2         3 my $type = 'method';
2378 2 50       8 if ($meth->name eq "method_named") {
    0          
    0          
    0          
2379 2 50       6 if ($] < 5.018) {
2380 0         0 $method_name = $self->const_sv($meth)->PV;
2381             } else {
2382 2         14 $method_name = $self->meth_sv($meth)->PV;
2383             }
2384 2         5 $type = 'named method';
2385             } elsif ($meth->name eq "method_super") {
2386 0         0 $method_name = "SUPER::".$self->meth_sv($meth)->PV;
2387 0         0 $type = 'SUPER:: method';
2388             } elsif ($meth->name eq "method_redir") {
2389 0         0 $method_name = $self->meth_rclass_sv($meth)->PV.'::'.$self->meth_sv($meth)->PV;
2390 0         0 $type = 'method redirected ::';
2391             } elsif ($meth->name eq "method_redir_super") {
2392 0         0 $type = '::SUPER:: redirected method';
2393 0         0 $method_name = $self->meth_rclass_sv($meth)->PV.'::SUPER::'.
2394             $self->meth_sv($meth)->PV;
2395             } else {
2396 0         0 $meth = $meth->first;
2397 0 0       0 if ($meth->name eq "const") {
2398             # As of 5.005_58, this case is probably obsoleted by the
2399             # method_named case above
2400 0         0 $method_name = $self->const_sv($meth)->PV; # needs to be bare
2401 0         0 $type = 'contant method';
2402             }
2403             }
2404              
2405 2         3 my $meth_node = undef;
2406 2 50       5 if ($method_name) {
2407 2         8 $meth_node = $self->info_from_string($type,
2408             $meth, $method_name,
2409             {other_ops => \@other_ops});
2410 2         6 $self->{optree}{$$meth} = $meth_node;
2411 2 50       6 $meth_node->{parent} = $$op if $op;
2412              
2413             }
2414             return {
2415 2         17 method_node => $meth_node,
2416             method => $meth,
2417             object => $obj,
2418             args => \@exprs,
2419             }, $cx;
2420             }
2421              
2422             sub e_method {
2423 2     2 0 5 my ($self, $op, $minfo, $cx) = @_;
2424 2         5 my $obj = $self->deparse($minfo->{object}, 24, $op);
2425 2         3 my @body = ($obj);
2426 2         5 my $other_ops = $minfo->{other_ops};
2427              
2428 2         2 my $meth_info = $minfo->{method_node};
2429 2 50       6 unless ($minfo->{method_node}) {
2430 0         0 $meth_info = $self->deparse($minfo->{meth}, 1, $op);
2431             }
2432 2         4 my @args = map { $self->deparse($_, 6, $op) } @{$minfo->{args}};
  1         3  
  2         6  
2433 2         13 my @args_texts = map $_->{text}, @args;
2434 2         6 my $args = join(", ", @args_texts);
2435              
2436 2         6 my $opts = {other_ops => $other_ops,
2437             prev_expr => $meth_info};
2438 2         3 my $type;
2439              
2440 2 50 33     13 if ($minfo->{object}->name eq 'scope' && B::Deparse::want_list $minfo->{object}) {
2441             # method { $object }
2442             # This must be deparsed this way to preserve list context
2443             # of $object.
2444             # FIXME
2445 0         0 my @texts = ();
2446 0         0 my $need_paren = $cx >= 6;
2447 0 0       0 if ($need_paren) {
2448 0         0 @texts = ('(', $meth_info->{text}, substr($obj,2),
2449             $args, ')');
2450 0         0 $type = 'e_method list ()';
2451             } else {
2452 0         0 @texts = ($meth_info->{text}, substr($obj,2), $args);
2453 0         0 $type = 'e_method list, no ()';
2454             }
2455 0         0 return info_from_list($op, $self, \@texts, '', $type, $opts);
2456             }
2457              
2458 2         6 my @nodes = ($obj, $meth_info);
2459 2         2 my $fmt;
2460 2         5 my @args_spec = (0, 1);
2461 2 100       2 if (@{$minfo->{args}}) {
  2         7  
2462 1         2 my $prev_expr = undef;
2463 1         2 foreach my $arg (@{$minfo->{args}}) {
  1         3  
2464 1         5 my $expr = $self->deparse($arg, 6, $op);
2465 1         2 $expr->{prev_expr} = $prev_expr;
2466 1         3 push @nodes, $expr;
2467             }
2468 1         2 $fmt = "%c->%c(%C)";
2469 1         2 push @args_spec, [2, $#nodes, ', '];
2470 1         3 $type = '$obj->method()';
2471             } else {
2472 1         2 $type = '$obj->method';
2473 1         2 $fmt = "%c->%c";
2474             }
2475 2         7 return $self->info_from_template($type, $op, $fmt, \@args_spec, \@nodes, $opts);
2476             }
2477              
2478             # Perl 5.14 doesn't have this
2479 8     8   109 use constant OP_GLOB => 25;
  8         15  
  8         38165  
2480              
2481             sub null_older
2482             {
2483 0     0 0 0 my($self, $op, $cx) = @_;
2484 0         0 my $info;
2485 0 0       0 if (B::class($op) eq "OP") {
    0          
2486 0 0       0 if ($op->targ == B::Deparse::OP_CONST) {
2487             # The Perl source constant value can't be recovered.
2488             # We'll use the 'ex_const' value as a substitute
2489 0         0 return $self->info_from_string('constant unrecoverable', $op, $self->{'ex_const'});
2490             } else {
2491             # FIXME: look over. Is this right?
2492 0         0 return $self->info_from_string('constant ""', $op, '');
2493             }
2494             } elsif (B::class ($op) eq "COP") {
2495 0         0 return $self->cops($op, $cx, $op->name);
2496             }
2497 0         0 my $kid = $op->first;
2498 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        
2499 0         0 my $node = $self->pp_list($op, $cx);
2500 0         0 $node->update_other_ops($kid);
2501 0         0 return $node;
2502             } elsif ($kid->name eq "enter") {
2503 0         0 return $self->pp_leave($op, $cx);
2504             } elsif ($kid->name eq "leave") {
2505 0         0 return $self->pp_leave($kid, $cx);
2506             } elsif ($kid->name eq "scope") {
2507 0         0 return $self->pp_scope($kid, $cx);
2508             } elsif ($op->targ == B::Deparse::OP_STRINGIFY) {
2509 0         0 return $self->dquote($op, $cx);
2510             } elsif ($op->targ == OP_GLOB) {
2511 0         0 my @other_ops = ($kid, $kid->first, $kid->first->first);
2512 0         0 my $info = $self->pp_glob(
2513             $kid # entersub
2514             ->first # ex-list
2515             ->first # pushmark
2516             ->sibling, # glob
2517             $cx
2518             );
2519 0         0 push @{$info->{other_ops}}, @other_ops;
  0         0  
2520 0         0 return $info;
2521             } elsif (!B::Deparse::null($kid->sibling) and
2522             $kid->sibling->name eq "readline" and
2523             $kid->sibling->flags & OPf_STACKED) {
2524 0         0 my $lhs = $self->deparse($kid, 7, $op);
2525 0         0 my $rhs = $self->deparse($kid->sibling, 7, $kid);
2526 0         0 return $self->info_from_template("readline = ", $op,
2527             "%c = %c", undef, [$lhs, $rhs],
2528             {maybe_parens => [$self, $cx, 7],
2529             prev_expr => $rhs});
2530             } elsif (!B::Deparse::null($kid->sibling) and
2531             $kid->sibling->name eq "trans" and
2532             $kid->sibling->flags & OPf_STACKED) {
2533 0         0 my $lhs = $self->deparse($kid, 20, $op);
2534 0         0 my $rhs = $self->deparse($kid->sibling, 20, $op);
2535 0         0 return $self->info_from_template("trans =~",$op,
2536             "%c =~ %c", undef, [$lhs, $rhs],
2537             { maybe_parens => [$self, $cx, 7],
2538             prev_expr => $rhs });
2539             } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) {
2540 0         0 my $kid_info = $self->deparse($kid, $cx, $op);
2541 0         0 return $self->info_from_template("do { }", $op,
2542             "do {\n%+%c\n%-}", undef, [$kid_info]);
2543             } elsif (!B::Deparse::null($kid->sibling) and
2544             $kid->sibling->name eq "null" and
2545             B::class($kid->sibling) eq "UNOP" and
2546             $kid->sibling->first->flags & OPf_STACKED and
2547             $kid->sibling->first->name eq "rcatline") {
2548 0         0 my $lhs = $self->deparse($kid, 18, $op);
2549 0         0 my $rhs = $self->deparse($kid->sibling, 18, $op);
2550 0         0 return $self->info_from_template("rcatline =",$op,
2551             "%c = %c", undef, [$lhs, $rhs],
2552             { maybe_parens => [$self, $cx, 20],
2553             prev_expr => $rhs });
2554             } else {
2555 0         0 return $self->deparse($kid, $cx, $op);
2556             }
2557 0         0 Carp::confess("unhandled condition in null");
2558             }
2559              
2560             sub pushmark_position($) {
2561 2611     2611 0 4351 my ($node) = @_;
2562 2611         3784 my $l = undef;
2563 2611 50       6190 if ($node->{parens}) {
    100          
2564 0         0 return [0, 1];
2565             } elsif (exists $node->{fmt}) {
2566             # Match up to %c, %C, or %F after ( or {
2567 1247 100       6377 if ($node->{fmt} =~ /^(.*)%[cCF]/) {
2568 1200         3176 $l = length($1);
2569             }
2570             } else {
2571             # Match up to first ( or {
2572 1364 100       6132 if ($node->{text} =~ /^(.*)\W/) {
2573 1356         3767 $l = length($1);
2574             }
2575             }
2576 2611 100       4854 if (defined($l)) {
2577 2556 100       5103 $l = $l > 0 ? $l-1 : 0;
2578 2556         5587 return [$l, 1]
2579             }
2580 55         100 return undef;
2581             }
2582              
2583              
2584             # Note 5.26 and up
2585             sub null_newer
2586             {
2587 5255     5255 0 8745 my($self, $op, $cx) = @_;
2588 5255         5819 my $node;
2589              
2590             # might be 'my $s :Foo(bar);'
2591 5255 50 33     10592 if ($] >= 5.028 && $op->targ == B::Deparse::OP_LIST) {
2592 0         0 my $my_attr = maybe_var_attr($self, $op, $cx);
2593 0 0       0 return $my_attr if defined $my_attr;
2594             }
2595              
2596 5255 100       38575 if (B::class($op) eq "OP") {
    50          
2597             # If the Perl source constant value can't be recovered.
2598             # We'll use the 'ex_const' value as a substitute
2599 1 50       8 return $self->info_from_string("null - constant_unrecoverable",$op, $self->{'ex_const'})
2600             if $op->targ == B::Deparse::OP_CONST;
2601 0 0       0 return $self->dquote($op, $cx) if $op->targ == B::Deparse::OP_STRINGIFY;
2602             } elsif (B::class($op) eq "COP") {
2603 0         0 return $self->cops($op, $cx, $op->name);
2604             } else {
2605             # All of these use $kid
2606 5254         18925 my $kid = $op->first;
2607 5254         7787 my $update_node = $kid;
2608 5254 100 66     11253 if ($self->is_list_newer($op)) {
    50 33        
    50 66        
    50 33        
    50 100        
    50 66        
    50 66        
    50 100        
    50 66        
    50 33        
2609 2611         7037 $node = $self->pp_list($op, $cx);
2610             } elsif ($kid->name eq "enter") {
2611 0         0 $node = $self->pp_leave($op, $cx);
2612             } elsif ($kid->name eq "leave") {
2613 0         0 $node = $self->pp_leave($kid, $cx);
2614             } elsif ($kid->name eq "scope") {
2615 0         0 $node = $self->pp_scope($kid, $cx);
2616             } elsif ($op->targ == B::Deparse::OP_STRINGIFY) {
2617             # This case is duplicated the below "else". Can it ever happen?
2618 0         0 $node = $self->dquote($op, $cx);
2619             } elsif ($op->targ == OP_GLOB) {
2620 0         0 my @other_ops = ($kid, $kid->first, $kid->first->first);
2621 0         0 my $info = $self->pp_glob(
2622             $kid # entersub
2623             ->first # ex-list
2624             ->first # pushmark
2625             ->sibling, # glob
2626             $cx
2627             );
2628             # FIXME: mark text.
2629 0         0 push @{$info->{other_ops}}, @other_ops;
  0         0  
2630 0         0 return $info;
2631             } elsif (!B::Deparse::null($kid->sibling) and
2632             $kid->sibling->name eq "readline" and
2633             $kid->sibling->flags & OPf_STACKED) {
2634 0         0 my $lhs = $self->deparse($kid, 7, $op);
2635 0         0 my $rhs = $self->deparse($kid->sibling, 7, $kid);
2636 0         0 $node = $self->info_from_template("null: readline = ", $op,
2637             "%c = %c", undef, [$lhs, $rhs],
2638             {maybe_parens => [$self, $cx, 7],
2639             prev_expr => $rhs});
2640             } elsif (!B::Deparse::null($kid->sibling) and
2641             $kid->sibling->name =~ /^transr?\z/ and
2642             $kid->sibling->flags & OPf_STACKED) {
2643 0         0 my $lhs = $self->deparse($kid, 20, $op);
2644 0         0 my $rhs = $self->deparse($kid->sibling, 20, $op);
2645 0         0 $node = $self->info_from_template("null: trans =~",$op,
2646             "%c =~ %c", undef, [$lhs, $rhs],
2647             { maybe_parens => [$self, $cx, 7],
2648             prev_expr => $rhs });
2649             } elsif ($op->flags & OPf_SPECIAL && $cx < 1 && !$op->targ) {
2650 0         0 my $kid_info = $self->deparse($kid, $cx, $op);
2651 0         0 $node = $self->info_from_template("null: do { }", $op,
2652             "do {\n%+%c\n%-}", undef, [$kid_info]);
2653             } elsif (!B::Deparse::null($kid->sibling) and
2654             $kid->sibling->name eq "null" and
2655             B::class($kid->sibling) eq "UNOP" and
2656             $kid->sibling->first->flags & OPf_STACKED and
2657             $kid->sibling->first->name eq "rcatline") {
2658 0         0 my $lhs = $self->deparse($kid, 18, $op);
2659 0         0 my $rhs = $self->deparse($kid->sibling, 18, $op);
2660 0         0 $node = $self->info_from_template("null: rcatline =",$op,
2661             "%c = %c", undef, [$lhs, $rhs],
2662             { maybe_parens => [$self, $cx, 20],
2663             prev_expr => $rhs });
2664             } else {
2665 2643         7600 my $node = $self->deparse($kid, $cx, $op);
2666 2643         10886 my $type = "null: " . $op->name;
2667 2643         8585 return $self->info_from_template($type, $op,
2668             "%c", undef, [$node]);
2669             }
2670 2611         6616 my $position = pushmark_position($node);
2671 2611 100       5204 if ($position) {
2672             $update_node =
2673             $self->info_from_string($kid->name, $kid,
2674             $node->{text},
2675 2556         16065 {position => $position});
2676             }
2677 2611         8262 $node->update_other_ops($update_node);
2678 2611         7032 return $node;
2679             }
2680 0         0 Carp::confess("unhandled condition in null");
2681             }
2682              
2683             sub pp_padsv {
2684 4400 50   4400 0 14383 $] >= 5.026 ? goto &pp_padsv_newer : goto &pp_padsv_older;
2685             }
2686              
2687             sub pp_padsv_newer {
2688 4400     4400 0 6233 my $self = shift;
2689 4400         6488 my($op, $cx, $forbid_parens) = @_;
2690 4400         11400 my $targ = $op->targ;
2691 4400         46511 return $self->maybe_my($op, $cx, $self->padname($targ),
2692             $self->padname_sv($targ),
2693             $forbid_parens);
2694             }
2695              
2696             sub pp_padsv_older
2697             {
2698 0     0 0 0 my ($self, $op, $cx, $forbid_parens) = @_;
2699 0         0 return $self->maybe_my($op, $cx, $self->padname($op->targ),
2700             $forbid_parens);
2701             }
2702              
2703             # This is the 5.26 version. It is different from earlier versions.
2704             # Is it compatable/
2705             #
2706             # 'x' is weird when the left arg is a list
2707             sub repeat {
2708 5     5 0 9 my $self = shift;
2709 5         13 my($op, $cx) = @_;
2710 5         21 my $left = $op->first;
2711 5         14 my $right = $op->last;
2712 5         12 my $eq = "";
2713 5         7 my $prec = 19;
2714 5         7 my @skipped_ops = ();
2715 5         6 my $left_fmt;
2716 5         9 my $type = "repeat";
2717 5         7 my @args_spec = ();
2718 5         7 my @exprs = ();
2719 5 50       16 if ($op->flags & OPf_STACKED) {
2720 0         0 $eq = "=";
2721 0         0 $prec = 7;
2722             }
2723              
2724 5 50       30 if (B::Deparse::null($right)) {
2725             # This branch occurs in 5.21.5 and earlier.
2726             # A list repeat; count is inside left-side ex-list
2727 0         0 $type = 'list repeat';
2728              
2729 0         0 my $kid = $left->first->sibling; # skip pushmark
2730 0         0 push @skipped_ops, $left->first, $kid;
2731 0         0 $self->deparse_op_siblings(\@exprs, $kid, $op, 6);
2732 0         0 $left_fmt = '(%C)';
2733 0         0 @args_spec = ([0, $#exprs, ', '], scalar(@exprs));
2734             } else {
2735 5         10 $type = 'repeat';
2736 5         27 my $dolist = $op->private & OPpREPEAT_DOLIST;
2737 5 100       20 push @exprs, $self->deparse_binop_left($op, $left, $dolist ? 1 : $prec);
2738 5         9 $left_fmt = '%c';
2739 5 100       17 if ($dolist) {
2740 1         2 $left_fmt = "(%c)";
2741             }
2742 5         14 @args_spec = (0, 1);
2743             }
2744 5         15 push @exprs, $self->deparse_binop_right($op, $right, $prec);
2745 5         11 my $opname = "x$eq";
2746 5         36 my $node = $self->info_from_template("$type $opname",
2747             $op, "$left_fmt $opname %c",
2748             \@args_spec,
2749             \@exprs,
2750             {maybe_parens => [$self, $cx, $prec],
2751             other_ops => \@skipped_ops});
2752              
2753 5 50       18 if (@skipped_ops) {
2754             # if we have skipped ops like pushmark, we will use the position
2755             # of the "x" as the part it represents.
2756 0         0 my @new_ops;
2757 0         0 my $str = $node->{text};
2758 0         0 my $right_text = "$opname " . $exprs[-1]->{text};
2759 0         0 my $start = rindex($str, $right_text);
2760 0         0 my $position;
2761 0 0       0 if ($start >= 0) {
2762 0         0 $position = [$start, length($opname)];
2763             } else {
2764 0         0 $position = [0, length($str)];
2765             }
2766 0         0 my @skipped_nodes;
2767 0         0 for my $skipped_op (@skipped_ops) {
2768 0         0 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
2769             {position => $position});
2770 0         0 push @new_ops, $new_op;
2771             }
2772 0         0 $node->{other_ops} = \@new_ops;
2773             }
2774              
2775 5         16 return $node;
2776             }
2777              
2778             sub stringify_older {
2779 0     0 0 0 maybe_targmy(@_, \&dquote)
2780             }
2781              
2782             # OP_STRINGIFY is a listop, but it only ever has one arg
2783             sub stringify_newer {
2784 0     0 0 0 my ($self, $op, $cx) = @_;
2785 0         0 my $kid = $op->first->sibling;
2786 0         0 my @other_ops = ();
2787 0   0     0 while ($kid->name eq 'null' && !B::Deparse::null($kid->first)) {
2788 0         0 push(@other_ops, $kid);
2789 0         0 $kid = $kid->first;
2790             }
2791 0         0 my $info;
2792 0 0       0 if ($kid->name =~ /^(?:const|padsv|rv2sv|av2arylen|gvsv|multideref
2793             |aelemfast(?:_lex)?|[ah]elem|join|concat)\z/x) {
2794 0         0 $info = maybe_targmy(@_, \&dquote);
2795             }
2796             else {
2797             # Actually an optimised join.
2798 0         0 my $info = listop(@_,"join");
2799 0         0 $info->{text} =~ s/join([( ])/join$1$self->{'ex_const'}, /;
2800             }
2801 0         0 push @{$info->{other_ops}}, @other_ops;
  0         0  
2802 0         0 return $info;
2803             }
2804              
2805             # Kind of silly, but we prefer, subst regexp flags joined together to
2806             # make words. For example: s/a/b/xo => s/a/b/ox
2807              
2808             # oxime -- any of various compounds obtained chiefly by the action of
2809             # hydroxylamine on aldehydes and ketones and characterized by the
2810             # bivalent grouping C=NOH [Webster's Tenth]
2811              
2812             my %substwords;
2813             map($substwords{join "", sort split //, $_} = $_, 'ego', 'egoism', 'em',
2814             'es', 'ex', 'exes', 'gee', 'go', 'goes', 'ie', 'ism', 'iso', 'me',
2815             'meese', 'meso', 'mig', 'mix', 'os', 'ox', 'oxime', 'see', 'seem',
2816             'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi', 'rogue',
2817             'sir', 'rise', 'smore', 'more', 'seer', 'rome', 'gore', 'grim', 'grime',
2818             'or', 'rose', 'rosie');
2819              
2820             # FIXME 522 and 526 could probably be combined or common parts pulled out.
2821             sub subst_older
2822             {
2823 0     0 0 0 my($self, $op, $cx) = @_;
2824 0         0 my $kid = $op->first;
2825 0         0 my($binop, $var, $re, @other_ops) = ("", "", "", ());
2826 0         0 my ($repl, $repl_info);
2827              
2828 0 0       0 if ($op->flags & OPf_STACKED) {
2829 0         0 $binop = 1;
2830 0         0 $var = $self->deparse($kid, 20, $op);
2831 0         0 $kid = $kid->sibling;
2832             }
2833 0         0 my $flags = "";
2834 0         0 my $pmflags = $op->pmflags;
2835 0 0       0 if (B::Deparse::null($op->pmreplroot)) {
2836 0         0 $repl = $kid;
2837 0         0 $kid = $kid->sibling;
2838             } else {
2839 0         0 push @other_ops, $op->pmreplroot;
2840 0         0 $repl = $op->pmreplroot->first; # skip substcont
2841             }
2842 0         0 while ($repl->name eq "entereval") {
2843 0         0 push @other_ops, $repl;
2844 0         0 $repl = $repl->first;
2845 0         0 $flags .= "e";
2846             }
2847             {
2848 0         0 local $self->{in_subst_repl} = 1;
  0         0  
2849 0 0       0 if ($pmflags & PMf_EVAL) {
2850 0         0 $repl_info = $self->deparse($repl->first, 0, $repl);
2851             } else {
2852 0         0 $repl_info = $self->dq($repl);
2853             }
2854             }
2855 0         0 my $extended = ($pmflags & PMf_EXTENDED);
2856 0 0       0 if (B::Deparse::null $kid) {
2857 0         0 my $unbacked = B::Deparse::re_unback($op->precomp);
2858 0 0       0 if ($extended) {
2859 0         0 $re = B::Deparse::re_uninterp_extended(escape_extended_re($unbacked));
2860             }
2861             else {
2862 0         0 $re = B::Deparse::re_uninterp(B::Deparse::escape_str($unbacked));
2863             }
2864             } else {
2865 0         0 my ($re_info, $junk) = $self->regcomp($kid, 1, $extended);
2866 0         0 $re = $re_info->{text};
2867             }
2868 0 0       0 $flags .= "r" if $pmflags & PMf_NONDESTRUCT;
2869 0 0       0 $flags .= "e" if $pmflags & PMf_EVAL;
2870 0         0 $flags .= $self->re_flags($op);
2871 0         0 $flags = join '', sort split //, $flags;
2872 0 0       0 $flags = $substwords{$flags} if $substwords{$flags};
2873 0         0 my $core_s = $self->keyword("s"); # maybe CORE::s
2874              
2875             # FIXME: we need to attach the $repl_info someplace.
2876 0         0 my $repl_text = $repl_info->{text};
2877 0         0 my $find_replace_re = double_delim($re, $repl_text);
2878 0         0 my $opts = {};
2879 0 0       0 $opts->{other_ops} = \@other_ops if @other_ops;
2880 0 0       0 if ($binop) {
2881 0         0 return $self->info_from_template("=~ s///", $op,
2882             "%c =~ ${core_s}%c$flags",
2883             undef,
2884             [$var, $find_replace_re],
2885             {maybe_parens => [$self, $cx, 20]});
2886             } else {
2887 0         0 return $self->info_from_string("s///", $op, "${core_s}${find_replace_re}$flags");
2888             }
2889 0         0 Carp::confess("unhandled condition in pp_subst");
2890             }
2891              
2892             sub slice
2893             {
2894 2     2 0 6 my ($self, $op, $cx, $left, $right, $regname, $padname) = @_;
2895 2         10 my $last;
2896 2         4 my(@elems, $kid, $array);
2897 2 50       42 if (B::class($op) eq "LISTOP") {
2898 2         12 $last = $op->last;
2899             } else {
2900             # ex-hslice inside delete()
2901 0         0 for ($kid = $op->first; !B::Deparse::null $kid->sibling; $kid = $kid->sibling) {
2902 0         0 $last = $kid;
2903             }
2904             }
2905 2         4 $array = $last;
2906 2 50 33     16 $array = $array->first
2907             if $array->name eq $regname or $array->name eq "null";
2908 2         10 my $array_info = $self->elem_or_slice_array_name($array, $left, $padname, 0);
2909 2         21 $kid = $op->first->sibling; # skip pushmark
2910              
2911 2 50       10 if ($kid->name eq "list") {
2912             # FIXME:
2913             # skip list, pushmark
2914 0         0 $kid = $kid->first->sibling;
2915 0         0 for (; !B::Deparse::null $kid; $kid = $kid->sibling) {
2916 0         0 push @elems, $self->deparse($kid, 6, $op);
2917             }
2918             } else {
2919 2         7 @elems = ($self->elem_or_slice_single_index($kid, $op));
2920             }
2921 2         5 my $lead = '@';
2922 2 50       18 $lead = '%' if $op->name =~ /^kv/i;
2923 2         7 my ($fmt, $args_spec);
2924 2         0 my (@texts, $type);
2925 2 50       5 if ($array_info) {
2926 2         5 unshift @elems, $array_info;
2927 2         4 $fmt = "${lead}%c$left%C$right";
2928 2         5 $args_spec = [0, [1, $#elems, ', ']];
2929 2         4 $type = "$lead$left .. $right";
2930             } else {
2931 0         0 $fmt = "${lead}$left%C$right";
2932 0         0 $args_spec = [0, $#elems, ', '];
2933 0         0 $type = "${lead}$left .. $right";
2934             }
2935 2         8 return $self->info_from_template($type, $op, $fmt, $args_spec,
2936             \@elems),
2937             }
2938              
2939             sub split
2940             {
2941 0     0 0 0 my($self, $op, $cx) = @_;
2942 0         0 my($kid, @exprs, $ary_info, $expr);
2943 0         0 my $ary = '';
2944 0         0 my @body = ();
2945 0         0 my @other_ops = ();
2946 0         0 $kid = $op->first;
2947              
2948             # For our kid (an OP_PUSHRE), pmreplroot is never actually the
2949             # root of a replacement; it's either empty, or abused to point to
2950             # the GV for an array we split into (an optimization to save
2951             # assignment overhead). Depending on whether we're using ithreads,
2952             # this OP* holds either a GV* or a PADOFFSET. Luckily, B.xs
2953             # figures out for us which it is.
2954 0         0 my $replroot = $kid->pmreplroot;
2955 0         0 my $gv = 0;
2956 0         0 my $stacked = $op->flags & OPf_STACKED;
2957 0 0 0     0 if (ref($replroot) eq "B::GV") {
    0          
    0          
    0          
2958 0         0 $gv = $replroot;
2959             } elsif (!ref($replroot) and $replroot > 0) {
2960 0         0 $gv = $self->padval($replroot);
2961             } elsif ($kid->targ) {
2962 0         0 $ary = $self->padname($kid->targ)
2963             } elsif ($stacked) {
2964 0         0 $ary_info = $self->deparse($op->last, 7, $op);
2965 0         0 push @body, $ary_info;
2966 0         0 $ary = $ary_info->{text};
2967             }
2968 0 0       0 $ary_info = $self->maybe_local(@_,
2969             $self->stash_variable('@',
2970             $self->gv_name($gv),
2971             $cx))
2972             if $gv;
2973              
2974             # Skip the last kid when OPf_STACKED is set, since it is the array
2975             # on the left.
2976 0 0       0 for (; !B::Deparse::null($stacked ? $kid->sibling : $kid);
2977             $kid = $kid->sibling) {
2978 0         0 push @exprs, $self->deparse($kid, 6, $op);
2979             }
2980              
2981 0         0 my $opts = {body => \@exprs};
2982              
2983 0         0 my @args_texts = map $_->{text}, @exprs;
2984             # handle special case of split(), and split(' ') that compiles to /\s+/
2985             # Under 5.10, the reflags may be undef if the split regexp isn't a constant
2986             # Under 5.17.5-5.17.9, the special flag is on split itself.
2987 0         0 $kid = $op->first;
2988 0 0       0 if ( $op->flags & OPf_SPECIAL ) {
2989 0         0 $exprs[0]->{text} = "' '";
2990             }
2991              
2992 0         0 my $sep = '';
2993 0         0 my $type;
2994             my @expr_texts;
2995 0 0       0 if ($ary) {
2996 0         0 @expr_texts = ("$ary", '=', join(', ', @args_texts));
2997 0         0 $sep = ' ';
2998 0         0 $type = 'split_array';
2999 0         0 $opts->{maybe_parens} = [$self, $cx, 7];
3000             } else {
3001 0         0 @expr_texts = ('split', '(', join(', ', @args_texts), ')');
3002 0         0 $type = 'split';
3003              
3004             }
3005 0         0 return info_from_list($op, $self, \@expr_texts, $sep, $type, $opts);
3006             }
3007              
3008             sub subst_newer
3009             {
3010 18     18 0 31 my($self, $op, $cx) = @_;
3011 18         62 my $kid = $op->first;
3012 18         32 my($binop, $var, $re, @other_ops) = ("", "", "", ());
3013 18         22 my ($repl, $repl_info);
3014              
3015 18 50       73 if ($op->flags & OPf_STACKED) {
    50          
3016 0         0 $binop = 1;
3017 0         0 $var = $self->deparse($kid, 20, $op);
3018 0         0 $kid = $kid->sibling;
3019             }
3020             elsif (my $targ = $op->targ) {
3021 0         0 $binop = 1;
3022 0         0 $var = $self->padname($targ);
3023             }
3024 18         29 my $flags = "";
3025 18         39 my $pmflags = $op->pmflags;
3026 18 100       116 if (B::Deparse::null($op->pmreplroot)) {
3027 14         25 $repl = $kid;
3028 14         41 $kid = $kid->sibling;
3029             } else {
3030 4         12 push @other_ops, $op->pmreplroot;
3031 4         22 $repl = $op->pmreplroot->first; # skip substcont
3032             }
3033 18         63 while ($repl->name eq "entereval") {
3034 0         0 push @other_ops, $repl;
3035 0         0 $repl = $repl->first;
3036 0         0 $flags .= "e";
3037             }
3038             {
3039 18         24 local $self->{in_subst_repl} = 1;
  18         40  
3040 18 100       33 if ($pmflags & PMf_EVAL) {
3041 4         18 $repl_info = $self->deparse($repl->first, 0, $repl);
3042             } else {
3043 14         33 $repl_info = $self->dq($repl);
3044             }
3045             }
3046 18 50       195 if (not B::Deparse::null my $code_list = $op->code_list) {
    50          
3047 0         0 $re = $self->code_list($code_list);
3048             } elsif (B::Deparse::null $kid) {
3049 18         1444 $re = B::Deparse::re_uninterp(B::Deparse::escape_re(B::Deparse::re_unback($op->precomp)));
3050             } else {
3051 0         0 my ($re_info, $junk) = $self->regcomp($kid, 1);
3052 0         0 $re = $re_info->{text};
3053             }
3054 18 100       77 $flags .= "r" if $pmflags & PMf_NONDESTRUCT;
3055 18 100       38 $flags .= "e" if $pmflags & PMf_EVAL;
3056 18         185 $flags .= $self->re_flags($op);
3057 18         62 $flags = join '', sort split //, $flags;
3058 18 50       49 $flags = $substwords{$flags} if $substwords{$flags};
3059 18         2016 my $core_s = $self->keyword("s"); # maybe CORE::s
3060              
3061             # FIXME: we need to attach the $repl_info someplace.
3062 18         45 my $repl_text = $repl_info->{text};
3063 18 100       39 my $opts->{other_ops} = \@other_ops if @other_ops;
3064 18         83 my $find_replace_re = double_delim($re, $repl_text);
3065              
3066 18 50       49 if ($binop) {
3067 0         0 return $self->info_from_template("=~ s///", $op,
3068             "%c =~ ${core_s}%c$flags",
3069             undef,
3070             [$var, $find_replace_re],
3071             {maybe_parens => [$self, $cx, 20]});
3072             } else {
3073 18         68 return $self->info_from_string("s///", $op, "${core_s}${find_replace_re}$flags");
3074             }
3075 0         0 Carp::confess("unhandled condition in pp_subst");
3076             }
3077              
3078             # This handles the category of unary operators, e.g. alarm(), caller(),
3079             # close()..
3080             sub unop
3081             {
3082 291     291 0 884 my($self, $op, $cx, $name, $nollafr) = @_;
3083 291         407 my $kid;
3084 291         536 my $opts = {};
3085 291 100       1182 if ($op->flags & B::OPf_KIDS) {
3086 231         351 my $parent = $op;
3087 231         816 $kid = $op->first;
3088 231 50       591 if (not $name) {
3089             # this deals with 'boolkeys' right now
3090 0         0 my $kid_node = $self->deparse($kid, $cx, $parent);
3091 0         0 $opts->{prev_expr} = $kid_node;
3092 0         0 return $self->info_from_template("unop, see child", $op, "%c",
3093             undef, [$kid_node], $opts);
3094             }
3095 231         393 my $builtinname = $name;
3096 231 50       684 $builtinname =~ /^CORE::/ or $builtinname = "CORE::$name";
3097 231 100 100     4035 if (defined prototype($builtinname)
      100        
      66        
3098             && $builtinname ne 'CORE::readline'
3099             && prototype($builtinname) =~ /^;?\*/
3100             && $kid->name eq "rv2gv") {
3101 24         58 my $rv2gv = $kid;
3102 24         38 $parent = $rv2gv;
3103 24         88 $kid = $kid->first;
3104 24         101 $opts->{other_ops} = [$rv2gv];
3105             }
3106              
3107 231 100       614 if ($nollafr) {
3108 5         18 $kid = $self->deparse($kid, 16, $parent);
3109 5         115 $opts->{maybe_parens} = [$self, $cx, 16],
3110             my $fullname = $self->keyword($name);
3111 5         39 return $self->info_from_template("unary operator $name noallafr", $op,
3112             "$fullname %c", undef, [$kid], $opts);
3113             }
3114 226         816 return $self->maybe_parens_unop($name, $kid, $cx, $parent, $opts)
3115              
3116             } else {
3117 60         287 $opts->{maybe_parens} = [$self, $cx, 16];
3118 60         2448 my $fullname = ($self->keyword($name));
3119 60         168 my $fmt = "$fullname";
3120 60 100       244 $fmt .= '()' if $op->flags & B::OPf_SPECIAL;
3121 60         355 return $self->info_from_template("unary operator $name", $op, $fmt,
3122             undef, [], $opts);
3123             }
3124             }
3125              
3126             # This handles category of symbolic prefix and postfix unary operators,
3127             # e.g $x++, -r, +$x.
3128             sub pfixop
3129             {
3130 6     6 0 10 my $self = shift;
3131 6         17 my($op, $cx, $operator, $prec, $flags) = (@_, 0);
3132 6         32 my $operand = $self->deparse($op->first, $prec, $op);
3133 6         17 my ($type, $fmt);
3134 6         0 my @nodes;
3135 6 50 66     28 if ($flags & POSTFIX) {
    50          
3136 0         0 @nodes = ($operand, $operator);
3137 0         0 $type = "prefix $operator";
3138 0         0 $fmt = "%c%c";
3139             } elsif ($operator eq '-' && $operand->{text} =~ /^[a-zA-Z](?!\w)/) {
3140             # Add () around operator to disambiguate with filetest operator
3141 0         0 @nodes = ($operator, $operand);
3142 0         0 $type = "prefix non-filetest $operator";
3143 0         0 $fmt = "%c(%c)";
3144             } else {
3145 6         11 @nodes = ($operator, $operand);
3146 6         23 $type = "postfix $operator";
3147 6         13 $fmt = "%c%c";
3148             }
3149              
3150 6         29 return $self->info_from_template($type, $op, $fmt, [0, 1],
3151             \@nodes,
3152             {maybe_parens => [$self, $cx, $prec]}) ;
3153             }
3154              
3155             # Produce an node for a range (".." or "..." op)
3156             sub range {
3157 0     0 0 0 my $self = shift;
3158 0         0 my ($op, $cx, $type) = @_;
3159 0         0 my $left = $op->first;
3160 0         0 my $right = $left->sibling;
3161 0         0 $left = $self->deparse($left, 9, $op);
3162 0         0 $right = $self->deparse($right, 9, $op);
3163 0         0 return $self->info_from_template("range $type", $op, "%c${type}%c",
3164             undef, [$left, $right],
3165             {maybe_parens => [$self, $cx, 9]});
3166             }
3167              
3168             sub rv2x
3169             {
3170 75     75 0 148 my($self, $op, $cx, $sigil) = @_;
3171 75 50 33     515 if (B::class($op) eq 'NULL' || !$op->can("first")) {
3172 0         0 carp("Unexpected op in pp_rv2x");
3173 0         0 return info_from_text($op, $self, 'XXX', 'bad_rv2x', {});
3174             }
3175 75         129 my ($info, $kid_info);
3176 75         214 my $kid = $op->first;
3177 75         165 $kid_info = $self->deparse($kid, 0, $op);
3178 75 50       296 if ($kid->name eq "gv") {
    0          
3179 75     850   383 my $transform_fn = sub {$self->stash_variable($sigil, $self->info2str(shift), $cx)};
  850         1640  
3180 75         326 return $self->info_from_template("rv2x $sigil", undef, "%F", [[0, $transform_fn]], [$kid_info])
3181             } elsif (B::Deparse::is_scalar $kid) {
3182 0         0 my $str = $self->info2str($kid_info);
3183 0         0 my $fmt = '%c';
3184 0         0 my @args_spec = (0);
3185 0 0       0 if ($str =~ /^\$([^\w\d])\z/) {
3186             # "$$+" isn't a legal way to write the scalar dereference
3187             # of $+, since the lexer can't tell you aren't trying to
3188             # do something like "$$ + 1" to get one more than your
3189             # PID. Either "${$+}" or "$${+}" are workable
3190             # disambiguations, but if the programmer did the former,
3191             # they'd be in the "else" clause below rather than here.
3192             # It's not clear if this should somehow be unified with
3193             # the code in dq and re_dq that also adds lexer
3194             # disambiguation braces.
3195 0     0   0 my $transform = sub { $_[0] =~ /^\$([^\w\d])\z/; '$' . "{$1}"};
  0         0  
  0         0  
3196 0         0 $fmt = '%F';
3197 0         0 @args_spec = (0, $transform);
3198             }
3199 0         0 return $self->info_from_template("scalar $str", $op, $fmt, undef, \@args_spec, {});
3200             } else {
3201 0         0 my $fmt = "$sigil\{%c\}";
3202 0         0 my $type = "rv2x: $sigil\{}";
3203 0         0 return $self->info_from_template($type, $op, $fmt, undef, [$kid_info]);
3204             }
3205 0         0 Carp::confess("unhandled condition in rv2x");
3206             }
3207              
3208             # Handle ops that can introduce blocks or scope. "while", "do", "until", and
3209             # possibly "map", and "grep" are examples such things.
3210             sub scopeop
3211             {
3212 12     12 0 23 my($real_block, $self, $op, $cx) = @_;
3213 12         17 my $kid;
3214             my @kids;
3215              
3216             local(@$self{qw'curstash warnings hints hinthash'})
3217 12 100       43 = @$self{qw'curstash warnings hints hinthash'} if $real_block;
3218 12         21 my @other_ops = ();
3219 12 100       22 if ($real_block) {
3220 7         21 push @other_ops, $op->first;
3221 7         27 $kid = $op->first->sibling; # skip enter
3222 7 50       88 if (B::Deparse::is_miniwhile($kid)) {
3223 0         0 my $top = $kid->first;
3224 0         0 my $name = $top->name;
3225 0 0       0 if ($name eq "and") {
    0          
3226 0         0 $name = $self->keyword("while");
3227             } elsif ($name eq "or") {
3228 0         0 $name = $self->keyword("until");
3229             } else { # no conditional -> while 1 or until 0
3230 0         0 my $body = $self->deparse($top->first, 1, $top);
3231 0         0 return $self->info_from_template("scopeop: $name 1", $op,
3232             "%c while 1", undef, [$body],
3233             {other_ops => \@other_ops});
3234             }
3235 0         0 my $cond = $top->first;
3236 0         0 push @other_ops, $cond->sibling;
3237 0         0 my $body = $cond->sibling->first; # skip lineseq
3238 0         0 my $cond_info = $self->deparse($cond, 1, $top);
3239 0         0 my $body_info = $self->deparse($body, 1, $top);
3240 0         0 return $self->info_from_template("scopeop: $name",
3241             $op,"%c $name %c",
3242             undef, [$body_info, $cond_info],
3243             {other_ops => \@other_ops});
3244             }
3245             } else {
3246 5         20 $kid = $op->first;
3247             }
3248 12         67 for (; !B::Deparse::null($kid); $kid = $kid->sibling) {
3249 27         153 push @kids, $kid;
3250             }
3251 12         22 my $node;
3252 12 50       27 if ($cx > 0) {
3253             # inside an expression, (a do {} while for lineseq)
3254 0         0 my $body = $self->lineseq($op, 0, @kids);
3255 0         0 my $text;
3256 0 0       0 if (is_lexical_subs(@kids)) {
3257 0         0 $node = $self->info_from_template("scoped expression", $op,
3258             '%c',[0], [$body]);
3259             } else {
3260 0         0 $node = $self->info_from_template("scoped do", $op,
3261             "do {\n%+%c\n%-}",
3262             [0], [$body]);
3263             }
3264             } else {
3265 12         32 $node = $self->lineseq($op, $cx, @kids);
3266             }
3267 12 100       42 $node->{other_ops} = \@other_ops if @other_ops;
3268 12         50 return $node;
3269             }
3270              
3271             sub single_delim($$$$$)
3272             {
3273 31     31 0 82 my($self, $op, $q, $default, $str) = @_;
3274              
3275 31 50 33     295 return $self->info_from_template("string $default .. $default (default)", $op,
3276             "$default%c$default", [0],
3277             [$str])
3278             if $default and index($str, $default) == -1;
3279 0           my $coreq = $self->keyword($q); # maybe CORE::q
3280 0 0         if ($q ne 'qr') {
3281 0           (my $succeed, $str) = balanced_delim($str);
3282 0 0         return $self->info_from_string("string $q", $op, "$coreq$str")
3283             if $succeed;
3284             }
3285 0           for my $delim ('/', '"', '#') {
3286 0 0         $self->info_from_string("string $q $delim$delim", $op, "qr$delim$str$delim")
3287             if index($str, $delim) == -1;
3288             }
3289 0 0         if ($default) {
3290             my $transform_fn = sub {
3291 0     0     s/$_[0]/\\$_[0]/g;
3292 0           return $_[0];
3293 0           };
3294              
3295 0           return $self->info_from_template("string $q $default$default",
3296             $op, "$default%F$default",
3297             [[0, $transform_fn]], [$str]);
3298             } else {
3299             my $transform_fn = sub {
3300 0     0     $_[0] =~ s[/][\\/]g;
3301 0           return $_[0];
3302 0           };
3303 0           return $self->info_from_template("string $q //",
3304             $op, "$coreq/%F/",
3305             [[0, $transform_fn]], [$str]);
3306             }
3307             }
3308              
3309             # Demo code
3310             unless(caller) {
3311             ;
3312             }
3313              
3314             1;