File Coverage

lib/B/DeparseTree/P526.pm
Criterion Covered Total %
statement 149 355 41.9
branch 65 204 31.8
condition 23 104 22.1
subroutine 28 37 75.6
pod 0 16 0.0
total 265 716 37.0


line stmt bran cond sub pod time code
1             # B::DeparseTree::P526.pm
2             # Copyright (c) 1998-2000, 2002, 2003, 2004, 2005, 2006 Stephen McCamant.
3             # Copyright (c) 2015, 2017, 2018 Rocky Bernstein
4             # All rights reserved.
5             # This module is free software; you can redistribute and/or modify
6             # it under the same terms as Perl itself.
7              
8             # This is based on the module B::Deparse (for perl 5.22) by Stephen McCamant.
9             # It has been extended save tree structure, and is addressible
10             # by opcode address.
11              
12             # B::Parse in turn is based on the module of the same name by Malcolm Beattie,
13             # but essentially none of his code remains.
14              
15 8     8   113 use v5.26;
  8         53  
16              
17 8     8   42 use rlib '../..';
  8         15  
  8         61  
18              
19             package B::DeparseTree::P526;
20 8     8   2697 use Carp;
  8         18  
  8         933  
21              
22 8         1855 use B qw(
23             CVf_METHOD
24             MDEREF_ACTION_MASK
25             MDEREF_AV_gvav_aelem
26             MDEREF_AV_gvsv_vivify_rv2av_aelem
27             MDEREF_AV_padav_aelem
28             MDEREF_AV_padsv_vivify_rv2av_aelem
29             MDEREF_AV_pop_rv2av_aelem
30             MDEREF_AV_vivify_rv2av_aelem
31             MDEREF_FLAG_last
32             MDEREF_HV_gvhv_helem
33             MDEREF_HV_gvsv_vivify_rv2hv_helem
34             MDEREF_HV_padhv_helem
35             MDEREF_HV_padsv_vivify_rv2hv_helem
36             MDEREF_HV_pop_rv2hv_helem
37             MDEREF_HV_vivify_rv2hv_helem
38             MDEREF_INDEX_MASK
39             MDEREF_INDEX_const
40             MDEREF_INDEX_gvsv
41             MDEREF_INDEX_none
42             MDEREF_INDEX_padsv
43             MDEREF_MASK
44             MDEREF_SHIFT
45             MDEREF_reload
46             OPf_KIDS
47             OPf_MOD
48             OPf_PARENS
49             OPf_REF
50             OPf_SPECIAL
51             OPf_STACKED
52             OPf_WANT
53             OPf_WANT_LIST
54             OPf_WANT_SCALAR
55             OPf_WANT_VOID
56             OPpCONST_BARE
57             OPpENTERSUB_AMPER
58             OPpEXISTS_SUB
59             OPpLVAL_INTRO
60             OPpMULTIDEREF_DELETE
61             OPpMULTIDEREF_EXISTS
62             OPpOUR_INTRO
63             OPpPADRANGE_COUNTSHIFT
64             OPpSLICE
65             OPpSORT_INTEGER
66             OPpSORT_NUMERIC
67             OPpSORT_REVERSE
68             OPpSPLIT_ASSIGN OPpSPLIT_LEX
69             OPpTARGET_MY
70             PADNAMEt_OUTER
71             PMf_CONTINUE
72             PMf_EVAL
73             PMf_EXTENDED
74             PMf_EXTENDED_MORE
75             PMf_FOLD
76             PMf_GLOBAL
77             PMf_KEEP
78             PMf_MULTILINE
79             PMf_ONCE
80             PMf_SINGLELINE
81             SVf_FAKE
82             SVf_ROK SVpad_OUR
83             SVpad_TYPED
84             SVs_RMG
85             SVs_SMG
86             class
87             main_cv
88             main_root
89             main_start
90             opnumber
91             perlstring
92             svref_2object
93 8     8   99 );
  8         16  
94              
95 8     8   4702 use B::DeparseTree::PPfns;
  8         28  
  8         2665  
96 8     8   66 use B::DeparseTree::SyntaxTree;
  8         18  
  8         700  
97 8     8   3972 use B::DeparseTree::PP;
  8         27  
  8         2739  
98 8     8   53 use B::Deparse;
  8         11  
  8         1311  
