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