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