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
|
3
|
|
|
3
|
|
19
|
use strict; use warnings; |
|
3
|
|
|
3
|
|
4
|
|
|
3
|
|
|
|
|
73
|
|
|
3
|
|
|
|
|
14
|
|
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
159
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
package B::DeparseTree; |
22
|
|
|
|
|
|
|
|
23
|
3
|
|
|
|
|
414
|
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
|
3
|
|
|
3
|
|
18
|
); |
|
3
|
|
|
|
|
5
|
|
41
|
|
|
|
|
|
|
|
42
|
3
|
|
|
3
|
|
19
|
use Carp; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
154
|
|
43
|
3
|
|
|
3
|
|
17
|
use B::Deparse; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
80
|
|
44
|
3
|
|
|
3
|
|
1207
|
use B::DeparseTree::PP_OPtable; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
283
|
|
45
|
3
|
|
|
3
|
|
1179
|
use B::DeparseTree::SyntaxTree; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
545
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Copy unchanged functions from B::Deparse |
48
|
|
|
|
|
|
|
*find_scope_en = *B::Deparse::find_scope_en; |
49
|
|
|
|
|
|
|
*find_scope_st = *B::Deparse::find_scope_st; |
50
|
|
|
|
|
|
|
*gv_name = *B::Deparse::gv_name; |
51
|
|
|
|
|
|
|
*lex_in_scope = *B::Deparse::lex_in_scope; |
52
|
|
|
|
|
|
|
*padname = *B::Deparse::padname; |
53
|
|
|
|
|
|
|
*rv2gv_or_string = *B::Deparse::rv2gv_or_string; |
54
|
|
|
|
|
|
|
*stash_subs = *B::Deparse::stash_subs; |
55
|
|
|
|
|
|
|
*stash_variable = *B::Deparse::stash_variable; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
our($VERSION, @EXPORT, @ISA); |
58
|
|
|
|
|
|
|
$VERSION = '3.2.0'; |
59
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
60
|
|
|
|
|
|
|
@EXPORT = qw( |
61
|
|
|
|
|
|
|
%globalnames |
62
|
|
|
|
|
|
|
%ignored_hints |
63
|
|
|
|
|
|
|
%rev_feature |
64
|
|
|
|
|
|
|
WARN_MASK |
65
|
|
|
|
|
|
|
coderef2info |
66
|
|
|
|
|
|
|
coderef2text |
67
|
|
|
|
|
|
|
const |
68
|
|
|
|
|
|
|
declare_hinthash |
69
|
|
|
|
|
|
|
declare_hints |
70
|
|
|
|
|
|
|
declare_warnings |
71
|
|
|
|
|
|
|
deparse_sub($$$$) |
72
|
|
|
|
|
|
|
deparse_subname($$) |
73
|
|
|
|
|
|
|
new |
74
|
|
|
|
|
|
|
next_todo |
75
|
|
|
|
|
|
|
pragmata |
76
|
|
|
|
|
|
|
print_protos |
77
|
|
|
|
|
|
|
seq_subs |
78
|
|
|
|
|
|
|
style_opts |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
3
|
|
|
3
|
|
20
|
use Config; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
491
|
|
82
|
|
|
|
|
|
|
my $is_cperl = $Config::Config{usecperl}; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
my $module; |
85
|
|
|
|
|
|
|
if ($] >= 5.016 and $] < 5.018) { |
86
|
|
|
|
|
|
|
# 5.16 and 5.18 are the same for now |
87
|
|
|
|
|
|
|
$module = "P518"; |
88
|
|
|
|
|
|
|
} elsif ($] >= 5.018 and $] < 5.020) { |
89
|
|
|
|
|
|
|
$module = "P518"; |
90
|
|
|
|
|
|
|
} elsif ($] >= 5.020 and $] < 5.022) { |
91
|
|
|
|
|
|
|
$module = "P520"; |
92
|
|
|
|
|
|
|
} elsif ($] >= 5.022 and $] < 5.024) { |
93
|
|
|
|
|
|
|
$module = "P522"; |
94
|
|
|
|
|
|
|
} elsif ($] >= 5.024 and $] < 5.026) { |
95
|
|
|
|
|
|
|
$module = "P524"; |
96
|
|
|
|
|
|
|
} elsif ($] >= 5.026) { |
97
|
|
|
|
|
|
|
$module = "P526"; |
98
|
|
|
|
|
|
|
} else { |
99
|
|
|
|
|
|
|
die "Can only handle Perl 5.16..5.26"; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
$module .= 'c' if $is_cperl; |
103
|
|
|
|
|
|
|
@ISA = ("Exporter", "B::DeparseTree::$module"); |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
require "B/DeparseTree/${module}.pm"; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# The BEGIN {} is used here because otherwise this code isn't executed |
108
|
|
|
|
|
|
|
# when you run B::Deparse on itself. |
109
|
|
|
|
|
|
|
my %globalnames; |
110
|
3
|
|
|
3
|
|
172
|
BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC", |
111
|
|
|
|
|
|
|
"ENV", "ARGV", "ARGVOUT", "_"); } |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
my $max_prec; |
114
|
3
|
|
|
3
|
|
163
|
BEGIN { $max_prec = int(0.999 + 8*length(pack("F", 42))*log(2)/log(10)); } |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
BEGIN { |
117
|
|
|
|
|
|
|
# List version-specific constants here. |
118
|
|
|
|
|
|
|
# Easiest way to keep this code portable between version looks to |
119
|
|
|
|
|
|
|
# be to fake up a dummy constant that will never actually be true. |
120
|
3
|
|
|
3
|
|
9
|
foreach (qw(OPpSORT_INPLACE OPpSORT_DESCEND OPpITER_REVERSED |
121
|
|
|
|
|
|
|
OPpCONST_NOVER OPpPAD_STATE PMf_SKIPWHITE RXf_SKIPWHITE |
122
|
|
|
|
|
|
|
RXf_PMf_CHARSET RXf_PMf_KEEPCOPY |
123
|
|
|
|
|
|
|
CVf_LOCKED OPpREVERSE_INPLACE OPpSUBSTR_REPL_FIRST |
124
|
|
|
|
|
|
|
PMf_NONDESTRUCT OPpCONST_ARYBASE OPpEVAL_BYTES)) { |
125
|
45
|
|
|
|
|
58
|
eval { import B $_ }; |
|
45
|
|
|
|
|
2997
|
|
126
|
3
|
|
|
3
|
|
17
|
no strict 'refs'; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
209
|
|
127
|
45
|
100
|
|
|
|
70
|
*{$_} = sub () {0} unless *{$_}{CODE}; |
|
9
|
|
|
|
|
33
|
|
|
45
|
|
|
|
|
1249
|
|
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub new { |
132
|
5
|
|
|
5
|
1
|
351322
|
my $class = shift; |
133
|
5
|
|
|
|
|
24
|
my $self = bless {}, $class; |
134
|
5
|
|
|
|
|
57
|
$self->{'cuddle'} = " "; #\n%| is another alternative |
135
|
5
|
|
|
|
|
19
|
$self->{'curcop'} = undef; |
136
|
5
|
|
|
|
|
21
|
$self->{'curstash'} = "main"; |
137
|
5
|
|
|
|
|
18
|
$self->{'ex_const'} = "'?unrecoverable constant?'"; |
138
|
5
|
|
|
|
|
16
|
$self->{'expand'} = 0; |
139
|
5
|
|
|
|
|
18
|
$self->{'files'} = {}; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# How many spaces per indent nesting? |
142
|
5
|
|
|
|
|
14
|
$self->{'indent_size'} = 4; |
143
|
|
|
|
|
|
|
|
144
|
5
|
|
|
|
|
19
|
$self->{'opaddr'} = 0; |
145
|
5
|
|
|
|
|
15
|
$self->{'linenums'} = 0; |
146
|
5
|
|
|
|
|
16
|
$self->{'parens'} = 0; |
147
|
5
|
|
|
|
|
15
|
$self->{'subs_todo'} = []; |
148
|
5
|
|
|
|
|
18
|
$self->{'unquote'} = 0; |
149
|
5
|
|
|
|
|
14
|
$self->{'use_dumper'} = 0; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# Compress spaces with tabs? 1 tab = 8 spaces |
152
|
5
|
|
|
|
|
11
|
$self->{'use_tabs'} = 0; |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Indentation level |
155
|
5
|
|
|
|
|
10
|
$self->{'level'} = 0; |
156
|
|
|
|
|
|
|
|
157
|
5
|
|
|
|
|
14
|
$self->{'ambient_arybase'} = 0; |
158
|
5
|
|
|
|
|
10
|
$self->{'ambient_warnings'} = undef; # Assume no lexical warnings |
159
|
5
|
|
|
|
|
9
|
$self->{'ambient_hints'} = 0; |
160
|
5
|
|
|
|
|
14
|
$self->{'ambient_hinthash'} = undef; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# Given an opcode address, get the accumulated OP tree |
163
|
|
|
|
|
|
|
# OP for that. FIXME: remove this |
164
|
5
|
|
|
|
|
15
|
$self->{optree} = {}; |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Extra opcode information: parent_op |
167
|
5
|
|
|
|
|
16
|
$self->{ops} = {}; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# For B::DeparseTree::Node's that are created and don't have real OPs associated |
170
|
|
|
|
|
|
|
# with them, we assign a fake address; |
171
|
5
|
|
|
|
|
15
|
$self->{'last_fake_addr'} = 0; |
172
|
|
|
|
|
|
|
|
173
|
5
|
|
|
|
|
22
|
$self->init(); |
174
|
|
|
|
|
|
|
|
175
|
5
|
|
|
|
|
18
|
while (my $arg = shift @_) { |
176
|
0
|
0
|
|
|
|
0
|
if ($arg eq "-d") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
177
|
0
|
|
|
|
|
0
|
$self->{'use_dumper'} = 1; |
178
|
0
|
|
|
|
|
0
|
require Data::Dumper; |
179
|
|
|
|
|
|
|
} elsif ($arg =~ /^-f(.*)/) { |
180
|
0
|
|
|
|
|
0
|
$self->{'files'}{$1} = 1; |
181
|
|
|
|
|
|
|
} elsif ($arg eq "-l") { |
182
|
0
|
|
|
|
|
0
|
$self->{'linenums'} = 1; |
183
|
|
|
|
|
|
|
} elsif ($arg eq "-a") { |
184
|
0
|
|
|
|
|
0
|
$self->{'linenums'} = 1; |
185
|
0
|
|
|
|
|
0
|
$self->{'opaddr'} = 1; |
186
|
|
|
|
|
|
|
} elsif ($arg eq "-p") { |
187
|
0
|
|
|
|
|
0
|
$self->{'parens'} = 1; |
188
|
|
|
|
|
|
|
} elsif ($arg eq "-P") { |
189
|
0
|
|
|
|
|
0
|
$self->{'noproto'} = 1; |
190
|
|
|
|
|
|
|
} elsif ($arg eq "-q") { |
191
|
0
|
|
|
|
|
0
|
$self->{'unquote'} = 1; |
192
|
|
|
|
|
|
|
} elsif (substr($arg, 0, 2) eq "-s") { |
193
|
0
|
|
|
|
|
0
|
$self->style_opts(substr $arg, 2); |
194
|
|
|
|
|
|
|
} elsif ($arg =~ /^-x(\d)$/) { |
195
|
0
|
|
|
|
|
0
|
$self->{'expand'} = $1; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
} |
198
|
5
|
|
|
|
|
10
|
return $self; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
{ |
202
|
|
|
|
|
|
|
# Mask out the bits that L uses |
203
|
|
|
|
|
|
|
my $WARN_MASK; |
204
|
|
|
|
|
|
|
BEGIN { |
205
|
3
|
|
|
3
|
|
518
|
$WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all}; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
sub WARN_MASK () { |
208
|
5262
|
|
|
5262
|
0
|
25462
|
return $WARN_MASK; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Initialize the contextual information, either from |
213
|
|
|
|
|
|
|
# defaults provided with the ambient_pragmas method, |
214
|
|
|
|
|
|
|
# or from Perl's own defaults otherwise. |
215
|
|
|
|
|
|
|
sub init { |
216
|
1409
|
|
|
1409
|
0
|
2262
|
my $self = shift; |
217
|
|
|
|
|
|
|
|
218
|
1409
|
|
|
|
|
2789
|
$self->{'arybase'} = $self->{'ambient_arybase'}; |
219
|
|
|
|
|
|
|
$self->{'warnings'} = defined ($self->{'ambient_warnings'}) |
220
|
1409
|
100
|
|
|
|
4048
|
? $self->{'ambient_warnings'} & WARN_MASK |
221
|
|
|
|
|
|
|
: undef; |
222
|
1409
|
|
|
|
|
2333
|
$self->{'hints'} = $self->{'ambient_hints'}; |
223
|
1409
|
50
|
|
|
|
3189
|
$self->{'hints'} &= 0xFF if $] < 5.009; |
224
|
1409
|
|
|
|
|
2401
|
$self->{'hinthash'} = $self->{'ambient_hinthash'}; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# also a convenient place to clear out subs_declared |
227
|
1409
|
|
|
|
|
3171
|
delete $self->{'subs_declared'}; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
3
|
|
|
3
|
|
11
|
BEGIN { for (qw[ pushmark ]) { |
231
|
3
|
|
|
|
|
2372
|
eval "sub OP_\U$_ () { " . opnumber($_) . "}" |
232
|
|
|
|
|
|
|
}} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub main2info |
235
|
|
|
|
|
|
|
{ |
236
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
237
|
0
|
|
|
|
|
0
|
$self->{'curcv'} = B::main_cv; |
238
|
0
|
|
|
|
|
0
|
$self->pessimise(B::main_root, B::main_start); |
239
|
0
|
|
|
|
|
0
|
return $self->deparse_root(B::main_root); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub coderef2info |
243
|
|
|
|
|
|
|
{ |
244
|
1345
|
|
|
1345
|
0
|
1010694
|
my ($self, $coderef, $start_op) = @_; |
245
|
1345
|
50
|
|
|
|
5288
|
croak "Usage: ->coderef2info(CODEREF)" unless UNIVERSAL::isa($coderef, "CODE"); |
246
|
1345
|
|
|
|
|
4863
|
$self->init(); |
247
|
1345
|
|
|
|
|
6342
|
return $self->deparse_sub(svref_2object($coderef), $start_op); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub coderef2text |
251
|
|
|
|
|
|
|
{ |
252
|
59
|
|
|
59
|
1
|
110463
|
my ($self, $func) = @_; |
253
|
59
|
50
|
|
|
|
265
|
croak "Usage: ->coderef2text(CODEREF)" unless UNIVERSAL::isa($func, "CODE"); |
254
|
|
|
|
|
|
|
|
255
|
59
|
|
|
|
|
210
|
$self->init(); |
256
|
59
|
|
|
|
|
205
|
my $info = $self->coderef2info($func); |
257
|
59
|
|
|
|
|
214
|
return $self->info2str($info); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub const { |
261
|
77
|
|
|
77
|
0
|
111
|
my $self = shift; |
262
|
77
|
|
|
|
|
143
|
my($sv, $cx) = @_; |
263
|
77
|
50
|
|
|
|
189
|
if ($self->{'use_dumper'}) { |
264
|
0
|
|
|
|
|
0
|
return $self->const_dumper($sv, $cx); |
265
|
|
|
|
|
|
|
} |
266
|
77
|
50
|
|
|
|
496
|
if (class($sv) eq "SPECIAL") { |
267
|
|
|
|
|
|
|
# sv_undef, sv_yes, sv_no |
268
|
0
|
|
|
|
|
0
|
my $text = ('undef', '1', $self->maybe_parens("!1", $cx, 21))[$$sv-1]; |
269
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $text, 'const_special', {}); |
270
|
|
|
|
|
|
|
} |
271
|
77
|
50
|
|
|
|
356
|
if (class($sv) eq "NULL") { |
272
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, 'undef', 'const_NULL', {}); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
# convert a version object into the "v1.2.3" string in its V magic |
275
|
77
|
50
|
|
|
|
273
|
if ($sv->FLAGS & SVs_RMG) { |
276
|
0
|
|
|
|
|
0
|
for (my $mg = $sv->MAGIC; $mg; $mg = $mg->MOREMAGIC) { |
277
|
0
|
0
|
|
|
|
0
|
if ($mg->TYPE eq 'V') { |
278
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $mg->PTR, 'const_magic', {}); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
77
|
100
|
33
|
|
|
342
|
if ($sv->FLAGS & SVf_IOK) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
284
|
54
|
|
|
|
|
203
|
my $str = $sv->int_value; |
285
|
54
|
50
|
|
|
|
135
|
$str = $self->maybe_parens($str, $cx, 21) if $str < 0; |
286
|
54
|
|
|
|
|
216
|
return $self->info_from_string("integer constant $str", $sv, $str); |
287
|
|
|
|
|
|
|
} elsif ($sv->FLAGS & SVf_NOK) { |
288
|
0
|
|
|
|
|
0
|
my $nv = $sv->NV; |
289
|
0
|
0
|
|
|
|
0
|
if ($nv == 0) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
290
|
0
|
0
|
|
|
|
0
|
if (pack("F", $nv) eq pack("F", 0)) { |
291
|
|
|
|
|
|
|
# positive zero |
292
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, "0", 'constant float positive 0', {}); |
293
|
|
|
|
|
|
|
} else { |
294
|
|
|
|
|
|
|
# negative zero |
295
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("-.0", $cx, 21), |
296
|
|
|
|
|
|
|
'constant float negative 0', {}); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
} elsif (1/$nv == 0) { |
299
|
0
|
0
|
|
|
|
0
|
if ($nv > 0) { |
300
|
|
|
|
|
|
|
# positive infinity |
301
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("9**9**9", $cx, 22), |
302
|
|
|
|
|
|
|
'constant float +infinity', {}); |
303
|
|
|
|
|
|
|
} else { |
304
|
|
|
|
|
|
|
# negative infinity |
305
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("-9**9**9", $cx, 21), |
306
|
|
|
|
|
|
|
'constant float -infinity', {}); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} elsif ($nv != $nv) { |
309
|
|
|
|
|
|
|
# NaN |
310
|
0
|
0
|
|
|
|
0
|
if (pack("F", $nv) eq pack("F", sin(9**9**9))) { |
|
|
0
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# the normal kind |
312
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, "sin(9**9**9)", 'const_Nan', {}); |
313
|
|
|
|
|
|
|
} elsif (pack("F", $nv) eq pack("F", -sin(9**9**9))) { |
314
|
|
|
|
|
|
|
# the inverted kind |
315
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("-sin(9**9**9)", $cx, 21), |
316
|
|
|
|
|
|
|
'constant float Nan invert', {}); |
317
|
|
|
|
|
|
|
} else { |
318
|
|
|
|
|
|
|
# some other kind |
319
|
0
|
|
|
|
|
0
|
my $hex = unpack("h*", pack("F", $nv)); |
320
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, qq'unpack("F", pack("h*", "$hex"))', |
321
|
|
|
|
|
|
|
'constant Na na na', {}); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
# first, try the default stringification |
325
|
0
|
|
|
|
|
0
|
my $str = "$nv"; |
326
|
0
|
0
|
|
|
|
0
|
if ($str != $nv) { |
327
|
|
|
|
|
|
|
# failing that, try using more precision |
328
|
0
|
|
|
|
|
0
|
$str = sprintf("%.${max_prec}g", $nv); |
329
|
|
|
|
|
|
|
# if (pack("F", $str) ne pack("F", $nv)) { |
330
|
0
|
0
|
|
|
|
0
|
if ($str != $nv) { |
331
|
|
|
|
|
|
|
# not representable in decimal with whatever sprintf() |
332
|
|
|
|
|
|
|
# and atof() Perl is using here. |
333
|
0
|
|
|
|
|
0
|
my($mant, $exp) = split_float($nv); |
334
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $self->maybe_parens("$mant * 2**$exp", $cx, 19), |
335
|
|
|
|
|
|
|
'constant float not-sprintf/atof-able', {}); |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
} |
338
|
0
|
0
|
|
|
|
0
|
$str = $self->maybe_parens($str, $cx, 21) if $nv < 0; |
339
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $str, 'constant nv', {}); |
340
|
|
|
|
|
|
|
} elsif ($sv->FLAGS & SVf_ROK && $sv->can("RV")) { |
341
|
0
|
|
|
|
|
0
|
my $ref = $sv->RV; |
342
|
0
|
0
|
|
|
|
0
|
if (class($ref) eq "AV") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
343
|
0
|
|
|
|
|
0
|
my $list_info = $self->list_const($sv, 2, $ref->ARRAY); |
344
|
0
|
|
|
|
|
0
|
return info_from_list($sv, $self, ['[', $list_info->{text}, ']'], '', 'const_av', |
345
|
|
|
|
|
|
|
{body => [$list_info]}); |
346
|
|
|
|
|
|
|
} elsif (class($ref) eq "HV") { |
347
|
0
|
|
|
|
|
0
|
my %hash = $ref->ARRAY; |
348
|
0
|
|
|
|
|
0
|
my @elts; |
349
|
0
|
|
|
|
|
0
|
for my $k (sort keys %hash) { |
350
|
0
|
|
|
|
|
0
|
push @elts, "$k => " . $self->const($hash{$k}, 6); |
351
|
|
|
|
|
|
|
} |
352
|
0
|
|
|
|
|
0
|
return info_from_list($sv, $self, ["{", join(", ", @elts), "}"], '', |
353
|
|
|
|
|
|
|
'constant hash value', {}); |
354
|
|
|
|
|
|
|
} elsif (class($ref) eq "CV") { |
355
|
|
|
|
|
|
|
BEGIN { |
356
|
3
|
50
|
|
3
|
|
15
|
if ($] > 5.0150051) { |
357
|
3
|
|
|
|
|
16
|
require overloading; |
358
|
3
|
|
|
|
|
5699
|
unimport overloading; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
} |
361
|
0
|
0
|
0
|
|
|
0
|
if ($] > 5.0150051 && $self->{curcv} && |
|
|
|
0
|
|
|
|
|
362
|
|
|
|
|
|
|
$self->{curcv}->object_2svref == $ref->object_2svref) { |
363
|
0
|
|
|
|
|
0
|
return $self->info_from_string('sub __SUB__', $sv, |
364
|
|
|
|
|
|
|
$self->keyword("__SUB__")); |
365
|
|
|
|
|
|
|
} |
366
|
0
|
|
|
|
|
0
|
my $sub_info = $self->deparse_sub($ref); |
367
|
0
|
|
|
|
|
0
|
return info_from_list($sub_info->{op}, $self, ["sub ", $sub_info->{text}], '', |
368
|
|
|
|
|
|
|
'constant sub 2', |
369
|
|
|
|
|
|
|
{body => [$sub_info]}); |
370
|
|
|
|
|
|
|
} |
371
|
0
|
0
|
|
|
|
0
|
if ($ref->FLAGS & SVs_SMG) { |
372
|
0
|
|
|
|
|
0
|
for (my $mg = $ref->MAGIC; $mg; $mg = $mg->MOREMAGIC) { |
373
|
0
|
0
|
|
|
|
0
|
if ($mg->TYPE eq 'r') { |
374
|
0
|
|
|
|
|
0
|
my $re = B::Deparse::re_uninterp(B::Deparse::escape_str(B::Deparse::re_unback($mg->precomp))); |
375
|
0
|
|
|
|
|
0
|
return $self->single_delim($sv, "qr", "", $re); |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
0
|
|
|
|
|
0
|
my $const = $self->const($ref, 20); |
381
|
0
|
0
|
0
|
|
|
0
|
if ($self->{in_subst_repl} && $const =~ /^[0-9]/) { |
382
|
0
|
|
|
|
|
0
|
$const = "($const)"; |
383
|
|
|
|
|
|
|
} |
384
|
0
|
|
|
|
|
0
|
my @texts = ("\\", $const); |
385
|
0
|
|
|
|
|
0
|
return info_from_list($sv, $self, \@texts, '', 'const_rv', |
386
|
|
|
|
|
|
|
{maybe_parens => [$self, $cx, 20]}); |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
} elsif ($sv->FLAGS & SVf_POK) { |
389
|
23
|
|
|
|
|
118
|
my $str = $sv->PV; |
390
|
23
|
50
|
|
|
|
70
|
if ($str =~ /[[:^print:]]/) { |
391
|
0
|
|
|
|
|
0
|
return $self->single_delim($sv, "qq", '"', |
392
|
|
|
|
|
|
|
B::Deparse::uninterp B::Deparse::escape_str B::Deparse::unback $str); |
393
|
|
|
|
|
|
|
} else { |
394
|
23
|
|
|
|
|
158
|
return $self->single_delim($sv, "q", "'", B::Deparse::unback $str); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
} else { |
397
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, "undef", 'constant undef', {}); |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
sub const_dumper |
402
|
|
|
|
|
|
|
{ |
403
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
404
|
0
|
|
|
|
|
0
|
my($sv, $cx) = @_; |
405
|
0
|
|
|
|
|
0
|
my $ref = $sv->object_2svref(); |
406
|
0
|
|
|
|
|
0
|
my $dumper = Data::Dumper->new([$$ref], ['$v']); |
407
|
0
|
|
|
|
|
0
|
$dumper->Purity(1)->Terse(1)->Deparse(1)->Indent(0)->Useqq(1)->Sortkeys(1); |
408
|
0
|
|
|
|
|
0
|
my $str = $dumper->Dump(); |
409
|
0
|
0
|
|
|
|
0
|
if ($str =~ /^\$v/) { |
410
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, ['${my', $str, '\$v}'], 'const_dumper_my', {}); |
411
|
|
|
|
|
|
|
} else { |
412
|
0
|
|
|
|
|
0
|
return info_from_text($sv, $self, $str, 'constant dumper', {}); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# This is a special case of scopeop and lineseq, for the case of the |
417
|
|
|
|
|
|
|
# main_root. |
418
|
|
|
|
|
|
|
sub deparse_root { |
419
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
420
|
0
|
|
|
|
|
0
|
my($op) = @_; |
421
|
|
|
|
|
|
|
local(@$self{qw'curstash warnings hints hinthash'}) |
422
|
0
|
|
|
|
|
0
|
= @$self{qw'curstash warnings hints hinthash'}; |
423
|
0
|
|
|
|
|
0
|
my @ops; |
424
|
0
|
0
|
|
|
|
0
|
return if B::Deparse::null $op->first; # Can happen, e.g., for Bytecode without -k |
425
|
0
|
|
|
|
|
0
|
for (my $kid = $op->first->sibling; !B::Deparse::null($kid); $kid = $kid->sibling) { |
426
|
0
|
|
|
|
|
0
|
push @ops, $kid; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
my $fn = sub { |
429
|
0
|
|
|
0
|
|
0
|
my ($exprs, $i, $info, $parent) = @_; |
430
|
0
|
|
|
|
|
0
|
my $text = $info->{text}; |
431
|
0
|
|
|
|
|
0
|
my $op = $ops[$i]; |
432
|
0
|
|
|
|
|
0
|
$text =~ s/\f//; |
433
|
0
|
|
|
|
|
0
|
$text =~ s/\n$//; |
434
|
0
|
|
|
|
|
0
|
$text =~ s/;\n?\z//; |
435
|
0
|
|
|
|
|
0
|
$text =~ s/^\((.+)\)$/$1/; |
436
|
0
|
|
|
|
|
0
|
$info->{type} = $op->name; |
437
|
0
|
|
|
|
|
0
|
$info->{op} = $op; |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# FIXME: this is going away... |
440
|
0
|
|
|
|
|
0
|
$self->{optree}{$$op} = $info; |
441
|
|
|
|
|
|
|
# in favor of... |
442
|
0
|
|
|
|
|
0
|
$self->{ops}{$$op}{info} = $info; |
443
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
0
|
$info->{text} = $text; |
445
|
0
|
0
|
|
|
|
0
|
$info->{parent} = $$parent if $parent; |
446
|
0
|
|
|
|
|
0
|
push @$exprs, $info; |
447
|
0
|
|
|
|
|
0
|
}; |
448
|
0
|
|
|
|
|
0
|
my $info = $self->walk_lineseq($op, \@ops, $fn); |
449
|
0
|
|
|
|
|
0
|
my @skipped_ops; |
450
|
0
|
0
|
|
|
|
0
|
if (exists $info->{other_ops}) { |
451
|
0
|
|
|
|
|
0
|
@skipped_ops = @{$info->{other_ops}}; |
|
0
|
|
|
|
|
0
|
|
452
|
0
|
|
|
|
|
0
|
push @skipped_ops, $op->first; |
453
|
|
|
|
|
|
|
} else { |
454
|
0
|
|
|
|
|
0
|
@skipped_ops = ($op->first); |
455
|
|
|
|
|
|
|
} |
456
|
0
|
|
|
|
|
0
|
$info->{other_ops} = \@skipped_ops; |
457
|
0
|
|
|
|
|
0
|
return $info; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
sub update_node($$$$) |
462
|
|
|
|
|
|
|
{ |
463
|
5531
|
|
|
5531
|
0
|
9028
|
my ($self, $node, $prev_expr, $op) = @_; |
464
|
5531
|
|
|
|
|
7790
|
$node->{prev_expr} = $prev_expr; |
465
|
5531
|
50
|
|
|
|
12551
|
$self->{optree}{$$op} = $node if $op; |
466
|
5531
|
50
|
|
|
|
12907
|
$self->{ops}{$$op}{info} = $node if $op; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub walk_lineseq |
470
|
|
|
|
|
|
|
{ |
471
|
1352
|
|
|
1352
|
0
|
2982
|
my ($self, $op, $kids, $callback) = @_; |
472
|
1352
|
|
|
|
|
2729
|
my @kids = @$kids; |
473
|
1352
|
|
|
|
|
2246
|
my @body = (); # Accumulated node structures |
474
|
1352
|
|
|
|
|
1576
|
my $expr; |
475
|
1352
|
|
|
|
|
1773
|
my $prev_expr = undef; |
476
|
1352
|
|
|
|
|
1647
|
my $fix_cop = undef; |
477
|
1352
|
|
|
|
|
2846
|
for (my $i = 0; $i < @kids; $i++) { |
478
|
2090
|
100
|
|
|
|
13003
|
if (B::Deparse::is_state $kids[$i]) { |
479
|
2089
|
|
|
|
|
5099
|
$expr = ($self->deparse($kids[$i], 0, $op)); |
480
|
2089
|
|
|
|
|
5590
|
$callback->(\@body, $i, $expr, $op); |
481
|
2089
|
|
|
|
|
5740
|
$self->update_node($expr, $prev_expr, $op); |
482
|
2089
|
|
|
|
|
2771
|
$prev_expr = $expr; |
483
|
2089
|
50
|
|
|
|
3685
|
if ($fix_cop) { |
484
|
0
|
|
|
|
|
0
|
$fix_cop->{text} = $expr->{text}; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
2089
|
|
|
|
|
2335
|
$i++; |
488
|
2089
|
50
|
|
|
|
4391
|
if ($i > $#kids) { |
489
|
0
|
|
|
|
|
0
|
last; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
} |
492
|
2090
|
50
|
|
|
|
36186
|
if (B::Deparse::is_for_loop($kids[$i])) { |
493
|
0
|
|
|
|
|
0
|
my $loop_expr = $self->for_loop($kids[$i], 0); |
494
|
0
|
0
|
|
|
|
0
|
$callback->(\@body, |
495
|
|
|
|
|
|
|
$i += $kids[$i]->sibling->name eq "unstack" ? 2 : 1, |
496
|
|
|
|
|
|
|
$loop_expr); |
497
|
0
|
|
|
|
|
0
|
$self->update_node($expr, $prev_expr, $op); |
498
|
0
|
|
|
|
|
0
|
$prev_expr = $expr; |
499
|
0
|
|
|
|
|
0
|
next; |
500
|
|
|
|
|
|
|
} |
501
|
2090
|
|
|
|
|
7416
|
$expr = $self->deparse($kids[$i], (@kids != 1)/2, $op); |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# Perform semantic action on $expr accumulating the result |
504
|
|
|
|
|
|
|
# in @body. $op is the parent, and $i is the child position |
505
|
2090
|
|
|
|
|
5423
|
$callback->(\@body, $i, $expr, $op); |
506
|
2090
|
|
|
|
|
4929
|
$self->update_node($expr, $prev_expr, $op); |
507
|
2090
|
|
|
|
|
2659
|
$prev_expr = $expr; |
508
|
2090
|
50
|
|
|
|
3529
|
if ($fix_cop) { |
509
|
0
|
|
|
|
|
0
|
$fix_cop->{text} = $expr->{text}; |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# If the text portion of a COP is empty, set up to fill it in |
513
|
|
|
|
|
|
|
# from the text portion of the next node. |
514
|
2090
|
50
|
33
|
|
|
17082
|
if (B::class($op) eq "COP" && !$expr->{text}) { |
515
|
0
|
|
|
|
|
0
|
$fix_cop = $op; |
516
|
|
|
|
|
|
|
} else { |
517
|
2090
|
|
|
|
|
5891
|
$fix_cop = undef; |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
# Add semicolons between statements. Don't null statements |
522
|
|
|
|
|
|
|
# (which can happen for nexstate which doesn't have source code |
523
|
|
|
|
|
|
|
# associated with it. |
524
|
1352
|
|
|
|
|
5004
|
$expr = $self->info_from_template("statements", $op, "%;", [], \@body); |
525
|
1352
|
|
|
|
|
3733
|
$self->update_node($expr, $prev_expr, $op); |
526
|
1352
|
|
|
|
|
11898
|
return $expr; |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
# $root should be the op which represents the root of whatever |
530
|
|
|
|
|
|
|
# we're sequencing here. If it's undefined, then we don't append |
531
|
|
|
|
|
|
|
# any subroutine declarations to the deparsed ops, otherwise we |
532
|
|
|
|
|
|
|
# append appropriate declarations. |
533
|
|
|
|
|
|
|
sub lineseq { |
534
|
1352
|
|
|
1352
|
0
|
3748
|
my($self, $root, $cx, @ops) = @_; |
535
|
|
|
|
|
|
|
|
536
|
1352
|
|
|
|
|
2660
|
my $out_cop = $self->{'curcop'}; |
537
|
1352
|
100
|
|
|
|
2535
|
my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef; |
538
|
1352
|
|
|
|
|
1569
|
my $limit_seq; |
539
|
1352
|
50
|
|
|
|
2870
|
if (defined $root) { |
540
|
1352
|
|
|
|
|
1822
|
$limit_seq = $out_seq; |
541
|
1352
|
|
|
|
|
1569
|
my $nseq; |
542
|
1352
|
50
|
|
|
|
1660
|
$nseq = $self->find_scope_st($root->sibling) if ${$root->sibling}; |
|
1352
|
|
|
|
|
5606
|
|
543
|
1352
|
100
|
33
|
|
|
4776
|
$limit_seq = $nseq if !defined($limit_seq) |
|
|
|
66
|
|
|
|
|
544
|
|
|
|
|
|
|
or defined($nseq) && $nseq < $limit_seq; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
$limit_seq = $self->{'limit_seq'} |
547
|
|
|
|
|
|
|
if defined($self->{'limit_seq'}) |
548
|
1352
|
0
|
0
|
|
|
3215
|
&& (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq); |
|
|
|
33
|
|
|
|
|
549
|
1352
|
|
|
|
|
2731
|
local $self->{'limit_seq'} = $limit_seq; |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
my $fn = sub { |
552
|
4179
|
|
|
4179
|
|
6884
|
my ($exprs, $i, $info, $parent) = @_; |
553
|
4179
|
|
|
|
|
5621
|
my $op = $ops[$i]; |
554
|
4179
|
50
|
|
|
|
7158
|
$info->{type} = $op->name unless $info->{type}; |
555
|
4179
|
|
|
|
|
6175
|
$info->{child_pos} = $i; |
556
|
4179
|
|
|
|
|
5463
|
$info->{op} = $op; |
557
|
4179
|
50
|
|
|
|
6552
|
if ($parent) { |
558
|
4179
|
50
|
|
|
|
7312
|
Carp::confess("nonref parent, op: $op->name") if !ref($parent); |
559
|
4179
|
|
|
|
|
6116
|
$info->{parent} = $$parent ; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# FIXME: remove optree? |
563
|
4179
|
|
|
|
|
6088
|
$self->{optree}{$$op} = $info; |
564
|
4179
|
|
|
|
|
8881
|
$self->{ops}{$$op}{info} = $info; |
565
|
|
|
|
|
|
|
|
566
|
4179
|
|
|
|
|
7805
|
push @$exprs, $info; |
567
|
1352
|
|
|
|
|
6868
|
}; |
568
|
1352
|
|
|
|
|
4309
|
return $self->walk_lineseq($root, \@ops, $fn); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub todo |
572
|
|
|
|
|
|
|
{ |
573
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
574
|
0
|
|
|
|
|
0
|
my($cv, $is_form, $name) = @_; |
575
|
0
|
|
0
|
|
|
0
|
my $cvfile = $cv->FILE//''; |
576
|
0
|
0
|
0
|
|
|
0
|
return unless ($cvfile eq $0 || exists $self->{files}{$cvfile}); |
577
|
0
|
|
|
|
|
0
|
my $seq; |
578
|
0
|
0
|
0
|
|
|
0
|
if ($cv->OUTSIDE_SEQ) { |
|
|
0
|
|
|
|
|
|
579
|
0
|
|
|
|
|
0
|
$seq = $cv->OUTSIDE_SEQ; |
580
|
|
|
|
|
|
|
} elsif (!B::Deparse::null($cv->START) and B::Deparse::is_state($cv->START)) { |
581
|
0
|
|
|
|
|
0
|
$seq = $cv->START->cop_seq; |
582
|
|
|
|
|
|
|
} else { |
583
|
0
|
|
|
|
|
0
|
$seq = 0; |
584
|
|
|
|
|
|
|
} |
585
|
0
|
|
|
|
|
0
|
push @{$self->{'subs_todo'}}, [$seq, $cv, $is_form, $name]; |
|
0
|
|
|
|
|
0
|
|
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
# _pessimise_walk(): recursively walk the optree of a sub, |
589
|
|
|
|
|
|
|
# possibly undoing optimisations along the way. |
590
|
|
|
|
|
|
|
# walk tree in root-to-branch order |
591
|
|
|
|
|
|
|
# We add parent pointers in the process. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
sub _pessimise_walk { |
594
|
12645
|
|
|
12645
|
|
19571
|
my ($self, $startop) = @_; |
595
|
|
|
|
|
|
|
|
596
|
12645
|
50
|
|
|
|
19369
|
return unless $$startop; |
597
|
12645
|
|
|
|
|
14743
|
my ($op, $parent_op); |
598
|
|
|
|
|
|
|
|
599
|
12645
|
|
|
|
|
20831
|
for ($op = $startop; $$op; $op = $op->sibling) { |
600
|
24880
|
|
|
|
|
61003
|
my $ppname = $op->name; |
601
|
|
|
|
|
|
|
|
602
|
24880
|
|
50
|
|
|
111071
|
$self->{ops}{$$op} ||= {}; |
603
|
24880
|
|
|
|
|
43850
|
$self->{ops}{$$op}{op} = $op; |
604
|
24880
|
|
|
|
|
34372
|
$self->{ops}{$$op}{parent_op} = $startop; |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# pessimisations start here |
607
|
|
|
|
|
|
|
|
608
|
24880
|
100
|
|
|
|
35141
|
if ($ppname eq "padrange") { |
609
|
|
|
|
|
|
|
# remove PADRANGE: |
610
|
|
|
|
|
|
|
# the original optimisation either (1) changed this: |
611
|
|
|
|
|
|
|
# pushmark -> (various pad and list and null ops) -> the_rest |
612
|
|
|
|
|
|
|
# or (2), for the = @_ case, changed this: |
613
|
|
|
|
|
|
|
# pushmark -> gv[_] -> rv2av -> (pad stuff) -> the_rest |
614
|
|
|
|
|
|
|
# into this: |
615
|
|
|
|
|
|
|
# padrange ----------------------------------------> the_rest |
616
|
|
|
|
|
|
|
# so we just need to convert the padrange back into a |
617
|
|
|
|
|
|
|
# pushmark, and in case (1), set its op_next to op_sibling, |
618
|
|
|
|
|
|
|
# which is the head of the original chain of optimised-away |
619
|
|
|
|
|
|
|
# pad ops, or for (2), set it to sibling->first, which is |
620
|
|
|
|
|
|
|
# the original gv[_]. |
621
|
|
|
|
|
|
|
|
622
|
857
|
|
|
|
|
4949
|
$B::overlay->{$$op} = { |
623
|
|
|
|
|
|
|
type => OP_PUSHMARK, |
624
|
|
|
|
|
|
|
name => 'pushmark', |
625
|
|
|
|
|
|
|
private => ($op->private & OPpLVAL_INTRO), |
626
|
|
|
|
|
|
|
}; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
# pessimisations end here |
630
|
|
|
|
|
|
|
|
631
|
24880
|
100
|
66
|
|
|
106308
|
if (class($op) eq 'PMOP' |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
632
|
|
|
|
|
|
|
&& ref($op->pmreplroot) |
633
|
24
|
|
|
|
|
128
|
&& ${$op->pmreplroot} |
634
|
|
|
|
|
|
|
&& $op->pmreplroot->isa( 'B::OP' )) |
635
|
|
|
|
|
|
|
{ |
636
|
4
|
|
|
|
|
13
|
$self-> _pessimise_walk($op->pmreplroot); |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
|
639
|
24880
|
100
|
|
|
|
120837
|
if ($op->flags & OPf_KIDS) { |
640
|
11296
|
|
|
|
|
34376
|
$self-> _pessimise_walk($op->first); |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
# _pessimise_walk_exe(): recursively walk the op_next chain of a sub, |
648
|
|
|
|
|
|
|
# possibly undoing optimisations along the way. |
649
|
|
|
|
|
|
|
# walk tree in execution order |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
sub _pessimise_walk_exe { |
652
|
1466
|
|
|
1466
|
|
2963
|
my ($self, $startop, $visited) = @_; |
653
|
|
|
|
|
|
|
|
654
|
1466
|
100
|
|
|
|
3253
|
return unless $$startop; |
655
|
1452
|
50
|
|
|
|
3440
|
return if $visited->{$$startop}; |
656
|
1452
|
|
|
|
|
2627
|
my $op; |
657
|
1452
|
|
|
|
|
3071
|
for ($op = $startop; $$op; $op = $op->next) { |
658
|
12847
|
100
|
|
|
|
24251
|
last if $visited->{$$op}; |
659
|
12744
|
|
|
|
|
19132
|
$visited->{$$op} = 1; |
660
|
|
|
|
|
|
|
|
661
|
12744
|
|
50
|
|
|
22168
|
$self->{ops}{$$op} ||= {}; |
662
|
12744
|
|
|
|
|
18187
|
$self->{ops}{$$op}{op} = $op; |
663
|
|
|
|
|
|
|
|
664
|
12744
|
|
|
|
|
29349
|
my $ppname = $op->name; |
665
|
12744
|
100
|
|
|
|
71755
|
if ($ppname =~ |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
666
|
|
|
|
|
|
|
/^((and|d?or)(assign)?|(map|grep)while|range|cond_expr|once)$/ |
667
|
|
|
|
|
|
|
# entertry is also a logop, but its op_other invariably points |
668
|
|
|
|
|
|
|
# into the same chain as the main execution path, so we skip it |
669
|
|
|
|
|
|
|
) { |
670
|
100
|
|
|
|
|
396
|
$self->_pessimise_walk_exe($op->other, $visited); |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
elsif ($ppname eq "subst") { |
673
|
18
|
|
|
|
|
61
|
$self->_pessimise_walk_exe($op->pmreplstart, $visited); |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
elsif ($ppname =~ /^(enter(loop|iter))$/) { |
676
|
|
|
|
|
|
|
# redoop and nextop will already be covered by the main block |
677
|
|
|
|
|
|
|
# of the loop |
678
|
3
|
|
|
|
|
13
|
$self->_pessimise_walk_exe($op->lastop, $visited); |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
# pessimisations start here |
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
} |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
# Go through an optree and "remove" some optimisations by using an |
686
|
|
|
|
|
|
|
# overlay to selectively modify or un-null some ops. Deparsing in the |
687
|
|
|
|
|
|
|
# absence of those optimisations is then easier. |
688
|
|
|
|
|
|
|
# |
689
|
|
|
|
|
|
|
# Note that older optimisations are not removed, as Deparse was already |
690
|
|
|
|
|
|
|
# written to recognise them before the pessimise/overlay system was added. |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
sub pessimise { |
693
|
1345
|
|
|
1345
|
0
|
2653
|
my ($self, $root, $start) = @_; |
694
|
|
|
|
|
|
|
|
695
|
3
|
|
|
3
|
|
21
|
no warnings 'recursion'; |
|
3
|
|
|
|
|
18
|
|
|
3
|
|
|
|
|
5178
|
|
696
|
|
|
|
|
|
|
# walk tree in root-to-branch order |
697
|
1345
|
|
|
|
|
4113
|
$self->_pessimise_walk($root); |
698
|
|
|
|
|
|
|
|
699
|
1345
|
|
|
|
|
2333
|
my %visited; |
700
|
|
|
|
|
|
|
# walk tree in execution order |
701
|
1345
|
|
|
|
|
3557
|
$self->_pessimise_walk_exe($start, \%visited); |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
sub print_protos { |
705
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
706
|
0
|
|
|
|
|
0
|
my $ar; |
707
|
|
|
|
|
|
|
my @ret; |
708
|
0
|
|
|
|
|
0
|
foreach $ar (@{$self->{'protos_todo'}}) { |
|
0
|
|
|
|
|
0
|
|
709
|
0
|
0
|
|
|
|
0
|
my $proto = defined $ar->[1] |
|
|
0
|
|
|
|
|
|
710
|
|
|
|
|
|
|
? ref $ar->[1] |
711
|
|
|
|
|
|
|
? " () {\n " . $self->const($ar->[1]->RV,0) . ";\n}" |
712
|
|
|
|
|
|
|
: " (". $ar->[1] . ");" |
713
|
|
|
|
|
|
|
: ";"; |
714
|
0
|
|
|
|
|
0
|
push @ret, "sub " . $ar->[0] . "$proto\n"; |
715
|
|
|
|
|
|
|
} |
716
|
0
|
|
|
|
|
0
|
delete $self->{'protos_todo'}; |
717
|
0
|
|
|
|
|
0
|
return @ret; |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub style_opts |
721
|
|
|
|
|
|
|
{ |
722
|
0
|
|
|
0
|
0
|
0
|
my ($self, $opts) = @_; |
723
|
0
|
|
|
|
|
0
|
my $opt; |
724
|
0
|
|
|
|
|
0
|
while (length($opt = substr($opts, 0, 1))) { |
725
|
0
|
0
|
|
|
|
0
|
if ($opt eq "C") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
726
|
0
|
|
|
|
|
0
|
$self->{'cuddle'} = " "; |
727
|
0
|
|
|
|
|
0
|
$opts = substr($opts, 1); |
728
|
|
|
|
|
|
|
} elsif ($opt eq "i") { |
729
|
0
|
|
|
|
|
0
|
$opts =~ s/^i(\d+)//; |
730
|
0
|
|
|
|
|
0
|
$self->{'indent_size'} = $1; |
731
|
|
|
|
|
|
|
} elsif ($opt eq "T") { |
732
|
0
|
|
|
|
|
0
|
$self->{'use_tabs'} = 1; |
733
|
0
|
|
|
|
|
0
|
$opts = substr($opts, 1); |
734
|
|
|
|
|
|
|
} elsif ($opt eq "v") { |
735
|
0
|
|
|
|
|
0
|
$opts =~ s/^v([^.]*)(.|$)//; |
736
|
0
|
|
|
|
|
0
|
$self->{'ex_const'} = $1; |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
# This gets called automatically when option: |
742
|
|
|
|
|
|
|
# -MO="DeparseTree,sC" is added |
743
|
|
|
|
|
|
|
# Running this prints out the program text. |
744
|
|
|
|
|
|
|
sub compile { |
745
|
0
|
|
|
0
|
0
|
0
|
my(@args) = @_; |
746
|
|
|
|
|
|
|
return sub { |
747
|
0
|
|
|
0
|
|
0
|
my $self = B::DeparseTree->new(@args); |
748
|
|
|
|
|
|
|
# First deparse command-line args |
749
|
0
|
0
|
|
|
|
0
|
if (defined $^I) { # deparse -i |
750
|
0
|
|
|
|
|
0
|
print q(BEGIN { $^I = ).perlstring($^I).qq(; }\n); |
751
|
|
|
|
|
|
|
} |
752
|
0
|
0
|
|
|
|
0
|
if ($^W) { # deparse -w |
753
|
0
|
|
|
|
|
0
|
print qq(BEGIN { \$^W = $^W; }\n); |
754
|
|
|
|
|
|
|
} |
755
|
0
|
0
|
0
|
|
|
0
|
if ($/ ne "\n" or defined $O::savebackslash) { # deparse -l and -0 |
756
|
0
|
|
0
|
|
|
0
|
my $fs = perlstring($/) || 'undef'; |
757
|
0
|
|
0
|
|
|
0
|
my $bs = perlstring($O::savebackslash) || 'undef'; |
758
|
0
|
|
|
|
|
0
|
print qq(BEGIN { \$/ = $fs; \$\\ = $bs; }\n); |
759
|
|
|
|
|
|
|
} |
760
|
0
|
0
|
|
|
|
0
|
my @BEGINs = B::begin_av->isa("B::AV") ? B::begin_av->ARRAY : (); |
761
|
0
|
0
|
|
|
|
0
|
my @UNITCHECKs = B::unitcheck_av->isa("B::AV") |
762
|
|
|
|
|
|
|
? B::unitcheck_av->ARRAY |
763
|
|
|
|
|
|
|
: (); |
764
|
0
|
0
|
|
|
|
0
|
my @CHECKs = B::check_av->isa("B::AV") ? B::check_av->ARRAY : (); |
765
|
0
|
0
|
|
|
|
0
|
my @INITs = B::init_av->isa("B::AV") ? B::init_av->ARRAY : (); |
766
|
0
|
0
|
|
|
|
0
|
my @ENDs = B::end_av->isa("B::AV") ? B::end_av->ARRAY : (); |
767
|
0
|
0
|
|
|
|
0
|
if ($] < 5.020) { |
768
|
0
|
|
|
|
|
0
|
for my $block (@BEGINs, @UNITCHECKs, @CHECKs, @INITs, @ENDs) { |
769
|
0
|
|
|
|
|
0
|
$self->todo($block, 0); |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
} else { |
772
|
0
|
|
|
|
|
0
|
my @names = qw(BEGIN UNITCHECK CHECK INIT END); |
773
|
0
|
|
|
|
|
0
|
my @blocks = (\@BEGINs, \@UNITCHECKs, \@CHECKs, \@INITs, \@ENDs); |
774
|
0
|
|
|
|
|
0
|
while (@names) { |
775
|
0
|
|
|
|
|
0
|
my ($name, $blocks) = (shift @names, shift @blocks); |
776
|
0
|
|
|
|
|
0
|
for my $block (@$blocks) { |
777
|
0
|
|
|
|
|
0
|
$self->todo($block, 0, $name); |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
} |
781
|
0
|
|
|
|
|
0
|
$self->stash_subs(); |
782
|
|
|
|
|
|
|
local($SIG{"__DIE__"}) = |
783
|
|
|
|
|
|
|
sub { |
784
|
0
|
0
|
|
|
|
0
|
if ($self->{'curcop'}) { |
785
|
0
|
|
|
|
|
0
|
my $cop = $self->{'curcop'}; |
786
|
0
|
|
|
|
|
0
|
my($line, $file) = ($cop->line, $cop->file); |
787
|
0
|
|
|
|
|
0
|
print STDERR "While deparsing $file near line $line,\n"; |
788
|
|
|
|
|
|
|
} |
789
|
3
|
|
|
3
|
|
1918
|
use Data::Printer; |
|
3
|
|
|
|
|
100435
|
|
|
3
|
|
|
|
|
17
|
|
790
|
0
|
|
|
|
|
0
|
my @bt = caller(1); |
791
|
0
|
|
|
|
|
0
|
p @bt; |
792
|
0
|
|
|
|
|
0
|
}; |
793
|
0
|
|
|
|
|
0
|
$self->{'curcv'} = main_cv; |
794
|
0
|
|
|
|
|
0
|
$self->{'curcvlex'} = undef; |
795
|
0
|
|
|
|
|
0
|
print $self->print_protos; |
796
|
0
|
|
|
|
|
0
|
@{$self->{'subs_todo'}} = |
797
|
0
|
|
|
|
|
0
|
sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
798
|
0
|
|
|
|
|
0
|
my $root = main_root; |
799
|
0
|
|
|
|
|
0
|
local $B::overlay = {}; |
800
|
|
|
|
|
|
|
|
801
|
0
|
0
|
|
|
|
0
|
if ($] < 5.021) { |
802
|
0
|
0
|
|
|
|
0
|
unless (B::Deparse::null $root) { |
803
|
0
|
|
|
|
|
0
|
$self->pessimise($root, main_start); |
804
|
|
|
|
|
|
|
# Print deparsed program |
805
|
0
|
|
|
|
|
0
|
print $self->deparse_root($root)->{text}, "\n"; |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
} else { |
808
|
0
|
0
|
|
|
|
0
|
unless (B::Deparse::null $root) { |
809
|
0
|
|
|
|
|
0
|
$self->B::Deparse::pad_subs($self->{'curcv'}); |
810
|
|
|
|
|
|
|
# Check for a stub-followed-by-ex-cop, resulting from a program |
811
|
|
|
|
|
|
|
# consisting solely of sub declarations. For backward-compati- |
812
|
|
|
|
|
|
|
# bility (and sane output) we don’t want to emit the stub. |
813
|
|
|
|
|
|
|
# leave |
814
|
|
|
|
|
|
|
# enter |
815
|
|
|
|
|
|
|
# stub |
816
|
|
|
|
|
|
|
# ex-nextstate (or ex-dbstate) |
817
|
0
|
|
|
|
|
0
|
my $kid; |
818
|
0
|
0
|
0
|
|
|
0
|
if ( $root->name eq 'leave' |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
819
|
|
|
|
|
|
|
and ($kid = $root->first)->name eq 'enter' |
820
|
|
|
|
|
|
|
and !B::Deparse::null($kid = $kid->sibling) and $kid->name eq 'stub' |
821
|
|
|
|
|
|
|
and !B::Deparse::null($kid = $kid->sibling) and $kid->name eq 'null' |
822
|
|
|
|
|
|
|
and class($kid) eq 'COP' and B::Deparse::null $kid->sibling ) |
823
|
|
|
|
|
|
|
{ |
824
|
|
|
|
|
|
|
# ignore deparsing routine |
825
|
|
|
|
|
|
|
} else { |
826
|
0
|
|
|
|
|
0
|
$self->pessimise($root, main_start); |
827
|
|
|
|
|
|
|
# Print deparsed program |
828
|
0
|
|
|
|
|
0
|
my $root_tree = $self->deparse_root($root); |
829
|
0
|
|
|
|
|
0
|
print $root_tree->{text}, "\n"; |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
} |
833
|
0
|
|
|
|
|
0
|
my @text; |
834
|
0
|
|
|
|
|
0
|
while (scalar(@{$self->{'subs_todo'}})) { |
|
0
|
|
|
|
|
0
|
|
835
|
0
|
|
|
|
|
0
|
push @text, $self->next_todo->{text}; |
836
|
|
|
|
|
|
|
} |
837
|
0
|
0
|
|
|
|
0
|
print join("", @text), "\n" if @text; |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
# Print __DATA__ section, if necessary |
840
|
3
|
|
|
3
|
|
1132
|
no strict 'refs'; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
8251
|
|
841
|
|
|
|
|
|
|
my $laststash = defined $self->{'curcop'} |
842
|
0
|
0
|
|
|
|
0
|
? $self->{'curcop'}->stash->NAME : $self->{'curstash'}; |
843
|
0
|
0
|
|
|
|
0
|
if (defined *{$laststash."::DATA"}{IO}) { |
|
0
|
|
|
|
|
0
|
|
844
|
|
|
|
|
|
|
print $self->keyword("package") . " $laststash;\n" |
845
|
0
|
0
|
|
|
|
0
|
unless $laststash eq $self->{'curstash'}; |
846
|
0
|
|
|
|
|
0
|
print $self->keyword("__DATA__") . "\n"; |
847
|
0
|
|
|
|
|
0
|
print readline(*{$laststash."::DATA"}); |
|
0
|
|
|
|
|
0
|
|
848
|
|
|
|
|
|
|
} |
849
|
|
|
|
|
|
|
} |
850
|
0
|
|
|
|
|
0
|
} |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# "deparse()" is the main function to call to produces a depare tree |
853
|
|
|
|
|
|
|
# for a give B::OP. This method is the inner loop. |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
# Rocky's comment with respect to: |
856
|
|
|
|
|
|
|
# so try to keep it simple |
857
|
|
|
|
|
|
|
# |
858
|
|
|
|
|
|
|
# Most normal Perl programs really aren't that big. Yeah, I know there |
859
|
|
|
|
|
|
|
# are a couple of big pigs like the B::Deparse code itself. The perl5 |
860
|
|
|
|
|
|
|
# debugger comes to mind too. But what's the likelihood of anyone wanting |
861
|
|
|
|
|
|
|
# to decompile all of this? |
862
|
|
|
|
|
|
|
# |
863
|
|
|
|
|
|
|
# On the other hand, error checking is too valuable to throw out here. |
864
|
|
|
|
|
|
|
# Also, in trying to use and modularize this code, I see there is |
865
|
|
|
|
|
|
|
# a lot of repetition in subroutine parsing routines. That's |
866
|
|
|
|
|
|
|
# why I added the above PP_MAPFNS table. I'm not going to trade off |
867
|
|
|
|
|
|
|
# table lookup and interpetation for a huge amount of subroutine |
868
|
|
|
|
|
|
|
# bloat. |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
# That said it is useful to note that this is inner-most loop |
871
|
|
|
|
|
|
|
# interpeter loop as it is called for each node in the B::OP tree. |
872
|
|
|
|
|
|
|
# |
873
|
|
|
|
|
|
|
sub deparse |
874
|
|
|
|
|
|
|
{ |
875
|
17231
|
|
|
17231
|
0
|
30024
|
my($self, $op, $cx, $parent) = @_; |
876
|
|
|
|
|
|
|
|
877
|
17231
|
50
|
|
|
|
45256
|
Carp::confess("deparse called on an invalid op $op") |
878
|
|
|
|
|
|
|
unless $op->can('name'); |
879
|
|
|
|
|
|
|
|
880
|
17231
|
|
|
|
|
48533
|
my $name = $op->name; |
881
|
17231
|
50
|
|
|
|
33908
|
print "YYY $name\n" if $ENV{'DEBUG_DEPARSETREE'}; |
882
|
17231
|
|
|
|
|
20448
|
my ($info, $meth); |
883
|
|
|
|
|
|
|
|
884
|
17231
|
100
|
|
|
|
29040
|
if (exists($PP_MAPFNS{$name})) { |
885
|
|
|
|
|
|
|
# Interpret method calls for our PP_MAPFNS table |
886
|
2564
|
100
|
|
|
|
4969
|
if (ref($PP_MAPFNS{$name}) eq 'ARRAY') { |
887
|
150
|
|
|
|
|
240
|
my @args = @{$PP_MAPFNS{$name}}; |
|
150
|
|
|
|
|
454
|
|
888
|
150
|
|
|
|
|
289
|
$meth = shift @args; |
889
|
150
|
100
|
|
|
|
320
|
if ($meth eq 'maybe_targmy') { |
890
|
|
|
|
|
|
|
# FIXME: This is an inline version of targmy. |
891
|
|
|
|
|
|
|
# Can we dedup it? do we want to? |
892
|
67
|
|
|
|
|
111
|
$meth = shift @args; |
893
|
67
|
100
|
|
|
|
201
|
unshift @args, $name unless @args; |
894
|
67
|
100
|
|
|
|
309
|
if ($op->private & OPpTARGET_MY) { |
895
|
4
|
|
|
|
|
87
|
my $var = $self->padname($op->targ); |
896
|
4
|
|
|
|
|
32
|
my $val = $self->$meth($op, 7, @args); |
897
|
4
|
|
|
|
|
18
|
my @texts = ($var, '=', $val); |
898
|
4
|
|
|
|
|
35
|
$info = $self->info_from_template("my", $op, |
899
|
|
|
|
|
|
|
"%c = %c", [0, 1], |
900
|
|
|
|
|
|
|
[$var, $val], |
901
|
|
|
|
|
|
|
{maybe_parens => [$self, $cx, 7]}); |
902
|
|
|
|
|
|
|
} else { |
903
|
63
|
|
|
|
|
324
|
$info = $self->$meth($op, $cx, @args); |
904
|
|
|
|
|
|
|
} |
905
|
|
|
|
|
|
|
} else { |
906
|
83
|
|
|
|
|
331
|
$info = $self->$meth($op, $cx, @args); |
907
|
|
|
|
|
|
|
} |
908
|
|
|
|
|
|
|
} else { |
909
|
|
|
|
|
|
|
# Simple case: one simple call of the |
910
|
|
|
|
|
|
|
# the method in the table. Call this |
911
|
|
|
|
|
|
|
# passing arguments $op, $cx, and $name. |
912
|
|
|
|
|
|
|
# Some functions might not use these, |
913
|
|
|
|
|
|
|
# but that's okay. |
914
|
2414
|
|
|
|
|
3830
|
$meth = $PP_MAPFNS{$name}; |
915
|
2414
|
|
|
|
|
8276
|
$info = $self->$meth($op, $cx, $name); |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
} else { |
918
|
|
|
|
|
|
|
# Tried and true fallback method: |
919
|
|
|
|
|
|
|
# a method has been defined for this pp_op special. |
920
|
|
|
|
|
|
|
# call that. |
921
|
14667
|
|
|
|
|
18954
|
$meth = "pp_" . $name; |
922
|
14667
|
|
|
|
|
39377
|
$info = $self->$meth($op, $cx); |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
|
925
|
17231
|
50
|
|
|
|
33010
|
Carp::confess("nonref return for $meth deparse: $info") if !ref($info); |
926
|
17231
|
50
|
|
|
|
49308
|
Carp::confess("not B::DeparseTree:Node returned for $meth: $info") |
927
|
|
|
|
|
|
|
if !$info->isa("B::DeparseTree::Node"); |
928
|
17231
|
100
|
|
|
|
38204
|
$info->{parent} = $$parent if $parent; |
929
|
17231
|
|
|
|
|
28372
|
$info->{cop} = $self->{'curcop'}; |
930
|
17231
|
|
|
|
|
21980
|
my $got_op = $info->{op}; |
931
|
17231
|
100
|
|
|
|
26188
|
if ($got_op) { |
932
|
17158
|
100
|
|
|
|
32776
|
if ($got_op != $op) { |
933
|
|
|
|
|
|
|
# Do something here? |
934
|
|
|
|
|
|
|
# printf("XX final op 0x%x is not requested 0x%x\n", |
935
|
|
|
|
|
|
|
# $$op, $$got_op); |
936
|
|
|
|
|
|
|
} |
937
|
|
|
|
|
|
|
} else { |
938
|
73
|
|
|
|
|
105
|
$info->{op} = $op; |
939
|
|
|
|
|
|
|
} |
940
|
17231
|
|
|
|
|
47330
|
$self->{optree}{$$op} = $info; |
941
|
17231
|
100
|
|
|
|
27522
|
if ($info->{other_ops}) { |
942
|
4133
|
|
|
|
|
4745
|
foreach my $other (@{$info->{other_ops}}) { |
|
4133
|
|
|
|
|
7306
|
|
943
|
8733
|
50
|
|
|
|
23797
|
if (!ref $other) { |
|
|
100
|
|
|
|
|
|
944
|
0
|
|
|
|
|
0
|
Carp::confess "$meth returns invalid other $other"; |
945
|
|
|
|
|
|
|
} elsif ($other->isa("B::DeparseTree::Node")) { |
946
|
|
|
|
|
|
|
# "$other" has been set up to mark a particular portion |
947
|
|
|
|
|
|
|
# of the info. |
948
|
5364
|
|
|
|
|
9520
|
$self->{optree}{$other->{addr}} = $other; |
949
|
5364
|
|
|
|
|
9373
|
$other->{parent} = $$op; |
950
|
|
|
|
|
|
|
} else { |
951
|
|
|
|
|
|
|
# "$other" is just the OP. Have it mark everything |
952
|
|
|
|
|
|
|
# or "info". |
953
|
3369
|
|
|
|
|
8239
|
$self->{optree}{$$other} = $info; |
954
|
|
|
|
|
|
|
} |
955
|
|
|
|
|
|
|
} |
956
|
|
|
|
|
|
|
} |
957
|
17231
|
|
|
|
|
37017
|
return $info; |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
# Deparse a subroutine |
961
|
|
|
|
|
|
|
sub deparse_sub($$$$) |
962
|
|
|
|
|
|
|
{ |
963
|
1345
|
|
|
1345
|
0
|
2731
|
my ($self, $cv, $start_op) = @_; |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
# Sanity checks.. |
966
|
1345
|
50
|
33
|
|
|
9037
|
Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL"); |
967
|
1345
|
50
|
|
|
|
4567
|
Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL"); |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
# First get protype and sub attribute information |
970
|
1345
|
|
|
|
|
3497
|
local $self->{'curcop'} = $self->{'curcop'}; |
971
|
1345
|
|
|
|
|
1963
|
my $proto = ''; |
972
|
1345
|
50
|
|
|
|
4473
|
if ($cv->FLAGS & SVf_POK) { |
973
|
0
|
|
|
|
|
0
|
$proto .= "(". $cv->PV . ")"; |
974
|
|
|
|
|
|
|
} |
975
|
1345
|
50
|
|
|
|
4457
|
if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE)) { |
976
|
0
|
|
|
|
|
0
|
$proto .= ":"; |
977
|
0
|
0
|
|
|
|
0
|
$proto .= " lvalue" if $cv->CvFLAGS & CVf_LVALUE; |
978
|
0
|
0
|
|
|
|
0
|
$proto .= " locked" if $cv->CvFLAGS & CVf_LOCKED; |
979
|
0
|
0
|
|
|
|
0
|
$proto .= " method" if $cv->CvFLAGS & CVf_METHOD; |
980
|
|
|
|
|
|
|
} |
981
|
|
|
|
|
|
|
|
982
|
1345
|
|
|
|
|
3222
|
local($self->{'curcv'}) = $cv; |
983
|
1345
|
|
|
|
|
2707
|
local($self->{'curcvlex'}); |
984
|
|
|
|
|
|
|
local(@$self{qw'curstash warnings hints hinthash'}) |
985
|
1345
|
|
|
|
|
5627
|
= @$self{qw'curstash warnings hints hinthash'}; |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
# Now deparse subroutine body |
988
|
|
|
|
|
|
|
|
989
|
1345
|
|
|
|
|
4164
|
my $root = $cv->ROOT; |
990
|
1345
|
|
|
|
|
2335
|
my ($body, $node); |
991
|
|
|
|
|
|
|
|
992
|
1345
|
|
|
|
|
2676
|
local $B::overlay = {}; |
993
|
1345
|
50
|
|
|
|
13346
|
if (not B::Deparse::null $root) { |
994
|
1345
|
|
|
|
|
6360
|
$self->pessimise($root, $cv->START); |
995
|
1345
|
|
|
|
|
5514
|
my $lineseq = $root->first; |
996
|
1345
|
50
|
|
|
|
4988
|
if ($lineseq->name eq "lineseq") { |
|
|
0
|
|
|
|
|
|
997
|
1345
|
|
|
|
|
1947
|
my @ops; |
998
|
1345
|
|
|
|
|
5665
|
for(my $o=$lineseq->first; $$o; $o=$o->sibling) { |
999
|
4162
|
|
|
|
|
13536
|
push @ops, $o; |
1000
|
|
|
|
|
|
|
} |
1001
|
1345
|
|
|
|
|
4119
|
$body = $self->lineseq($root, 0, @ops); |
1002
|
1345
|
|
|
|
|
30877
|
my $scope_en = $self->find_scope_en($lineseq); |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
elsif ($start_op) { |
1005
|
0
|
|
|
|
|
0
|
$body = $self->deparse($start_op, 0, $root); |
1006
|
|
|
|
|
|
|
} else { |
1007
|
0
|
|
|
|
|
0
|
$body = $self->deparse($root->first, 0, $root); |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
|
1010
|
1345
|
|
|
|
|
7074
|
my $fn_name = $cv->GV->NAME; |
1011
|
1345
|
|
|
|
|
7006
|
$node = $self->info_from_template("sub $fn_name$proto", |
1012
|
|
|
|
|
|
|
$root, |
1013
|
|
|
|
|
|
|
"$proto\n%|{\n%+%c\n%-}", |
1014
|
|
|
|
|
|
|
[0], [$body]); |
1015
|
|
|
|
|
|
|
|
1016
|
1345
|
|
|
|
|
6127
|
$self->{optree}{$$lineseq} = $node; |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
} else { |
1019
|
0
|
|
|
|
|
0
|
my $sv = $cv->const_sv; |
1020
|
0
|
0
|
|
|
|
0
|
if ($$sv) { |
1021
|
|
|
|
|
|
|
# uh-oh. inlinable sub... format it differently |
1022
|
0
|
|
|
|
|
0
|
$node = $self->info_from_template('inline sub', $sv, |
1023
|
|
|
|
|
|
|
"$proto\n%|{\n%+%c\n%-}", |
1024
|
|
|
|
|
|
|
[0], [$self->const($sv, 0)]); |
1025
|
|
|
|
|
|
|
} else { |
1026
|
|
|
|
|
|
|
# XSUB? (or just a declaration) |
1027
|
0
|
|
|
|
|
0
|
$node = $self->info_from_string("XSUB or sub declaration", $proto); |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
} |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
# Add additional DeparseTree tracking info |
1033
|
1345
|
50
|
|
|
|
3082
|
if ($start_op) { |
1034
|
0
|
|
|
|
|
0
|
$node->{op} = $start_op; |
1035
|
0
|
|
|
|
|
0
|
$self->{'optree'}{$$start_op} = $node; |
1036
|
|
|
|
|
|
|
} |
1037
|
1345
|
|
|
|
|
3130
|
$node->{cop} = undef; |
1038
|
1345
|
|
|
|
|
2724
|
$node->{'parent'} = $cv; |
1039
|
1345
|
|
|
|
|
26469
|
return $node; |
1040
|
|
|
|
|
|
|
} |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
# We have a TODO list of things that must be handled |
1043
|
|
|
|
|
|
|
# at the top level. There are things like |
1044
|
|
|
|
|
|
|
# format statements, "BEGIN" and "use" statements. |
1045
|
|
|
|
|
|
|
# Here we handle the next one. |
1046
|
|
|
|
|
|
|
sub next_todo |
1047
|
|
|
|
|
|
|
{ |
1048
|
0
|
|
|
0
|
0
|
0
|
my ($self, $parent) = @_; |
1049
|
0
|
|
|
|
|
0
|
my $ent = shift @{$self->{'subs_todo'}}; |
|
0
|
|
|
|
|
0
|
|
1050
|
0
|
|
|
|
|
0
|
my $cv = $ent->[1]; |
1051
|
0
|
|
|
|
|
0
|
my $gv = $cv->GV; |
1052
|
0
|
|
|
|
|
0
|
my $name = $self->gv_name($gv); |
1053
|
0
|
0
|
|
|
|
0
|
if ($ent->[2]) { |
1054
|
0
|
|
|
|
|
0
|
my $node = $self->deparse_format($ent->[1], $cv); |
1055
|
0
|
|
|
|
|
0
|
return $self->info_from_template("format $name", |
1056
|
|
|
|
|
|
|
"format $name = %c", |
1057
|
|
|
|
|
|
|
undef, [$node]) |
1058
|
|
|
|
|
|
|
} else { |
1059
|
0
|
|
|
|
|
0
|
my ($fmt, $type); |
1060
|
0
|
|
|
|
|
0
|
$self->{'subs_declared'}{$name} = 1; |
1061
|
0
|
0
|
|
|
|
0
|
if ($name eq "BEGIN") { |
1062
|
0
|
|
|
|
|
0
|
my $use_dec = $self->begin_is_use($cv); |
1063
|
0
|
0
|
0
|
|
|
0
|
if (defined ($use_dec) and $self->{'expand'} < 5) { |
1064
|
0
|
0
|
|
|
|
0
|
if (0 == length($use_dec)) { |
1065
|
0
|
|
|
|
|
0
|
$self->info_from_string('BEGIN', $cv, ''); |
1066
|
|
|
|
|
|
|
} else { |
1067
|
0
|
|
|
|
|
0
|
$self->info_from_string('use', $cv, $use_dec); |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
} |
1070
|
|
|
|
|
|
|
} |
1071
|
0
|
|
|
|
|
0
|
my $l = ''; |
1072
|
0
|
0
|
|
|
|
0
|
if ($self->{'linenums'}) { |
1073
|
0
|
|
|
|
|
0
|
my $line = $gv->LINE; |
1074
|
0
|
|
|
|
|
0
|
my $file = $gv->FILE; |
1075
|
0
|
|
|
|
|
0
|
$l = "\n# line $line \"$file\"\n"; |
1076
|
|
|
|
|
|
|
} |
1077
|
0
|
0
|
|
|
|
0
|
if (class($cv->STASH) ne "SPECIAL") { |
1078
|
0
|
|
|
|
|
0
|
my $stash = $cv->STASH->NAME; |
1079
|
0
|
0
|
|
|
|
0
|
if ($stash ne $self->{'curstash'}) { |
1080
|
0
|
|
|
|
|
0
|
$fmt = "package $stash;\n"; |
1081
|
0
|
|
|
|
|
0
|
$type = "package $stash"; |
1082
|
0
|
0
|
|
|
|
0
|
$name = "$self->{'curstash'}::$name" unless $name =~ /::/; |
1083
|
0
|
|
|
|
|
0
|
$self->{'curstash'} = $stash; |
1084
|
|
|
|
|
|
|
} |
1085
|
0
|
|
|
|
|
0
|
$name =~ s/^\Q$stash\E::(?!\z|.*::)//; |
1086
|
0
|
|
|
|
|
0
|
$fmt .= "sub $name"; |
1087
|
0
|
|
|
|
|
0
|
$type .= "sub $name"; |
1088
|
|
|
|
|
|
|
} |
1089
|
0
|
|
|
|
|
0
|
my $node = $self->deparse_sub($cv, $parent); |
1090
|
0
|
|
|
|
|
0
|
$fmt .= '%c'; |
1091
|
0
|
|
|
|
|
0
|
return $self->info_from_template($type, $cv, $fmt, [0], [$node]); |
1092
|
|
|
|
|
|
|
} |
1093
|
|
|
|
|
|
|
} |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
# Deparse a subroutine by name |
1096
|
|
|
|
|
|
|
sub deparse_subname($$) |
1097
|
|
|
|
|
|
|
{ |
1098
|
0
|
|
|
0
|
0
|
0
|
my ($self, $funcname) = @_; |
1099
|
0
|
|
|
|
|
0
|
my $cv = svref_2object(\&$funcname); |
1100
|
0
|
|
|
|
|
0
|
my $info = $self->deparse_sub($cv); |
1101
|
0
|
|
|
|
|
0
|
return $self->info_from_template("sub $funcname", $cv, "sub $funcname %c", |
1102
|
|
|
|
|
|
|
undef, [$info]); |
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
# Return a list of info nodes for "use" and "no" pragmas. |
1106
|
|
|
|
|
|
|
sub declare_hints |
1107
|
|
|
|
|
|
|
{ |
1108
|
1337
|
|
|
1337
|
0
|
3144
|
my ($self, $from, $to) = @_; |
1109
|
1337
|
|
|
|
|
2638
|
my $use = $to & ~$from; |
1110
|
1337
|
|
|
|
|
2247
|
my $no = $from & ~$to; |
1111
|
|
|
|
|
|
|
|
1112
|
1337
|
|
|
|
|
1934
|
my @decls = (); |
1113
|
1337
|
|
|
|
|
16870
|
for my $pragma (B::Deparse::hint_pragmas($use)) { |
1114
|
1288
|
|
|
|
|
28361
|
my $type = $self->keyword("use") . " $pragma"; |
1115
|
1288
|
|
|
|
|
5969
|
push @decls, $self->info_from_template($type, undef, "$type", [], []); |
1116
|
|
|
|
|
|
|
} |
1117
|
1337
|
|
|
|
|
8735
|
for my $pragma (B::Deparse::hint_pragmas($no)) { |
1118
|
0
|
|
|
|
|
0
|
my $type = $self->keyword("no") . " $pragma"; |
1119
|
0
|
|
|
|
|
0
|
push @decls, $self->info_from_template($type, undef, "$type", [], []); |
1120
|
|
|
|
|
|
|
} |
1121
|
1337
|
|
|
|
|
3978
|
return @decls; |
1122
|
|
|
|
|
|
|
} |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
# Internal implementation hints that the core sets automatically, so don't need |
1125
|
|
|
|
|
|
|
# (or want) to be passed back to the user |
1126
|
|
|
|
|
|
|
my %ignored_hints = ( |
1127
|
|
|
|
|
|
|
'open<' => 1, |
1128
|
|
|
|
|
|
|
'open>' => 1, |
1129
|
|
|
|
|
|
|
':' => 1, |
1130
|
|
|
|
|
|
|
'strict/refs' => 1, |
1131
|
|
|
|
|
|
|
'strict/subs' => 1, |
1132
|
|
|
|
|
|
|
'strict/vars' => 1, |
1133
|
|
|
|
|
|
|
); |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
my %rev_feature; |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
sub declare_hinthash { |
1138
|
2089
|
|
|
2089
|
0
|
4339
|
my ($self, $from, $to, $indent, $hints) = @_; |
1139
|
2089
|
|
|
|
|
3483
|
my $doing_features = |
1140
|
|
|
|
|
|
|
($hints & $feature::hint_mask) == $feature::hint_mask; |
1141
|
2089
|
|
|
|
|
4015
|
my @decls; |
1142
|
|
|
|
|
|
|
my @features; |
1143
|
2089
|
|
|
|
|
0
|
my @unfeatures; # bugs? |
1144
|
2089
|
|
|
|
|
6157
|
for my $key (sort keys %$to) { |
1145
|
67
|
50
|
|
|
|
149
|
next if $ignored_hints{$key}; |
1146
|
67
|
|
33
|
|
|
534
|
my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6; |
1147
|
67
|
100
|
66
|
|
|
265
|
next if $is_feature and not $doing_features; |
1148
|
54
|
100
|
66
|
|
|
195
|
if (!exists $from->{$key} or $from->{$key} ne $to->{$key}) { |
1149
|
12
|
50
|
|
|
|
33
|
push(@features, $key), next if $is_feature; |
1150
|
|
|
|
|
|
|
push @decls, |
1151
|
|
|
|
|
|
|
qq(\$^H{) . single_delim($self, "q", "'", $key, "'") . qq(} = ) |
1152
|
|
|
|
|
|
|
. ( |
1153
|
|
|
|
|
|
|
defined $to->{$key} |
1154
|
0
|
0
|
|
|
|
0
|
? single_delim($self, "q", "'", $to->{$key}, "'") |
1155
|
|
|
|
|
|
|
: 'undef' |
1156
|
|
|
|
|
|
|
) |
1157
|
|
|
|
|
|
|
. qq(;); |
1158
|
|
|
|
|
|
|
} |
1159
|
|
|
|
|
|
|
} |
1160
|
2089
|
|
|
|
|
5096
|
for my $key (sort keys %$from) { |
1161
|
56
|
50
|
|
|
|
112
|
next if $ignored_hints{$key}; |
1162
|
56
|
|
33
|
|
|
382
|
my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6; |
1163
|
56
|
100
|
66
|
|
|
219
|
next if $is_feature and not $doing_features; |
1164
|
42
|
50
|
|
|
|
85
|
if (!exists $to->{$key}) { |
1165
|
0
|
0
|
|
|
|
0
|
push(@unfeatures, $key), next if $is_feature; |
1166
|
0
|
|
|
|
|
0
|
push @decls, qq(delete \$^H{'$key'};); |
1167
|
|
|
|
|
|
|
} |
1168
|
|
|
|
|
|
|
} |
1169
|
2089
|
|
|
|
|
2671
|
my @ret; |
1170
|
2089
|
100
|
66
|
|
|
7837
|
if (@features || @unfeatures) { |
1171
|
3
|
100
|
|
|
|
9
|
if (!%rev_feature) { %rev_feature = reverse %feature::feature } |
|
1
|
|
|
|
|
20
|
|
1172
|
|
|
|
|
|
|
} |
1173
|
2089
|
100
|
|
|
|
4320
|
if (@features) { |
1174
|
3
|
|
|
|
|
1349
|
push @ret, $self->keyword("use") . " feature " |
1175
|
|
|
|
|
|
|
. join(", ", map "'$rev_feature{$_}'", @features) . ";\n"; |
1176
|
|
|
|
|
|
|
} |
1177
|
2089
|
50
|
|
|
|
3960
|
if (@unfeatures) { |
1178
|
0
|
|
|
|
|
0
|
push @ret, $self->keyword("no") . " feature " |
1179
|
|
|
|
|
|
|
. join(", ", map "'$rev_feature{$_}'", @unfeatures) |
1180
|
|
|
|
|
|
|
. ";\n"; |
1181
|
|
|
|
|
|
|
} |
1182
|
|
|
|
|
|
|
@decls and |
1183
|
2089
|
50
|
|
|
|
3861
|
push @ret, |
1184
|
|
|
|
|
|
|
join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n"; |
1185
|
2089
|
|
|
|
|
5387
|
return @ret; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
# generate any pragmas, 'package foo' etc needed to synchronise |
1189
|
|
|
|
|
|
|
# with the given cop |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
sub pragmata { |
1192
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
1193
|
0
|
|
|
|
|
0
|
my($op) = @_; |
1194
|
|
|
|
|
|
|
|
1195
|
0
|
|
|
|
|
0
|
my @text; |
1196
|
|
|
|
|
|
|
|
1197
|
0
|
|
|
|
|
0
|
my $stash = $op->stashpv; |
1198
|
0
|
0
|
|
|
|
0
|
if ($stash ne $self->{'curstash'}) { |
1199
|
0
|
|
|
|
|
0
|
push @text, $self->keyword("package") . " $stash;\n"; |
1200
|
0
|
|
|
|
|
0
|
$self->{'curstash'} = $stash; |
1201
|
|
|
|
|
|
|
} |
1202
|
|
|
|
|
|
|
|
1203
|
0
|
|
|
|
|
0
|
if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) { |
1204
|
|
|
|
|
|
|
push @text, '$[ = '. $op->arybase .";\n"; |
1205
|
|
|
|
|
|
|
$self->{'arybase'} = $op->arybase; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
|
1208
|
0
|
|
|
|
|
0
|
my $warnings = $op->warnings; |
1209
|
0
|
|
|
|
|
0
|
my $warning_bits; |
1210
|
0
|
0
|
0
|
|
|
0
|
if ($warnings->isa("B::SPECIAL") && $$warnings == 4) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1211
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings::Bits{"all"} & WARN_MASK; |
1212
|
|
|
|
|
|
|
} |
1213
|
|
|
|
|
|
|
elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) { |
1214
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings::NONE; |
1215
|
|
|
|
|
|
|
} |
1216
|
|
|
|
|
|
|
elsif ($warnings->isa("B::SPECIAL")) { |
1217
|
0
|
|
|
|
|
0
|
$warning_bits = undef; |
1218
|
|
|
|
|
|
|
} |
1219
|
|
|
|
|
|
|
else { |
1220
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings->PV & WARN_MASK; |
1221
|
|
|
|
|
|
|
} |
1222
|
|
|
|
|
|
|
|
1223
|
0
|
0
|
0
|
|
|
0
|
if (defined ($warning_bits) and |
|
|
|
0
|
|
|
|
|
1224
|
|
|
|
|
|
|
!defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) { |
1225
|
|
|
|
|
|
|
push @text, |
1226
|
0
|
|
|
|
|
0
|
$self->declare_warnings($self->{'warnings'}, $warning_bits); |
1227
|
0
|
|
|
|
|
0
|
$self->{'warnings'} = $warning_bits; |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
|
1230
|
0
|
0
|
|
|
|
0
|
my $hints = $] < 5.008009 ? $op->private : $op->hints; |
1231
|
0
|
|
|
|
|
0
|
my $old_hints = $self->{'hints'}; |
1232
|
0
|
0
|
|
|
|
0
|
if ($self->{'hints'} != $hints) { |
1233
|
0
|
|
|
|
|
0
|
push @text, $self->declare_hints($self->{'hints'}, $hints); |
1234
|
0
|
|
|
|
|
0
|
$self->{'hints'} = $hints; |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
|
1237
|
0
|
|
|
|
|
0
|
my $newhh; |
1238
|
0
|
0
|
|
|
|
0
|
if ($] > 5.009) { |
1239
|
0
|
|
|
|
|
0
|
$newhh = $op->hints_hash->HASH; |
1240
|
|
|
|
|
|
|
} |
1241
|
|
|
|
|
|
|
|
1242
|
0
|
0
|
|
|
|
0
|
if ($] >= 5.015006) { |
1243
|
|
|
|
|
|
|
# feature bundle hints |
1244
|
0
|
|
|
|
|
0
|
my $from = $old_hints & $feature::hint_mask; |
1245
|
0
|
|
|
|
|
0
|
my $to = $ hints & $feature::hint_mask; |
1246
|
0
|
0
|
|
|
|
0
|
if ($from != $to) { |
1247
|
0
|
0
|
|
|
|
0
|
if ($to == $feature::hint_mask) { |
1248
|
0
|
0
|
|
|
|
0
|
if ($self->{'hinthash'}) { |
1249
|
|
|
|
|
|
|
delete $self->{'hinthash'}{$_} |
1250
|
0
|
|
|
|
|
0
|
for grep /^feature_/, keys %{$self->{'hinthash'}}; |
|
0
|
|
|
|
|
0
|
|
1251
|
|
|
|
|
|
|
} |
1252
|
0
|
|
|
|
|
0
|
else { $self->{'hinthash'} = {} } |
1253
|
|
|
|
|
|
|
$self->{'hinthash'} |
1254
|
0
|
|
|
|
|
0
|
= _features_from_bundle($from, $self->{'hinthash'}); |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
else { |
1257
|
0
|
|
|
|
|
0
|
my $bundle = |
1258
|
|
|
|
|
|
|
$feature::hint_bundles[$to >> $feature::hint_shift]; |
1259
|
0
|
|
|
|
|
0
|
$bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12 |
|
0
|
|
|
|
|
0
|
|
1260
|
0
|
|
|
|
|
0
|
push @text, |
1261
|
|
|
|
|
|
|
$self->keyword("no") . " feature ':all';\n", |
1262
|
|
|
|
|
|
|
$self->keyword("use") . " feature ':$bundle';\n"; |
1263
|
|
|
|
|
|
|
} |
1264
|
|
|
|
|
|
|
} |
1265
|
|
|
|
|
|
|
} |
1266
|
|
|
|
|
|
|
|
1267
|
0
|
0
|
|
|
|
0
|
if ($] > 5.009) { |
1268
|
|
|
|
|
|
|
push @text, $self->declare_hinthash( |
1269
|
|
|
|
|
|
|
$self->{'hinthash'}, $newhh, |
1270
|
|
|
|
|
|
|
$self->{indent_size}, $self->{hints}, |
1271
|
0
|
|
|
|
|
0
|
); |
1272
|
0
|
|
|
|
|
0
|
$self->{'hinthash'} = $newhh; |
1273
|
|
|
|
|
|
|
} |
1274
|
|
|
|
|
|
|
|
1275
|
0
|
|
|
|
|
0
|
return join("", @text); |
1276
|
|
|
|
|
|
|
} |
1277
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
# Create a "use", "no", or "BEGIN" block to set warnings. |
1280
|
|
|
|
|
|
|
sub declare_warnings |
1281
|
|
|
|
|
|
|
{ |
1282
|
1288
|
|
|
1288
|
0
|
2914
|
my ($self, $from, $to) = @_; |
1283
|
1288
|
100
|
|
|
|
2941
|
if (($to & WARN_MASK) eq (warnings::bits("all") & WARN_MASK)) { |
|
|
50
|
|
|
|
|
|
1284
|
2
|
|
|
|
|
1010
|
my $type = $self->keyword("use") . " warnings"; |
1285
|
2
|
|
|
|
|
31
|
return $self->info_from_template($type, undef, "$type;\n", |
1286
|
|
|
|
|
|
|
[], []); |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
elsif (($to & WARN_MASK) eq ("\0"x length($to) & WARN_MASK)) { |
1289
|
1286
|
|
|
|
|
27511
|
my $type = $self->keyword("no") . " warnings"; |
1290
|
1286
|
|
|
|
|
6138
|
return $self->info_from_template($type, undef, "$type;\n", |
1291
|
|
|
|
|
|
|
[], []); |
1292
|
|
|
|
|
|
|
} |
1293
|
0
|
|
|
|
|
0
|
my $bit_expr = join('', map { sprintf("\\x%02x", ord $_) } split "", $to); |
|
0
|
|
|
|
|
0
|
|
1294
|
0
|
|
|
|
|
0
|
my $str = "BEGIN {\n%+\${^WARNING_BITS} = \"$bit_expr;\n%-"; |
1295
|
0
|
|
|
|
|
0
|
return $self->info_from_template('warning bits begin', undef, |
1296
|
|
|
|
|
|
|
"%|$str\n", [], [], {omit_next_semicolon=>1}); |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
# Iterate over $self->{subs_todo} picking up the |
1300
|
|
|
|
|
|
|
# text of of $self->next_todo. |
1301
|
|
|
|
|
|
|
# We return an array of strings. The calling |
1302
|
|
|
|
|
|
|
# routine will join these together |
1303
|
|
|
|
|
|
|
sub seq_subs { |
1304
|
2089
|
|
|
2089
|
0
|
4167
|
my ($self, $seq) = @_; |
1305
|
2089
|
|
|
|
|
2497
|
my @texts; |
1306
|
|
|
|
|
|
|
|
1307
|
2089
|
50
|
|
|
|
3900
|
return () if !defined $seq; |
1308
|
2089
|
|
|
|
|
2801
|
my @pending; |
1309
|
2089
|
|
33
|
|
|
2631
|
while (scalar(@{$self->{'subs_todo'}}) |
|
2089
|
|
|
|
|
6070
|
|
1310
|
|
|
|
|
|
|
and $seq > $self->{'subs_todo'}[0][0]) { |
1311
|
0
|
|
|
|
|
0
|
my $cv = $self->{'subs_todo'}[0][1]; |
1312
|
|
|
|
|
|
|
# Skip the OUTSIDE check for lexical subs. We may be deparsing a |
1313
|
|
|
|
|
|
|
# cloned anon sub with lexical subs declared in it, in which case |
1314
|
|
|
|
|
|
|
# the OUTSIDE pointer points to the anon protosub. |
1315
|
0
|
|
|
|
|
0
|
my $lexical = ref $self->{'subs_todo'}[0][3]; |
1316
|
0
|
|
0
|
|
|
0
|
my $outside = !$lexical && $cv && $cv->OUTSIDE; |
1317
|
0
|
0
|
0
|
|
|
0
|
if (!$lexical and $cv |
|
|
|
0
|
|
|
|
|
1318
|
0
|
0
|
|
|
|
0
|
and ${$cv->OUTSIDE || \0} != ${$self->{'curcv'}}) |
|
0
|
|
|
|
|
0
|
|
1319
|
|
|
|
|
|
|
{ |
1320
|
|
|
|
|
|
|
# rocky: What do we do with @pending? |
1321
|
0
|
|
|
|
|
0
|
push @pending, shift @{$self->{'subs_todo'}}; |
|
0
|
|
|
|
|
0
|
|
1322
|
0
|
|
|
|
|
0
|
next; |
1323
|
|
|
|
|
|
|
} |
1324
|
0
|
|
|
|
|
0
|
push @texts, $self->next_todo; |
1325
|
|
|
|
|
|
|
} |
1326
|
2089
|
|
|
|
|
5299
|
return @texts; |
1327
|
|
|
|
|
|
|
} |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
# FIXME: this code has to be here. Find out why and fix. |
1330
|
|
|
|
|
|
|
# Truncate is special because OPf_SPECIAL makes a bareword first arg |
1331
|
|
|
|
|
|
|
# be a filehandle. This could probably be better fixed in the core |
1332
|
|
|
|
|
|
|
# by moving the GV lookup into ck_truc. |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
# Demo code |
1335
|
|
|
|
|
|
|
unless(caller) { |
1336
|
|
|
|
|
|
|
my @texts = ('a', 'b', 'c'); |
1337
|
|
|
|
|
|
|
my $deparse = __PACKAGE__->new(); |
1338
|
|
|
|
|
|
|
my $info = info_from_list('op', $deparse, \@texts, ', ', 'test', {}); |
1339
|
|
|
|
|
|
|
|
1340
|
3
|
|
|
3
|
|
27
|
use Data::Printer; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
11
|
|
1341
|
|
|
|
|
|
|
my $str = $deparse->template_engine("%c", [0], ["16"]); |
1342
|
|
|
|
|
|
|
p $str; |
1343
|
|
|
|
|
|
|
my $str2 = $deparse->template_engine("%F", [[0, sub {'0x' . sprintf "%x", shift}]], [$str]); |
1344
|
|
|
|
|
|
|
p $str2; |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
# print $deparse->template_engine("100%% "), "\n"; |
1347
|
|
|
|
|
|
|
# print $deparse->template_engine("%c,\n%+%c\n%|%c %c!", |
1348
|
|
|
|
|
|
|
# [1, 0, 2, 3], |
1349
|
|
|
|
|
|
|
# ["is", "now", "the", "time"]), "\n"; |
1350
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("demo", undef, "%C", |
1352
|
|
|
|
|
|
|
# [[0, 1, ";\n%|"]], |
1353
|
|
|
|
|
|
|
# ['$x=1', '$y=2']); |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
# @texts = ("use warnings;", "use strict", "my(\$a)"); |
1356
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("demo", undef, "%;", [], \@texts); |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("list", undef, |
1359
|
|
|
|
|
|
|
# "%C", [[0, $#texts, ', ']], |
1360
|
|
|
|
|
|
|
# \@texts); |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
# p $info; |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
# @texts = (['a', 1], ['b', 2], 'c'); |
1366
|
|
|
|
|
|
|
# $info = info_from_list('op', $deparse, \@texts, ', ', 'test', {}); |
1367
|
|
|
|
|
|
|
# p $info; |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
1; |