line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright (c) 2015-2018 Rocky Bernstein |
2
|
|
|
|
|
|
|
# Copyright (c) 1998-2000, 2002, 2003, 2004, 2005, 2006 Stephen McCamant. |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# All rights reserved. |
5
|
|
|
|
|
|
|
# This module is free software; you can redistribute and/or modify |
6
|
|
|
|
|
|
|
# it under the same terms as Perl itself. |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# This is based on the module B::Deparse by Stephen McCamant. |
9
|
|
|
|
|
|
|
# It has been extended save tree structure, and is addressible |
10
|
|
|
|
|
|
|
# by opcode address. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# B::Parse in turn is based on the module of the same name by Malcolm Beattie, |
13
|
|
|
|
|
|
|
# but essentially none of his code remains. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# The is the main entrypoint for DeparseTree objects and routines. |
16
|
|
|
|
|
|
|
# In the future there may be a StringMain which is like this |
17
|
|
|
|
|
|
|
# but doesn't save copious tree information but instead just gathers |
18
|
|
|
|
|
|
|
# strings in the same way B::Deparse does. |
19
|
8
|
|
|
8
|
|
47
|
use strict; use warnings; |
|
8
|
|
|
8
|
|
15
|
|
|
8
|
|
|
|
|
210
|
|
|
8
|
|
|
|
|
37
|
|
|
8
|
|
|
|
|
17
|
|
|
8
|
|
|
|
|
463
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
package B::DeparseTree; |
22
|
|
|
|
|
|
|
|
23
|
8
|
|
|
|
|
1062
|
use B qw(class |
24
|
|
|
|
|
|
|
CVf_LVALUE |
25
|
|
|
|
|
|
|
CVf_METHOD |
26
|
|
|
|
|
|
|
OPf_KIDS |
27
|
|
|
|
|
|
|
OPf_SPECIAL |
28
|
|
|
|
|
|
|
OPpLVAL_INTRO |
29
|
|
|
|
|
|
|
OPpTARGET_MY |
30
|
|
|
|
|
|
|
SVf_IOK |
31
|
|
|
|
|
|
|
SVf_NOK |
32
|
|
|
|
|
|
|
SVf_POK |
33
|
|
|
|
|
|
|
SVf_ROK |
34
|
|
|
|
|
|
|
SVs_RMG |
35
|
|
|
|
|
|
|
SVs_SMG |
36
|
|
|
|
|
|
|
main_cv main_root main_start |
37
|
|
|
|
|
|
|
opnumber |
38
|
|
|
|
|
|
|
perlstring |
39
|
|
|
|
|
|
|
svref_2object |
40
|
8
|
|
|
8
|
|
48
|
); |
|
8
|
|
|
|
|
15
|
|
41
|
|
|
|
|
|
|
|
42
|
8
|
|
|
8
|
|
48
|
use Carp; |
|
8
|
|
|
|
|
15
|
|
|
8
|
|
|
|
|
447
|
|
43
|
8
|
|
|
8
|
|
59
|
use B::Deparse; |
|
8
|
|
|
|
|
48
|
|
|
8
|
|
|
|
|
201
|
|
44
|
8
|
|
|
8
|
|
3263
|
use B::DeparseTree::OPflags; |
|
8
|
|
|
|
|
21
|
|
|
8
|
|
|
|
|
439
|
|
45
|
8
|
|
|
8
|
|
3232
|
use B::DeparseTree::PP_OPtable; |
|
8
|
|
|
|
|
39
|
|
|
8
|
|
|
|
|
899
|
|
46
|
8
|
|
|
8
|
|
3378
|
use B::DeparseTree::SyntaxTree; |
|
8
|
|
|
|
|
28
|
|
|
8
|
|
|
|
|
1975
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Copy unchanged functions from B::Deparse |
49
|
|
|
|
|
|
|
*find_scope_en = *B::Deparse::find_scope_en; |
50
|
|
|
|
|
|
|
*find_scope_st = *B::Deparse::find_scope_st; |
51
|
|
|
|
|
|
|
*gv_name = *B::Deparse::gv_name; |
52
|
|
|
|
|
|
|
*lex_in_scope = *B::Deparse::lex_in_scope; |
53
|
|
|
|
|
|
|
*padname = *B::Deparse::padname; |
54
|
|
|
|
|
|
|
*stash_subs = *B::Deparse::stash_subs; |
55
|
|
|
|
|
|
|
*stash_variable = *B::Deparse::stash_variable; |
56
|
|
|
|
|
|
|
*todo = *B::Deparse::todo; |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
our($VERSION, @EXPORT, @ISA); |
59
|
|
|
|
|
|
|
$VERSION = '3.3.0'; |
60
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
61
|
|
|
|
|
|
|
@EXPORT = qw( |
62
|
|
|
|
|
|
|
%globalnames |
63
|
|
|
|
|
|
|
%ignored_hints |
64
|
|
|
|
|
|
|
%rev_feature |
65
|
|
|
|
|
|
|
WARN_MASK |
66
|
|
|
|
|
|
|
coderef2info |
67
|
|
|
|
|
|
|
coderef2text |
68
|
|
|
|
|
|
|
const |
69
|
|
|
|
|
|
|
declare_hinthash |
70
|
|
|
|
|
|
|
declare_hints |
71
|
|
|
|
|
|
|
declare_warnings |
72
|
|
|
|
|
|
|
deparse_sub($$$$) |
73
|
|
|
|
|
|
|
deparse_subname($$) |
74
|
|
|
|
|
|
|
new |
75
|
|
|
|
|
|
|
next_todo |
76
|
|
|
|
|
|
|
pragmata |
77
|
|
|
|
|
|
|
seq_subs |
78
|
|
|
|
|
|
|
style_opts |
79
|
|
|
|
|
|
|
todo |
80
|
|
|
|
|
|
|
); |
81
|
|
|
|
|
|
|
|
82
|
8
|
|
|
8
|
|
59
|
use Config; |
|
8
|
|
|
|
|
18
|
|
|
8
|
|
|
|
|
1837
|
|
83
|
|
|
|
|
|
|
my $is_cperl = $Config::Config{usecperl}; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
my $module; |
86
|
|
|
|
|
|
|
if ($] >= 5.014 and $] < 5.016) { |
87
|
|
|
|
|
|
|
$module = "P514"; |
88
|
|
|
|
|
|
|
} elsif ($] >= 5.016 and $] < 5.018) { |
89
|
|
|
|
|
|
|
$module = "P516"; |
90
|
|
|
|
|
|
|
} elsif ($] >= 5.018 and $] < 5.020) { |
91
|
|
|
|
|
|
|
$module = "P518"; |
92
|
|
|
|
|
|
|
} elsif ($] >= 5.020 and $] < 5.022) { |
93
|
|
|
|
|
|
|
$module = "P520"; |
94
|
|
|
|
|
|
|
} elsif ($] >= 5.022 and $] < 5.024) { |
95
|
|
|
|
|
|
|
$module = "P522"; |
96
|
|
|
|
|
|
|
} elsif ($] >= 5.024 and $] < 5.026) { |
97
|
|
|
|
|
|
|
$module = "P524"; |
98
|
|
|
|
|
|
|
} elsif ($] >= 5.026) { |
99
|
|
|
|
|
|
|
$module = "P526"; |
100
|
|
|
|
|
|
|
} else { |
101
|
|
|
|
|
|
|
die "Can only handle Perl 5.16..5.26"; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
$module .= 'c' if $is_cperl; |
105
|
|
|
|
|
|
|
@ISA = ("Exporter", "B::DeparseTree::$module"); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
require "B/DeparseTree/${module}.pm"; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# The BEGIN {} is used here because otherwise this code isn't executed |
110
|
|
|
|
|
|
|
# when you run B::Deparse on itself. |
111
|
|
|
|
|
|
|
my %globalnames; |
112
|
8
|
|
|
8
|
|
489
|
BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC", |
113
|
|
|
|
|
|
|
"ENV", "ARGV", "ARGVOUT", "_"); } |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
my $max_prec; |
116
|
8
|
|
|
8
|
|
624
|
BEGIN { $max_prec = int(0.999 + 8*length(pack("F", 42))*log(2)/log(10)); } |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
BEGIN { |
119
|
|
|
|
|
|
|
# List version-specific constants here. |
120
|
|
|
|
|
|
|
# Easiest way to keep this code portable between version looks to |
121
|
|
|
|
|
|
|
# be to fake up a dummy constant that will never actually be true. |
122
|
8
|
|
|
8
|
|
36
|
foreach (qw(OPpSORT_INPLACE OPpSORT_DESCEND OPpITER_REVERSED |
123
|
|
|
|
|
|
|
OPpCONST_NOVER OPpPAD_STATE PMf_SKIPWHITE RXf_SKIPWHITE |
124
|
|
|
|
|
|
|
RXf_PMf_CHARSET RXf_PMf_KEEPCOPY |
125
|
|
|
|
|
|
|
CVf_LOCKED OPpREVERSE_INPLACE OPpSUBSTR_REPL_FIRST |
126
|
|
|
|
|
|
|
PMf_NONDESTRUCT OPpCONST_ARYBASE OPpEVAL_BYTES)) { |
127
|
120
|
|
|
|
|
210
|
eval { import B $_ }; |
|
120
|
|
|
|
|
9870
|
|
128
|
8
|
|
|
8
|
|
55
|
no strict 'refs'; |
|
8
|
|
|
|
|
20
|
|
|
8
|
|
|
|
|
627
|
|
129
|
120
|
100
|
|
|
|
239
|
*{$_} = sub () {0} unless *{$_}{CODE}; |
|
24
|
|
|
|
|
97
|
|
|
120
|
|
|
|
|
4084
|
|
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub new { |
134
|
10
|
|
|
10
|
1
|
750929
|
my $class = shift; |
135
|
10
|
|
|
|
|
39
|
my $self = bless {}, $class; |
136
|
10
|
|
|
|
|
167
|
$self->{'cuddle'} = " "; #\n%| is another alternative |
137
|
10
|
|
|
|
|
42
|
$self->{'curcop'} = undef; |
138
|
10
|
|
|
|
|
41
|
$self->{'curstash'} = "main"; |
139
|
10
|
|
|
|
|
37
|
$self->{'ex_const'} = "'?unrecoverable constant?'"; |
140
|
10
|
|
|
|
|
34
|
$self->{'expand'} = 0; |
141
|
10
|
|
|
|
|
36
|
$self->{'files'} = {}; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# How many spaces per indent nesting? |
144
|
10
|
|
|
|
|
35
|
$self->{'indent_size'} = 4; |
145
|
|
|
|
|
|
|
|
146
|
10
|
|
|
|
|
40
|
$self->{'opaddr'} = 0; |
147
|
10
|
|
|
|
|
35
|
$self->{'linenums'} = 0; |
148
|
10
|
|
|
|
|
35
|
$self->{'parens'} = 0; |
149
|
10
|
|
|
|
|
39
|
$self->{'subs_todo'} = []; |
150
|
10
|
|
|
|
|
33
|
$self->{'unquote'} = 0; |
151
|
10
|
|
|
|
|
29
|
$self->{'use_dumper'} = 0; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Compress spaces with tabs? 1 tab = 8 spaces |
154
|
10
|
|
|
|
|
25
|
$self->{'use_tabs'} = 0; |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Indentation level |
157
|
10
|
|
|
|
|
25
|
$self->{'level'} = 0; |
158
|
|
|
|
|
|
|
|
159
|
10
|
|
|
|
|
40
|
$self->{'ambient_arybase'} = 0; |
160
|
10
|
|
|
|
|
21
|
$self->{'ambient_warnings'} = undef; # Assume no lexical warnings |
161
|
10
|
|
|
|
|
27
|
$self->{'ambient_hints'} = 0; |
162
|
10
|
|
|
|
|
32
|
$self->{'ambient_hinthash'} = undef; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Given an opcode address, get the accumulated OP tree |
165
|
|
|
|
|
|
|
# OP for that. FIXME: remove this |
166
|
10
|
|
|
|
|
30
|
$self->{optree} = {}; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# For B::DeparseTree::TreeNode's that are created and don't have |
169
|
|
|
|
|
|
|
# real OPs associated with them, we assign a fake address; |
170
|
10
|
|
|
|
|
31
|
$self->{'last_fake_addr'} = 0; |
171
|
|
|
|
|
|
|
|
172
|
10
|
|
|
|
|
55
|
$self->init(); |
173
|
|
|
|
|
|
|
|
174
|
10
|
|
|
|
|
44
|
while (my $arg = shift @_) { |
175
|
0
|
0
|
|
|
|
0
|
if ($arg eq "-d") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
176
|
0
|
|
|
|
|
0
|
$self->{'use_dumper'} = 1; |
177
|
0
|
|
|
|
|
0
|
require Data::Dumper; |
178
|
|
|
|
|
|
|
} elsif ($arg =~ /^-f(.*)/) { |
179
|
0
|
|
|
|
|
0
|
$self->{'files'}{$1} = 1; |
180
|
|
|
|
|
|
|
} elsif ($arg eq "-l") { |
181
|
0
|
|
|
|
|
0
|
$self->{'linenums'} = 1; |
182
|
|
|
|
|
|
|
} elsif ($arg eq "-a") { |
183
|
0
|
|
|
|
|
0
|
$self->{'linenums'} = 1; |
184
|
0
|
|
|
|
|
0
|
$self->{'opaddr'} = 1; |
185
|
|
|
|
|
|
|
} elsif ($arg eq "-p") { |
186
|
0
|
|
|
|
|
0
|
$self->{'parens'} = 1; |
187
|
|
|
|
|
|
|
} elsif ($arg eq "-P") { |
188
|
0
|
|
|
|
|
0
|
$self->{'noproto'} = 1; |
189
|
|
|
|
|
|
|
} elsif ($arg eq "-q") { |
190
|
0
|
|
|
|
|
0
|
$self->{'unquote'} = 1; |
191
|
|
|
|
|
|
|
} elsif (substr($arg, 0, 2) eq "-s") { |
192
|
0
|
|
|
|
|
0
|
$self->style_opts(substr $arg, 2); |
193
|
|
|
|
|
|
|
} elsif ($arg =~ /^-x(\d)$/) { |
194
|
0
|
|
|
|
|
0
|
$self->{'expand'} = $1; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
} |
197
|
10
|
|
|
|
|
34
|
return $self; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
{ |
201
|
|
|
|
|
|
|
# Mask out the bits that L uses |
202
|
|
|
|
|
|
|
my $WARN_MASK; |
203
|
|
|
|
|
|
|
BEGIN { |
204
|
8
|
|
|
8
|
|
1616
|
$WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all}; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
sub WARN_MASK () { |
207
|
5184
|
|
|
5184
|
0
|
27479
|
return $WARN_MASK; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# Initialize the contextual information, either from |
212
|
|
|
|
|
|
|
# defaults provided with the ambient_pragmas method, |
213
|
|
|
|
|
|
|
# or from Perl's own defaults otherwise. |
214
|
|
|
|
|
|
|
sub init { |
215
|
1402
|
|
|
1402
|
0
|
2668
|
my $self = shift; |
216
|
|
|
|
|
|
|
|
217
|
1402
|
|
|
|
|
3224
|
$self->{'arybase'} = $self->{'ambient_arybase'}; |
218
|
|
|
|
|
|
|
$self->{'warnings'} = defined ($self->{'ambient_warnings'}) |
219
|
1402
|
100
|
|
|
|
3695
|
? $self->{'ambient_warnings'} & WARN_MASK |
220
|
|
|
|
|
|
|
: undef; |
221
|
1402
|
|
|
|
|
2363
|
$self->{'hints'} = $self->{'ambient_hints'}; |
222
|
1402
|
50
|
|
|
|
3263
|
$self->{'hints'} &= 0xFF if $] < 5.009; |
223
|
1402
|
|
|
|
|
2197
|
$self->{'hinthash'} = $self->{'ambient_hinthash'}; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# also a convenient place to clear out subs_declared |
226
|
1402
|
|
|
|
|
2967
|
delete $self->{'subs_declared'}; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
BEGIN { |
230
|
8
|
|
|
8
|
|
35
|
for (qw[ pushmark ]) |
231
|
|
|
|
|
|
|
{ |
232
|
8
|
|
|
|
|
8357
|
eval "sub OP_\U$_ () { " . opnumber($_) . "}" |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub main2info |
237
|
|
|
|
|
|
|
{ |
238
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
239
|
0
|
|
|
|
|
0
|
$self->{'curcv'} = B::main_cv; |
240
|
0
|
|
|
|
|
0
|
$self->pessimise(B::main_root, B::main_start); |
241
|
0
|
|
|
|
|
0
|
return $self->deparse_root(B::main_root); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub coderef2info |
245
|
|
|
|
|
|
|
{ |
246
|
1328
|
|
|
1328
|
0
|
1083936
|
my ($self, $coderef, $start_op) = @_; |
247
|
1328
|
|
|
|
|
5539
|
my $cv = svref_2object ( $coderef ); |
248
|
1328
|
|
|
|
|
4617
|
my $gv = $cv->GV; |
249
|
1328
|
50
|
|
|
|
5614
|
if ($gv->NAME eq 'main') { |
250
|
0
|
|
|
|
|
0
|
return $self->main2info(); |
251
|
|
|
|
|
|
|
} else { |
252
|
1328
|
50
|
|
|
|
5032
|
croak "Usage: ->coderef2info(CODEREF)" |
253
|
|
|
|
|
|
|
unless UNIVERSAL::isa($coderef, "CODE"); |
254
|
1328
|
|
|
|
|
4375
|
$self->init(); |
255
|
1328
|
|
|
|
|
4118
|
return $self->deparse_sub($cv, $start_op); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub coderef2text |
260
|
|
|
|
|
|
|
{ |
261
|
64
|
|
|
64
|
1
|
125635
|
my ($self, $func) = @_; |
262
|
64
|
|
|
|
|
134
|
my $info; |
263
|
64
|
50
|
|
|
|
238
|
if ($func eq 'main::main') { |
264
|
0
|
|
|
|
|
0
|
$info = $self->main2info(); |
265
|
|
|
|
|
|
|
} else { |
266
|
64
|
50
|
|
|
|
277
|
croak "Usage: ->coderef2text(CODEREF)" unless UNIVERSAL::isa($func, "CODE"); |
267
|
64
|
|
|
|
|
242
|
$self->init(); |
268
|
64
|
|
|
|
|
199
|
$info = $self->coderef2info($func); |
269
|
|
|
|
|
|
|
} |
270
|
64
|
|
|
|
|
219
|
return $self->info2str($info); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub const { |
274
|
91
|
|
|
91
|
0
|
162
|
my $self = shift; |
275
|
91
|
|
|
|
|
198
|
my($sv, $cx) = @_; |
276
|
91
|
50
|
|
|
|
261
|
if ($self->{'use_dumper'}) { |
277
|
0
|
|
|
|
|
0
|
return $self->const_dumper($sv, $cx); |
278
|
|
|
|
|
|
|
} |
279
|
91
|
50
|
|
|
|
707
|
if (class($sv) eq "SPECIAL") { |
280
|
|
|
|
|
|
|
# sv_undef, sv_yes, sv_no |
281
|
0
|
|
|
|
|
0
|
my $text = ('undef', '1', $self->maybe_parens("!1", $cx, 21))[$$sv-1]; |
282
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: special', $sv, $text); |
283
|
|
|
|
|
|
|
} |
284
|
91
|
50
|
|
|
|
559
|
if (class($sv) eq "NULL") { |
285
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: NULL', $sv, 'undef'); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
# convert a version object into the "v1.2.3" string in its V magic |
288
|
91
|
50
|
|
|
|
409
|
if ($sv->FLAGS & SVs_RMG) { |
289
|
0
|
|
|
|
|
0
|
for (my $mg = $sv->MAGIC; $mg; $mg = $mg->MOREMAGIC) { |
290
|
0
|
0
|
|
|
|
0
|
if ($mg->TYPE eq 'V') { |
291
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const_magic', $sv, |
292
|
|
|
|
|
|
|
$mg->PTR); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
91
|
100
|
33
|
|
|
499
|
if ($sv->FLAGS & SVf_IOK) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
298
|
62
|
|
|
|
|
329
|
my $str = $sv->int_value; |
299
|
62
|
50
|
|
|
|
194
|
$str = $self->maybe_parens($str, $cx, 21) if $str < 0; |
300
|
62
|
|
|
|
|
302
|
return $self->info_from_string("const: integer $str", $sv, $str); |
301
|
|
|
|
|
|
|
} elsif ($sv->FLAGS & SVf_NOK) { |
302
|
0
|
|
|
|
|
0
|
my $nv = $sv->NV; |
303
|
0
|
0
|
|
|
|
0
|
if ($nv == 0) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
304
|
0
|
0
|
|
|
|
0
|
if (pack("F", $nv) eq pack("F", 0)) { |
305
|
|
|
|
|
|
|
# positive zero |
306
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: float positive 0', |
307
|
|
|
|
|
|
|
$sv, |
308
|
|
|
|
|
|
|
"0"); |
309
|
|
|
|
|
|
|
} else { |
310
|
|
|
|
|
|
|
# negative zero |
311
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: float negative 0', |
312
|
|
|
|
|
|
|
$sv, $self, |
313
|
|
|
|
|
|
|
$self->maybe_parens("-.0", $cx, 21)); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} elsif (1/$nv == 0) { |
316
|
0
|
0
|
|
|
|
0
|
if ($nv > 0) { |
317
|
|
|
|
|
|
|
# positive infinity |
318
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: float +infinity', |
319
|
|
|
|
|
|
|
$sv, |
320
|
|
|
|
|
|
|
$self->maybe_parens("9**9**9", $cx, 22)); |
321
|
|
|
|
|
|
|
} else { |
322
|
|
|
|
|
|
|
# negative infinity |
323
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: float -infinity', |
324
|
|
|
|
|
|
|
$sv, |
325
|
|
|
|
|
|
|
$self->maybe_parens("-9**9**9", $cx, 21)); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
} elsif ($nv != $nv) { |
328
|
|
|
|
|
|
|
# NaN |
329
|
0
|
0
|
|
|
|
0
|
if (pack("F", $nv) eq pack("F", sin(9**9**9))) { |
|
|
0
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# the normal kind |
331
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, "sin(9**9**9)", 'const_Nan', {}); |
332
|
|
|
|
|
|
|
} elsif (pack("F", $nv) eq pack("F", -sin(9**9**9))) { |
333
|
|
|
|
|
|
|
# the inverted kind |
334
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("-sin(9**9**9)", $cx, 21), |
335
|
|
|
|
|
|
|
'const: float Nan invert', {}); |
336
|
|
|
|
|
|
|
} else { |
337
|
|
|
|
|
|
|
# some other kind |
338
|
0
|
|
|
|
|
0
|
my $hex = unpack("h*", pack("F", $nv)); |
339
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, qq'unpack("F", pack("h*", "$hex"))', |
340
|
|
|
|
|
|
|
'const: Na na na', {}); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
# first, try the default stringification |
344
|
0
|
|
|
|
|
0
|
my $str = "$nv"; |
345
|
0
|
0
|
|
|
|
0
|
if ($str != $nv) { |
346
|
|
|
|
|
|
|
# failing that, try using more precision |
347
|
0
|
|
|
|
|
0
|
$str = sprintf("%.${max_prec}g", $nv); |
348
|
|
|
|
|
|
|
# if (pack("F", $str) ne pack("F", $nv)) { |
349
|
0
|
0
|
|
|
|
0
|
if ($str != $nv) { |
350
|
|
|
|
|
|
|
# not representable in decimal with whatever sprintf() |
351
|
|
|
|
|
|
|
# and atof() Perl is using here. |
352
|
0
|
|
|
|
|
0
|
my($mant, $exp) = B::Deparse::split_float($nv); |
353
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("$mant * 2**$exp", $cx, 19), |
354
|
|
|
|
|
|
|
'const: float not-sprintf/atof-able', {}); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
} |
357
|
0
|
0
|
|
|
|
0
|
$str = $self->maybe_parens($str, $cx, 21) if $nv < 0; |
358
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $str, 'constant nv', {}); |
359
|
|
|
|
|
|
|
} elsif ($sv->FLAGS & SVf_ROK && $sv->can("RV")) { |
360
|
0
|
|
|
|
|
0
|
my $ref = $sv->RV; |
361
|
0
|
0
|
|
|
|
0
|
if (class($ref) eq "AV") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
my $list_info = $self->list_const($sv, 2, $ref->ARRAY); |
363
|
0
|
|
|
|
|
0
|
return info_from_list($sv, $self, ['[', $list_info->{text}, ']'], '', 'const_av', |
364
|
|
|
|
|
|
|
{body => [$list_info]}); |
365
|
|
|
|
|
|
|
} elsif (class($ref) eq "HV") { |
366
|
0
|
|
|
|
|
0
|
my %hash = $ref->ARRAY; |
367
|
0
|
|
|
|
|
0
|
my @elts; |
368
|
0
|
|
|
|
|
0
|
for my $k (sort keys %hash) { |
369
|
0
|
|
|
|
|
0
|
push @elts, "$k => " . $self->const($hash{$k}, 6); |
370
|
|
|
|
|
|
|
} |
371
|
0
|
|
|
|
|
0
|
return info_from_list($sv, $self, ["{", join(", ", @elts), "}"], '', |
372
|
|
|
|
|
|
|
'constant hash value', {}); |
373
|
|
|
|
|
|
|
} elsif (class($ref) eq "CV") { |
374
|
|
|
|
|
|
|
BEGIN { |
375
|
8
|
50
|
|
8
|
|
72
|
if ($] > 5.0150051) { |
376
|
8
|
|
|
|
|
86
|
require overloading; |
377
|
8
|
|
|
|
|
17773
|
unimport overloading; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
} |
380
|
0
|
0
|
0
|
|
|
0
|
if ($] > 5.0150051 && $self->{curcv} && |
|
|
|
0
|
|
|
|
|
381
|
|
|
|
|
|
|
$self->{curcv}->object_2svref == $ref->object_2svref) { |
382
|
0
|
|
|
|
|
0
|
return $self->info_from_string('sub __SUB__', $sv, |
383
|
|
|
|
|
|
|
$self->keyword("__SUB__")); |
384
|
|
|
|
|
|
|
} |
385
|
0
|
|
|
|
|
0
|
my $sub_info = $self->deparse_sub($ref); |
386
|
0
|
|
|
|
|
0
|
return info_from_list($sub_info->{op}, $self, ["sub ", $sub_info->{text}], '', |
387
|
|
|
|
|
|
|
'constant sub 2', |
388
|
|
|
|
|
|
|
{body => [$sub_info]}); |
389
|
|
|
|
|
|
|
} |
390
|
0
|
0
|
|
|
|
0
|
if ($ref->FLAGS & SVs_SMG) { |
391
|
0
|
|
|
|
|
0
|
for (my $mg = $ref->MAGIC; $mg; $mg = $mg->MOREMAGIC) { |
392
|
0
|
0
|
|
|
|
0
|
if ($mg->TYPE eq 'r') { |
393
|
0
|
|
|
|
|
0
|
my $re = B::Deparse::re_uninterp(B::Deparse::escape_str(B::Deparse::re_unback($mg->precomp))); |
394
|
0
|
|
|
|
|
0
|
return $self->single_delim($sv, "qr", "", $re); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
0
|
my $const = $self->const($ref, 20); |
400
|
0
|
0
|
0
|
|
|
0
|
if ($self->{in_subst_repl} && $const =~ /^[0-9]/) { |
401
|
0
|
|
|
|
|
0
|
$const = "($const)"; |
402
|
|
|
|
|
|
|
} |
403
|
0
|
|
|
|
|
0
|
my @texts = ("\\", $const); |
404
|
0
|
|
|
|
|
0
|
return info_from_list($sv, $self, \@texts, '', 'const_rv', |
405
|
|
|
|
|
|
|
{maybe_parens => [$self, $cx, 20]}); |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
} elsif ($sv->FLAGS & SVf_POK) { |
408
|
29
|
|
|
|
|
71
|
my $str = $sv->PV; |
409
|
29
|
50
|
|
|
|
90
|
if ($str =~ /[[:^print:]]/) { |
410
|
0
|
|
|
|
|
0
|
return $self->single_delim($sv, "qq", '"', |
411
|
|
|
|
|
|
|
B::Deparse::uninterp B::Deparse::escape_str B::Deparse::unback $str); |
412
|
|
|
|
|
|
|
} else { |
413
|
29
|
|
|
|
|
245
|
return $self->single_delim($sv, "q", "'", B::Deparse::unback $str); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
} else { |
416
|
0
|
|
|
|
|
0
|
return $self->info_from_string('const: undef', $sv, "undef"); |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub const_dumper |
421
|
|
|
|
|
|
|
{ |
422
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
423
|
0
|
|
|
|
|
0
|
my($sv, $cx) = @_; |
424
|
0
|
|
|
|
|
0
|
my $ref = $sv->object_2svref(); |
425
|
0
|
|
|
|
|
0
|
my $dumper = Data::Dumper->new([$$ref], ['$v']); |
426
|
0
|
|
|
|
|
0
|
$dumper->Purity(1)->Terse(1)->Deparse(1)->Indent(0)->Useqq(1)->Sortkeys(1); |
427
|
0
|
|
|
|
|
0
|
my $str = $dumper->Dump(); |
428
|
0
|
0
|
|
|
|
0
|
if ($str =~ /^\$v/) { |
429
|
|
|
|
|
|
|
# FIXME: ??? |
430
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, ['${my', $str, '\$v}'], 'const_dumper_my', {}); |
431
|
|
|
|
|
|
|
} else { |
432
|
0
|
|
|
|
|
0
|
return $self->info_from_string("constant string", $sv, $str); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
# This is a special case of scopeop and lineseq, for the case of the |
437
|
|
|
|
|
|
|
# main_root. |
438
|
|
|
|
|
|
|
sub deparse_root { |
439
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
440
|
0
|
|
|
|
|
0
|
my($op) = @_; |
441
|
|
|
|
|
|
|
local(@$self{qw'curstash warnings hints hinthash'}) |
442
|
0
|
|
|
|
|
0
|
= @$self{qw'curstash warnings hints hinthash'}; |
443
|
0
|
|
|
|
|
0
|
my @ops; |
444
|
0
|
0
|
|
|
|
0
|
return if B::Deparse::null $op->first; # Can happen, e.g., for Bytecode without -k |
445
|
0
|
|
|
|
|
0
|
for (my $kid = $op->first->sibling; !B::Deparse::null($kid); $kid = $kid->sibling) { |
446
|
0
|
|
|
|
|
0
|
push @ops, $kid; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
my $fn = sub { |
449
|
0
|
|
|
0
|
|
0
|
my ($exprs, $i, $info, $parent) = @_; |
450
|
0
|
|
|
|
|
0
|
my $text = $info->{text}; |
451
|
0
|
|
|
|
|
0
|
my $op = $ops[$i]; |
452
|
0
|
|
|
|
|
0
|
$text =~ s/\f//; |
453
|
0
|
|
|
|
|
0
|
$text =~ s/\n$//; |
454
|
0
|
|
|
|
|
0
|
$text =~ s/;\n?\z//; |
455
|
0
|
|
|
|
|
0
|
$text =~ s/^\((.+)\)$/$1/; |
456
|
0
|
|
|
|
|
0
|
$info->{type} = $op->name; |
457
|
0
|
|
|
|
|
0
|
$info->{op} = $op; |
458
|
|
|
|
|
|
|
|
459
|
0
|
|
|
|
|
0
|
$self->{optree}{$$op} = $info; |
460
|
|
|
|
|
|
|
|
461
|
0
|
|
|
|
|
0
|
$info->{text} = $text; |
462
|
0
|
0
|
|
|
|
0
|
$info->{parent} = $$parent if $parent; |
463
|
0
|
|
|
|
|
0
|
push @$exprs, $info; |
464
|
0
|
|
|
|
|
0
|
}; |
465
|
0
|
|
|
|
|
0
|
my $info = $self->walk_lineseq($op, \@ops, $fn); |
466
|
0
|
|
|
|
|
0
|
my @skipped_ops; |
467
|
0
|
0
|
|
|
|
0
|
if (exists $info->{other_ops}) { |
468
|
0
|
|
|
|
|
0
|
@skipped_ops = @{$info->{other_ops}}; |
|
0
|
|
|
|
|
0
|
|
469
|
0
|
|
|
|
|
0
|
push @skipped_ops, $op->first; |
470
|
|
|
|
|
|
|
} else { |
471
|
0
|
|
|
|
|
0
|
@skipped_ops = ($op->first); |
472
|
|
|
|
|
|
|
} |
473
|
0
|
|
|
|
|
0
|
$info->{other_ops} = \@skipped_ops; |
474
|
0
|
|
|
|
|
0
|
return $info; |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub update_node($$$$) |
479
|
|
|
|
|
|
|
{ |
480
|
2101
|
|
|
2101
|
0
|
4344
|
my ($self, $node, $prev_expr, $op) = @_; |
481
|
2101
|
|
|
|
|
3493
|
$node->{prev_expr} = $prev_expr; |
482
|
2101
|
|
|
|
|
3265
|
my $addr = $prev_expr->{addr}; |
483
|
2101
|
100
|
66
|
|
|
9418
|
if ($addr && ! exists $self->{optree}{$addr}) { |
484
|
4
|
50
|
|
|
|
18
|
$self->{optree}{$addr} = $node if $op; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub walk_lineseq |
489
|
|
|
|
|
|
|
{ |
490
|
1342
|
|
|
1342
|
0
|
3008
|
my ($self, $op, $kids, $callback) = @_; |
491
|
1342
|
|
|
|
|
2654
|
my @kids = @$kids; |
492
|
1342
|
|
|
|
|
2320
|
my @body = (); # Accumulated node structures |
493
|
1342
|
|
|
|
|
1667
|
my $expr; |
494
|
1342
|
|
|
|
|
1859
|
my $prev_expr = undef; |
495
|
1342
|
|
|
|
|
1847
|
my $fix_cop = undef; |
496
|
1342
|
|
|
|
|
3326
|
for (my $i = 0; $i < @kids; $i++) { |
497
|
2088
|
100
|
|
|
|
13735
|
if (B::Deparse::is_state $kids[$i]) { |
498
|
2087
|
|
|
|
|
5817
|
$expr = ($self->deparse($kids[$i], 0, $op)); |
499
|
2087
|
|
|
|
|
6236
|
$callback->(\@body, $i, $expr, $op); |
500
|
2087
|
|
|
|
|
3267
|
$prev_expr = $expr; |
501
|
2087
|
50
|
|
|
|
3759
|
if ($fix_cop) { |
502
|
0
|
|
|
|
|
0
|
$fix_cop->{text} = $expr->{text}; |
503
|
|
|
|
|
|
|
} |
504
|
2087
|
|
|
|
|
2800
|
$i++; |
505
|
2087
|
50
|
|
|
|
4315
|
if ($i > $#kids) { |
506
|
0
|
|
|
|
|
0
|
last; |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
} |
509
|
2088
|
50
|
|
|
|
38684
|
if (B::Deparse::is_for_loop($kids[$i])) { |
510
|
0
|
|
|
|
|
0
|
my $loop_expr = $self->for_loop($kids[$i], 0); |
511
|
0
|
0
|
|
|
|
0
|
$callback->(\@body, |
512
|
|
|
|
|
|
|
$i += $kids[$i]->sibling->name eq "unstack" ? 2 : 1, |
513
|
|
|
|
|
|
|
$loop_expr); |
514
|
0
|
|
|
|
|
0
|
$prev_expr = $expr; |
515
|
0
|
|
|
|
|
0
|
next; |
516
|
|
|
|
|
|
|
} |
517
|
2088
|
|
|
|
|
7778
|
$expr = $self->deparse($kids[$i], (@kids != 1)/2, $op); |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
# Perform semantic action on $expr accumulating the result |
520
|
|
|
|
|
|
|
# in @body. $op is the parent, and $i is the child position |
521
|
2088
|
|
|
|
|
6187
|
$callback->(\@body, $i, $expr, $op); |
522
|
2088
|
100
|
|
|
|
4604
|
unless (exists $expr->{prev_expr}) { |
523
|
759
|
|
|
|
|
2047
|
$self->update_node($expr, $prev_expr, $op); |
524
|
|
|
|
|
|
|
} |
525
|
2088
|
|
|
|
|
2891
|
$prev_expr = $expr; |
526
|
2088
|
50
|
|
|
|
3868
|
if ($fix_cop) { |
527
|
0
|
|
|
|
|
0
|
$fix_cop->{text} = $expr->{text}; |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
# If the text portion of a COP is empty, set up to fill it in |
531
|
|
|
|
|
|
|
# from the text portion of the next node. |
532
|
2088
|
50
|
33
|
|
|
17245
|
if (B::class($op) eq "COP" && !$expr->{text}) { |
533
|
0
|
|
|
|
|
0
|
$fix_cop = $op; |
534
|
|
|
|
|
|
|
} else { |
535
|
2088
|
|
|
|
|
6684
|
$fix_cop = undef; |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# Add semicolons between statements. Don't null statements |
540
|
|
|
|
|
|
|
# (which can happen for nexstate which doesn't have source code |
541
|
|
|
|
|
|
|
# associated with it. |
542
|
1342
|
|
|
|
|
4815
|
$expr = $self->info_from_template("statements", $op, "%;", [], \@body); |
543
|
1342
|
|
|
|
|
4453
|
$self->update_node($expr, $prev_expr, $op); |
544
|
1342
|
|
|
|
|
12047
|
return $expr; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
# $root should be the op which represents the root of whatever |
548
|
|
|
|
|
|
|
# we're sequencing here. If it's undefined, then we don't append |
549
|
|
|
|
|
|
|
# any subroutine declarations to the deparsed ops, otherwise we |
550
|
|
|
|
|
|
|
# append appropriate declarations. |
551
|
|
|
|
|
|
|
sub lineseq { |
552
|
1342
|
|
|
1342
|
0
|
4035
|
my($self, $root, $cx, @ops) = @_; |
553
|
|
|
|
|
|
|
|
554
|
1342
|
|
|
|
|
2663
|
my $out_cop = $self->{'curcop'}; |
555
|
1342
|
100
|
|
|
|
2846
|
my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef; |
556
|
1342
|
|
|
|
|
1825
|
my $limit_seq; |
557
|
1342
|
50
|
|
|
|
2932
|
if (defined $root) { |
558
|
1342
|
|
|
|
|
1994
|
$limit_seq = $out_seq; |
559
|
1342
|
|
|
|
|
1656
|
my $nseq; |
560
|
1342
|
50
|
|
|
|
1783
|
$nseq = $self->find_scope_st($root->sibling) if ${$root->sibling}; |
|
1342
|
|
|
|
|
5493
|
|
561
|
1342
|
100
|
33
|
|
|
4448
|
$limit_seq = $nseq if !defined($limit_seq) |
|
|
|
66
|
|
|
|
|
562
|
|
|
|
|
|
|
or defined($nseq) && $nseq < $limit_seq; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
$limit_seq = $self->{'limit_seq'} |
565
|
|
|
|
|
|
|
if defined($self->{'limit_seq'}) |
566
|
1342
|
50
|
33
|
|
|
3118
|
&& (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq); |
|
|
|
66
|
|
|
|
|
567
|
1342
|
|
|
|
|
2962
|
local $self->{'limit_seq'} = $limit_seq; |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
my $fn = sub { |
570
|
4175
|
|
|
4175
|
|
7335
|
my ($exprs, $i, $info, $parent) = @_; |
571
|
4175
|
|
|
|
|
5935
|
my $op = $ops[$i]; |
572
|
4175
|
50
|
|
|
|
7772
|
$info->{type} = $op->name unless $info->{type}; |
573
|
4175
|
|
|
|
|
6381
|
$info->{child_pos} = $i; |
574
|
4175
|
|
|
|
|
5880
|
$info->{op} = $op; |
575
|
4175
|
50
|
|
|
|
7034
|
if ($parent) { |
576
|
4175
|
50
|
|
|
|
7400
|
Carp::confess("nonref parent, op: $op->name") if !ref($parent); |
577
|
4175
|
|
|
|
|
6281
|
$info->{parent} = $$parent ; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
4175
|
|
|
|
|
6527
|
$self->{optree}{$$op} = $info; |
581
|
|
|
|
|
|
|
|
582
|
4175
|
|
|
|
|
7757
|
push @$exprs, $info; |
583
|
1342
|
|
|
|
|
7115
|
}; |
584
|
1342
|
|
|
|
|
4709
|
return $self->walk_lineseq($root, \@ops, $fn); |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
# _pessimise_walk(): recursively walk the optree of a sub, |
588
|
|
|
|
|
|
|
# possibly undoing optimisations along the way. |
589
|
|
|
|
|
|
|
# walk tree in root-to-branch order |
590
|
|
|
|
|
|
|
# We add parent pointers in the process. |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
sub _pessimise_walk { |
593
|
12558
|
|
|
12558
|
|
20361
|
my ($self, $startop) = @_; |
594
|
|
|
|
|
|
|
|
595
|
12558
|
50
|
|
|
|
19889
|
return unless $$startop; |
596
|
12558
|
|
|
|
|
14810
|
my ($op, $parent_op); |
597
|
|
|
|
|
|
|
|
598
|
12558
|
|
|
|
|
21271
|
for ($op = $startop; $$op; $op = $op->sibling) { |
599
|
24710
|
|
|
|
|
65066
|
my $ppname = $op->name; |
600
|
|
|
|
|
|
|
|
601
|
24710
|
|
50
|
|
|
113608
|
$self->{ops}{$$op} ||= {}; |
602
|
24710
|
|
|
|
|
42836
|
$self->{ops}{$$op}{op} = $op; |
603
|
24710
|
|
|
|
|
34395
|
$self->{ops}{$$op}{parent_op} = $startop; |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
# pessimisations start here |
606
|
|
|
|
|
|
|
|
607
|
24710
|
100
|
|
|
|
36875
|
if ($ppname eq "padrange") { |
608
|
|
|
|
|
|
|
# remove PADRANGE: |
609
|
|
|
|
|
|
|
# the original optimisation either (1) changed this: |
610
|
|
|
|
|
|
|
# pushmark -> (various pad and list and null ops) -> the_rest |
611
|
|
|
|
|
|
|
# or (2), for the = @_ case, changed this: |
612
|
|
|
|
|
|
|
# pushmark -> gv[_] -> rv2av -> (pad stuff) -> the_rest |
613
|
|
|
|
|
|
|
# into this: |
614
|
|
|
|
|
|
|
# padrange ----------------------------------------> the_rest |
615
|
|
|
|
|
|
|
# so we just need to convert the padrange back into a |
616
|
|
|
|
|
|
|
# pushmark, and in case (1), set its op_next to op_sibling, |
617
|
|
|
|
|
|
|
# which is the head of the original chain of optimised-away |
618
|
|
|
|
|
|
|
# pad ops, or for (2), set it to sibling->first, which is |
619
|
|
|
|
|
|
|
# the original gv[_]. |
620
|
|
|
|
|
|
|
|
621
|
827
|
|
|
|
|
4932
|
$B::overlay->{$$op} = { |
622
|
|
|
|
|
|
|
type => OP_PUSHMARK, |
623
|
|
|
|
|
|
|
name => 'pushmark', |
624
|
|
|
|
|
|
|
private => ($op->private & OPpLVAL_INTRO), |
625
|
|
|
|
|
|
|
}; |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# pessimisations end here |
629
|
|
|
|
|
|
|
|
630
|
24710
|
100
|
66
|
|
|
109515
|
if (class($op) eq 'PMOP' |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
631
|
|
|
|
|
|
|
&& ref($op->pmreplroot) |
632
|
24
|
|
|
|
|
96
|
&& ${$op->pmreplroot} |
633
|
|
|
|
|
|
|
&& $op->pmreplroot->isa( 'B::OP' )) |
634
|
|
|
|
|
|
|
{ |
635
|
4
|
|
|
|
|
13
|
$self-> _pessimise_walk($op->pmreplroot); |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
24710
|
100
|
|
|
|
124690
|
if ($op->flags & OPf_KIDS) { |
639
|
11224
|
|
|
|
|
36008
|
$self-> _pessimise_walk($op->first); |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
# _pessimise_walk_exe(): recursively walk the op_next chain of a sub, |
647
|
|
|
|
|
|
|
# possibly undoing optimisations along the way. |
648
|
|
|
|
|
|
|
# walk tree in execution order |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
sub _pessimise_walk_exe { |
651
|
1469
|
|
|
1469
|
|
3274
|
my ($self, $startop, $visited) = @_; |
652
|
|
|
|
|
|
|
|
653
|
1469
|
100
|
|
|
|
3313
|
return unless $$startop; |
654
|
1455
|
50
|
|
|
|
3963
|
return if $visited->{$$startop}; |
655
|
1455
|
|
|
|
|
2136
|
my $op; |
656
|
1455
|
|
|
|
|
3680
|
for ($op = $startop; $$op; $op = $op->next) { |
657
|
12891
|
100
|
|
|
|
25600
|
last if $visited->{$$op}; |
658
|
12770
|
|
|
|
|
19851
|
$visited->{$$op} = 1; |
659
|
|
|
|
|
|
|
|
660
|
12770
|
|
50
|
|
|
22276
|
$self->{ops}{$$op} ||= {}; |
661
|
12770
|
|
|
|
|
19198
|
$self->{ops}{$$op}{op} = $op; |
662
|
|
|
|
|
|
|
|
663
|
12770
|
|
|
|
|
31735
|
my $ppname = $op->name; |
664
|
12770
|
100
|
|
|
|
75337
|
if ($ppname =~ |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
665
|
|
|
|
|
|
|
/^((and|d?or)(assign)?|(map|grep)while|range|cond_expr|once)$/ |
666
|
|
|
|
|
|
|
# entertry is also a logop, but its op_other invariably points |
667
|
|
|
|
|
|
|
# into the same chain as the main execution path, so we skip it |
668
|
|
|
|
|
|
|
) { |
669
|
116
|
|
|
|
|
481
|
$self->_pessimise_walk_exe($op->other, $visited); |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
elsif ($ppname eq "subst") { |
672
|
18
|
|
|
|
|
52
|
$self->_pessimise_walk_exe($op->pmreplstart, $visited); |
673
|
|
|
|
|
|
|
} |
674
|
|
|
|
|
|
|
elsif ($ppname =~ /^(enter(loop|iter))$/) { |
675
|
|
|
|
|
|
|
# redoop and nextop will already be covered by the main block |
676
|
|
|
|
|
|
|
# of the loop |
677
|
5
|
|
|
|
|
22
|
$self->_pessimise_walk_exe($op->lastop, $visited); |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
# pessimisations start here |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
# Go through an optree and "remove" some optimisations by using an |
685
|
|
|
|
|
|
|
# overlay to selectively modify or un-null some ops. Deparsing in the |
686
|
|
|
|
|
|
|
# absence of those optimisations is then easier. |
687
|
|
|
|
|
|
|
# |
688
|
|
|
|
|
|
|
# Note that older optimisations are not removed, as Deparse was already |
689
|
|
|
|
|
|
|
# written to recognise them before the pessimise/overlay system was added. |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
sub pessimise { |
692
|
1330
|
|
|
1330
|
0
|
2960
|
my ($self, $root, $start) = @_; |
693
|
|
|
|
|
|
|
|
694
|
8
|
|
|
8
|
|
64
|
no warnings 'recursion'; |
|
8
|
|
|
|
|
21
|
|
|
8
|
|
|
|
|
6528
|
|
695
|
|
|
|
|
|
|
# walk tree in root-to-branch order |
696
|
1330
|
|
|
|
|
3942
|
$self->_pessimise_walk($root); |
697
|
|
|
|
|
|
|
|
698
|
1330
|
|
|
|
|
2348
|
my %visited; |
699
|
|
|
|
|
|
|
# walk tree in execution order |
700
|
1330
|
|
|
|
|
4037
|
$self->_pessimise_walk_exe($start, \%visited); |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
sub style_opts |
704
|
|
|
|
|
|
|
{ |
705
|
0
|
|
|
0
|
0
|
0
|
my ($self, $opts) = @_; |
706
|
0
|
|
|
|
|
0
|
my $opt; |
707
|
0
|
|
|
|
|
0
|
while (length($opt = substr($opts, 0, 1))) { |
708
|
0
|
0
|
|
|
|
0
|
if ($opt eq "C") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
709
|
0
|
|
|
|
|
0
|
$self->{'cuddle'} = " "; |
710
|
0
|
|
|
|
|
0
|
$opts = substr($opts, 1); |
711
|
|
|
|
|
|
|
} elsif ($opt eq "i") { |
712
|
0
|
|
|
|
|
0
|
$opts =~ s/^i(\d+)//; |
713
|
0
|
|
|
|
|
0
|
$self->{'indent_size'} = $1; |
714
|
|
|
|
|
|
|
} elsif ($opt eq "T") { |
715
|
0
|
|
|
|
|
0
|
$self->{'use_tabs'} = 1; |
716
|
0
|
|
|
|
|
0
|
$opts = substr($opts, 1); |
717
|
|
|
|
|
|
|
} elsif ($opt eq "v") { |
718
|
0
|
|
|
|
|
0
|
$opts =~ s/^v([^.]*)(.|$)//; |
719
|
0
|
|
|
|
|
0
|
$self->{'ex_const'} = $1; |
720
|
|
|
|
|
|
|
} |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
# B::Deparse name is print_protos |
725
|
|
|
|
|
|
|
sub extract_prototypes($) |
726
|
|
|
|
|
|
|
{ |
727
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
728
|
0
|
|
|
|
|
0
|
my $ar; |
729
|
|
|
|
|
|
|
my @ret; |
730
|
0
|
|
|
|
|
0
|
foreach $ar (@{$self->{'protos_todo'}}) { |
|
0
|
|
|
|
|
0
|
|
731
|
0
|
|
|
|
|
0
|
my $body; |
732
|
0
|
0
|
|
|
|
0
|
if (defined $ar->[1]) { |
733
|
0
|
0
|
|
|
|
0
|
if (ref $ar->[1]) { |
734
|
|
|
|
|
|
|
# FIXME: better optree tracking? |
735
|
|
|
|
|
|
|
# And use formatting markup? |
736
|
0
|
|
|
|
|
0
|
my $node = $self->const($ar->[1]->RV,0); |
737
|
0
|
|
|
|
|
0
|
my $body_node = |
738
|
|
|
|
|
|
|
$self->info_from_template("protos", undef, |
739
|
|
|
|
|
|
|
"() {\n %c;\n}", |
740
|
|
|
|
|
|
|
undef, [$node]); |
741
|
0
|
|
|
|
|
0
|
$body = $body_node->{text}; |
742
|
|
|
|
|
|
|
} else { |
743
|
0
|
|
|
|
|
0
|
$body = sprintf " (%s);", $ar->[1]; |
744
|
|
|
|
|
|
|
} |
745
|
|
|
|
|
|
|
} else { |
746
|
0
|
|
|
|
|
0
|
$body = ";"; |
747
|
|
|
|
|
|
|
} |
748
|
0
|
|
|
|
|
0
|
push @ret, sprintf "sub %s%s\n", $ar->[0], $body; |
749
|
|
|
|
|
|
|
} |
750
|
0
|
|
|
|
|
0
|
delete $self->{'protos_todo'}; |
751
|
0
|
|
|
|
|
0
|
return @ret; |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
# This gets called automatically when option: |
755
|
|
|
|
|
|
|
# -MO="DeparseTree,sC" is added |
756
|
|
|
|
|
|
|
# Running this prints out the program text. |
757
|
|
|
|
|
|
|
sub compile { |
758
|
0
|
|
|
0
|
0
|
0
|
my(@args) = @_; |
759
|
|
|
|
|
|
|
return sub { |
760
|
0
|
|
|
0
|
|
0
|
my $self = B::DeparseTree->new(@args); |
761
|
|
|
|
|
|
|
# First deparse command-line args |
762
|
0
|
0
|
|
|
|
0
|
if (defined $^I) { # deparse -i |
763
|
0
|
|
|
|
|
0
|
print q(BEGIN { $^I = ).perlstring($^I).qq(; }\n); |
764
|
|
|
|
|
|
|
} |
765
|
0
|
0
|
|
|
|
0
|
if ($^W) { # deparse -w |
766
|
0
|
|
|
|
|
0
|
print qq(BEGIN { \$^W = $^W; }\n); |
767
|
|
|
|
|
|
|
} |
768
|
0
|
0
|
0
|
|
|
0
|
if ($/ ne "\n" or defined $O::savebackslash) { # deparse -l and -0 |
769
|
0
|
|
0
|
|
|
0
|
my $fs = perlstring($/) || 'undef'; |
770
|
0
|
|
0
|
|
|
0
|
my $bs = perlstring($O::savebackslash) || 'undef'; |
771
|
0
|
|
|
|
|
0
|
print qq(BEGIN { \$/ = $fs; \$\\ = $bs; }\n); |
772
|
|
|
|
|
|
|
} |
773
|
0
|
0
|
|
|
|
0
|
my @BEGINs = B::begin_av->isa("B::AV") ? B::begin_av->ARRAY : (); |
774
|
0
|
0
|
|
|
|
0
|
my @UNITCHECKs = B::unitcheck_av->isa("B::AV") |
775
|
|
|
|
|
|
|
? B::unitcheck_av->ARRAY |
776
|
|
|
|
|
|
|
: (); |
777
|
0
|
0
|
|
|
|
0
|
my @CHECKs = B::check_av->isa("B::AV") ? B::check_av->ARRAY : (); |
778
|
0
|
0
|
|
|
|
0
|
my @INITs = B::init_av->isa("B::AV") ? B::init_av->ARRAY : (); |
779
|
0
|
0
|
|
|
|
0
|
my @ENDs = B::end_av->isa("B::AV") ? B::end_av->ARRAY : (); |
780
|
0
|
0
|
|
|
|
0
|
if ($] < 5.020) { |
781
|
0
|
|
|
|
|
0
|
for my $block (@BEGINs, @UNITCHECKs, @CHECKs, @INITs, @ENDs) { |
782
|
0
|
|
|
|
|
0
|
$self->B::Deparse::todo($block, 0); |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
} else { |
785
|
0
|
|
|
|
|
0
|
my @names = qw(BEGIN UNITCHECK CHECK INIT END); |
786
|
0
|
|
|
|
|
0
|
my @blocks = (\@BEGINs, \@UNITCHECKs, \@CHECKs, \@INITs, \@ENDs); |
787
|
0
|
|
|
|
|
0
|
while (@names) { |
788
|
0
|
|
|
|
|
0
|
my ($name, $blocks) = (shift @names, shift @blocks); |
789
|
0
|
|
|
|
|
0
|
for my $block (@$blocks) { |
790
|
0
|
|
|
|
|
0
|
$self->todo($block, 0, $name); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
} |
793
|
|
|
|
|
|
|
} |
794
|
0
|
|
|
|
|
0
|
$self->B::Deparse::stash_subs(); |
795
|
|
|
|
|
|
|
local($SIG{"__DIE__"}) = |
796
|
|
|
|
|
|
|
sub { |
797
|
0
|
0
|
|
|
|
0
|
if ($self->{'curcop'}) { |
798
|
0
|
|
|
|
|
0
|
my $cop = $self->{'curcop'}; |
799
|
0
|
|
|
|
|
0
|
my($line, $file) = ($cop->line, $cop->file); |
800
|
0
|
|
|
|
|
0
|
print STDERR "While deparsing $file near line $line,\n"; |
801
|
|
|
|
|
|
|
} |
802
|
8
|
|
|
8
|
|
58
|
use Data::Printer; |
|
8
|
|
|
|
|
31
|
|
|
8
|
|
|
|
|
97
|
|
803
|
0
|
|
|
|
|
0
|
my @bt = caller(1); |
804
|
0
|
|
|
|
|
0
|
p @bt; |
805
|
0
|
|
|
|
|
0
|
}; |
806
|
0
|
|
|
|
|
0
|
$self->{'curcv'} = main_cv; |
807
|
0
|
|
|
|
|
0
|
$self->{'curcvlex'} = undef; |
808
|
0
|
|
|
|
|
0
|
print $self->extract_prototypes; |
809
|
0
|
|
|
|
|
0
|
@{$self->{'subs_todo'}} = |
810
|
0
|
|
|
|
|
0
|
sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
811
|
0
|
|
|
|
|
0
|
my $root = main_root; |
812
|
0
|
|
|
|
|
0
|
local $B::overlay = {}; |
813
|
|
|
|
|
|
|
|
814
|
0
|
0
|
|
|
|
0
|
if ($] < 5.021) { |
815
|
0
|
0
|
|
|
|
0
|
unless (B::Deparse::null $root) { |
816
|
0
|
|
|
|
|
0
|
$self->pessimise($root, main_start); |
817
|
|
|
|
|
|
|
# Print deparsed program |
818
|
0
|
|
|
|
|
0
|
print $self->deparse_root($root)->{text}, "\n"; |
819
|
|
|
|
|
|
|
} |
820
|
|
|
|
|
|
|
} else { |
821
|
0
|
0
|
|
|
|
0
|
unless (B::Deparse::null $root) { |
822
|
0
|
|
|
|
|
0
|
$self->B::Deparse::pad_subs($self->{'curcv'}); |
823
|
|
|
|
|
|
|
# Check for a stub-followed-by-ex-cop, resulting from a program |
824
|
|
|
|
|
|
|
# consisting solely of sub declarations. For backward-compati- |
825
|
|
|
|
|
|
|
# bility (and sane output) we don’t want to emit the stub. |
826
|
|
|
|
|
|
|
# leave |
827
|
|
|
|
|
|
|
# enter |
828
|
|
|
|
|
|
|
# stub |
829
|
|
|
|
|
|
|
# ex-nextstate (or ex-dbstate) |
830
|
0
|
|
|
|
|
0
|
my $kid; |
831
|
0
|
0
|
0
|
|
|
0
|
if ( $root->name eq 'leave' |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
832
|
|
|
|
|
|
|
and ($kid = $root->first)->name eq 'enter' |
833
|
|
|
|
|
|
|
and !B::Deparse::null($kid = $kid->sibling) and $kid->name eq 'stub' |
834
|
|
|
|
|
|
|
and !B::Deparse::null($kid = $kid->sibling) and $kid->name eq 'null' |
835
|
|
|
|
|
|
|
and class($kid) eq 'COP' and B::Deparse::null $kid->sibling ) |
836
|
|
|
|
|
|
|
{ |
837
|
|
|
|
|
|
|
# ignore deparsing routine |
838
|
|
|
|
|
|
|
} else { |
839
|
0
|
|
|
|
|
0
|
$self->pessimise($root, main_start); |
840
|
|
|
|
|
|
|
# Print deparsed program |
841
|
0
|
|
|
|
|
0
|
my $root_tree = $self->deparse_root($root); |
842
|
0
|
|
|
|
|
0
|
print $root_tree->{text}, "\n"; |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
} |
845
|
|
|
|
|
|
|
} |
846
|
0
|
|
|
|
|
0
|
my @text; |
847
|
0
|
|
|
|
|
0
|
while (scalar(@{$self->{'subs_todo'}})) { |
|
0
|
|
|
|
|
0
|
|
848
|
0
|
|
|
|
|
0
|
push @text, $self->next_todo->{text}; |
849
|
|
|
|
|
|
|
} |
850
|
0
|
0
|
|
|
|
0
|
print join("", @text), "\n" if @text; |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# Print __DATA__ section, if necessary |
853
|
8
|
|
|
8
|
|
2753
|
no strict 'refs'; |
|
8
|
|
|
|
|
18
|
|
|
8
|
|
|
|
|
26245
|
|
854
|
|
|
|
|
|
|
my $laststash = defined $self->{'curcop'} |
855
|
0
|
0
|
|
|
|
0
|
? $self->{'curcop'}->stash->NAME : $self->{'curstash'}; |
856
|
0
|
0
|
|
|
|
0
|
if (defined *{$laststash."::DATA"}{IO}) { |
|
0
|
|
|
|
|
0
|
|
857
|
|
|
|
|
|
|
print $self->keyword("package") . " $laststash;\n" |
858
|
0
|
0
|
|
|
|
0
|
unless $laststash eq $self->{'curstash'}; |
859
|
0
|
|
|
|
|
0
|
print $self->keyword("__DATA__") . "\n"; |
860
|
0
|
|
|
|
|
0
|
print readline(*{$laststash."::DATA"}); |
|
0
|
|
|
|
|
0
|
|
861
|
|
|
|
|
|
|
} |
862
|
|
|
|
|
|
|
} |
863
|
0
|
|
|
|
|
0
|
} |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
# "deparse()" is the main function to call to produces a depare tree |
866
|
|
|
|
|
|
|
# for a give B::OP. This method is the inner loop. |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
# Rocky's comment with respect to: |
869
|
|
|
|
|
|
|
# so try to keep it simple |
870
|
|
|
|
|
|
|
# |
871
|
|
|
|
|
|
|
# Most normal Perl programs really aren't that big. Yeah, I know there |
872
|
|
|
|
|
|
|
# are a couple of big pigs like the B::Deparse code itself. The perl5 |
873
|
|
|
|
|
|
|
# debugger comes to mind too. But what's the likelihood of anyone wanting |
874
|
|
|
|
|
|
|
# to decompile all of this? |
875
|
|
|
|
|
|
|
# |
876
|
|
|
|
|
|
|
# On the other hand, error checking is too valuable to throw out here. |
877
|
|
|
|
|
|
|
# Also, in trying to use and modularize this code, I see there is |
878
|
|
|
|
|
|
|
# a lot of repetition in subroutine parsing routines. That's |
879
|
|
|
|
|
|
|
# why I added the above PP_MAPFNS table. I'm not going to trade off |
880
|
|
|
|
|
|
|
# table lookup and interpetation for a huge amount of subroutine |
881
|
|
|
|
|
|
|
# bloat. |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
# That said it is useful to note that this is inner-most loop |
884
|
|
|
|
|
|
|
# interpeter loop as it is called for each node in the B::OP tree. |
885
|
|
|
|
|
|
|
# |
886
|
|
|
|
|
|
|
sub deparse |
887
|
|
|
|
|
|
|
{ |
888
|
19281
|
|
|
19281
|
0
|
33433
|
my($self, $op, $cx, $parent) = @_; |
889
|
|
|
|
|
|
|
|
890
|
19281
|
50
|
|
|
|
54871
|
Carp::confess("deparse called on an invalid op $op") |
891
|
|
|
|
|
|
|
unless $op->can('name'); |
892
|
|
|
|
|
|
|
|
893
|
19281
|
|
|
|
|
57827
|
my $name = $op->name; |
894
|
19281
|
50
|
|
|
|
55469
|
print "YYY $name\n" if $ENV{'DEBUG_DEPARSETREE'}; |
895
|
19281
|
|
|
|
|
25348
|
my ($info, $meth); |
896
|
|
|
|
|
|
|
|
897
|
19281
|
100
|
|
|
|
35484
|
if (exists($PP_MAPFNS{$name})) { |
898
|
|
|
|
|
|
|
# Interpret method calls for our PP_MAPFNS table |
899
|
4092
|
100
|
|
|
|
8184
|
if (ref($PP_MAPFNS{$name}) eq 'ARRAY') { |
900
|
1664
|
|
|
|
|
2367
|
my @args = @{$PP_MAPFNS{$name}}; |
|
1664
|
|
|
|
|
5304
|
|
901
|
1664
|
|
|
|
|
3014
|
$meth = shift @args; |
902
|
1664
|
100
|
|
|
|
3492
|
if ($meth eq 'maybe_targmy') { |
903
|
|
|
|
|
|
|
# FIXME: This is an inline version of targmy. |
904
|
|
|
|
|
|
|
# Can we dedup it? do we want to? |
905
|
231
|
|
|
|
|
407
|
$meth = shift @args; |
906
|
231
|
100
|
|
|
|
641
|
unshift @args, $name unless @args; |
907
|
231
|
100
|
|
|
|
981
|
if ($op->private & OPpTARGET_MY) { |
908
|
4
|
|
|
|
|
34
|
my $var = $self->padname($op->targ); |
909
|
4
|
|
|
|
|
11
|
my $val = $self->$meth($op, 7, @args); |
910
|
4
|
|
|
|
|
10
|
my @texts = ($var, '=', $val); |
911
|
4
|
|
|
|
|
25
|
$info = $self->info_from_template("my", $op, |
912
|
|
|
|
|
|
|
"%c = %c", [0, 1], |
913
|
|
|
|
|
|
|
[$var, $val], |
914
|
|
|
|
|
|
|
{maybe_parens => [$self, $cx, 7]}); |
915
|
|
|
|
|
|
|
} else { |
916
|
227
|
|
|
|
|
1135
|
$info = $self->$meth($op, $cx, @args); |
917
|
|
|
|
|
|
|
} |
918
|
|
|
|
|
|
|
} else { |
919
|
1433
|
|
|
|
|
5922
|
$info = $self->$meth($op, $cx, @args); |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
} else { |
922
|
|
|
|
|
|
|
# Simple case: one simple call of the |
923
|
|
|
|
|
|
|
# the method in the table. Call this |
924
|
|
|
|
|
|
|
# passing arguments $op, $cx, and $name. |
925
|
|
|
|
|
|
|
# Some functions might not use these, |
926
|
|
|
|
|
|
|
# but that's okay. |
927
|
2428
|
|
|
|
|
4158
|
$meth = $PP_MAPFNS{$name}; |
928
|
2428
|
|
|
|
|
9378
|
$info = $self->$meth($op, $cx, $name); |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
} else { |
931
|
|
|
|
|
|
|
# Tried and true fallback method: |
932
|
|
|
|
|
|
|
# a method has been defined for this pp_op special. |
933
|
|
|
|
|
|
|
# call that. |
934
|
15189
|
|
|
|
|
20634
|
$meth = "pp_" . $name; |
935
|
15189
|
|
|
|
|
44484
|
$info = $self->$meth($op, $cx); |
936
|
|
|
|
|
|
|
} |
937
|
|
|
|
|
|
|
|
938
|
19281
|
50
|
|
|
|
39659
|
Carp::confess("nonref return for $meth deparse: $info") if !ref($info); |
939
|
19281
|
50
|
|
|
|
47760
|
Carp::confess("not B::DeparseTree:Node returned for $meth: $info") |
940
|
|
|
|
|
|
|
if !$info->isa("B::DeparseTree::TreeNode"); |
941
|
19281
|
100
|
|
|
|
43277
|
$info->{parent} = $$parent if $parent; |
942
|
19281
|
|
|
|
|
30611
|
$info->{cop} = $self->{'curcop'}; |
943
|
19281
|
|
|
|
|
24962
|
my $got_op = $info->{op}; |
944
|
19281
|
100
|
|
|
|
27953
|
if ($got_op) { |
945
|
19212
|
100
|
|
|
|
34514
|
if ($got_op != $op) { |
946
|
|
|
|
|
|
|
# Do something here? |
947
|
|
|
|
|
|
|
# printf("XX final op 0x%x is not requested 0x%x\n", |
948
|
|
|
|
|
|
|
# $$op, $$got_op); |
949
|
|
|
|
|
|
|
} |
950
|
|
|
|
|
|
|
} else { |
951
|
69
|
|
|
|
|
438
|
$info->{op} = $op; |
952
|
|
|
|
|
|
|
} |
953
|
19281
|
|
|
|
|
49448
|
$self->{optree}{$$op} = $info; |
954
|
19281
|
100
|
|
|
|
32195
|
if ($info->{other_ops}) { |
955
|
4183
|
|
|
|
|
4932
|
foreach my $other (@{$info->{other_ops}}) { |
|
4183
|
|
|
|
|
7501
|
|
956
|
8884
|
50
|
|
|
|
26010
|
if (!ref $other) { |
|
|
100
|
|
|
|
|
|
957
|
0
|
|
|
|
|
0
|
Carp::confess "$meth returns invalid other $other"; |
958
|
|
|
|
|
|
|
} elsif ($other->isa("B::DeparseTree::TreeNode")) { |
959
|
|
|
|
|
|
|
# "$other" has been set up to mark a particular portion |
960
|
|
|
|
|
|
|
# of the info. |
961
|
5501
|
|
|
|
|
10258
|
$self->{optree}{$other->{addr}} = $other; |
962
|
5501
|
|
|
|
|
10440
|
$other->{parent} = $$op; |
963
|
|
|
|
|
|
|
} else { |
964
|
|
|
|
|
|
|
# "$other" is just the OP. Have it mark everything |
965
|
|
|
|
|
|
|
# or "info". |
966
|
3383
|
|
|
|
|
10617
|
$self->{optree}{$$other} = $info; |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
} |
969
|
|
|
|
|
|
|
} |
970
|
19281
|
|
|
|
|
43986
|
return $info; |
971
|
|
|
|
|
|
|
} |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# Deparse a subroutine |
974
|
|
|
|
|
|
|
sub deparse_sub($$$$) |
975
|
|
|
|
|
|
|
{ |
976
|
1330
|
|
|
1330
|
0
|
3022
|
my ($self, $cv, $start_op) = @_; |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
# Sanity checks.. |
979
|
1330
|
50
|
33
|
|
|
9942
|
Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL"); |
980
|
1330
|
50
|
|
|
|
5991
|
Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL"); |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
# First get protype and sub attribute information |
983
|
1330
|
|
|
|
|
3635
|
local $self->{'curcop'} = $self->{'curcop'}; |
984
|
1330
|
|
|
|
|
2204
|
my $proto = ''; |
985
|
1330
|
50
|
|
|
|
4864
|
if ($cv->FLAGS & SVf_POK) { |
986
|
0
|
|
|
|
|
0
|
$proto .= "(". $cv->PV . ")"; |
987
|
|
|
|
|
|
|
} |
988
|
1330
|
100
|
|
|
|
4929
|
if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE)) { |
989
|
2
|
|
|
|
|
4
|
$proto .= ":"; |
990
|
2
|
100
|
|
|
|
7
|
$proto .= " lvalue" if $cv->CvFLAGS & CVf_LVALUE; |
991
|
2
|
50
|
|
|
|
8
|
$proto .= " locked" if $cv->CvFLAGS & CVf_LOCKED; |
992
|
2
|
100
|
|
|
|
15
|
$proto .= " method" if $cv->CvFLAGS & CVf_METHOD; |
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
|
995
|
1330
|
|
|
|
|
4096
|
local($self->{'curcv'}) = $cv; |
996
|
1330
|
|
|
|
|
2723
|
local($self->{'curcvlex'}); |
997
|
|
|
|
|
|
|
local(@$self{qw'curstash warnings hints hinthash'}) |
998
|
1330
|
|
|
|
|
5755
|
= @$self{qw'curstash warnings hints hinthash'}; |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# Now deparse subroutine body |
1001
|
|
|
|
|
|
|
|
1002
|
1330
|
|
|
|
|
4453
|
my $root = $cv->ROOT; |
1003
|
1330
|
|
|
|
|
2363
|
my ($body, $node); |
1004
|
|
|
|
|
|
|
|
1005
|
1330
|
|
|
|
|
2555
|
local $B::overlay = {}; |
1006
|
1330
|
50
|
|
|
|
14303
|
if (not B::Deparse::null $root) { |
1007
|
1330
|
|
|
|
|
6822
|
$self->pessimise($root, $cv->START); |
1008
|
1330
|
|
|
|
|
6497
|
my $lineseq = $root->first; |
1009
|
1330
|
50
|
|
|
|
5071
|
if ($lineseq->name eq "lineseq") { |
|
|
0
|
|
|
|
|
|
1010
|
1330
|
|
|
|
|
1927
|
my @ops; |
1011
|
1330
|
|
|
|
|
5698
|
for(my $o=$lineseq->first; $$o; $o=$o->sibling) { |
1012
|
4148
|
|
|
|
|
13987
|
push @ops, $o; |
1013
|
|
|
|
|
|
|
} |
1014
|
1330
|
|
|
|
|
3902
|
$body = $self->lineseq($root, 0, @ops); |
1015
|
1330
|
|
|
|
|
35391
|
my $scope_en = $self->find_scope_en($lineseq); |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
elsif ($start_op) { |
1018
|
0
|
|
|
|
|
0
|
$body = $self->deparse($start_op, 0, $lineseq); |
1019
|
|
|
|
|
|
|
} else { |
1020
|
0
|
|
|
|
|
0
|
$body = $self->deparse($root->first, 0, $lineseq); |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
|
1023
|
1330
|
|
|
|
|
7491
|
my $fn_name = $cv->GV->NAME; |
1024
|
1330
|
|
|
|
|
8668
|
$node = $self->info_from_template("sub $fn_name$proto", |
1025
|
|
|
|
|
|
|
$lineseq, |
1026
|
|
|
|
|
|
|
"$proto\n%|{\n%+%c\n%-}", |
1027
|
|
|
|
|
|
|
[0], [$body]); |
1028
|
1330
|
|
|
|
|
4049
|
$body->{parent} = $$lineseq; |
1029
|
1330
|
|
|
|
|
4645
|
$self->{optree}{$$lineseq} = $node; |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
} else { |
1032
|
0
|
|
|
|
|
0
|
my $sv = $cv->const_sv; |
1033
|
0
|
0
|
|
|
|
0
|
if ($$sv) { |
1034
|
|
|
|
|
|
|
# uh-oh. inlinable sub... format it differently |
1035
|
0
|
|
|
|
|
0
|
$node = $self->info_from_template('inline sub', $sv, |
1036
|
|
|
|
|
|
|
"$proto\n%|{\n%+%c\n%-}", |
1037
|
|
|
|
|
|
|
[0], [$self->const($sv, 0)]); |
1038
|
|
|
|
|
|
|
} else { |
1039
|
|
|
|
|
|
|
# XSUB? (or just a declaration) |
1040
|
0
|
|
|
|
|
0
|
$node = $self->info_from_string("XSUB or sub declaration", $proto); |
1041
|
|
|
|
|
|
|
} |
1042
|
|
|
|
|
|
|
} |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# Should we create a real node for this instead of the copy? |
1046
|
1330
|
|
|
|
|
4087
|
$self->{optree}{$$root} = $node; |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
# Add additional DeparseTree tracking info |
1049
|
1330
|
50
|
|
|
|
3258
|
if ($start_op) { |
1050
|
0
|
|
|
|
|
0
|
$node->{op} = $start_op; |
1051
|
0
|
|
|
|
|
0
|
$self->{'optree'}{$$start_op} = $node; |
1052
|
|
|
|
|
|
|
} |
1053
|
1330
|
|
|
|
|
2606
|
$node->{cop} = undef; |
1054
|
1330
|
|
|
|
|
2246
|
$node->{'parent'} = $cv; |
1055
|
1330
|
|
|
|
|
35035
|
return $node; |
1056
|
|
|
|
|
|
|
} |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
# We have a TODO list of things that must be handled |
1059
|
|
|
|
|
|
|
# at the top level. There are things like |
1060
|
|
|
|
|
|
|
# format statements, "BEGIN" and "use" statements. |
1061
|
|
|
|
|
|
|
# Here we handle the next one. |
1062
|
|
|
|
|
|
|
sub next_todo |
1063
|
|
|
|
|
|
|
{ |
1064
|
0
|
|
|
0
|
0
|
0
|
my ($self, $parent) = @_; |
1065
|
0
|
|
|
|
|
0
|
my $ent = shift @{$self->{'subs_todo'}}; |
|
0
|
|
|
|
|
0
|
|
1066
|
0
|
|
|
|
|
0
|
my ($seq, $cv, $is_form, $name) = @$ent; |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
# any 'use strict; package foo' that should come before the sub |
1069
|
|
|
|
|
|
|
# declaration to sync with the first COP of the sub |
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
## FIXME: $self->pragmata messes scoping up, although I don't know |
1072
|
|
|
|
|
|
|
## how it does that. |
1073
|
|
|
|
|
|
|
# my $pragmata = ''; |
1074
|
|
|
|
|
|
|
# if ($cv and !B::Deparse::null($cv->START) and B::Deparse::is_state($cv->START)) { |
1075
|
|
|
|
|
|
|
# $pragmata = $self->B::Deparse::pragmata($cv->START); |
1076
|
|
|
|
|
|
|
# } |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
# if (ref $name) { # lexical sub |
1079
|
|
|
|
|
|
|
# # emit the sub. |
1080
|
|
|
|
|
|
|
# my @text; |
1081
|
|
|
|
|
|
|
# my $flags = $name->FLAGS; |
1082
|
|
|
|
|
|
|
# push @text, |
1083
|
|
|
|
|
|
|
# !$cv || $seq <= $name->COP_SEQ_RANGE_LOW |
1084
|
|
|
|
|
|
|
# ? $self->keyword($flags & B::SVpad_OUR |
1085
|
|
|
|
|
|
|
# ? "our" |
1086
|
|
|
|
|
|
|
# : $flags & SVpad_STATE |
1087
|
|
|
|
|
|
|
# ? "state" |
1088
|
|
|
|
|
|
|
# : "my") . " " |
1089
|
|
|
|
|
|
|
# : ""; |
1090
|
|
|
|
|
|
|
# # XXX We would do $self->keyword("sub"), but ‘my CORE::sub’ |
1091
|
|
|
|
|
|
|
# # doesn’t work and ‘my sub’ ignores a &sub in scope. I.e., |
1092
|
|
|
|
|
|
|
# # we have a core bug here. |
1093
|
|
|
|
|
|
|
# push @text, "sub " . substr $name->PVX, 1; |
1094
|
|
|
|
|
|
|
# my $text = join('', @text); |
1095
|
|
|
|
|
|
|
# if ($cv) { |
1096
|
|
|
|
|
|
|
# # my sub foo { } |
1097
|
|
|
|
|
|
|
# my $cv_node = $self->deparse_sub($cv); |
1098
|
|
|
|
|
|
|
# my $fmt = sprintf("%s%s%%c", $pragmata, $text); |
1099
|
|
|
|
|
|
|
# return $self->info_from_template("sub", $cv, |
1100
|
|
|
|
|
|
|
# $fmt, undef, |
1101
|
|
|
|
|
|
|
# [$cv_node]); |
1102
|
|
|
|
|
|
|
# } else { |
1103
|
|
|
|
|
|
|
# return $self->info_from_string("sub no body", $cv, $text); |
1104
|
|
|
|
|
|
|
# } |
1105
|
|
|
|
|
|
|
# } |
1106
|
|
|
|
|
|
|
|
1107
|
0
|
|
|
|
|
0
|
my $gv = $cv->GV; |
1108
|
0
|
|
0
|
|
|
0
|
$name //= $self->gv_name($gv); |
1109
|
0
|
0
|
|
|
|
0
|
if ($is_form) { |
1110
|
0
|
|
|
|
|
0
|
my $node = $self->deparse_format($ent->[1], $cv); |
1111
|
0
|
|
|
|
|
0
|
return $self->info_from_template("format $name", |
1112
|
|
|
|
|
|
|
"format $name = %c", |
1113
|
|
|
|
|
|
|
undef, [$node]) |
1114
|
|
|
|
|
|
|
} else { |
1115
|
0
|
|
|
|
|
0
|
my ($fmt, $type); |
1116
|
0
|
|
|
|
|
0
|
$self->{'subs_declared'}{$name} = 1; |
1117
|
0
|
0
|
|
|
|
0
|
if ($name eq "BEGIN") { |
1118
|
0
|
|
|
|
|
0
|
my $use_dec = $self->begin_is_use($cv); |
1119
|
0
|
0
|
0
|
|
|
0
|
if (defined ($use_dec) and $self->{'expand'} < 5) { |
1120
|
0
|
0
|
|
|
|
0
|
if (0 == length($use_dec)) { |
1121
|
0
|
|
|
|
|
0
|
$self->info_from_string('BEGIN', $cv, ''); |
1122
|
|
|
|
|
|
|
} else { |
1123
|
0
|
|
|
|
|
0
|
$self->info_from_string('use', $cv, $use_dec); |
1124
|
|
|
|
|
|
|
} |
1125
|
|
|
|
|
|
|
} |
1126
|
|
|
|
|
|
|
} |
1127
|
0
|
|
|
|
|
0
|
my $l = ''; |
1128
|
0
|
0
|
|
|
|
0
|
if ($self->{'linenums'}) { |
1129
|
0
|
|
|
|
|
0
|
my $line = $gv->LINE; |
1130
|
0
|
|
|
|
|
0
|
my $file = $gv->FILE; |
1131
|
0
|
|
|
|
|
0
|
$l = "\n# line $line \"$file\"\n"; |
1132
|
|
|
|
|
|
|
} |
1133
|
0
|
0
|
|
|
|
0
|
if (class($cv->STASH) ne "SPECIAL") { |
1134
|
0
|
|
|
|
|
0
|
my $stash = $cv->STASH->NAME; |
1135
|
0
|
0
|
|
|
|
0
|
if ($stash ne $self->{'curstash'}) { |
1136
|
0
|
|
|
|
|
0
|
$fmt = "package $stash;\n"; |
1137
|
0
|
|
|
|
|
0
|
$type = "package $stash"; |
1138
|
0
|
0
|
|
|
|
0
|
$name = "$self->{'curstash'}::$name" unless $name =~ /::/; |
1139
|
0
|
|
|
|
|
0
|
$self->{'curstash'} = $stash; |
1140
|
|
|
|
|
|
|
} |
1141
|
0
|
|
|
|
|
0
|
$name =~ s/^\Q$stash\E::(?!\z|.*::)//; |
1142
|
0
|
|
|
|
|
0
|
$fmt .= "sub $name"; |
1143
|
0
|
|
|
|
|
0
|
$type .= "sub $name"; |
1144
|
|
|
|
|
|
|
} |
1145
|
0
|
|
|
|
|
0
|
my $node = $self->deparse_sub($cv, $parent); |
1146
|
0
|
|
|
|
|
0
|
$fmt .= '%c'; |
1147
|
0
|
|
|
|
|
0
|
my $sub_node = $self->info_from_template($type, $cv, $fmt, [0], [$node]); |
1148
|
0
|
|
|
|
|
0
|
$node->{parent} = $sub_node->{addr}; |
1149
|
0
|
|
|
|
|
0
|
$self->{optree}{$$cv} = $sub_node; |
1150
|
0
|
|
|
|
|
0
|
return $sub_node; |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
} |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
# Deparse a subroutine by name |
1155
|
|
|
|
|
|
|
sub deparse_subname($$) |
1156
|
|
|
|
|
|
|
{ |
1157
|
0
|
|
|
0
|
0
|
0
|
my ($self, $funcname) = @_; |
1158
|
0
|
|
|
|
|
0
|
my $cv = svref_2object(\&$funcname); |
1159
|
0
|
|
|
|
|
0
|
my $info = $self->deparse_sub($cv); |
1160
|
0
|
|
|
|
|
0
|
my $sub_node = $self->info_from_template("sub $funcname", $cv, "sub $funcname %c", |
1161
|
|
|
|
|
|
|
undef, [$info]); |
1162
|
0
|
|
|
|
|
0
|
$self->{optree}{$$cv} = $sub_node; |
1163
|
0
|
|
|
|
|
0
|
return $sub_node; |
1164
|
|
|
|
|
|
|
} |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
# Return a list of info nodes for "use" and "no" pragmas. |
1167
|
|
|
|
|
|
|
sub declare_hints |
1168
|
|
|
|
|
|
|
{ |
1169
|
1321
|
|
|
1321
|
0
|
3063
|
my ($self, $from, $to) = @_; |
1170
|
1321
|
|
|
|
|
2464
|
my $use = $to & ~$from; |
1171
|
1321
|
|
|
|
|
2235
|
my $no = $from & ~$to; |
1172
|
|
|
|
|
|
|
|
1173
|
1321
|
|
|
|
|
2194
|
my @decls = (); |
1174
|
1321
|
|
|
|
|
18978
|
for my $pragma (B::Deparse::hint_pragmas($use)) { |
1175
|
1266
|
|
|
|
|
31223
|
my $type = $self->keyword("use") . " $pragma"; |
1176
|
1266
|
|
|
|
|
6570
|
push @decls, $self->info_from_template($type, undef, "$type", [], []); |
1177
|
|
|
|
|
|
|
} |
1178
|
1321
|
|
|
|
|
9396
|
for my $pragma (B::Deparse::hint_pragmas($no)) { |
1179
|
0
|
|
|
|
|
0
|
my $type = $self->keyword("no") . " $pragma"; |
1180
|
0
|
|
|
|
|
0
|
push @decls, $self->info_from_template($type, undef, "$type", [], []); |
1181
|
|
|
|
|
|
|
} |
1182
|
1321
|
|
|
|
|
3845
|
return @decls; |
1183
|
|
|
|
|
|
|
} |
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# Internal implementation hints that the core sets automatically, so don't need |
1186
|
|
|
|
|
|
|
# (or want) to be passed back to the user |
1187
|
|
|
|
|
|
|
my %ignored_hints = ( |
1188
|
|
|
|
|
|
|
'open<' => 1, |
1189
|
|
|
|
|
|
|
'open>' => 1, |
1190
|
|
|
|
|
|
|
':' => 1, |
1191
|
|
|
|
|
|
|
'strict/refs' => 1, |
1192
|
|
|
|
|
|
|
'strict/subs' => 1, |
1193
|
|
|
|
|
|
|
'strict/vars' => 1, |
1194
|
|
|
|
|
|
|
); |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
my %rev_feature; |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
sub declare_hinthash { |
1199
|
2087
|
|
|
2087
|
0
|
4598
|
my ($self, $from, $to, $indent, $hints) = @_; |
1200
|
2087
|
|
|
|
|
2650
|
my $doing_features; |
1201
|
2087
|
50
|
|
|
|
3632
|
if ($] >= 5.016) { |
1202
|
2087
|
|
|
|
|
3538
|
$doing_features = ($hints & $feature::hint_mask) == $feature::hint_mask; |
1203
|
|
|
|
|
|
|
} else { |
1204
|
0
|
|
|
|
|
0
|
$doing_features = 0; |
1205
|
|
|
|
|
|
|
} |
1206
|
2087
|
|
|
|
|
4446
|
my @decls; |
1207
|
|
|
|
|
|
|
my @features; |
1208
|
2087
|
|
|
|
|
0
|
my @unfeatures; # bugs? |
1209
|
2087
|
|
|
|
|
6996
|
for my $key (sort keys %$to) { |
1210
|
67
|
50
|
|
|
|
149
|
next if $ignored_hints{$key}; |
1211
|
67
|
|
33
|
|
|
605
|
my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6; |
1212
|
67
|
100
|
66
|
|
|
283
|
next if $is_feature and not $doing_features; |
1213
|
54
|
100
|
66
|
|
|
221
|
if (!exists $from->{$key} or $from->{$key} ne $to->{$key}) { |
1214
|
12
|
50
|
|
|
|
24
|
if ($is_cperl){ |
1215
|
0
|
0
|
|
|
|
0
|
next if $key eq 'feature_lexsubs'; |
1216
|
0
|
0
|
|
|
|
0
|
next if $key eq 'feature_signatures'; |
1217
|
|
|
|
|
|
|
} |
1218
|
12
|
50
|
|
|
|
39
|
push(@features, $key), next if $is_feature; |
1219
|
|
|
|
|
|
|
push @decls, |
1220
|
|
|
|
|
|
|
qq(\$^H{) . single_delim($self, "q", "'", $key, "'") . qq(} = ) |
1221
|
|
|
|
|
|
|
. ( |
1222
|
|
|
|
|
|
|
defined $to->{$key} |
1223
|
0
|
0
|
|
|
|
0
|
? single_delim($self, "q", "'", $to->{$key}, "'") |
1224
|
|
|
|
|
|
|
: 'undef' |
1225
|
|
|
|
|
|
|
) |
1226
|
|
|
|
|
|
|
. qq(;); |
1227
|
|
|
|
|
|
|
} |
1228
|
|
|
|
|
|
|
} |
1229
|
2087
|
|
|
|
|
5100
|
for my $key (sort keys %$from) { |
1230
|
55
|
50
|
|
|
|
104
|
next if $ignored_hints{$key}; |
1231
|
55
|
|
33
|
|
|
473
|
my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6; |
1232
|
55
|
100
|
66
|
|
|
210
|
next if $is_feature and not $doing_features; |
1233
|
42
|
50
|
|
|
|
210
|
if (!exists $to->{$key}) { |
1234
|
0
|
0
|
|
|
|
0
|
push(@unfeatures, $key), next if $is_feature; |
1235
|
0
|
|
|
|
|
0
|
push @decls, qq(delete \$^H{'$key'};); |
1236
|
|
|
|
|
|
|
} |
1237
|
|
|
|
|
|
|
} |
1238
|
2087
|
|
|
|
|
3004
|
my @ret; |
1239
|
2087
|
100
|
66
|
|
|
7673
|
if (@features || @unfeatures) { |
1240
|
3
|
100
|
|
|
|
9
|
if (!%rev_feature) { %rev_feature = reverse %feature::feature } |
|
1
|
|
|
|
|
10
|
|
1241
|
|
|
|
|
|
|
} |
1242
|
2087
|
100
|
|
|
|
4022
|
if (@features) { |
1243
|
3
|
|
|
|
|
1709
|
push @ret, $self->keyword("use") . " feature " |
1244
|
|
|
|
|
|
|
. join(", ", map "'$rev_feature{$_}'", @features) . ";\n"; |
1245
|
|
|
|
|
|
|
} |
1246
|
2087
|
50
|
|
|
|
3805
|
if (@unfeatures) { |
1247
|
0
|
|
|
|
|
0
|
push @ret, $self->keyword("no") . " feature " |
1248
|
|
|
|
|
|
|
. join(", ", map "'$rev_feature{$_}'", @unfeatures) |
1249
|
|
|
|
|
|
|
. ";\n"; |
1250
|
|
|
|
|
|
|
} |
1251
|
|
|
|
|
|
|
@decls and |
1252
|
2087
|
50
|
|
|
|
3795
|
push @ret, |
1253
|
|
|
|
|
|
|
join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n"; |
1254
|
2087
|
|
|
|
|
5507
|
return @ret; |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
# generate any pragmas, 'package foo' etc needed to synchronise |
1258
|
|
|
|
|
|
|
# with the given cop |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
sub pragmata { |
1261
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
1262
|
0
|
|
|
|
|
0
|
my($op) = @_; |
1263
|
|
|
|
|
|
|
|
1264
|
0
|
|
|
|
|
0
|
my @text; |
1265
|
|
|
|
|
|
|
|
1266
|
0
|
|
|
|
|
0
|
my $stash = $op->stashpv; |
1267
|
0
|
0
|
|
|
|
0
|
if ($stash ne $self->{'curstash'}) { |
1268
|
0
|
|
|
|
|
0
|
push @text, $self->keyword("package") . " $stash;\n"; |
1269
|
0
|
|
|
|
|
0
|
$self->{'curstash'} = $stash; |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
|
1272
|
0
|
|
|
|
|
0
|
if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) { |
1273
|
|
|
|
|
|
|
push @text, '$[ = '. $op->arybase .";\n"; |
1274
|
|
|
|
|
|
|
$self->{'arybase'} = $op->arybase; |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
|
1277
|
0
|
|
|
|
|
0
|
my $warnings = $op->warnings; |
1278
|
0
|
|
|
|
|
0
|
my $warning_bits; |
1279
|
0
|
0
|
0
|
|
|
0
|
if ($warnings->isa("B::SPECIAL") && $$warnings == 4) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1280
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings::Bits{"all"} & WARN_MASK; |
1281
|
|
|
|
|
|
|
} |
1282
|
|
|
|
|
|
|
elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) { |
1283
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings::NONE; |
1284
|
|
|
|
|
|
|
} |
1285
|
|
|
|
|
|
|
elsif ($warnings->isa("B::SPECIAL")) { |
1286
|
0
|
|
|
|
|
0
|
$warning_bits = undef; |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
else { |
1289
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings->PV & WARN_MASK; |
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
|
1292
|
0
|
0
|
0
|
|
|
0
|
if (defined ($warning_bits) and |
|
|
|
0
|
|
|
|
|
1293
|
|
|
|
|
|
|
!defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) { |
1294
|
|
|
|
|
|
|
push @text, |
1295
|
0
|
|
|
|
|
0
|
$self->declare_warnings($self->{'warnings'}, $warning_bits); |
1296
|
0
|
|
|
|
|
0
|
$self->{'warnings'} = $warning_bits; |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
|
1299
|
0
|
0
|
|
|
|
0
|
my $hints = $] < 5.008009 ? $op->private : $op->hints; |
1300
|
0
|
|
|
|
|
0
|
my $old_hints = $self->{'hints'}; |
1301
|
0
|
0
|
|
|
|
0
|
if ($self->{'hints'} != $hints) { |
1302
|
0
|
|
|
|
|
0
|
push @text, $self->declare_hints($self->{'hints'}, $hints); |
1303
|
0
|
|
|
|
|
0
|
$self->{'hints'} = $hints; |
1304
|
|
|
|
|
|
|
} |
1305
|
|
|
|
|
|
|
|
1306
|
0
|
|
|
|
|
0
|
my $newhh; |
1307
|
0
|
0
|
|
|
|
0
|
if ($] > 5.009) { |
1308
|
0
|
|
|
|
|
0
|
$newhh = $op->hints_hash->HASH; |
1309
|
|
|
|
|
|
|
} |
1310
|
|
|
|
|
|
|
|
1311
|
0
|
0
|
|
|
|
0
|
if ($] >= 5.015006) { |
1312
|
|
|
|
|
|
|
# feature bundle hints |
1313
|
0
|
|
|
|
|
0
|
my $from = $old_hints & $feature::hint_mask; |
1314
|
0
|
|
|
|
|
0
|
my $to = $ hints & $feature::hint_mask; |
1315
|
0
|
0
|
|
|
|
0
|
if ($from != $to) { |
1316
|
0
|
0
|
|
|
|
0
|
if ($to == $feature::hint_mask) { |
1317
|
0
|
0
|
|
|
|
0
|
if ($self->{'hinthash'}) { |
1318
|
|
|
|
|
|
|
delete $self->{'hinthash'}{$_} |
1319
|
0
|
|
|
|
|
0
|
for grep /^feature_/, keys %{$self->{'hinthash'}}; |
|
0
|
|
|
|
|
0
|
|
1320
|
|
|
|
|
|
|
} |
1321
|
0
|
|
|
|
|
0
|
else { $self->{'hinthash'} = {} } |
1322
|
|
|
|
|
|
|
$self->{'hinthash'} |
1323
|
0
|
|
|
|
|
0
|
= _features_from_bundle($from, $self->{'hinthash'}); |
1324
|
|
|
|
|
|
|
} |
1325
|
|
|
|
|
|
|
else { |
1326
|
0
|
|
|
|
|
0
|
my $bundle = |
1327
|
|
|
|
|
|
|
$feature::hint_bundles[$to >> $feature::hint_shift]; |
1328
|
0
|
|
|
|
|
0
|
$bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12 |
|
0
|
|
|
|
|
0
|
|
1329
|
0
|
|
|
|
|
0
|
push @text, |
1330
|
|
|
|
|
|
|
$self->keyword("no") . " feature ':all';\n", |
1331
|
|
|
|
|
|
|
$self->keyword("use") . " feature ':$bundle';\n"; |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
} |
1335
|
|
|
|
|
|
|
|
1336
|
0
|
0
|
|
|
|
0
|
if ($] > 5.009) { |
1337
|
|
|
|
|
|
|
push @text, $self->declare_hinthash( |
1338
|
|
|
|
|
|
|
$self->{'hinthash'}, $newhh, |
1339
|
|
|
|
|
|
|
$self->{indent_size}, $self->{hints}, |
1340
|
0
|
|
|
|
|
0
|
); |
1341
|
0
|
|
|
|
|
0
|
$self->{'hinthash'} = $newhh; |
1342
|
|
|
|
|
|
|
} |
1343
|
|
|
|
|
|
|
|
1344
|
0
|
|
|
|
|
0
|
return join("", @text); |
1345
|
|
|
|
|
|
|
} |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
# Create a "use", "no", or "BEGIN" block to set warnings. |
1349
|
|
|
|
|
|
|
sub declare_warnings |
1350
|
|
|
|
|
|
|
{ |
1351
|
1266
|
|
|
1266
|
0
|
2968
|
my ($self, $from, $to) = @_; |
1352
|
1266
|
100
|
|
|
|
3329
|
if (($to & WARN_MASK) eq (warnings::bits("all") & WARN_MASK)) { |
|
|
50
|
|
|
|
|
|
1353
|
2
|
|
|
|
|
1439
|
my $type = $self->keyword("use") . " warnings"; |
1354
|
2
|
|
|
|
|
26
|
return $self->info_from_string($type, undef, "$type"); |
1355
|
|
|
|
|
|
|
} |
1356
|
|
|
|
|
|
|
elsif (($to & WARN_MASK) eq ("\0"x length($to) & WARN_MASK)) { |
1357
|
1264
|
|
|
|
|
31482
|
my $type = $self->keyword("no") . " warnings"; |
1358
|
1264
|
|
|
|
|
5796
|
return $self->info_from_string($type, undef, "$type"); |
1359
|
|
|
|
|
|
|
} |
1360
|
0
|
|
|
|
|
0
|
my $bit_expr = join('', map { sprintf("\\x%02x", ord $_) } split "", $to); |
|
0
|
|
|
|
|
0
|
|
1361
|
0
|
|
|
|
|
0
|
my $str = "BEGIN {\n%+\${^WARNING_BITS} = \"$bit_expr;\n%-"; |
1362
|
0
|
|
|
|
|
0
|
return $self->info_from_template('warning bits begin', undef, |
1363
|
|
|
|
|
|
|
"$str", [], [], {omit_next_semicolon=>1}); |
1364
|
|
|
|
|
|
|
} |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
# Iterate over $self->{subs_todo} picking up the |
1367
|
|
|
|
|
|
|
# text of of $self->next_todo. |
1368
|
|
|
|
|
|
|
# We return an array of strings. The calling |
1369
|
|
|
|
|
|
|
# routine will join these together |
1370
|
|
|
|
|
|
|
sub seq_subs { |
1371
|
2087
|
|
|
2087
|
0
|
4413
|
my ($self, $seq) = @_; |
1372
|
2087
|
|
|
|
|
2605
|
my @texts; |
1373
|
|
|
|
|
|
|
|
1374
|
2087
|
50
|
|
|
|
4355
|
return () if !defined $seq; |
1375
|
2087
|
|
|
|
|
2730
|
my @pending; |
1376
|
2087
|
|
33
|
|
|
2700
|
while (scalar(@{$self->{'subs_todo'}}) |
|
2087
|
|
|
|
|
6272
|
|
1377
|
|
|
|
|
|
|
and $seq > $self->{'subs_todo'}[0][0]) { |
1378
|
0
|
|
|
|
|
0
|
my $cv = $self->{'subs_todo'}[0][1]; |
1379
|
|
|
|
|
|
|
# Skip the OUTSIDE check for lexical subs. We may be deparsing a |
1380
|
|
|
|
|
|
|
# cloned anon sub with lexical subs declared in it, in which case |
1381
|
|
|
|
|
|
|
# the OUTSIDE pointer points to the anon protosub. |
1382
|
0
|
|
|
|
|
0
|
my $lexical = ref $self->{'subs_todo'}[0][3]; |
1383
|
0
|
|
0
|
|
|
0
|
my $outside = !$lexical && $cv && $cv->OUTSIDE; |
1384
|
0
|
0
|
0
|
|
|
0
|
if (!$lexical and $cv |
|
|
|
0
|
|
|
|
|
1385
|
0
|
0
|
|
|
|
0
|
and ${$cv->OUTSIDE || \0} != ${$self->{'curcv'}}) |
|
0
|
|
|
|
|
0
|
|
1386
|
|
|
|
|
|
|
{ |
1387
|
|
|
|
|
|
|
# rocky: What do we do with @pending? |
1388
|
0
|
|
|
|
|
0
|
push @pending, shift @{$self->{'subs_todo'}}; |
|
0
|
|
|
|
|
0
|
|
1389
|
0
|
|
|
|
|
0
|
next; |
1390
|
|
|
|
|
|
|
} |
1391
|
0
|
|
|
|
|
0
|
push @texts, $self->next_todo; |
1392
|
|
|
|
|
|
|
} |
1393
|
2087
|
|
|
|
|
5295
|
return @texts; |
1394
|
|
|
|
|
|
|
} |
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
# FIXME: this code has to be here. Find out why and fix. |
1397
|
|
|
|
|
|
|
# Truncate is special because OPf_SPECIAL makes a bareword first arg |
1398
|
|
|
|
|
|
|
# be a filehandle. This could probably be better fixed in the core |
1399
|
|
|
|
|
|
|
# by moving the GV lookup into ck_truc. |
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
# Demo code |
1402
|
|
|
|
|
|
|
unless(caller) { |
1403
|
|
|
|
|
|
|
my @texts = ('a', 'b', 'c'); |
1404
|
|
|
|
|
|
|
my $deparse = __PACKAGE__->new(); |
1405
|
|
|
|
|
|
|
my $info = info_from_list('op', $deparse, \@texts, ', ', 'test', {}); |
1406
|
|
|
|
|
|
|
|
1407
|
8
|
|
|
8
|
|
75
|
use Data::Printer; |
|
8
|
|
|
|
|
28
|
|
|
8
|
|
|
|
|
66
|
|
1408
|
|
|
|
|
|
|
my $str = $deparse->template_engine("%c", [0], ["16"]); |
1409
|
|
|
|
|
|
|
p $str; |
1410
|
|
|
|
|
|
|
my $str2 = $deparse->template_engine("%F", [[0, sub {'0x' . sprintf "%x", shift}]], [$str]); |
1411
|
|
|
|
|
|
|
p $str2; |
1412
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
# print $deparse->template_engine("100%% "), "\n"; |
1414
|
|
|
|
|
|
|
# print $deparse->template_engine("%c,\n%+%c\n%|%c %c!", |
1415
|
|
|
|
|
|
|
# [1, 0, 2, 3], |
1416
|
|
|
|
|
|
|
# ["is", "now", "the", "time"]), "\n"; |
1417
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("demo", undef, "%C", |
1419
|
|
|
|
|
|
|
# [[0, 1, ";\n%|"]], |
1420
|
|
|
|
|
|
|
# ['$x=1', '$y=2']); |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
# @texts = ("use warnings;", "use strict", "my(\$a)"); |
1423
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("demo", undef, "%;", [], \@texts); |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("list", undef, |
1426
|
|
|
|
|
|
|
# "%C", [[0, $#texts, ', ']], |
1427
|
|
|
|
|
|
|
# \@texts); |
1428
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
# p $info; |
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
# @texts = (['a', 1], ['b', 2], 'c'); |
1433
|
|
|
|
|
|
|
# $info = info_from_list('op', $deparse, \@texts, ', ', 'test', {}); |
1434
|
|
|
|
|
|
|
# p $info; |
1435
|
|
|
|
|
|
|
} |
1436
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
1; |