99              
100             # Copy unchanged functions from B::Deparse
101             *begin_is_use = *B::Deparse::begin_is_use;
102             *const_sv = *B::Deparse::const_sv;
103             *escape_re = *B::Deparse::escape_re;
104             *find_scope_st = *B::Deparse::find_scope_st;
105             *gv_name = *B::Deparse::gv_name;
106             *keyword = *B::Deparse::keyword;
107             *meth_pad_subs = *B::Deparse::pad_subs;
108             *meth_rclass_sv = *B::Deparse::meth_rclass_sv;
109             *meth_sv = *B::Deparse::meth_sv;
110             *padany = *B::Deparse::padany;
111             *padname = *B::Deparse::padname;
112             *padname_sv = *B::Deparse::padname_sv;
113             *padval = *B::Deparse::padval;
114             *re_flags = *B::Deparse::re_flags;
115             *stash_variable = *B::Deparse::stash_variable;
116             *stash_variable_name = *B::Deparse::stash_variable_name;
117             *tr_chr = *B::Deparse::tr_chr;
118              
119 8     8   66 use strict;
  8         13  
  8         197  
120 8     8   49 use vars qw/$AUTOLOAD/;
  8         13  
  8         330  
121 8     8   47 use warnings ();
  8         13  
  8         800  
122             require feature;
123              
124             our(@EXPORT, @ISA);
125             our $VERSION = '3.2.0';
126              
127             @ISA = qw(B::DeparseTree::PP);
128              
129             @EXPORT = qw(slice);
130              
131             BEGIN {
132             # List version-specific constants here.
133             # Easiest way to keep this code portable between version looks to
134             # be to fake up a dummy constant that will never actually be true.
135 8     8   34 foreach (qw(OPpSORT_INPLACE OPpSORT_DESCEND OPpITER_REVERSED OPpCONST_NOVER
136             OPpPAD_STATE PMf_SKIPWHITE RXf_SKIPWHITE
137             PMf_CHARSET PMf_KEEPCOPY PMf_NOCAPTURE CVf_ANONCONST
138             CVf_LOCKED OPpREVERSE_INPLACE OPpSUBSTR_REPL_FIRST
139             PMf_NONDESTRUCT OPpCONST_ARYBASE OPpEVAL_BYTES
140             OPpLVREF_TYPE OPpLVREF_SV OPpLVREF_AV OPpLVREF_HV
141             OPpLVREF_CV OPpLVREF_ELEM SVpad_STATE)) {
142 192         265 eval { B->import($_) };
  192         8790  
143 8     8   44 no strict 'refs';
  8         13  
  8         554  
144 192 100       320 *{$_} = sub () {0} unless *{$_}{CODE};
  24         97  
  192         1588  
145             }
146             }
147              
148 8     8   38 BEGIN { for (qw[ rv2sv aelem
149             rv2av rv2hv helem custom ]) {
150 48         2837 eval "sub OP_\U$_ () { " . opnumber($_) . "}"
151             }}
152              
153             # pp_padany -- does not exist after parsing
154              
155             sub AUTOLOAD {
156 0 0   0   0 if ($AUTOLOAD =~ s/^.*::pp_//) {
157 0         0 warn "unexpected OP_".uc $AUTOLOAD;
158 0 0       0 ($_[1]->type == OP_CUSTOM ? "CUSTOM ($AUTOLOAD)" : uc $AUTOLOAD);
159 0         0 return "XXX";
160             } else {
161 0         0 Carp::confess "Undefined subroutine $AUTOLOAD called";
162             }
163             }
164              
165       0     sub DESTROY {} # Do not AUTOLOAD
166              
167             # The BEGIN {} is used here because otherwise this code isn't executed
168             # when you run B::Deparse on itself.
169             my %globalnames;
170 8     8   292 BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
171             "ENV", "ARGV", "ARGVOUT", "_"); }
172              
173 8     8   54 { no strict 'refs'; *{"pp_r$_"} = *{"pp_$_"} for qw< keys each values >; }
  8         19  
  8         32900  
