File Coverage

lib/B/DeparseTree/PP.pm
Criterion Covered Total %
statement 312 540 57.7
branch 102 210 48.5
condition 63 156 40.3
subroutine 67 112 59.8
pod 0 97 0.0
total 544 1115 48.7


line stmt bran cond sub pod time code
1             # Copyright (c) 2015, 2018 Rocky Bernstein
2              
3             # Common PP (push-pull) opcodes methods. Most of these are called
4             # from the method dispatch in Common.
5             #
6             # Specifc Perl versions can override these. Note some PP opcodes are
7             # handled via table lookup to their underlying base-handling function,
8             # e.g. binop, listop, unop, ....
9              
10 8     8   48 use strict;
  8         13  
  8         220  
11 8     8   32 use warnings ();
  8         14  
  8         309  
12             require feature;
13              
14             my %feature_keywords = (
15             # keyword => 'feature',
16             state => 'state',
17             say => 'say',
18             given => 'switch',
19             when => 'switch',
20             default => 'switch',
21             break => 'switch',
22             evalbytes=>'evalbytes',
23             __SUB__ => '__SUB__',
24             fc => 'fc',
25             );
26              
27 8     8   32 use rlib '../..';
  8         16  
  8         57  
28              
29             package B::DeparseTree::PP;
30              
31 8     8   2550 use B::DeparseTree::SyntaxTree;
  8         18  
  8         524  
32 8     8   40 use B::DeparseTree::OPflags;
  8         12  
  8         330  
33 8     8   35 use B::DeparseTree::PPfns;
  8         15  
  8         1915  
34 8     8   60 use B::DeparseTree::TreeNode;
  8         26  
  8         652  
35 8     8   44 use B::Deparse;
  8         13  
  8         1125  
36             our($VERSION, @EXPORT, @ISA);
37             $VERSION = '3.2.0';
38              
39             @ISA = qw(Exporter B::Deparse );
40              
41             # Copy unchanged functions from B::Deparse
42             *lex_in_scope = *B::Deparse::lex_in_scope;
43             *gv_or_padgv = *B::Deparse::gv_or_padgv;
44             *padany = *B::Deparse::padany;
45             *padname = *B::Deparse::padname;
46             *pp_anonhash = *B::Deparse::pp_anonhash;
47             *pp_anonlist = *B::Deparse::pp_anonlist;
48             *pp_i_negate = *B::Deparse::pp_i_negate;
49             *pp_negate = *B::Deparse::pp_negate;
50             *real_negate = *B::Deparse::real_negate;
51 8         1155 use B qw(
52             OPf_MOD OPpENTERSUB_AMPER
53             OPf_SPECIAL
54             OPf_STACKED
55             OPpEXISTS_SUB
56             OPpTRANS_COMPLEMENT
57             OPpTRANS_DELETE
58             OPpTRANS_SQUASH
59             SVf_POK
60             SVf_ROK
61             class
62             opnumber
63 8     8   43 );
  8         12  
