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; |