174              
175             # FIXME:
176             # Different in 5.20. Go over differences to see if okay in 5.20.
177             sub pp_chdir {
178 0     0 0 0 my ($self, $op, $cx) = @_;
179 0 0       0 if (($op->flags & (OPf_SPECIAL|OPf_KIDS)) == (OPf_SPECIAL|OPf_KIDS)) {
180 0         0 my $kw = $self->keyword("chdir");
181 0         0 my $kid = $self->const_sv($op->first)->PV;
182             my $code = $kw
183 0 0 0     0 . ($cx >= 16 || $self->{'parens'} ? "($kid)" : " $kid");
184 0     0   0 maybe_targmy(@_, sub { $_[3] }, $code);
  0         0  
185             } else {
186 0         0 maybe_targmy(@_, \&unop, "chdir")
187             }
188             }
189              
190             my @threadsv_names = B::threadsv_names;
191             sub pp_threadsv {
192 0     0 0 0 my $self = shift;
193 0         0 my($op, $cx) = @_;
194 0         0 return $self->maybe_local_str($op, $cx, "\$" . $threadsv_names[$op->targ]);
195             }
196              
197 0     0 0 0 sub pp_rv2sv { maybe_local_str(@_, rv2x(@_, "\$")) }
198 4     4 0 16 sub pp_rv2hv { maybe_local_str(@_, rv2x(@_, "%")) }
199 6     6 0 19 sub pp_rv2gv { maybe_local_str(@_, rv2x(@_, "*")) }
200              
201             # skip rv2av
202             sub pp_av2arylen {
203 32     32 0 69 my $self = shift;
204 32         71 my($op, $cx) = @_;
205 32 50       240 if ($op->first->name eq "padav") {
206 0         0 return $self->maybe_local_str($op, $cx, '$#' . $self->padany($op->first));
207             } else {
208 32         201 return $self->maybe_local_str($op, $cx,
209             $self->rv2x($op->first, $cx, '$#'));
210             }
211             }
212              
213             sub list_const($$$) {
214 0     0 0 0 my $self = shift;
215 0         0 my($op, $cx, @list) = @_;
216 0         0 my @a = map $self->const($_, 6), @list;
217 0         0 my @texts = $self->map_texts(\@a);
218 0         0 my $type = 'list_const';
219 0         0 my $prec = 6;
220 0 0 0     0 if (@texts == 0) {
    0          
    0          
221 0         0 return info_from_list($op, $self, ['(', ')'], '', 'list_const_null', {});
222             } elsif (@texts == 1) {
223 0         0 return info_from_text($op, $self, $texts[0], 'list_const_one',
224             {body => \@a});
225             } elsif ( @texts > 2 and !grep(!/^-?\d+$/, @texts)) {
226             # collapse (-1,0,1,2) into (-1..2)
227 0         0 my ($s, $e) = @texts[0,-1];
228 0         0 my $i = $s;
229 0 0       0 unless (grep $i++ != $_, @texts) {
230 0         0 @texts = ($s, '..', $e);
231 0         0 $type = 'list_const_range';
232 0         0 $prec = 9;
233             }
234             }
235 0         0 return info_from_list($op, $self, \@texts, '', $type,
236             {maybe_parens => [$self, $cx, $prec]});
237             }
238              
239             sub pp_rv2av {
240 33     33 0 75 my $self = shift;
241 33         85 my($op, $cx) = @_;
242 33         141 my $kid = $op->first;
243 33 50       155 if ($kid->name eq "const") { # constant list
244 0         0 my $av = $self->const_sv($kid);
245 0         0 return $self->list_const($kid, $cx, $av->ARRAY);
246             } else {
247 33         173 return $self->maybe_local_str($op, $cx,
248             $self->rv2x($op, $cx, "\@"));
249             }
250             }
251              
252             sub elem_or_slice_array_name
253             {
254 3     3 0 6 my $self = shift;
255 3         13 my ($array, $left, $padname, $allow_arrow) = @_;
256              
257 3 50 0     16 if ($array->name eq $padname) {
    0          
    0          
    0          
258 3         39 return $self->padany($array);
259             } elsif (B::Deparse::is_scope($array)) { # ${expr}[0]
260 0         0 return "{" . $self->deparse($array, 0) . "}";
261             } elsif ($array->name eq "gv") {
262 0 0       0 ($array, my $quoted) =
263             $self->stash_variable_name(
264             $left eq '[' ? '@' : '%', $self->gv_or_padgv($array)
265             );
266 0 0 0     0 if (!$allow_arrow && $quoted) {
267             # This cannot happen.
268 0         0 die "Invalid variable name $array for slice";
269             }
270 0 0       0 return $quoted ? "$array->" : $array;
271             } elsif (!$allow_arrow || B::Deparse::is_scalar $array) {
272             # $x[0], $$x[0], ...
273 0         0 return $self->deparse($array, 24)->{text};
274             } else {
275 0         0 return undef;
276             }
277             }
278              
279             sub elem_or_slice_single_index($$)
280             {
281 3     3 0 7 my ($self, $idx, $parent) = @_;
282              
283 3         10 my $idx_info = $self->deparse($idx, 1, $parent);
284 3         7 my $idx_str = $idx_info->{text};
285              
286             # Outer parens in an array index will confuse perl
287             # if we're interpolating in a regular expression, i.e.
288             # /$x$foo[(-1)]/ is *not* the same as /$x$foo[-1]/
289             #
290             # If $self->{parens}, then an initial '(' will
291             # definitely be paired with a final ')'. If
292             # !$self->{parens}, the misleading parens won't
293             # have been added in the first place.
294             #
295             # [You might think that we could get "(...)...(...)"
296             # where the initial and final parens do not match
297             # each other. But we can't, because the above would
298             # only happen if there's an infix binop between the
299             # two pairs of parens, and *that* means that the whole
300             # expression would be parenthesized as well.]
301             #
302 3 50       7 $idx_str =~ s/^\((.*)\)$/$1/ if $self->{'parens'};
303              
304             # Hash-element braces will autoquote a bareword inside themselves.
305             # We need to make sure that C<$hash{warn()}> doesn't come out as
306             # C<$hash{warn}>, which has a quite different meaning. Currently
307             # B::Deparse will always quote strings, even if the string was a
308             # bareword in the original (i.e. the OPpCONST_BARE flag is ignored
309             # for constant strings.) So we can cheat slightly here - if we see
310             # a bareword, we know that it is supposed to be a function call.
311             #
312 3         15 $idx_str =~ s/^([A-Za-z_]\w*)$/$1()/;
313              
314 3         15 return info_from_text($idx_info->{op}, $self, $idx_str,
315             'elem_or_slice_single_index',
316             {body => [$idx_info]});
317             }
318              
319             sub elem
320             {
321 0     0   0 my ($self, $op, $cx, $left, $right, $padname) = @_;
322 0         0 my($array, $idx) = ($op->first, $op->first->sibling);
323              
324 0         0 my $idx_info = $self->elem_or_slice_single_index($idx, $op);
325 0         0 my $opts = {body => [$idx_info]};
326              
327 0 0       0 unless ($array->name eq $padname) { # Maybe this has been fixed
328 0         0 $opts->{other_ops} = [$array];
329 0         0 $array = $array->first; # skip rv2av (or ex-rv2av in _53+)
330             }
331 0         0 my @texts = ();
332 0         0 my $info;
333 0         0 my $array_name=$self->elem_or_slice_array_name($array, $left, $padname, 1);
334 0 0       0 if ($array_name) {
335 0 0       0 if ($array_name !~ /->\z/) {
336 0 0       0 if ($array_name eq '#') {
337 0         0 $array_name = '${#}';
338             } else {
339 0         0 $array_name = '$' . $array_name ;
340             }
341             }
342 0         0 push @texts, $array_name;
343 0 0       0 push @texts, $left if $left;
344 0         0 push @texts, $idx_info->{text}, $right;
345 0         0 return info_from_list($op, $self, \@texts, '', 'elem', $opts)
346             } else {
347             # $x[20][3]{hi} or expr->[20]
348 0         0 my $type;
349 0         0 my $array_info = $self->deparse($array, 24, $op);
350 0         0 push @{$info->{body}}, $array_info;
  0         0  
351 0         0 @texts = ($array_info->{text});
352 0 0       0 if (B::Deparse::is_subscriptable($array)) {
353 0         0 push @texts, $left, $idx_info->{text}, $right;
354 0         0 $type = 'elem_no_arrow';
355             } else {
356 0         0 push @texts, '->', $left, $idx_info->{text}, $right;
357 0         0 $type = 'elem_arrow';
358             }
359 0         0 return info_from_list($op, $self, \@texts, '', $type, $opts);
360             }
361 0         0 Carp::confess("unhandled condition in elem");
362             }
363              
364             # a simplified version of elem_or_slice_array_name()
365             # for the use of pp_multideref
366              
367             sub multideref_var_name($$$)
368             {
369 7     7 0 17 my ($self, $gv, $is_hash) = @_;
370              
371 7 100       157 my ($name, $quoted) =
372             $self->stash_variable_name( $is_hash ? '%' : '@', $gv);
373 7 100       64 return $quoted ? "$name->"
    50          
374             : $name eq '#'
375             ? '${#}' # avoid ${#}[1] => $#[1]
376             : '$' . $name;
377             }
378              
379             sub pp_multideref
380             {
381 9     9 0 22 my($self, $op, $cx) = @_;
382 9         19 my @texts = ();
383              
384 9 100       67 if ($op->private & OPpMULTIDEREF_EXISTS) {
    100          
    50          
385 4         67 @texts = ($self->keyword("exists"), ' ');
386             }
387             elsif ($op->private & OPpMULTIDEREF_DELETE) {
388 4         85 @texts = ($self->keyword("delete"), ' ')
389             }
390             elsif ($op->private & OPpLVAL_INTRO) {
391 0         0 @texts = ($self->keyword("local"), ' ')
392             }
393              
394 9 50 33     105 if ($op->first && ($op->first->flags & OPf_KIDS)) {
395             # arbitrary initial expression, e.g. f(1,2,3)->[...]
396 0         0 my $first = $self->deparse($op->first, 24, $op);
397 0         0 push @texts, $first->{text};
398             }
399              
400 9         53 my @items = $op->aux_list($self->{curcv});
401 9         19 my $actions = shift @items;
402              
403 9         16 my $is_hash;
404 9         20 my $derefs = 0;
405              
406 9         12 while (1) {
407 9 50       31 if (($actions & MDEREF_ACTION_MASK) == MDEREF_reload) {
408 0         0 $actions = shift @items;
409 0         0 next;
410             }
411              
412             $is_hash = (
413 9   66     121 ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_pop_rv2hv_helem
414             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_gvsv_vivify_rv2hv_helem
415             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_padsv_vivify_rv2hv_helem
416             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_vivify_rv2hv_helem
417             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_padhv_helem
418             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_gvhv_helem
419             );
420              
421 9 100 66     52 if ( ($actions & MDEREF_ACTION_MASK) == MDEREF_AV_padav_aelem
    50 66        
422             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_padhv_helem)
423             {
424 2         5 $derefs = 1;
425 2         19 push @texts, '$' . substr($self->padname(shift @items), 1);
426             }
427             elsif ( ($actions & MDEREF_ACTION_MASK) == MDEREF_AV_gvav_aelem
428             || ($actions & MDEREF_ACTION_MASK) == MDEREF_HV_gvhv_helem)
429             {
430 7         12 $derefs = 1;
431 7         32 push @texts, $self->multideref_var_name(shift @items, $is_hash);
432             }
433             else {
434 0 0 0     0 if ( ($actions & MDEREF_ACTION_MASK) ==
    0 0        
    0 0        
435             MDEREF_AV_padsv_vivify_rv2av_aelem
436             || ($actions & MDEREF_ACTION_MASK) ==
437             MDEREF_HV_padsv_vivify_rv2hv_helem)
438             {
439 0         0 push @texts, $self->padname(shift @items);
440             }
441             elsif ( ($actions & MDEREF_ACTION_MASK) ==
442             MDEREF_AV_gvsv_vivify_rv2av_aelem
443             || ($actions & MDEREF_ACTION_MASK) ==
444             MDEREF_HV_gvsv_vivify_rv2hv_helem)
445             {
446 0         0 push @texts, $self->multideref_var_name(shift @items, $is_hash);
447             }
448             elsif ( ($actions & MDEREF_ACTION_MASK) ==
449             MDEREF_AV_pop_rv2av_aelem
450             || ($actions & MDEREF_ACTION_MASK) ==
451             MDEREF_HV_pop_rv2hv_helem)
452             {
453 0 0 0     0 if ( ($op->flags & OPf_KIDS)
      0        
      0        
      0        
      0        
454             && ( B::Deparse::_op_is_or_was($op->first, OP_RV2AV)
455             || B::Deparse::_op_is_or_was($op->first, OP_RV2HV))
456             && ($op->first->flags & OPf_KIDS)
457             && ( B::Deparse::_op_is_or_was($op->first->first, OP_AELEM)
458             || B::Deparse::_op_is_or_was($op->first->first, OP_HELEM))
459             )
460             {
461 0         0 $derefs++;
462             }
463             }
464              
465 0 0       0 push(@texts, '->') if !$derefs++;
466             }
467              
468              
469 9 50       41 if (($actions & MDEREF_INDEX_MASK) == MDEREF_INDEX_none) {
470 0         0 last;
471             }
472              
473 9 100       29 push(@texts, $is_hash ? '{' : '[');
474              
475 9 50       26 if (($actions & MDEREF_INDEX_MASK) == MDEREF_INDEX_const) {
    0          
    0          
476 9         17 my $key = shift @items;
477 9 100       21 if ($is_hash) {
478 5         30 push @texts, $self->const($key, $cx)->{text};
479             }
480             else {
481 4         10 push @texts, $key;
482             }
483             }
484             elsif (($actions & MDEREF_INDEX_MASK) == MDEREF_INDEX_padsv) {
485 0         0 push @texts, $self->padname(shift @items);
486             }
487             elsif (($actions & MDEREF_INDEX_MASK) == MDEREF_INDEX_gvsv) {
488 0         0 push @texts,('$' . ($self->stash_variable_name('$', shift @items))[0]);
489             }
490              
491 9 100       49 push(@texts, $is_hash ? '}' : ']');
492              
493 9 50       28 if ($actions & MDEREF_FLAG_last) {
494 9         14 last;
495             }
496 0         0 $actions >>= MDEREF_SHIFT;
497             }
498              
499 9         41 return info_from_list($op, $self, \@texts, '', 'multideref', {});
500             }
501              
502             # returns "&" and the argument bodies if the prototype doesn't match the args,
503             # or ("", $args_after_prototype_demunging) if it does.
504             sub check_proto {
505 1     1 0 2 my $self = shift;
506 1         2 my $op = shift;
507 1 50       4 return ('&', []) if $self->{'noproto'};
508 1         2 my($proto, @args) = @_;
509 1         2 my($arg, $real);
510 1         2 my $doneok = 0;
511 1         1 my @reals;
512             # An unbackslashed @ or % gobbles up the rest of the args
513 1         5 1 while $proto =~ s/(?
514 1         4 $proto =~ s/^\s*//;
515 1         3 while ($proto) {
516 4         15 $proto =~ s/^(\\?[\$\@&%*_]|\\\[[\$\@&%*]+\]|;)\s*//;
517 4         8 my $chr = $1;
518 4 50 33     17 if ($chr eq "") {
    100          
    50          
519 0 0       0 return ('&', []) if @args;
520             } elsif ($chr eq ";") {
521 1         3 $doneok = 1;
522             } elsif ($chr eq "@" or $chr eq "%") {
523 0         0 push @reals, map($self->deparse($_, 6), @args, $op);
524 0         0 @args = ();
525             } else {
526 3         4 $arg = shift @args;
527 3 100       6 last unless $arg;
528 2 50 33     13 if ($chr eq "\$" || $chr eq "_") {
    0          
    0          
    0          
529 2 50       17 if (B::Deparse::want_scalar $arg) {
530 2         7 push @reals, $self->deparse($arg, 6, $op);
531             } else {
532 0         0 return ('&', []);
533             }
534             } elsif ($chr eq "&") {
535 0 0       0 if ($arg->name =~ /^(s?refgen|undef)$/) {
536 0         0 push @reals, $self->deparse($arg, 6, $op);
537             } else {
538 0         0 return ('&', []);
539             }
540             } elsif ($chr eq "*") {
541 0 0 0     0 if ($arg->name =~ /^s?refgen$/
542             and $arg->first->first->name eq "rv2gv")
543             {
544 0         0 $real = $arg->first->first; # skip refgen, null
545 0 0       0 if ($real->first->name eq "gv") {
546 0         0 push @reals, $self->deparse($real, 6, $op);
547             } else {
548 0         0 push @reals, $self->deparse($real->first, 6, $op);
549             }
550             } else {
551 0         0 return ('&', []);
552             }
553             } elsif (substr($chr, 0, 1) eq "\\") {
554 0         0 $chr =~ tr/\\[]//d;
555 0 0 0     0 if ($arg->name =~ /^s?refgen$/ and
      0        
      0        
556             !B::Deparse::null($real = $arg->first) and
557             ($chr =~ /\$/ && B::Deparse::is_scalar($real->first)
558             or ($chr =~ /@/
559             && class($real->first->sibling) ne 'NULL'
560             && $real->first->sibling->name
561             =~ /^(rv2|pad)av$/)
562             or ($chr =~ /%/
563             && class($real->first->sibling) ne 'NULL'
564             && $real->first->sibling->name
565             =~ /^(rv2|pad)hv$/)
566             #or ($chr =~ /&/ # This doesn't work
567             # && $real->first->name eq "rv2cv")
568             or ($chr =~ /\*/
569             && $real->first->name eq "rv2gv")))
570             {
571 0         0 push @reals, $self->deparse($real, 6, $op);
572             } else {
573 0         0 return ('&', []);
574             }
575             }
576             }
577             }
578 1 50 33     4 return ('&', []) if $proto and !$doneok; # too few args and no ';'
579 1 50       3 return ('&', []) if @args; # too many args
580 1         4 return ('', \@reals);
581             }
582              
583             # Like dq(), but different
584             sub re_dq {
585 1     1 0 3 my $self = shift;
586 1         4 my ($op) = @_;
587 1         3 my ($re_dq_info, $fmt);
588              
589 1         9 my $type = $op->name;
590 1 50       76 if ($type eq "const") {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
591 0 0       0 return '$[' if $op->private & OPpCONST_ARYBASE;
592 0         0 my $unbacked = B::Deparse::re_unback($self->const_sv($op)->as_string);
593 0         0 return B::Deparse::re_uninterp(escape_re($unbacked));
594             } elsif ($type eq "concat") {
595 0         0 my $first = $self->re_dq($op->first);
596 0         0 my $last = $self->re_dq($op->last);
597 0         0 return B::Deparse::re_dq_disambiguate($first, $last);
598             } elsif ($type eq "uc") {
599 0         0 $re_dq_info = $self->re_dq($op->first->sibling);
600 0         0 $fmt = '\U%c\E';
601 0         0 $type .= ' uc';
602             } elsif ($type eq "lc") {
603 0         0 $re_dq_info = $self->re_dq($op->first->sibling);
604 0         0 $fmt = '\L%c\E';
605 0         0 $type .= ' lc';
606             } elsif ($type eq "ucfirst") {
607 0         0 $re_dq_info = $self->re_dq($op->first->sibling);
608 0         0 $fmt = '\u%c';
609 0         0 $type .= ' ucfirst';
610             } elsif ($type eq "lcfirst") {
611 0         0 $re_dq_info = $self->re_dq($op->first->sibling);
612 0         0 $fmt = '\u%c';
613 0         0 $type .= ' lcfirst';
614             } elsif ($type eq "quotemeta") {
615 0         0 $re_dq_info = $self->re_dq($op->first->sibling);
616 0         0 $fmt = '\Q%c\E';
617 0         0 $type .= ' quotemeta';
618             } elsif ($type eq "fc") {
619 0         0 $re_dq_info = $self->re_dq($op->first->sibling);
620 0         0 $fmt = '\F%c\E';
621 0         0 $type .= ' fc';
622             } elsif ($type eq "join") {
623 0         0 return $self->deparse($op->last, 26); # was join($", @ary)
624             } else {
625 1         10 my $ret = $self->deparse($op, 26);
626 1 50       14 $ret =~ s/^\$([(|)])\z/\${$1}/ # $( $| $) need braces
627             or $ret =~ s/^\@([-+])\z/\@{$1}/; # @- @+ need braces
628 1         4 return $ret;
629             }
630 0         0 return $self->info_from_template($type, $op->first->sibling,
631             $fmt, [$re_dq_info], [0]);
632             }
633              
634             sub pure_string {
635 8     8 0 20 my ($self, $op) = @_;
636 8 50       94 return 0 if B::Deparse::null $op;
637 8         77 my $type = $op->name;
638              
639 8 50 33     383 if ($type eq 'const' || $type eq 'av2arylen') {
    50 33        
    50 33        
    50 66        
    50 66        
    100 33        
      33        
640 0         0 return 1;
641             }
642             elsif ($type =~ /^(?:[ul]c(first)?|fc)$/ || $type eq 'quotemeta') {
643 0         0 return $self->pure_string($op->first->sibling);
644             }
645             elsif ($type eq 'join') {
646 0         0 my $join_op = $op->first->sibling; # Skip pushmark
647 0 0 0     0 return 0 unless $join_op->name eq 'null' && $join_op->targ == OP_RV2SV;
648              
649 0         0 my $gvop = $join_op->first;
650 0 0       0 return 0 unless $gvop->name eq 'gvsv';
651 0 0       0 return 0 unless '"' eq $self->gv_name($self->gv_or_padgv($gvop));
652              
653 0 0       0 return 0 unless ${$join_op->sibling} eq ${$op->last};
  0         0  
  0         0  
654 0 0       0 return 0 unless $op->last->name =~ /^(?:[ah]slice|(?:rv2|pad)av)$/;
655             }
656             elsif ($type eq 'concat') {
657 0   0     0 return $self->pure_string($op->first)
658             && $self->pure_string($op->last);
659             }
660             elsif (B::Deparse::is_scalar($op) || $type =~ /^[ah]elem$/) {
661 0         0 return 1;
662             }
663             elsif ($type eq "null" and $op->can('first') and not B::Deparse::null $op->first and
664             ($op->first->name eq "null" and $op->first->can('first')
665             and not B::Deparse::null $op->first->first and
666             $op->first->first->name eq "aelemfast"
667             or
668             $op->first->name =~ /^aelemfast(?:_lex)?\z/
669             )) {
670 1         45 return 1;
671             }
672             else {
673 7         23 return 0;
674             }
675              
676 0         0 return 1;
677             }
678              
679             sub regcomp
680             {
681 5     5 0 15 my($self, $op, $cx, $extended) = @_;
682 5         10 my @other_ops = ();
683 5         23 my $kid = $op->first;
684 5 50       19 if ($kid->name eq "regcmaybe") {
685 0         0 push @other_ops, $kid;
686 0         0 $kid = $kid->first;
687             }
688 5 50       19 if ($kid->name eq "regcreset") {
689 0         0 push @other_ops, $kid;
690 0         0 $kid = $kid->first;
691             }
692 5 50 66     133 if ($kid->name eq "null" and !B::Deparse::null($kid->first)
      66        
693             and $kid->first->name eq 'pushmark') {
694 0         0 my $str = '';
695 0         0 push(@other_ops, $kid);
696 0         0 $kid = $kid->first->sibling;
697 0         0 my @body = ();
698 0         0 while (!B::Deparse::null($kid)) {
699 0         0 my $first = $str;
700 0         0 my $last = $self->re_dq($kid, $extended);
701 0         0 push @body, $last;
702 0         0 push(@other_ops, $kid);
703 0         0 $str = B::Deparse::re_dq_disambiguate($first,
704             $self->info2str($last));
705 0         0 $kid = $kid->sibling;
706             }
707 0         0 return (info_from_text($op, $self, $str, 'regcomp',
708             {other_ops => \@other_ops,
709             body => \@body}), 1);
710             }
711              
712 5 100       19 if ($self->pure_string($kid)) {
713 1         14 my $info = $self->re_dq($kid, $extended);
714 1 50       7 my @kid_ops = $info->{other_ops} ? @{$info->{other_ops}} : ();
  0         0  
715 1         3 push @other_ops, @kid_ops;
716 1         4 $info->{other_ops} = \@other_ops;
717 1         7 return ($info, 1);
718             }
719 4         13 return ($self->deparse($kid, $cx, $op), 0, $op);
720             }
721              
722             sub pp_split
723             {
724 0     0     my($self, $op, $cx) = @_;
725 0           my($kid, @exprs, $ary_info, $expr);
726 0           my $stacked = $op->flags & OPf_STACKED;
727 0           my $ary = '';
728 0           my @body = ();
729 0           my @other_ops = ();
730 0           $kid = $op->first;
731              
732 0           $kid = $op->first;
733 0 0         $kid = $kid->sibling if $kid->name eq 'regcomp';
734 0           for (; !B::Deparse::null($kid); $kid = $kid->sibling) {
735 0           push @exprs, $self->deparse($kid, 6, $op);
736             }
737              
738 0           unshift @exprs, $self->matchop($op, $cx, "m", "/");
739              
740 0 0         if ($op->private & OPpSPLIT_ASSIGN) {
741             # With C<@array = split(/pat/, str);>,
742             # array is stored in split's pmreplroot; either
743             # as an integer index into the pad (for a lexical array)
744             # or as GV for a package array (which will be a pad index
745             # on threaded builds)
746             # With my/our @array = split(/pat/, str), the array is instead
747             # accessed via an extra padav/rv2av op at the end of the
748             # split's kid ops.
749              
750 0 0         if ($stacked) {
751 0           $ary = pop @exprs;
752             }
753             else {
754 0 0         if ($op->private & OPpSPLIT_LEX) {
755 0           $ary = $self->padname($op->pmreplroot);
756             }
757             else {
758             # union with op_pmtargetoff, op_pmtargetgv
759 0           my $gv = $op->pmreplroot;
760 0 0         $gv = $self->padval($gv) if !ref($gv);
761 0           $ary = $self->maybe_local(@_,
762             $self->stash_variable('@',
763             $self->gv_name($gv),
764             $cx))
765             }
766 0 0         if ($op->private & OPpLVAL_INTRO) {
767 0 0         $ary = $op->private & OPpSPLIT_LEX ? "my $ary" : "local $ary";
768             }
769             }
770             }
771              
772 0           push @body, @exprs;
773 0           my $opts = {body => \@exprs};
774              
775             # handle special case of split(), and split(' ') that compiles to /\s+/
776 0 0 0       if (($op->reflags // 0) & RXf_SKIPWHITE()) {
777 0           my $expr0 = $exprs[0];
778 0           my $expr0b0 = $expr0->{body}[0];
779 0           my $bsep = $expr0b0->{sep};
780 0           my $sep = $expr0->{sep};
781 0           $expr0b0->{texts}[1] = ' ';
782             # substr($expr0b0->{text}, 1, 0) = ' ';
783 0           substr($expr0->{texts}[0], 1, 0) = ' ';
784 0           substr($expr0->{text}, 1, 0) = ' ';
785             }
786 0           my @args_texts = map $_->{text}, @exprs;
787              
788 0           my $sep = '';
789 0           my $type;
790             my @expr_texts;
791 0 0         if ($ary) {
792 0           @expr_texts = ("$ary", '=', join(', ', @args_texts));
793 0           $sep = ' ';
794 0           $type = 'split_array';
795 0           $opts->{maybe_parens} = [$self, $cx, 7];
796             } else {
797 0           @expr_texts = ('split', '(', join(', ', @args_texts), ')');
798 0           $type = 'split';
799              
800             }
801 0           return info_from_list($op, $self, \@expr_texts, $sep, $type, $opts);
802             }
803              
804             # Not in Perl 5.20 and presumably < 5.20. No harm in adding to 5.20?
805             *pp_ncomplement = *pp_complement;
806              
807             1;