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