64              
65             @EXPORT = qw(
66             feature_enabled
67             gv_or_padgv
68             pp_aelem
69             pp_aelemfast
70             pp_aelemfast_lex
71             pp_and
72             pp_anonhash
73             pp_anonlist
74             pp_aslice
75             pp_avalues
76             pp_backtick
77             pp_boolkeys
78             pp_clonecv
79             pp_cmp
80             pp_cond_expr
81             pp_connect
82             pp_const
83             pp_delete
84             pp_dofile
85             pp_entereval
86             pp_entersub
87             pp_eq
88             pp_exec
89             pp_exists
90             pp_exp
91             pp_flop
92             pp_ge
93             pp_gelem
94             pp_glob
95             pp_gt
96             pp_gv
97             pp_gvsv
98             pp_helem
99             pp_hslice
100             pp_i_cmp
101             pp_i_eq
102             pp_i_ge
103             pp_i_gt
104             pp_i_le
105             pp_i_lt
106             pp_i_ne
107             pp_i_negate
108             pp_introcv
109             pp_kvaslice
110             pp_kvhslice
111             pp_le
112             pp_leave
113             pp_leavegiven
114             pp_leaveloop
115             pp_leavetry
116             pp_leavewhen
117             pp_lineseq
118             pp_list
119             pp_lslice
120             pp_lt
121             pp_mapstart
122             pp_ne
123             pp_negate
124             pp_not
125             pp_null
126             pp_once
127             pp_open_dir
128             pp_or
129             pp_padcv
130             pp_pos
131             pp_preinc
132             pp_print
133             pp_prtf
134             pp_pushre
135             pp_qr
136             pp_rcatline
137             pp_readline
138             pp_refgen
139             pp_require
140             pp_rv2cv
141             pp_sassign
142             pp_scalar
143             pp_scmp
144             pp_scope
145             pp_seq
146             pp_sge
147             pp_sgt
148             pp_sle
149             pp_slt
150             pp_sne
151             pp_sockpair
152             pp_split
153             pp_smartmatch
154             pp_stringify
155             pp_stub
156             pp_subst
157             pp_substr
158             pp_trans
159             pp_transr
160             pp_truncate
161             pp_unstack
162             pp_values
163             pp_vec
164             pp_waitpid
165             pp_xor
166             );
167              
168             BEGIN {
169             # List version-specific constants here.
170             # Easiest way to keep this code portable between version looks to
171             # be to fake up a dummy constant that will never actually be true.
172 8     8   26 foreach (qw(OPpCONST_ARYBASE OPpEVAL_BYTES)) {
173 16         26 eval { import B $_ };
  16         3412  
174 8     8   50 no strict 'refs';
  8         11  
  8         473  
175 16 100       33 *{$_} = sub () {0} unless *{$_}{CODE};
  8         26  
  16         557  
176             }
177             }
178              
179 8     8   38 BEGIN { for (qw[ const stringify rv2sv list glob pushmark null aelem
180             nextstate dbstate rv2av rv2hv helem custom ]) {
181 112         38759 eval "sub OP_\U$_ () { " . opnumber($_) . "}"
182             }}
183              
184             sub feature_enabled {
185 27     27 0 71 my($self,$name) = @_;
186 27         35 my $hh;
187 27         50 my $hints = $self->{hints} & $feature::hint_mask;
188 27 100 100     123 if ($hints && $hints != $feature::hint_mask) {
    100          
189 6         81 $hh = B::Deparse::_features_from_bundle($hints);
190             }
191 7         15 elsif ($hints) { $hh = $self->{'hinthash'} }
192 27   66     2250 return $hh && $hh->{"feature_$feature_keywords{$name}"}
193             }
194              
195             # FIXME: These don't seem to be able to go into the table.
196             # PPfns calls pp_sockpair for example?
197 0     0 0 0 sub pp_avalues { unop(@_, "values") }
198 6     6 0 28 sub pp_exec { maybe_targmy(@_, \&listop, "exec") }
199 4     4 0 21 sub pp_exp { maybe_targmy(@_, \&unop, "exp") }
200 7     7 0 21 sub pp_leave { scopeop(1, @_); }
201 5     5 0 19 sub pp_lineseq { scopeop(0, @_); }
202             sub pp_or { logop(@_, "or", 2, "||", 10, "unless") }
203             sub pp_preinc { pfixop(@_, "++", 23) }
204 16     16 0 44 sub pp_print { indirop(@_, "print") }
205 13     13 0 36 sub pp_prtf { indirop(@_, "printf") }
206 2     2 0 11 sub pp_sockpair { listop(@_, "socketpair") }
207 0     0 0 0 sub pp_values { unop(@_, "values") }
208 0     0 0 0 sub pp_pushre { matchop(@_, "m", "/") } # Is also in OP_PP table
209 0     0 0 0 sub pp_qr { matchop(@_, "qr", "") } # Is also in OP_PP table
210              
211             # Convert these to table entries...
212 0     0 0 0 sub pp_aelem { maybe_local(@_, elem(@_, "[", "]", "padav")) }
213 1     1 0 6 sub pp_aslice { maybe_local(@_, slice(@_, "[", "]", "rv2av", "padav")) }
214 0     0 0 0 sub pp_cmp { binop(@_, "<=>", 14) }
215 0     0 0 0 sub pp_eq { binop(@_, "==", 14) }
216 0     0 0 0 sub pp_ge { binop(@_, ">=", 15) }
217 0     0 0 0 sub pp_gt { binop(@_, ">", 15) }
218 1     1 0 5 sub pp_helem { maybe_local(@_, elem(@_, "{", "}", "padhv")) }
219 1     1 0 5 sub pp_hslice { maybe_local(@_, slice(@_, "{", "}", "rv2hv", "padhv")) }
220 0     0 0 0 sub pp_i_cmp { maybe_targmy(@_, \&binop, "<=>", 14) }
221 0     0 0 0 sub pp_i_eq { binop(@_, "==", 14) }
222 0     0 0 0 sub pp_i_ge { binop(@_, ">=", 15) }
223 0     0 0 0 sub pp_i_gt { binop(@_, ">", 15) }
224 0     0 0 0 sub pp_i_le { binop(@_, "<=", 15) }
225 0     0 0 0 sub pp_i_lt { binop(@_, "<", 15) }
226 0     0 0 0 sub pp_i_ne { binop(@_, "!=", 14) }
227 0     0 0 0 sub pp_kvaslice { slice(@_, "[", "]", "rv2av", "padav") }
228 0     0 0 0 sub pp_kvhslice { slice(@_, "{", "}", "rv2hv", "padhv") }
229 0     0 0 0 sub pp_le { binop(@_, "<=", 15) }
230 0     0 0 0 sub pp_lt { binop(@_, "<", 15) }
231 0     0 0 0 sub pp_ne { binop(@_, "!=", 14) }
232              
233 14     14 0 52 sub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) }
234 6     6 0 19 sub pp_scmp { binop(@_, "cmp", 14) }
235 4     4 0 12 sub pp_seq { binop(@_, "eq", 14) }
236 4     4 0 12 sub pp_sge { binop(@_, "ge", 15) }
237 4     4 0 13 sub pp_sgt { binop(@_, "gt", 15) }
238 4     4 0 13 sub pp_sle { binop(@_, "le", 15) }
239 4     4 0 12 sub pp_slt { binop(@_, "lt", 15) }
240 4     4 0 10 sub pp_sne { binop(@_, "ne", 14) }
241              
242             sub pp_aelemfast
243             {
244 1     1 0 3 my($self, $op, $cx) = @_;
245             # optimised PADAV, pre 5.15
246 1 50       17 return $self->pp_aelemfast_lex(@_) if ($op->flags & OPf_SPECIAL);
247              
248 1         14 my $gv = $self->gv_or_padgv($op);
249 1         16 my($name,$quoted) = $self->stash_variable_name('@',$gv);
250 1 50       4 $name = $quoted ? "$name->" : '$' . $name;
251 1         3 my $i = $op->private;
252 1 50       4 $i -= 256 if $i > 127;
253 1         8 return info_from_list($op, $self, [$name, "[", ($op->private + $self->{'arybase'}), "]"],
254             '', 'pp_aelemfast', {});
255             }
256              
257             sub pp_aelemfast_lex
258             {
259 2     2 0 5 my($self, $op, $cx) = @_;
260 2         18 my $name = $self->padname($op->targ);
261 2         11 $name =~ s/^@/\$/;
262 2         29 return info_from_list($op, $self, [$name, "[", ($op->private + $self->{'arybase'}), "]"],
263             '', 'pp_aelemfast_lex', {});
264             }
265              
266             sub pp_backtick
267             {
268 3     3 0 7 my($self, $op, $cx) = @_;
269             # skip pushmark if it exists (readpipe() vs ``)
270 3 50       30 my $child = $op->first->sibling->isa('B::NULL')
271             ? $op->first : $op->first->sibling;
272 3 50       25 if ($self->pure_string($child)) {
273 0         0 return $self->single_delim($op, "qx", '`', $self->dq($child, 1)->{text});
274             }
275 3         12 unop($self, $op, $cx, "readpipe");
276             }
277              
278             sub pp_boolkeys
279             {
280             # no name because its an optimisation op that has no keyword
281 0     0 0 0 unop(@_,"");
282             }
283              
284             sub pp_dofile
285             {
286 3     3 0 12 my $code = unop(@_, "do", 1); # llafr does not apply
287 3 50       14 if ($code =~ s/^((?:CORE::)?do) \{/$1({/) { $code .= ')' }
  0         0  
288 3         8 $code;
289             }
290              
291             sub pp_gelem
292             {
293 0     0 0 0 my($self, $op, $cx) = @_;
294 0         0 my($rv2gv, $part) = ($op->first, $op->last);
295 0         0 my $glob = $rv2gv->first; # skip rv2gv
296 0 0       0 $glob = $glob->first if $glob->name eq "rv2gv"; # this one's a bug
297 0         0 my $scope = B::Deparse::is_scope($glob);
298 0         0 my $glob_node = $self->deparse($glob, 0);
299 0         0 my $part_node = $self->deparse($part, 1);
300 0 0       0 my $fmt = ($scope ? '*{%c}{%c}' : '*%c{%c}');
301             # FIXME: fill in $rv2gv and possibly other node skipped above.
302 0         0 return $self->info_from_template("gelem *", $fmt, undef,
303             [$glob_node, $part_node],
304             {other_ops => [$rv2gv]});
305             }
306              
307 0     0 0 0 sub pp_leavegiven { givwhen(@_, $_[0]->keyword("given")); }
308 0     0 0 0 sub pp_leavewhen { givwhen(@_, $_[0]->keyword("when")); }
309              
310             sub pp_lslice
311             {
312 1     1 0 3 my ($self, $op, $cs) = @_;
313 1         4 my $idx = $op->first;
314 1         4 my $list = $op->last;
315 1         2 my(@elems, $kid);
316 1         4 my $list_info = $self->deparse($list, 1, $op);
317 1         4 my $idx_info = $self->deparse($idx, 1, $op);
318 1         4 return $self->info_from_template('lslice ()[]',
319             $op, '(%c)[%c]', undef,
320             [$list_info, $idx_info]);
321             }
322              
323 8     8 0 27 sub pp_pos { maybe_local(@_, unop(@_, "pos")) }
324              
325             sub pp_not
326             {
327 27     27 0 58 my($self, $op, $cx) = @_;
328 27 50       61 if ($cx <= 4) {
329 27         162 $self->listop($op, $cx, "not", $op->first);
330             } else {
331 0         0 $self->pfixop($op, $cx, "!", 21);
332             }
333             }
334              
335              
336             # skip down to the old, ex-rv2cv
337             sub pp_rv2cv {
338 0     0 0 0 my ($self, $op, $cx) = @_;
339 0 0 0     0 if (!B::Deparse::null($op->first) && $op->first->name eq 'null' &&
      0        
340             $op->first->targ == OP_LIST)
341             {
342 0         0 return $self->rv2x($op->first->first->sibling, $cx, "&")
343             }
344             else {
345 0         0 return $self->rv2x($op, $cx, "")
346             }
347             }
348              
349              
350             sub pp_scalar
351             {
352 4     4 0 7 my($self, $op, $cx) = @_;
353 4         12 my $kid = $op->first;
354 4 50       27 if (not B::Deparse::null $kid->sibling) {
355             # XXX Was a here-doc
356 0         0 return $self->dquote($op);
357             }
358 4         13 $self->unop($op, $cx, "scalar");
359             }
360              
361             sub pp_smartmatch {
362 0     0 0 0 my ($self, $op, $cx) = @_;
363 0 0       0 if ($op->flags & OPf_SPECIAL) {
364 0         0 my $child = $self->deparse($op->last, $cx, $op);
365 0         0 return $self->info_from_template('~~ special',
366             '%c', undef, [$child]);
367             } else {
368 0         0 binop(@_, "~~", 14);
369             }
370             }
371              
372             # Truncate is special because OPf_SPECIAL makes a bareword first arg
373             # be a filehandle. This could probably be better fixed in the core
374             # by moving the GV lookup into ck_truc.
375              
376             sub pp_truncate
377             {
378 2     2 0 4 my($self, $op, $cx) = @_;
379 2         4 my(@exprs);
380 2   33     5 my $parens = ($cx >= 5) || $self->{'parens'};
381 2         9 my $opts = {'other_ops' => [$op->first]};
382 2         19 my $kid = $op->first->sibling;
383 2         4 my $fh;
384 2 50       8 if ($op->flags & B::OPf_SPECIAL) {
385             # $kid is an OP_CONST
386 0         0 $fh = $self->const_sv($kid)->PV;
387             } else {
388 2         6 $fh = $self->deparse($kid, 6, $op);
389 2 50 33     17 $fh = "+$fh" if not $parens and substr($fh, 0, 1) eq "(";
390             }
391 2         13 my $len = $self->deparse($kid->sibling, 6, $op);
392 2         47 my $name = $self->keyword('truncate');
393 2         8 my $args = "$fh->{text}, $len->{text}";
394 2 50       6 if ($parens) {
395 2         8 return info_from_list($op, $self, [$name, '(', $args, ')'], '',
396             'truncate_parens', $opts);
397             } else {
398 0         0 return info_from_list($op, $self, [$name, $args], '', 'truncate', $opts);
399             }
400             }
401              
402 2     2 0 11 sub pp_vec { maybe_local(@_, listop(@_, "vec")) }
403              
404             sub pp_glob
405             {
406 2     2 0 5 my($self, $op, $cx) = @_;
407              
408 2         8 my $opts = {other_ops => [$op->first]};
409 2         9 my $kid = $op->first->sibling; # skip pushmark
410 2 50       36 my $keyword =
411             $op->flags & OPf_SPECIAL ? 'glob' : $self->keyword('glob');
412              
413 2 50 33     14 if ($keyword =~ /^CORE::/ or $kid->name ne 'const') {
414 2         7 my $kid_info = $self->dq($kid, $op);
415 2         3 my $body = [$kid_info];
416 2         4 my $text = $kid_info->{text};
417 2 50 33     24 if ($text =~ /^\$?(\w|::|\`)+$/ # could look like a readline
418             or $text =~ /[<>]/) {
419 2         7 $kid_info = $self->deparse($kid, 0, $op);
420 2         6 $body = [$kid_info];
421 2         3 $text = $kid_info->{text};
422 2         5 $opts->{body} = $body;
423 2 50 33     10 if ($cx >= 5 || $self->{'parens'}) {
424             # FIXME: turn into template
425 0         0 return info_from_list($op, $self, [$keyword, '(', $text, ')'], '',
426             'glob_paren', $opts);
427             } else {
428             # FIXME: turn into template
429 2         7 return info_from_list($op, $self, [$keyword, $text], ' ',
430             'glob_space', $opts);
431             }
432             } else {
433 0         0 return $self->info_from_template('', $op, '<%c>', undef,
434             [$kid_info], $opts);
435             }
436             }
437 0         0 return $self->info_from_string("<>", $op, $opts);
438             }
439              
440             sub pp_clonecv {
441 0     0 0 0 my $self = shift;
442 0         0 my($op, $cx) = @_;
443 0         0 my $sv = $self->padname_sv($op->targ);
444 0         0 my $name = substr $sv->PVX, 1; # skip &/$/@/%, like $self->padany
445 0         0 return $self->info_from_string("clonev my sub", $op, "my sub $name");
446             }
447              
448             sub pp_delete($$$)
449             {
450 0     0 0 0 my($self, $op, $cx) = @_;
451 0         0 my $arg;
452 0         0 my ($info, $body, $type);
453 0 0       0 if ($op->private & B::OPpSLICE) {
454 0 0       0 if ($op->flags & B::OPf_SPECIAL) {
455             # Deleting from an array, not a hash
456 0         0 $info = $self->pp_aslice($op->first, 16);
457 0         0 $type = 'delete slice';
458             }
459             } else {
460 0 0       0 if ($op->flags & B::OPf_SPECIAL) {
461             # Deleting from an array, not a hash
462 0         0 $info = $self->pp_aelem($op->first, 16);
463 0         0 $type = 'delete array'
464             } else {
465 0         0 $info = $self->pp_helem($op->first, 16);
466 0         0 $type = 'delete hash';
467             }
468             }
469             my @texts = $self->maybe_parens_func("delete",
470 0         0 $info->{text}, $cx, 16);
471 0         0 return info_from_list($op, $self, \@texts, '', $type, {body => [$info]});
472             }
473              
474             sub pp_exists
475             {
476 0     0 0 0 my($self, $op, $cx) = @_;
477 0         0 my ($info, $type);
478 0         0 my $name = $self->keyword("exists");
479 0 0       0 if ($op->private & OPpEXISTS_SUB) {
    0          
480             # Checking for the existence of a subroutine
481 0         0 $info = $self->pp_rv2cv($op->first, 16);
482 0         0 $type = 'exists sub';
483             } elsif ($op->flags & OPf_SPECIAL) {
484             # Array element, not hash helement
485 0         0 $info = $self->pp_aelem($op->first, 16);
486 0         0 $type = 'exists array';
487             } else {
488 0         0 $info = $self->pp_helem($op->first, 16);
489 0         0 $type = 'exists hash';
490             }
491 0         0 my @texts = $self->maybe_parens_func($name, $info->{text}, $cx, 16);
492 0         0 return info_from_list($op, $self, \@texts, '', $type, {});
493             }
494              
495             sub pp_introcv
496             {
497 0     0 0 0 my($self, $op, $cx) = @_;
498             # For now, deparsing doesn't worry about the distinction between introcv
499             # and clonecv, so pretend this op doesn't exist:
500 0         0 return info_from_text($op, $self, '', 'introcv', {});
501             }
502              
503 5     5 0 31 sub pp_leaveloop { shift->loop_common(@_, undef); }
504              
505             sub pp_leavetry {
506 0     0 0 0 my ($self, $op, $cx) = @_;
507 0         0 my $leave_info = $self->pp_leave($op, $cx);
508 0         0 return $self->info_from_template('eval {}', $op, "eval {\n%+%c\n%-}",
509             undef, [$leave_info]);
510             }
511              
512             sub pp_list
513             {
514 3243     3243 0 5197 my($self, $op, $cx) = @_;
515 3243         3945 my($expr, @exprs);
516              
517 3243         8994 my $pushmark_op = $op->first;
518 3243         8661 my $kid = $pushmark_op->sibling; # skip a pushmark
519 3243         5889 my @other_ops = ($pushmark_op);
520              
521 3243 100       15716 if (class($kid) eq 'NULL') {
522 1         5 return $self->info_from_string("list ''", $op, '', {other_ops => \@other_ops});
523             }
524 3242         4732 my $lop;
525 3242         4139 my $local = "either"; # could be local(...), my(...), state(...) or our(...)
526 3242         16892 for ($lop = $kid; !B::Deparse::null($lop); $lop = $lop->sibling) {
527             # This assumes that no other private flags equal 128, and that
528             # OPs that store things other than flags in their op_private,
529             # like OP_AELEMFAST, won't be immediate children of a list.
530             #
531             # OP_ENTERSUB and OP_SPLIT can break this logic, so check for them.
532             # I suspect that open and exit can too.
533             # XXX This really needs to be rewritten to accept only those ops
534             # known to take the OPpLVAL_INTRO flag.
535              
536 5750 100 100     36602 if (!($lop->private & (B::Deparse::OPpLVAL_INTRO|B::Deparse::OPpOUR_INTRO)
      66        
537             or $lop->name eq "undef")
538             or $lop->name =~ /^(?:entersub|exit|open|split)\z/)
539             {
540 2586         4161 $local = ""; # or not
541 2586         3623 last;
542             }
543 3164 100 33     12288 if ($lop->name =~ /^pad[ash]v$/) {
    100 66        
    100 100        
      33        
      33        
      66        
544 3141 100       8480 if ($lop->private & B::Deparse::OPpPAD_STATE) { # state()
545 10 50       39 ($local = "", last) if $local =~ /^(?:local|our|my)$/;
546 10         65 $local = "state";
547             } else { # my()
548 3131 50       5692 ($local = "", last) if $local =~ /^(?:local|our|state)$/;
549 3131         18990 $local = "my";
550             }
551             } elsif ($lop->name =~ /^(gv|rv2)[ash]v$/
552             && $lop->private & B::Deparse::OPpOUR_INTRO
553             or $lop->name eq "null" && $lop->first->name eq "gvsv"
554             && $lop->first->private & B::Deparse::OPpOUR_INTRO) { # our()
555 12 50       30 ($local = "", last) if $local =~ /^(?:my|local|state)$/;
556 12         74 $local = "our";
557             } elsif ($lop->name ne "undef"
558             # specifically avoid the "reverse sort" optimisation,
559             # where "reverse" is nullified
560             && !($lop->name eq 'sort' && ($lop->flags & B::Deparse::OPpSORT_REVERSE)))
561             {
562             # local()
563 2 50       10 ($local = "", last) if $local =~ /^(?:my|our|state)$/;
564 2         16 $local = "local";
565             }
566             }
567 3242 100       6728 $local = "" if $local eq "either"; # no point if it's all undefs
568 3242 100 100     23363 if (B::Deparse::null $kid->sibling and not $local) {
569 2566         7129 my $info = $self->deparse($kid, $cx, $op);
570 2566         7398 $info->update_other_ops($pushmark_op);
571 2566         7589 return $info;
572             }
573              
574 676         3766 for (; !B::Deparse::null($kid); $kid = $kid->sibling) {
575 3241 100       6455 if ($local) {
576 3156 100 66     12777 if (class($kid) eq "UNOP" and $kid->first->name eq "gvsv") {
577 14         22 push @other_ops, $kid;
578 14         31 $lop = $kid->first;
579             } else {
580 3142         4630 $lop = $kid;
581             }
582 3156         7100 $self->{'avoid_local'}{$$lop}++;
583 3156         7216 $expr = $self->deparse($kid, 6, $op);
584 3156         6757 delete $self->{'avoid_local'}{$$lop};
585             } else {
586 85         171 $expr = $self->deparse($kid, 6, $op);
587             }
588 3241         29954 push @exprs, $expr;
589             }
590              
591 676 100       2037 if ($local) {
592 648         5558 return $self->info_from_template("$local ()", $op,
593             "$local(%C)", [[0, $#exprs, ', ']],
594             \@exprs, {other_ops => \@other_ops});
595              
596             } else {
597 28         159 return $self->info_from_template("list", $op,
598             "%C", [[0, $#exprs, ', ']],
599             \@exprs,
600             {maybe_parens => [$self, $cx, 6],
601             other_ops => \@other_ops});
602             }
603             }
604              
605             sub pp_padcv($$$) {
606 0     0 0 0 my($self, $op, $cx) = @_;
607 0         0 return info_from_text($op, $self, $self->padany($op), 'padcv', {});
608             }
609              
610             sub pp_refgen
611             {
612 2     2 0 7 my($self, $op, $cx) = @_;
613 2         8 my $kid = $op->first;
614 2 50       18 if ($kid->name eq "null") {
615 2         10 my $other_ops = [$kid];
616 2         12 my $anoncode = $kid = $kid->first;
617 2 50       9 if ($anoncode->name eq "anonconst") {
618 0         0 $anoncode = $anoncode->first->first->sibling;
619             }
620 2 50 0     20 if ($anoncode->name eq "anoncode"
    0 33        
621             or !B::Deparse::null($anoncode = $kid->sibling) and
622             $anoncode->name eq "anoncode") {
623 2         27 return $self->e_anoncode({ code => $self->padval($anoncode->targ) });
624             } elsif ($kid->name eq "pushmark") {
625 0         0 my $sib_name = $kid->sibling->name;
626 0 0       0 if ($sib_name =~ /^enter(xs)?sub/) {
627 0         0 my $kid_info = $self->deparse($kid->sibling, 1, $op);
628             # Always show parens for \(&func()), but only with -p otherwise
629 0         0 my @texts = ('\\', $kid_info->{text});
630 0 0 0     0 if ($self->{'parens'} or $kid->sibling->private & OPpENTERSUB_AMPER) {
631 0         0 @texts = ('(', "\\", $kid_info->{text}, ')');
632             }
633 0         0 return info_from_list($op, $self, \@texts, '', 'refgen_entersub',
634             {body => [$kid_info],
635             other_ops => $other_ops});
636             }
637             }
638             }
639 0         0 local $self->{'in_refgen'} = 1;
640 0         0 $self->pfixop($op, $cx, "\\", 20);
641             }
642              
643             sub pp_require
644             {
645 2     2 0 7 my($self, $op, $cx) = @_;
646 2 50       14 my $opname = $op->flags & OPf_SPECIAL ? 'CORE::require' : 'require';
647 2 50 66     48 if (class($op) eq "UNOP" and $op->first->name eq "const"
      66        
648             and $op->first->private & B::OPpCONST_BARE) {
649 0         0 my $name = $self->const_sv($op->first)->PV;
650 0         0 $name =~ s[/][::]g;
651 0         0 $name =~ s/\.pm//g;
652 0         0 return info_from_list($op, $self, [$opname, $name], ' ',
653             'require',
654             {maybe_parens => [$self, $cx, 16]});
655             } else {
656 2 50 66     35 return $self->unop(
657             $op, $cx,
658             $op->first->name eq 'const'
659             && $op->first->private & B::OPpCONST_NOVER
660             ? "no"
661             : $opname,
662             1, # llafr does not apply
663             );
664             }
665 0         0 Carp::confess("unhandled condition in pp_require");
666             }
667              
668              
669 0     0 0 0 sub pp_scope { scopeop(0, @_); }
670 46     46 0 148 sub pp_and { logop(@_, "and", 3, "&&", 11, "if") }
671              
672             sub pp_cond_expr
673             {
674 0     0 0 0 my $self = shift;
675 0         0 my($op, $cx) = @_;
676 0         0 my $cond = $op->first;
677 0         0 my $true = $cond->sibling;
678 0         0 my $false = $true->sibling;
679 0         0 my $cuddle = $self->{'cuddle'};
680 0         0 my $type = 'if';
681 0 0 0     0 unless ($cx < 1 and (B::Deparse::is_scope($true) and $true->name ne "null") and
      0        
      0        
      0        
      0        
682             (B::Deparse::is_scope($false) || B::Deparse::is_ifelse_cont($false))
683             and $self->{'expand'} < 7) {
684             # FIXME: turn into template
685 0         0 my $cond_info = $self->deparse($cond, 8, $op);
686 0         0 my $true_info = $self->deparse($true, 6, $op);
687 0         0 my $false_info = $self->deparse($false, 8, $op);
688 0         0 return $self->info_from_template('ternary ?', $op, "%c ? %c : %c",
689             [0, 1, 2],
690             [$cond_info, $true_info, $false_info],
691             {maybe_parens => [$self, $cx, 8]});
692             }
693              
694 0         0 my $cond_info = $self->deparse($cond, 1, $op);
695 0         0 my $true_info = $self->deparse($true, 0, $op);
696 0         0 my $fmt = "%|if (%c) {\n%+%c\n%-}";
697 0         0 my @exprs = ($cond_info, $true_info);
698 0         0 my @args_spec = (0, 1);
699              
700 0         0 my $i;
701 0   0     0 for ($i=0; !B::Deparse::null($false) and B::Deparse::is_ifelse_cont($false); $i++) {
702 0         0 my $newop = $false->first;
703 0         0 my $newcond = $newop->first;
704 0         0 my $newtrue = $newcond->sibling;
705 0         0 $false = $newtrue->sibling; # last in chain is OP_AND => no else
706 0 0       0 if ($newcond->name eq "lineseq")
707             {
708             # lineseq to ensure correct line numbers in elsif()
709             # Bug #37302 fixed by change #33710.
710 0         0 $newcond = $newcond->first->sibling;
711             }
712 0         0 my $newcond_info = $self->deparse($newcond, 1, $op);
713 0         0 my $newtrue_info = $self->deparse($newtrue, 0, $op);
714 0         0 push @args_spec, scalar(@args_spec), scalar(@args_spec)+1;
715 0         0 push @exprs, $newcond_info, $newtrue_info;
716 0         0 $fmt .= " elsif ( %c ) {\n%+%c\n\%-}";
717             }
718 0 0       0 $type .= " elsif($i)" if $i;
719 0         0 my $false_info;
720 0 0       0 if (!B::Deparse::null($false)) {
721 0         0 $false_info = $self->deparse($false, 0, $op);
722 0         0 $fmt .= "${cuddle}else {\n%+%c\n%-}";
723 0         0 push @args_spec, scalar(@args_spec);
724 0         0 push @exprs, $false_info;
725 0         0 $type .= ' else';
726             }
727 0         0 return $self->info_from_template($type, $op, $fmt, \@args_spec, \@exprs);
728             }
729              
730             sub pp_const {
731 86     86 0 114 my $self = shift;
732 86         136 my($op, $cx) = @_;
733 86 50       294 if ($op->private & OPpCONST_ARYBASE) {
734 0         0 return $self->info_from_string('const $[', $op, '$[');
735             }
736             # if ($op->private & OPpCONST_BARE) { # trouble with '=>' autoquoting
737             # return $self->const_sv($op)->PV;
738             # }
739 86         428 my $sv = $self->const_sv($op);
740 86         238 return $self->const($sv, $cx);;
741             }
742              
743             # Handle subroutine calls. These are a bit complicated.
744             # NOTE: this is not right for CPerl, so it needs to be split out.
745             sub pp_entersub
746             {
747 576     576 0 1316 my($self, $op, $cx) = @_;
748 576 100       5644 return $self->e_method($op, $self->_method($op, $cx))
749             unless B::Deparse::null $op->first->sibling;
750 574         1485 my $prefix = "";
751 574         993 my $amper = "";
752 574         884 my($kid, @exprs, @args_spec);
753 574 50 33     3909 if ($op->flags & OPf_SPECIAL && !($op->flags & OPf_MOD)) {
    50          
754 0         0 $prefix = "do ";
755             } elsif ($op->private & OPpENTERSUB_AMPER) {
756 0         0 $amper = "&";
757             }
758              
759 574         1741 $kid = $op->first;
760              
761 574         2164 my $other_ops = [$kid, $kid->first];
762 574         2663 $kid = $kid->first->sibling; # skip ex-list, pushmark
763              
764 574         992 my $kid_start = $kid;
765             # FIXME: phase this out.
766 574         4308 for (; not B::Deparse::null $kid->sibling; $kid = $kid->sibling) {
767 722         5484 push @exprs, $kid;
768             }
769 574         2024 my ($simple, $proto, $subname_info) = (0, undef, undef);
770 574 50 0     15117 if (B::Deparse::is_scope($kid)) {
    50          
    0          
771 0         0 $amper = "&";
772 0         0 $subname_info = $self->deparse($kid, 0, $op);
773 0         0 $subname_info->{texts} = ['{', $subname_info->texts, '}'];
774 0         0 $subname_info->{text} = join('', @$subname_info->{texts});
775             } elsif ($kid->first->name eq "gv") {
776 574         7047 my $gv = $self->gv_or_padgv($kid->first);
777 574         1083 my $cv;
778 574 100 66     7232 if (class($gv) eq 'GV' && class($cv = $gv->CV) ne "SPECIAL"
      33        
      66        
779             || $gv->FLAGS & SVf_ROK && class($cv = $gv->RV) eq 'CV') {
780 540 100       2358 $proto = $cv->PV if $cv->FLAGS & SVf_POK;
781             }
782 574         1121 $simple = 1; # only calls of named functions can be prototyped
783 574         2091 $subname_info = $self->deparse($kid, 24, $op);
784 574         1036 my $fq;
785             # Fully qualify any sub name that conflicts with a lexical.
786 574 50 33     10192 if ($self->lex_in_scope("&$kid")
    50          
787             || $self->lex_in_scope("&$kid", 1))
788             {
789 0         0 $fq++;
790             } elsif (!$amper) {
791 574 50       1970 if ($subname_info->{text} eq 'main::') {
792 0         0 $subname_info->{text} = '::';
793             } else {
794 574 50 33     3054 if ($kid !~ /::/ && $kid ne 'x') {
795             # Fully qualify any sub name that is also a keyword. While
796             # we could check the import flag, we cannot guarantee that
797             # the code deparsed so far would set that flag, so we qual-
798             # ify the names regardless of importation.
799 0 0       0 if (exists $feature_keywords{$kid}) {
    0          
800 0 0       0 $fq++ if $self->feature_enabled($kid);
801 0         0 } elsif (do { local $@; local $SIG{__DIE__};
  0         0  
802 0         0 eval { () = prototype "CORE::$kid"; 1 } }) {
  0         0  
  0         0  
803 0         0 $fq++
804             }
805             }
806             }
807 574 50       4442 if ($subname_info->{text} !~ /^(?:\w|::)(?:[\w\d]|::(?!\z))*\z/) {
808 0         0 $subname_info->{text} = $self->single_delim($$kid, "q", "'", $kid) . '->';
809             }
810             }
811             } elsif (B::Deparse::is_scalar ($kid->first) && $kid->first->name ne 'rv2cv') {
812 0         0 $amper = "&";
813 0         0 $subname_info = $self->deparse($kid, 24, $op);
814             } else {
815 0         0 $prefix = "";
816 0 0 0     0 my $arrow = B::Deparse::is_subscriptable($kid->first)
817             || $kid->first->name eq "padcv" ? "" : "->";
818 0         0 $subname_info = $self->deparse($kid, 24, $op);
819 0         0 $subname_info->{text} .= $arrow;
820             }
821              
822             # Doesn't matter how many prototypes there are, if
823             # they haven't happened yet!
824 574         1216 my $declared;
825 574         1271 my $sub_name = $subname_info->{text};
826             {
827 8     8   83 no strict 'refs';
  8         17  
  8         239  
  574         872  
828 8     8   37 no warnings 'uninitialized';
  8         17  
  8         11181  
829             $declared = exists $self->{'subs_declared'}{$sub_name}
830             || (
831             defined &{ ${$self->{'curstash'}."::"}{$sub_name} }
832             && !exists
833             $self->{'subs_deparsed'}{$self->{'curstash'}."::" . $sub_name}
834 574   66     2092 && defined prototype $self->{'curstash'}."::" . $sub_name
835             );
836 574 50 66     2829 if (!$declared && defined($proto)) {
837             # Avoid "too early to check prototype" warning
838 0         0 ($amper, $proto) = ('&');
839             }
840             }
841              
842 574         1151 my (@texts, @nodes, $type);
843 574         1015 @nodes = ();
844 574 100 66     1767 if ($declared and defined $proto and not $amper) {
      66        
845 1         2 my $args;
846 1         10 ($amper, $args) = $self->check_proto($op, $proto, @exprs);
847 1 50       5 if ($amper eq "&") {
848 0         0 $self->deparse_op_siblings(\@nodes, $kid_start, $op, 6);
849             } else {
850 1 50       5 @nodes = @$args if @$args;
851             }
852             } else {
853 573         2684 $self->deparse_op_siblings(\@nodes, $kid_start, $op, 6);
854 573         2316 @nodes = map($self->deparse($_, 6, $op), @exprs);
855             }
856              
857 574 50 33     2955 if ($prefix or $amper) {
858 0 0       0 if ($sub_name eq '&') {
859             # &{&} cannot be written as &&
860 0         0 $subname_info->{texts} = ["{", @{$subname_info->{texts}}, "}"];
  0         0  
861 0         0 $subname_info->{text} = join('', $subname_info->{texts});
862             }
863 0 0       0 if ($op->flags & OPf_STACKED) {
864 0         0 $type = "$prefix$amper call()";
865 0         0 @texts = ($prefix, $amper, $subname_info, "(", $self->combine2str(', ', \@nodes), ")");
866             } else {
867 0         0 $type = "$prefix$amper call";
868 0         0 @texts = ($prefix, $amper, $subname_info);
869             }
870             } else {
871             # It's a syntax error to call CORE::GLOBAL::foo with a prefix,
872             # so it must have been translated from a keyword call. Translate
873             # it back.
874 574         1517 $subname_info->{text} =~ s/^CORE::GLOBAL:://;
875 574 100       1443 my $dproto = defined($proto) ? $proto : "undefined";
876 574 100 33     1260 if (!$declared) {
    50 33        
    50 33        
    50          
877 573         897 $type = 'call (fn without prototype)';
878 573         914 my ($fmt, $args_spec);
879 573 100       1590 my $first_param_text = (@nodes > 0) ? $nodes[0]->{text} : '';
880 573         1191 unshift @nodes, $subname_info;
881 573 50       2289 if ($self->dedup_func_parens(\@nodes)) {
882 0         0 $fmt = "%c %c";
883 0         0 $args_spec = undef;
884             } else {
885 573         887 $fmt = "%c(%C)";
886 573         1473 $args_spec = [0, [1, $#nodes, ', ']];
887             }
888 573         2474 my $node = $self->info_from_template($type, $op, $fmt, $args_spec,
889             \@nodes,
890             {other_ops => $other_ops});
891              
892              
893             # Take the subname_info portion of $node and use that as the
894             # part of the parent, null, pushmark ops.
895 573 50 33     2467 if ($subname_info && $other_ops) {
896 573         1187 my $str = $node->{text};
897 573         1455 my $position = [0, length($subname_info->{text})];
898 573         1065 my @new_ops = ();
899 573         1329 foreach my $skipped_op (@$other_ops) {
900 1146         6177 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
901             {position => $position});
902 1146         2900 push @new_ops, $new_op;
903             }
904 573         1405 $node->{other_ops} = \@new_ops;
905             }
906 573         2381 return $node;
907              
908             } elsif ($dproto =~ /^\s*\z/) {
909 0         0 $type = 'call no protype';
910 0         0 @texts = ($subname_info);
911             } elsif ($dproto eq "\$" and B::Deparse::is_scalar($exprs[0])) {
912 0         0 $type = 'call - $ prototype';
913             # is_scalar is an excessively conservative test here:
914             # really, we should be comparing to the precedence of the
915             # top operator of $exprs[0] (ala unop()), but that would
916             # take some major code restructuring to do right.
917 0         0 @texts = $self->maybe_parens_func($sub_name,
918             $self->combine2str(', ', \@nodes), $cx, 16);
919             } elsif ($dproto ne '$' and defined($proto) || $simple) { #'
920 1         5 $type = "call $sub_name having prototype";
921 1         4 @texts = $self->maybe_parens_func($sub_name,
922             $self->combine2str(', ', \@nodes), $cx, 5);
923 1         6 return B::DeparseTree::TreeNode->new($op, $self, \@texts,
924             '', $type,
925             {other_ops => $other_ops});
926             } else {
927 0         0 $type = 'call';
928 0         0 @texts = dedup_parens_func($self, $subname_info, \@nodes);
929 0         0 return B::DeparseTree::TreeNode->new($op, $self, \@texts,
930             '', $type,
931             {other_ops => $other_ops});
932             }
933             }
934 0         0 my $node = $self->info_from_template($type, $op,
935             '%C', [[0, $#texts, '']], \@texts,
936             {other_ops => $other_ops});
937              
938             # Take the subname_info portion of $node and use that as the
939             # part of the parent, null, pushmark ops.
940 0 0 0     0 if ($subname_info && $other_ops) {
941 0         0 my $str = $node->{text};
942 0         0 my $position = [0, length($subname_info->{text})];
943 0         0 my @new_ops = ();
944 0         0 foreach my $skipped_op (@$other_ops) {
945 0         0 my $new_op = $self->info_from_string($op->name, $skipped_op, $str,
946             {position => $position});
947 0         0 push @new_ops, $new_op;
948             }
949 0         0 $node->{other_ops} = \@new_ops;
950             }
951 0         0 return $node;
952             }
953              
954             sub pp_entereval {
955 12 100   12 0 87 unop(
956             @_,
957             $_[1]->private & OPpEVAL_BYTES ? 'evalbytes' : "eval"
958             )
959             }
960              
961             sub pp_flop
962             {
963 0     0 0 0 my $self = shift;
964 0         0 my($op, $cx) = @_;
965 0         0 my $flip = $op->first;
966 0 0       0 my $type = ($flip->flags & OPf_SPECIAL) ? "..." : "..";
967 0         0 my $node =$self->range($flip->first, $cx, $type);
968 0         0 return $self->info_from_template("pp_flop $type", $op, "%c", undef, [$node], {});
969             }
970              
971             sub pp_gv
972             {
973 1224     1224 0 2171 my($self, $op, $cx) = @_;
974 1224         9666 my $gv = $self->gv_or_padgv($op);
975 1224         21990 my $name = $self->gv_name($gv);
976 1224         5328 return $self->info_from_string("global variable $name", $op, $name);
977             }
978              
979             # FIXME: adjust use of maybe_local_str
980             sub pp_gvsv
981             {
982 1353     1353 0 2409 my($self, $op, $cx) = @_;
983 1353         11083 my $gv = $self->gv_or_padgv($op);
984 1353         25751 return $self->maybe_local_str($op, $cx,
985             $self->stash_variable("\$",
986             $self->gv_name($gv), $cx));
987             }
988              
989             sub pp_null
990             {
991 5255 50   5255 0 15514 $] < 5.022 ? null_older(@_) : null_newer(@_);
992             }
993              
994             sub pp_once
995             {
996 1     1 0 4 my ($self, $op, $cx) = @_;
997 1         16 my $cond = $op->first;
998 1         6 my $true = $cond->sibling;
999              
1000 1         4 return $self->deparse($true, $cx);
1001             }
1002              
1003 45     45 0 154 sub pp_or { logop(@_, "or", 2, "||", 10, "unless") }
1004 0     0 0 0 sub pp_dor { logop(@_, "//", 10) }
1005              
1006 0     0 0 0 sub pp_mapwhile { mapop(@_, "map") }
1007 0     0 0 0 sub pp_grepwhile { mapop(@_, "grep") }
1008              
1009 5     5 0 27 sub pp_preinc { pfixop(@_, "++", 23) }
1010 0     0 0 0 sub pp_predec { pfixop(@_, "--", 23) }
1011 0     0 0 0 sub pp_i_preinc { pfixop(@_, "++", 23) }
1012 0     0 0 0 sub pp_i_predec { pfixop(@_, "--", 23) }
1013              
1014             sub pp_rcatline {
1015 0     0 0 0 my ($self, $op) = @_;
1016 0         0 return $self->info_from_string('rcatline <$fh>', $op,
1017             sprintf "<%s>", $self->gv_name($self->gv_or_padgv($op)));
1018             }
1019              
1020             sub pp_readline {
1021 6     6 0 19 my $self = shift;
1022 6         11 my($op, $cx) = @_;
1023 6         21 my $first_kid = $op->first;
1024 6         8 my $kid = $first_kid;
1025 6         8 my @other_ops;
1026             # Do we have <$fh>?
1027 6 50       26 if ($first_kid->name eq "rv2gv") {
1028 0         0 push @other_ops, $kid;
1029 0         0 $kid = $first_kid->first;
1030             }
1031 6 50 33     88 if (B::Deparse::is_scalar($kid) and
      66        
1032             ($] < 5.021 or
1033             ($op->flags & OPf_SPECIAL))) {
1034 0         0 my $kid_node = $self->deparse($kid, 1, $op);
1035 0 0       0 if ($kid_node->{text} eq 'ARGV') {
1036 0 0       0 if (@other_ops) {
1037             # skipped first node, also add $kid_node.
1038 0         0 push @other_ops, $kid_node;
1039             } else {
1040             # upgrade @other_ops from an op to a node
1041 0         0 @other_ops = ($kid_node);
1042             }
1043 0         0 return $self->info_from_string('readline <<>>', $op, '<<>>',
1044             {other_ops => [$first_kid, $kid_node]});
1045             } else {
1046 0         0 return $self->info_from_template('readline <$fh>', $op, "<%c>",
1047             undef, [$kid_node],
1048             {other_ops => @other_ops});
1049             }
1050             }
1051 6         27 my $node = $self->unop($op, $cx, "readline");
1052 6         8 push @{$node->{other_ops}}, $first_kid;
  6         15  
1053 6         12 return $node
1054             }
1055              
1056             sub pp_split {
1057             # 5.20 might drop "maybe_targmy?"
1058 0     0 0 0 maybe_targmy(@_, \&split, "split");
1059             }
1060              
1061             sub pp_stringify {
1062 0 0   0 0 0 $] < 5.022 ? stringify_older(@_) : stringify_newer(@_);
1063             }
1064              
1065             sub pp_subst {
1066 18 50   18 0 57 $] < 5.022 ? subst_older(@_) : subst_newer(@_);
1067             }
1068              
1069             # Perl 5.14 doesn't have this
1070 8     8   55 use constant OPpSUBSTR_REPL_FIRST => 16;
  8         18  
  8         3919  
1071              
1072             sub pp_substr {
1073 6     6 0 16 my ($self,$op,$cx) = @_;
1074 6 50       32 if ($op->private & OPpSUBSTR_REPL_FIRST) {
1075 0         0 my $left = listop($self, $op, 7, "substr", $op->first->sibling->sibling);
1076 0         0 my $right = $self->deparse($op->first->sibling, 7, $op);
1077 0         0 return info_from_list($op, $self,[$left, '=', $right], ' ',
1078             'substr_repl_first', {});
1079             }
1080 6         34 return maybe_local(@_, listop(@_, "substr"))
1081             }
1082              
1083             # FIXME:
1084             # Different between 5.20 and 5.22. We've used 5.22 though.
1085             # Go over and make sure this is okay.
1086             sub pp_stub {
1087 1286     1286 0 2401 my ($self, $op) = @_;
1088 1286         3629 $self->info_from_string('stub ()', $op, '()')
1089             };
1090              
1091             sub pp_trans {
1092 6     6 0 10 my $self = shift;
1093 6         9 my($op, $cx) = @_;
1094 6         9 my($from, $to);
1095 6         33 my $class = class($op);
1096 6         21 my $priv_flags = $op->private;
1097 6 50       13 if ($class eq "PVOP") {
    0          
1098 6         724 ($from, $to) = B::Deparse::tr_decode_byte($op->pv, $priv_flags);
1099             } elsif ($class eq "PADOP") {
1100 0         0 ($from, $to)
1101             = tr_decode_utf8($self->padval($op->padix)->RV, $priv_flags);
1102             } else { # class($op) eq "SVOP"
1103 0         0 ($from, $to) = B::Deparse::tr_decode_utf8($op->sv->RV, $priv_flags);
1104             }
1105 6         14 my $flags = "";
1106 6 100       16 $flags .= "c" if $priv_flags & OPpTRANS_COMPLEMENT;
1107 6 100       12 $flags .= "d" if $priv_flags & OPpTRANS_DELETE;
1108 6 100 66     19 $to = "" if $from eq $to and $flags eq "";
1109 6 100       13 $flags .= "s" if $priv_flags & OPpTRANS_SQUASH;
1110 6         42 return info_from_list($op, $self, ['tr', double_delim($from, $to), $flags],
1111             '', 'pp_trans', {});
1112             }
1113              
1114             sub pp_transr {
1115 2     2 0 5 my $self = $_[0];
1116 2         3 my $op = $_[1];
1117 2         5 my $info = pp_trans(@_);
1118             # FIXME: thrn into template as below
1119 2         13 return $self->info_from_string('pp_transr', $op, $info->{text} . 'r',
1120             {other_ops => [$info]});
1121             # return $self->info_from_template("trans r", "%cr", undef, [$info]);
1122             }
1123              
1124             sub pp_unstack {
1125 1     1 0 5 my ($self, $op) = @_;
1126             # see also leaveloop
1127 1         6 return $self->info_from_string("unstack", $op, '');
1128             }
1129              
1130             # xor is syntactically a logop, but it's really a binop (contrary to
1131             # old versions of opcode.pl). Syntax is what matters here.
1132 6     6 0 22 sub pp_xor { logop(@_, "xor", 2, "", 0, "") }
1133              
1134             1;