| 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
|
|
39
|
use strict; use warnings; |
|
|
8
|
|
|
8
|
|
11
|
|
|
|
8
|
|
|
|
|
176
|
|
|
|
8
|
|
|
|
|
29
|
|
|
|
8
|
|
|
|
|
13
|
|
|
|
8
|
|
|
|
|
347
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
package B::DeparseTree; |
|
22
|
|
|
|
|
|
|
|
|
23
|
8
|
|
|
|
|
905
|
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
|
|
37
|
); |
|
|
8
|
|
|
|
|
12
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
8
|
|
|
8
|
|
41
|
use Carp; |
|
|
8
|
|
|
|
|
10
|
|
|
|
8
|
|
|
|
|
332
|
|
|
43
|
8
|
|
|
8
|
|
34
|
use B::Deparse; |
|
|
8
|
|
|
|
|
31
|
|
|
|
8
|
|
|
|
|
155
|
|
|
44
|
8
|
|
|
8
|
|
2673
|
use B::DeparseTree::OPflags; |
|
|
8
|
|
|
|
|
16
|
|
|
|
8
|
|
|
|
|
405
|
|
|
45
|
8
|
|
|
8
|
|
2759
|
use B::DeparseTree::PP_OPtable; |
|
|
8
|
|
|
|
|
38
|
|
|
|
8
|
|
|
|
|
901
|
|
|
46
|
8
|
|
|
8
|
|
3082
|
use B::DeparseTree::SyntaxTree; |
|
|
8
|
|
|
|
|
21
|
|
|
|
8
|
|
|
|
|
1580
|
|
|
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
|
|
49
|
use Config; |
|
|
8
|
|
|
|
|
13
|
|
|
|
8
|
|
|
|
|
1397
|
|
|
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
|
|
511
|
BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC", |
|
113
|
|
|
|
|
|
|
"ENV", "ARGV", "ARGVOUT", "_"); } |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
my $max_prec; |
|
116
|
8
|
|
|
8
|
|
517
|
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
|
|
28
|
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
|
|
|
|
|
151
|
eval { import B $_ }; |
|
|
120
|
|
|
|
|
8235
|
|
|
128
|
8
|
|
|
8
|
|
47
|
no strict 'refs'; |
|
|
8
|
|
|
|
|
17
|
|
|
|
8
|
|
|
|
|
513
|
|
|
129
|
120
|
100
|
|
|
|
199
|
*{$_} = sub () {0} unless *{$_}{CODE}; |
|
|
24
|
|
|
|
|
78
|
|
|
|
120
|
|
|
|
|
3256
|
|
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub new { |
|
134
|
10
|
|
|
10
|
1
|
662388
|
my $class = shift; |
|
135
|
10
|
|
|
|
|
39
|
my $self = bless {}, $class; |
|
136
|
10
|
|
|
|
|
163
|
$self->{'cuddle'} = " "; #\n%| is another alternative |
|
137
|
10
|
|
|
|
|
69
|
$self->{'curcop'} = undef; |
|
138
|
10
|
|
|
|
|
40
|
$self->{'curstash'} = "main"; |
|
139
|
10
|
|
|
|
|
36
|
$self->{'ex_const'} = "'?unrecoverable constant?'"; |
|
140
|
10
|
|
|
|
|
29
|
$self->{'expand'} = 0; |
|
141
|
10
|
|
|
|
|
35
|
$self->{'files'} = {}; |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# How many spaces per indent nesting? |
|
144
|
10
|
|
|
|
|
34
|
$self->{'indent_size'} = 4; |
|
145
|
|
|
|
|
|
|
|
|
146
|
10
|
|
|
|
|
37
|
$self->{'opaddr'} = 0; |
|
147
|
10
|
|
|
|
|
30
|
$self->{'linenums'} = 0; |
|
148
|
10
|
|
|
|
|
31
|
$self->{'parens'} = 0; |
|
149
|
10
|
|
|
|
|
32
|
$self->{'subs_todo'} = []; |
|
150
|
10
|
|
|
|
|
27
|
$self->{'unquote'} = 0; |
|
151
|
10
|
|
|
|
|
27
|
$self->{'use_dumper'} = 0; |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Compress spaces with tabs? 1 tab = 8 spaces |
|
154
|
10
|
|
|
|
|
21
|
$self->{'use_tabs'} = 0; |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Indentation level |
|
157
|
10
|
|
|
|
|
25
|
$self->{'level'} = 0; |
|
158
|
|
|
|
|
|
|
|
|
159
|
10
|
|
|
|
|
33
|
$self->{'ambient_arybase'} = 0; |
|
160
|
10
|
|
|
|
|
26
|
$self->{'ambient_warnings'} = undef; # Assume no lexical warnings |
|
161
|
10
|
|
|
|
|
24
|
$self->{'ambient_hints'} = 0; |
|
162
|
10
|
|
|
|
|
29
|
$self->{'ambient_hinthash'} = undef; |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Given an opcode address, get the accumulated OP tree |
|
165
|
|
|
|
|
|
|
# OP for that. FIXME: remove this |
|
166
|
10
|
|
|
|
|
28
|
$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
|
|
|
|
|
28
|
$self->{'last_fake_addr'} = 0; |
|
171
|
|
|
|
|
|
|
|
|
172
|
10
|
|
|
|
|
54
|
$self->init(); |
|
173
|
|
|
|
|
|
|
|
|
174
|
10
|
|
|
|
|
39
|
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
|
|
|
|
|
35
|
return $self; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
{ |
|
201
|
|
|
|
|
|
|
# Mask out the bits that L uses |
|
202
|
|
|
|
|
|
|
my $WARN_MASK; |
|
203
|
|
|
|
|
|
|
BEGIN { |
|
204
|
8
|
|
|
8
|
|
1248
|
$WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all}; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
sub WARN_MASK () { |
|
207
|
5184
|
|
|
5184
|
0
|
26958
|
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
|
2550
|
my $self = shift; |
|
216
|
|
|
|
|
|
|
|
|
217
|
1402
|
|
|
|
|
3416
|
$self->{'arybase'} = $self->{'ambient_arybase'}; |
|
218
|
|
|
|
|
|
|
$self->{'warnings'} = defined ($self->{'ambient_warnings'}) |
|
219
|
1402
|
100
|
|
|
|
3898
|
? $self->{'ambient_warnings'} & WARN_MASK |
|
220
|
|
|
|
|
|
|
: undef; |
|
221
|
1402
|
|
|
|
|
2304
|
$self->{'hints'} = $self->{'ambient_hints'}; |
|
222
|
1402
|
50
|
|
|
|
3048
|
$self->{'hints'} &= 0xFF if $] < 5.009; |
|
223
|
1402
|
|
|
|
|
2364
|
$self->{'hinthash'} = $self->{'ambient_hinthash'}; |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# also a convenient place to clear out subs_declared |
|
226
|
1402
|
|
|
|
|
2950
|
delete $self->{'subs_declared'}; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
BEGIN { |
|
230
|
8
|
|
|
8
|
|
31
|
for (qw[ pushmark ]) |
|
231
|
|
|
|
|
|
|
{ |
|
232
|
8
|
|
|
|
|
6425
|
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
|
1089180
|
my ($self, $coderef, $start_op) = @_; |
|
247
|
1328
|
|
|
|
|
6417
|
my $cv = svref_2object ( $coderef ); |
|
248
|
1328
|
|
|
|
|
4424
|
my $gv = $cv->GV; |
|
249
|
1328
|
50
|
|
|
|
6117
|
if ($gv->NAME eq 'main') { |
|
250
|
0
|
|
|
|
|
0
|
return $self->main2info(); |
|
251
|
|
|
|
|
|
|
} else { |
|
252
|
1328
|
50
|
|
|
|
5050
|
croak "Usage: ->coderef2info(CODEREF)" |
|
253
|
|
|
|
|
|
|
unless UNIVERSAL::isa($coderef, "CODE"); |
|
254
|
1328
|
|
|
|
|
4712
|
$self->init(); |
|
255
|
1328
|
|
|
|
|
3878
|
return $self->deparse_sub($cv, $start_op); |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub coderef2text |
|
260
|
|
|
|
|
|
|
{ |
|
261
|
64
|
|
|
64
|
1
|
104936
|
my ($self, $func) = @_; |
|
262
|
64
|
|
|
|
|
134
|
my $info; |
|
263
|
64
|
50
|
|
|
|
199
|
if ($func eq 'main::main') { |
|
264
|
0
|
|
|
|
|
0
|
$info = $self->main2info(); |
|
265
|
|
|
|
|
|
|
} else { |
|
266
|
64
|
50
|
|
|
|
248
|
croak "Usage: ->coderef2text(CODEREF)" unless UNIVERSAL::isa($func, "CODE"); |
|
267
|
64
|
|
|
|
|
197
|
$self->init(); |
|
268
|
64
|
|
|
|
|
179
|
$info = $self->coderef2info($func); |
|
269
|
|
|
|
|
|
|
} |
|
270
|
64
|
|
|
|
|
209
|
return $self->info2str($info); |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub const { |
|
274
|
91
|
|
|
91
|
0
|
120
|
my $self = shift; |
|
275
|
91
|
|
|
|
|
156
|
my($sv, $cx) = @_; |
|
276
|
91
|
50
|
|
|
|
184
|
if ($self->{'use_dumper'}) { |
|
277
|
0
|
|
|
|
|
0
|
return $self->const_dumper($sv, $cx); |
|
278
|
|
|
|
|
|
|
} |
|
279
|
91
|
50
|
|
|
|
478
|
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
|
|
|
|
384
|
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
|
|
|
|
280
|
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
|
|
|
377
|
if ($sv->FLAGS & SVf_IOK) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
298
|
62
|
|
|
|
|
212
|
my $str = $sv->int_value; |
|
299
|
62
|
50
|
|
|
|
146
|
$str = $self->maybe_parens($str, $cx, 21) if $str < 0; |
|
300
|
62
|
|
|
|
|
201
|
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
|
|
65
|
if ($] > 5.0150051) { |
|
376
|
8
|
|
|
|
|
72
|
require overloading; |
|
377
|
8
|
|
|
|
|
14729
|
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
|
|
|
|
|
78
|
my $str = $sv->PV; |
|
409
|
29
|
50
|
|
|
|
105
|
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
|
|
|
|
|
202
|
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
|
4461
|
my ($self, $node, $prev_expr, $op) = @_; |
|
481
|
2101
|
|
|
|
|
3730
|
$node->{prev_expr} = $prev_expr; |
|
482
|
2101
|
|
|
|
|
2823
|
my $addr = $prev_expr->{addr}; |
|
483
|
2101
|
100
|
66
|
|
|
8386
|
if ($addr && ! exists $self->{optree}{$addr}) { |
|
484
|
4
|
50
|
|
|
|
27
|
$self->{optree}{$addr} = $node if $op; |
|
485
|
|
|
|
|
|
|
} |
|
486
|
|
|
|
|
|
|
} |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub walk_lineseq |
|
489
|
|
|
|
|
|
|
{ |
|
490
|
1342
|
|
|
1342
|
0
|
2665
|
my ($self, $op, $kids, $callback) = @_; |
|
491
|
1342
|
|
|
|
|
2308
|
my @kids = @$kids; |
|
492
|
1342
|
|
|
|
|
2040
|
my @body = (); # Accumulated node structures |
|
493
|
1342
|
|
|
|
|
1660
|
my $expr; |
|
494
|
1342
|
|
|
|
|
1809
|
my $prev_expr = undef; |
|
495
|
1342
|
|
|
|
|
1813
|
my $fix_cop = undef; |
|
496
|
1342
|
|
|
|
|
3228
|
for (my $i = 0; $i < @kids; $i++) { |
|
497
|
2088
|
100
|
|
|
|
13231
|
if (B::Deparse::is_state $kids[$i]) { |
|
498
|
2087
|
|
|
|
|
6286
|
$expr = ($self->deparse($kids[$i], 0, $op)); |
|
499
|
2087
|
|
|
|
|
5743
|
$callback->(\@body, $i, $expr, $op); |
|
500
|
2087
|
|
|
|
|
2836
|
$prev_expr = $expr; |
|
501
|
2087
|
50
|
|
|
|
3854
|
if ($fix_cop) { |
|
502
|
0
|
|
|
|
|
0
|
$fix_cop->{text} = $expr->{text}; |
|
503
|
|
|
|
|
|
|
} |
|
504
|
2087
|
|
|
|
|
2668
|
$i++; |
|
505
|
2087
|
50
|
|
|
|
4482
|
if ($i > $#kids) { |
|
506
|
0
|
|
|
|
|
0
|
last; |
|
507
|
|
|
|
|
|
|
} |
|
508
|
|
|
|
|
|
|
} |
|
509
|
2088
|
50
|
|
|
|
38520
|
if (B::Deparse::is_for_loop($kids[$i])) { |
|
510
|
0
|
0
|
|
|
|
0
|
print "YYY for loop\n" if $ENV{'DEBUG_DEPARSETREE'}; |
|
511
|
0
|
|
|
|
|
0
|
my $loop_expr = $self->for_loop($kids[$i], 0); |
|
512
|
0
|
0
|
|
|
|
0
|
$callback->(\@body, |
|
513
|
|
|
|
|
|
|
$i += $kids[$i]->sibling->name eq "unstack" ? 2 : 1, |
|
514
|
|
|
|
|
|
|
$loop_expr); |
|
515
|
0
|
|
|
|
|
0
|
$prev_expr = $loop_expr; |
|
516
|
0
|
|
|
|
|
0
|
next; |
|
517
|
|
|
|
|
|
|
} |
|
518
|
2088
|
|
|
|
|
7823
|
$expr = $self->deparse($kids[$i], (@kids != 1)/2, $op); |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# Perform semantic action on $expr accumulating the result |
|
521
|
|
|
|
|
|
|
# in @body. $op is the parent, and $i is the child position |
|
522
|
2088
|
|
|
|
|
6163
|
$callback->(\@body, $i, $expr, $op); |
|
523
|
2088
|
100
|
|
|
|
4654
|
unless (exists $expr->{prev_expr}) { |
|
524
|
759
|
|
|
|
|
1977
|
$self->update_node($expr, $prev_expr, $op); |
|
525
|
|
|
|
|
|
|
} |
|
526
|
2088
|
|
|
|
|
2875
|
$prev_expr = $expr; |
|
527
|
2088
|
50
|
|
|
|
3583
|
if ($fix_cop) { |
|
528
|
0
|
|
|
|
|
0
|
$fix_cop->{text} = $expr->{text}; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# If the text portion of a COP is empty, set up to fill it in |
|
532
|
|
|
|
|
|
|
# from the text portion of the next node. |
|
533
|
2088
|
50
|
33
|
|
|
16099
|
if (B::class($op) eq "COP" && !$expr->{text}) { |
|
534
|
0
|
|
|
|
|
0
|
$fix_cop = $op; |
|
535
|
|
|
|
|
|
|
} else { |
|
536
|
2088
|
|
|
|
|
6440
|
$fix_cop = undef; |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
} |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# Add semicolons between statements. Don't null statements |
|
541
|
|
|
|
|
|
|
# (which can happen for nexstate which doesn't have source code |
|
542
|
|
|
|
|
|
|
# associated with it. |
|
543
|
1342
|
|
|
|
|
4593
|
$expr = $self->info_from_template("statements", $op, "%;", [], \@body); |
|
544
|
1342
|
|
|
|
|
4499
|
$self->update_node($expr, $prev_expr, $op); |
|
545
|
1342
|
|
|
|
|
12533
|
return $expr; |
|
546
|
|
|
|
|
|
|
} |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
# $root should be the op which represents the root of whatever |
|
549
|
|
|
|
|
|
|
# we're sequencing here. If it's undefined, then we don't append |
|
550
|
|
|
|
|
|
|
# any subroutine declarations to the deparsed ops, otherwise we |
|
551
|
|
|
|
|
|
|
# append appropriate declarations. |
|
552
|
|
|
|
|
|
|
sub lineseq { |
|
553
|
1342
|
|
|
1342
|
0
|
3806
|
my($self, $root, $cx, @ops) = @_; |
|
554
|
|
|
|
|
|
|
|
|
555
|
1342
|
|
|
|
|
2430
|
my $out_cop = $self->{'curcop'}; |
|
556
|
1342
|
100
|
|
|
|
2776
|
my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef; |
|
557
|
1342
|
|
|
|
|
1781
|
my $limit_seq; |
|
558
|
1342
|
50
|
|
|
|
2679
|
if (defined $root) { |
|
559
|
1342
|
|
|
|
|
2227
|
$limit_seq = $out_seq; |
|
560
|
1342
|
|
|
|
|
1580
|
my $nseq; |
|
561
|
1342
|
50
|
|
|
|
1597
|
$nseq = $self->find_scope_st($root->sibling) if ${$root->sibling}; |
|
|
1342
|
|
|
|
|
5389
|
|
|
562
|
1342
|
100
|
33
|
|
|
4237
|
$limit_seq = $nseq if !defined($limit_seq) |
|
|
|
|
66
|
|
|
|
|
|
563
|
|
|
|
|
|
|
or defined($nseq) && $nseq < $limit_seq; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
$limit_seq = $self->{'limit_seq'} |
|
566
|
|
|
|
|
|
|
if defined($self->{'limit_seq'}) |
|
567
|
1342
|
50
|
33
|
|
|
3128
|
&& (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq); |
|
|
|
|
66
|
|
|
|
|
|
568
|
1342
|
|
|
|
|
2714
|
local $self->{'limit_seq'} = $limit_seq; |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
my $fn = sub { |
|
571
|
4175
|
|
|
4175
|
|
7335
|
my ($exprs, $i, $info, $parent) = @_; |
|
572
|
4175
|
|
|
|
|
5838
|
my $op = $ops[$i]; |
|
573
|
4175
|
50
|
|
|
|
7349
|
$info->{type} = $op->name unless $info->{type}; |
|
574
|
4175
|
|
|
|
|
6015
|
$info->{child_pos} = $i; |
|
575
|
4175
|
|
|
|
|
5353
|
$info->{op} = $op; |
|
576
|
4175
|
50
|
|
|
|
6955
|
if ($parent) { |
|
577
|
4175
|
50
|
|
|
|
7131
|
Carp::confess("nonref parent, op: $op->name") if !ref($parent); |
|
578
|
4175
|
|
|
|
|
6028
|
$info->{parent} = $$parent ; |
|
579
|
|
|
|
|
|
|
} |
|
580
|
|
|
|
|
|
|
|
|
581
|
4175
|
|
|
|
|
6624
|
$self->{optree}{$$op} = $info; |
|
582
|
|
|
|
|
|
|
|
|
583
|
4175
|
|
|
|
|
7352
|
push @$exprs, $info; |
|
584
|
1342
|
|
|
|
|
6543
|
}; |
|
585
|
1342
|
|
|
|
|
4468
|
return $self->walk_lineseq($root, \@ops, $fn); |
|
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
|
12558
|
|
|
12558
|
|
19514
|
my ($self, $startop) = @_; |
|
595
|
|
|
|
|
|
|
|
|
596
|
12558
|
50
|
|
|
|
18657
|
return unless $$startop; |
|
597
|
12558
|
|
|
|
|
14877
|
my ($op, $parent_op); |
|
598
|
|
|
|
|
|
|
|
|
599
|
12558
|
|
|
|
|
20705
|
for ($op = $startop; $$op; $op = $op->sibling) { |
|
600
|
24710
|
|
|
|
|
62258
|
my $ppname = $op->name; |
|
601
|
|
|
|
|
|
|
|
|
602
|
24710
|
|
50
|
|
|
109491
|
$self->{ops}{$$op} ||= {}; |
|
603
|
24710
|
|
|
|
|
40283
|
$self->{ops}{$$op}{op} = $op; |
|
604
|
24710
|
|
|
|
|
31572
|
$self->{ops}{$$op}{parent_op} = $startop; |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# pessimisations start here |
|
607
|
|
|
|
|
|
|
|
|
608
|
24710
|
100
|
|
|
|
34808
|
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
|
827
|
|
|
|
|
4532
|
$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
|
24710
|
100
|
66
|
|
|
100354
|
if (class($op) eq 'PMOP' |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
632
|
|
|
|
|
|
|
&& ref($op->pmreplroot) |
|
633
|
24
|
|
|
|
|
109
|
&& ${$op->pmreplroot} |
|
634
|
|
|
|
|
|
|
&& $op->pmreplroot->isa( 'B::OP' )) |
|
635
|
|
|
|
|
|
|
{ |
|
636
|
4
|
|
|
|
|
14
|
$self-> _pessimise_walk($op->pmreplroot); |
|
637
|
|
|
|
|
|
|
} |
|
638
|
|
|
|
|
|
|
|
|
639
|
24710
|
100
|
|
|
|
118242
|
if ($op->flags & OPf_KIDS) { |
|
640
|
11224
|
|
|
|
|
34337
|
$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
|
1469
|
|
|
1469
|
|
3355
|
my ($self, $startop, $visited) = @_; |
|
653
|
|
|
|
|
|
|
|
|
654
|
1469
|
100
|
|
|
|
3366
|
return unless $$startop; |
|
655
|
1455
|
50
|
|
|
|
3974
|
return if $visited->{$$startop}; |
|
656
|
1455
|
|
|
|
|
2277
|
my $op; |
|
657
|
1455
|
|
|
|
|
3490
|
for ($op = $startop; $$op; $op = $op->next) { |
|
658
|
12891
|
100
|
|
|
|
23851
|
last if $visited->{$$op}; |
|
659
|
12770
|
|
|
|
|
18641
|
$visited->{$$op} = 1; |
|
660
|
|
|
|
|
|
|
|
|
661
|
12770
|
|
50
|
|
|
21014
|
$self->{ops}{$$op} ||= {}; |
|
662
|
12770
|
|
|
|
|
17762
|
$self->{ops}{$$op}{op} = $op; |
|
663
|
|
|
|
|
|
|
|
|
664
|
12770
|
|
|
|
|
30058
|
my $ppname = $op->name; |
|
665
|
12770
|
100
|
|
|
|
70867
|
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
|
116
|
|
|
|
|
443
|
$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
|
5
|
|
|
|
|
24
|
$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
|
1330
|
|
|
1330
|
0
|
2779
|
my ($self, $root, $start) = @_; |
|
694
|
|
|
|
|
|
|
|
|
695
|
8
|
|
|
8
|
|
55
|
no warnings 'recursion'; |
|
|
8
|
|
|
|
|
18
|
|
|
|
8
|
|
|
|
|
5417
|
|
|
696
|
|
|
|
|
|
|
# walk tree in root-to-branch order |
|
697
|
1330
|
|
|
|
|
4340
|
$self->_pessimise_walk($root); |
|
698
|
|
|
|
|
|
|
|
|
699
|
1330
|
|
|
|
|
2120
|
my %visited; |
|
700
|
|
|
|
|
|
|
# walk tree in execution order |
|
701
|
1330
|
|
|
|
|
3621
|
$self->_pessimise_walk_exe($start, \%visited); |
|
702
|
|
|
|
|
|
|
} |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
sub style_opts |
|
705
|
|
|
|
|
|
|
{ |
|
706
|
0
|
|
|
0
|
0
|
0
|
my ($self, $opts) = @_; |
|
707
|
0
|
|
|
|
|
0
|
my $opt; |
|
708
|
0
|
|
|
|
|
0
|
while (length($opt = substr($opts, 0, 1))) { |
|
709
|
0
|
0
|
|
|
|
0
|
if ($opt eq "C") { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
710
|
0
|
|
|
|
|
0
|
$self->{'cuddle'} = " "; |
|
711
|
0
|
|
|
|
|
0
|
$opts = substr($opts, 1); |
|
712
|
|
|
|
|
|
|
} elsif ($opt eq "i") { |
|
713
|
0
|
|
|
|
|
0
|
$opts =~ s/^i(\d+)//; |
|
714
|
0
|
|
|
|
|
0
|
$self->{'indent_size'} = $1; |
|
715
|
|
|
|
|
|
|
} elsif ($opt eq "T") { |
|
716
|
0
|
|
|
|
|
0
|
$self->{'use_tabs'} = 1; |
|
717
|
0
|
|
|
|
|
0
|
$opts = substr($opts, 1); |
|
718
|
|
|
|
|
|
|
} elsif ($opt eq "v") { |
|
719
|
0
|
|
|
|
|
0
|
$opts =~ s/^v([^.]*)(.|$)//; |
|
720
|
0
|
|
|
|
|
0
|
$self->{'ex_const'} = $1; |
|
721
|
|
|
|
|
|
|
} |
|
722
|
|
|
|
|
|
|
} |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
# B::Deparse name is print_protos |
|
726
|
|
|
|
|
|
|
sub extract_prototypes($) |
|
727
|
|
|
|
|
|
|
{ |
|
728
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
729
|
0
|
|
|
|
|
0
|
my $ar; |
|
730
|
|
|
|
|
|
|
my @ret; |
|
731
|
0
|
|
|
|
|
0
|
foreach $ar (@{$self->{'protos_todo'}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
732
|
0
|
|
|
|
|
0
|
my $body; |
|
733
|
0
|
0
|
|
|
|
0
|
if (defined $ar->[1]) { |
|
734
|
0
|
0
|
|
|
|
0
|
if (ref $ar->[1]) { |
|
735
|
|
|
|
|
|
|
# FIXME: better optree tracking? |
|
736
|
|
|
|
|
|
|
# And use formatting markup? |
|
737
|
0
|
|
|
|
|
0
|
my $node = $self->const($ar->[1]->RV,0); |
|
738
|
0
|
|
|
|
|
0
|
my $body_node = |
|
739
|
|
|
|
|
|
|
$self->info_from_template("protos", undef, |
|
740
|
|
|
|
|
|
|
"() {\n %c;\n}", |
|
741
|
|
|
|
|
|
|
undef, [$node]); |
|
742
|
0
|
|
|
|
|
0
|
$body = $body_node->{text}; |
|
743
|
|
|
|
|
|
|
} else { |
|
744
|
0
|
|
|
|
|
0
|
$body = sprintf " (%s);", $ar->[1]; |
|
745
|
|
|
|
|
|
|
} |
|
746
|
|
|
|
|
|
|
} else { |
|
747
|
0
|
|
|
|
|
0
|
$body = ";"; |
|
748
|
|
|
|
|
|
|
} |
|
749
|
0
|
|
|
|
|
0
|
push @ret, sprintf "sub %s%s\n", $ar->[0], $body; |
|
750
|
|
|
|
|
|
|
} |
|
751
|
0
|
|
|
|
|
0
|
delete $self->{'protos_todo'}; |
|
752
|
0
|
|
|
|
|
0
|
return @ret; |
|
753
|
|
|
|
|
|
|
} |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
# This gets called automatically when option: |
|
756
|
|
|
|
|
|
|
# -MO="DeparseTree,sC" is added |
|
757
|
|
|
|
|
|
|
# Running this prints out the program text. |
|
758
|
|
|
|
|
|
|
sub compile { |
|
759
|
0
|
|
|
0
|
0
|
0
|
my(@args) = @_; |
|
760
|
|
|
|
|
|
|
return sub { |
|
761
|
0
|
|
|
0
|
|
0
|
my $self = B::DeparseTree->new(@args); |
|
762
|
|
|
|
|
|
|
# First deparse command-line args |
|
763
|
0
|
0
|
|
|
|
0
|
if (defined $^I) { # deparse -i |
|
764
|
0
|
|
|
|
|
0
|
print q(BEGIN { $^I = ).perlstring($^I).qq(; }\n); |
|
765
|
|
|
|
|
|
|
} |
|
766
|
0
|
0
|
|
|
|
0
|
if ($^W) { # deparse -w |
|
767
|
0
|
|
|
|
|
0
|
print qq(BEGIN { \$^W = $^W; }\n); |
|
768
|
|
|
|
|
|
|
} |
|
769
|
0
|
0
|
0
|
|
|
0
|
if ($/ ne "\n" or defined $O::savebackslash) { # deparse -l and -0 |
|
770
|
0
|
|
0
|
|
|
0
|
my $fs = perlstring($/) || 'undef'; |
|
771
|
0
|
|
0
|
|
|
0
|
my $bs = perlstring($O::savebackslash) || 'undef'; |
|
772
|
0
|
|
|
|
|
0
|
print qq(BEGIN { \$/ = $fs; \$\\ = $bs; }\n); |
|
773
|
|
|
|
|
|
|
} |
|
774
|
0
|
0
|
|
|
|
0
|
my @BEGINs = B::begin_av->isa("B::AV") ? B::begin_av->ARRAY : (); |
|
775
|
0
|
0
|
|
|
|
0
|
my @UNITCHECKs = B::unitcheck_av->isa("B::AV") |
|
776
|
|
|
|
|
|
|
? B::unitcheck_av->ARRAY |
|
777
|
|
|
|
|
|
|
: (); |
|
778
|
0
|
0
|
|
|
|
0
|
my @CHECKs = B::check_av->isa("B::AV") ? B::check_av->ARRAY : (); |
|
779
|
0
|
0
|
|
|
|
0
|
my @INITs = B::init_av->isa("B::AV") ? B::init_av->ARRAY : (); |
|
780
|
0
|
0
|
|
|
|
0
|
my @ENDs = B::end_av->isa("B::AV") ? B::end_av->ARRAY : (); |
|
781
|
0
|
0
|
|
|
|
0
|
if ($] < 5.020) { |
|
782
|
0
|
|
|
|
|
0
|
for my $block (@BEGINs, @UNITCHECKs, @CHECKs, @INITs, @ENDs) { |
|
783
|
0
|
|
|
|
|
0
|
$self->B::Deparse::todo($block, 0); |
|
784
|
|
|
|
|
|
|
} |
|
785
|
|
|
|
|
|
|
} else { |
|
786
|
0
|
|
|
|
|
0
|
my @names = qw(BEGIN UNITCHECK CHECK INIT END); |
|
787
|
0
|
|
|
|
|
0
|
my @blocks = (\@BEGINs, \@UNITCHECKs, \@CHECKs, \@INITs, \@ENDs); |
|
788
|
0
|
|
|
|
|
0
|
while (@names) { |
|
789
|
0
|
|
|
|
|
0
|
my ($name, $blocks) = (shift @names, shift @blocks); |
|
790
|
0
|
|
|
|
|
0
|
for my $block (@$blocks) { |
|
791
|
0
|
|
|
|
|
0
|
$self->todo($block, 0, $name); |
|
792
|
|
|
|
|
|
|
} |
|
793
|
|
|
|
|
|
|
} |
|
794
|
|
|
|
|
|
|
} |
|
795
|
0
|
|
|
|
|
0
|
$self->B::Deparse::stash_subs(); |
|
796
|
|
|
|
|
|
|
local($SIG{"__DIE__"}) = |
|
797
|
|
|
|
|
|
|
sub { |
|
798
|
0
|
0
|
|
|
|
0
|
if ($self->{'curcop'}) { |
|
799
|
0
|
|
|
|
|
0
|
my $cop = $self->{'curcop'}; |
|
800
|
0
|
|
|
|
|
0
|
my($line, $file) = ($cop->line, $cop->file); |
|
801
|
0
|
|
|
|
|
0
|
print STDERR "While deparsing $file near line $line,\n"; |
|
802
|
|
|
|
|
|
|
} |
|
803
|
8
|
|
|
8
|
|
50
|
use Data::Printer; |
|
|
8
|
|
|
|
|
13
|
|
|
|
8
|
|
|
|
|
68
|
|
|
804
|
0
|
|
|
|
|
0
|
my @bt = caller(1); |
|
805
|
0
|
|
|
|
|
0
|
p @bt; |
|
806
|
0
|
|
|
|
|
0
|
}; |
|
807
|
0
|
|
|
|
|
0
|
$self->{'curcv'} = main_cv; |
|
808
|
0
|
|
|
|
|
0
|
$self->{'curcvlex'} = undef; |
|
809
|
0
|
|
|
|
|
0
|
print $self->extract_prototypes; |
|
810
|
0
|
|
|
|
|
0
|
@{$self->{'subs_todo'}} = |
|
811
|
0
|
|
|
|
|
0
|
sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
812
|
0
|
|
|
|
|
0
|
my $root = main_root; |
|
813
|
0
|
|
|
|
|
0
|
local $B::overlay = {}; |
|
814
|
|
|
|
|
|
|
|
|
815
|
0
|
0
|
|
|
|
0
|
if ($] < 5.021) { |
|
816
|
0
|
0
|
|
|
|
0
|
unless (B::Deparse::null $root) { |
|
817
|
0
|
|
|
|
|
0
|
$self->pessimise($root, main_start); |
|
818
|
|
|
|
|
|
|
# Print deparsed program |
|
819
|
0
|
|
|
|
|
0
|
print $self->deparse_root($root)->{text}, "\n"; |
|
820
|
|
|
|
|
|
|
} |
|
821
|
|
|
|
|
|
|
} else { |
|
822
|
0
|
0
|
|
|
|
0
|
unless (B::Deparse::null $root) { |
|
823
|
0
|
|
|
|
|
0
|
$self->B::Deparse::pad_subs($self->{'curcv'}); |
|
824
|
|
|
|
|
|
|
# Check for a stub-followed-by-ex-cop, resulting from a program |
|
825
|
|
|
|
|
|
|
# consisting solely of sub declarations. For backward-compati- |
|
826
|
|
|
|
|
|
|
# bility (and sane output) we don’t want to emit the stub. |
|
827
|
|
|
|
|
|
|
# leave |
|
828
|
|
|
|
|
|
|
# enter |
|
829
|
|
|
|
|
|
|
# stub |
|
830
|
|
|
|
|
|
|
# ex-nextstate (or ex-dbstate) |
|
831
|
0
|
|
|
|
|
0
|
my $kid; |
|
832
|
0
|
0
|
0
|
|
|
0
|
if ( $root->name eq 'leave' |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
833
|
|
|
|
|
|
|
and ($kid = $root->first)->name eq 'enter' |
|
834
|
|
|
|
|
|
|
and !B::Deparse::null($kid = $kid->sibling) and $kid->name eq 'stub' |
|
835
|
|
|
|
|
|
|
and !B::Deparse::null($kid = $kid->sibling) and $kid->name eq 'null' |
|
836
|
|
|
|
|
|
|
and class($kid) eq 'COP' and B::Deparse::null $kid->sibling ) |
|
837
|
|
|
|
|
|
|
{ |
|
838
|
|
|
|
|
|
|
# ignore deparsing routine |
|
839
|
|
|
|
|
|
|
} else { |
|
840
|
0
|
|
|
|
|
0
|
$self->pessimise($root, main_start); |
|
841
|
|
|
|
|
|
|
# Print deparsed program |
|
842
|
0
|
|
|
|
|
0
|
my $root_tree = $self->deparse_root($root); |
|
843
|
0
|
|
|
|
|
0
|
print $root_tree->{text}, "\n"; |
|
844
|
|
|
|
|
|
|
} |
|
845
|
|
|
|
|
|
|
} |
|
846
|
|
|
|
|
|
|
} |
|
847
|
0
|
|
|
|
|
0
|
my @text; |
|
848
|
0
|
|
|
|
|
0
|
while (scalar(@{$self->{'subs_todo'}})) { |
|
|
0
|
|
|
|
|
0
|
|
|
849
|
0
|
|
|
|
|
0
|
push @text, $self->next_todo->{text}; |
|
850
|
|
|
|
|
|
|
} |
|
851
|
0
|
0
|
|
|
|
0
|
print join("", @text), "\n" if @text; |
|
852
|
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
# Print __DATA__ section, if necessary |
|
854
|
8
|
|
|
8
|
|
2371
|
no strict 'refs'; |
|
|
8
|
|
|
|
|
15
|
|
|
|
8
|
|
|
|
|
22663
|
|
|
855
|
|
|
|
|
|
|
my $laststash = defined $self->{'curcop'} |
|
856
|
0
|
0
|
|
|
|
0
|
? $self->{'curcop'}->stash->NAME : $self->{'curstash'}; |
|
857
|
0
|
0
|
|
|
|
0
|
if (defined *{$laststash."::DATA"}{IO}) { |
|
|
0
|
|
|
|
|
0
|
|
|
858
|
|
|
|
|
|
|
print $self->keyword("package") . " $laststash;\n" |
|
859
|
0
|
0
|
|
|
|
0
|
unless $laststash eq $self->{'curstash'}; |
|
860
|
0
|
|
|
|
|
0
|
print $self->keyword("__DATA__") . "\n"; |
|
861
|
0
|
|
|
|
|
0
|
print readline(*{$laststash."::DATA"}); |
|
|
0
|
|
|
|
|
0
|
|
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
} |
|
864
|
0
|
|
|
|
|
0
|
} |
|
865
|
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
# "deparse()" is the main function to call to produces a depare tree |
|
867
|
|
|
|
|
|
|
# for a give B::OP. This method is the inner loop. |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
# Rocky's comment with respect to: |
|
870
|
|
|
|
|
|
|
# so try to keep it simple |
|
871
|
|
|
|
|
|
|
# |
|
872
|
|
|
|
|
|
|
# Most normal Perl programs really aren't that big. Yeah, I know there |
|
873
|
|
|
|
|
|
|
# are a couple of big pigs like the B::Deparse code itself. The perl5 |
|
874
|
|
|
|
|
|
|
# debugger comes to mind too. But what's the likelihood of anyone wanting |
|
875
|
|
|
|
|
|
|
# to decompile all of this? |
|
876
|
|
|
|
|
|
|
# |
|
877
|
|
|
|
|
|
|
# On the other hand, error checking is too valuable to throw out here. |
|
878
|
|
|
|
|
|
|
# Also, in trying to use and modularize this code, I see there is |
|
879
|
|
|
|
|
|
|
# a lot of repetition in subroutine parsing routines. That's |
|
880
|
|
|
|
|
|
|
# why I added the above PP_MAPFNS table. I'm not going to trade off |
|
881
|
|
|
|
|
|
|
# table lookup and interpetation for a huge amount of subroutine |
|
882
|
|
|
|
|
|
|
# bloat. |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
# That said it is useful to note that this is inner-most loop |
|
885
|
|
|
|
|
|
|
# interpeter loop as it is called for each node in the B::OP tree. |
|
886
|
|
|
|
|
|
|
# |
|
887
|
|
|
|
|
|
|
sub deparse |
|
888
|
|
|
|
|
|
|
{ |
|
889
|
19281
|
|
|
19281
|
0
|
32811
|
my($self, $op, $cx, $parent) = @_; |
|
890
|
|
|
|
|
|
|
|
|
891
|
19281
|
50
|
|
|
|
50465
|
Carp::confess("deparse called on an invalid op $op") |
|
892
|
|
|
|
|
|
|
unless $op->can('name'); |
|
893
|
|
|
|
|
|
|
|
|
894
|
19281
|
|
|
|
|
54475
|
my $name = $op->name; |
|
895
|
19281
|
50
|
|
|
|
37065
|
print "YYY $name\n" if $ENV{'DEBUG_DEPARSETREE'}; |
|
896
|
19281
|
|
|
|
|
23002
|
my ($info, $meth); |
|
897
|
|
|
|
|
|
|
|
|
898
|
19281
|
100
|
|
|
|
33014
|
if (exists($PP_MAPFNS{$name})) { |
|
899
|
|
|
|
|
|
|
# Interpret method calls for our PP_MAPFNS table |
|
900
|
4092
|
100
|
|
|
|
8429
|
if (ref($PP_MAPFNS{$name}) eq 'ARRAY') { |
|
901
|
1664
|
|
|
|
|
2388
|
my @args = @{$PP_MAPFNS{$name}}; |
|
|
1664
|
|
|
|
|
4742
|
|
|
902
|
1664
|
|
|
|
|
2924
|
$meth = shift @args; |
|
903
|
1664
|
100
|
|
|
|
3384
|
if ($meth eq 'maybe_targmy') { |
|
904
|
|
|
|
|
|
|
# FIXME: This is an inline version of targmy. |
|
905
|
|
|
|
|
|
|
# Can we dedup it? do we want to? |
|
906
|
231
|
|
|
|
|
345
|
$meth = shift @args; |
|
907
|
231
|
100
|
|
|
|
547
|
unshift @args, $name unless @args; |
|
908
|
231
|
100
|
|
|
|
843
|
if ($op->private & OPpTARGET_MY) { |
|
909
|
4
|
|
|
|
|
33
|
my $var = $self->padname($op->targ); |
|
910
|
4
|
|
|
|
|
13
|
my $val = $self->$meth($op, 7, @args); |
|
911
|
4
|
|
|
|
|
9
|
my @texts = ($var, '=', $val); |
|
912
|
4
|
|
|
|
|
18
|
$info = $self->info_from_template("my", $op, |
|
913
|
|
|
|
|
|
|
"%c = %c", [0, 1], |
|
914
|
|
|
|
|
|
|
[$var, $val], |
|
915
|
|
|
|
|
|
|
{maybe_parens => [$self, $cx, 7]}); |
|
916
|
|
|
|
|
|
|
} else { |
|
917
|
227
|
|
|
|
|
988
|
$info = $self->$meth($op, $cx, @args); |
|
918
|
|
|
|
|
|
|
} |
|
919
|
|
|
|
|
|
|
} else { |
|
920
|
1433
|
|
|
|
|
5846
|
$info = $self->$meth($op, $cx, @args); |
|
921
|
|
|
|
|
|
|
} |
|
922
|
|
|
|
|
|
|
} else { |
|
923
|
|
|
|
|
|
|
# Simple case: one simple call of the |
|
924
|
|
|
|
|
|
|
# the method in the table. Call this |
|
925
|
|
|
|
|
|
|
# passing arguments $op, $cx, and $name. |
|
926
|
|
|
|
|
|
|
# Some functions might not use these, |
|
927
|
|
|
|
|
|
|
# but that's okay. |
|
928
|
2428
|
|
|
|
|
3859
|
$meth = $PP_MAPFNS{$name}; |
|
929
|
2428
|
|
|
|
|
9425
|
$info = $self->$meth($op, $cx, $name); |
|
930
|
|
|
|
|
|
|
} |
|
931
|
|
|
|
|
|
|
} else { |
|
932
|
|
|
|
|
|
|
# Tried and true fallback method: |
|
933
|
|
|
|
|
|
|
# a method has been defined for this pp_op special. |
|
934
|
|
|
|
|
|
|
# call that. |
|
935
|
15189
|
|
|
|
|
19603
|
$meth = "pp_" . $name; |
|
936
|
15189
|
|
|
|
|
43048
|
$info = $self->$meth($op, $cx); |
|
937
|
|
|
|
|
|
|
} |
|
938
|
|
|
|
|
|
|
|
|
939
|
19281
|
50
|
|
|
|
37520
|
Carp::confess("nonref return for $meth deparse: $info") if !ref($info); |
|
940
|
19281
|
50
|
|
|
|
45981
|
Carp::confess("not B::DeparseTree:Node returned for $meth: $info") |
|
941
|
|
|
|
|
|
|
if !$info->isa("B::DeparseTree::TreeNode"); |
|
942
|
19281
|
100
|
|
|
|
40489
|
$info->{parent} = $$parent if $parent; |
|
943
|
19281
|
|
|
|
|
29365
|
$info->{cop} = $self->{'curcop'}; |
|
944
|
19281
|
|
|
|
|
24195
|
my $got_op = $info->{op}; |
|
945
|
19281
|
100
|
|
|
|
26728
|
if ($got_op) { |
|
946
|
19212
|
100
|
|
|
|
33797
|
if ($got_op != $op) { |
|
947
|
|
|
|
|
|
|
# Do something here? |
|
948
|
|
|
|
|
|
|
# printf("XX final op 0x%x is not requested 0x%x\n", |
|
949
|
|
|
|
|
|
|
# $$op, $$got_op); |
|
950
|
|
|
|
|
|
|
} |
|
951
|
|
|
|
|
|
|
} else { |
|
952
|
69
|
|
|
|
|
90
|
$info->{op} = $op; |
|
953
|
|
|
|
|
|
|
} |
|
954
|
19281
|
|
|
|
|
46415
|
$self->{optree}{$$op} = $info; |
|
955
|
19281
|
100
|
|
|
|
31030
|
if ($info->{other_ops}) { |
|
956
|
4183
|
|
|
|
|
4887
|
foreach my $other (@{$info->{other_ops}}) { |
|
|
4183
|
|
|
|
|
7516
|
|
|
957
|
8884
|
50
|
|
|
|
24387
|
if (!ref $other) { |
|
|
|
100
|
|
|
|
|
|
|
958
|
0
|
|
|
|
|
0
|
Carp::confess "$meth returns invalid other $other"; |
|
959
|
|
|
|
|
|
|
} elsif ($other->isa("B::DeparseTree::TreeNode")) { |
|
960
|
|
|
|
|
|
|
# "$other" has been set up to mark a particular portion |
|
961
|
|
|
|
|
|
|
# of the info. |
|
962
|
5501
|
|
|
|
|
9862
|
$self->{optree}{$other->{addr}} = $other; |
|
963
|
5501
|
|
|
|
|
9665
|
$other->{parent} = $$op; |
|
964
|
|
|
|
|
|
|
} else { |
|
965
|
|
|
|
|
|
|
# "$other" is just the OP. Have it mark everything |
|
966
|
|
|
|
|
|
|
# or "info". |
|
967
|
3383
|
|
|
|
|
9796
|
$self->{optree}{$$other} = $info; |
|
968
|
|
|
|
|
|
|
} |
|
969
|
|
|
|
|
|
|
} |
|
970
|
|
|
|
|
|
|
} |
|
971
|
19281
|
|
|
|
|
41235
|
return $info; |
|
972
|
|
|
|
|
|
|
} |
|
973
|
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
# Deparse a subroutine |
|
975
|
|
|
|
|
|
|
sub deparse_sub($$$$) |
|
976
|
|
|
|
|
|
|
{ |
|
977
|
1330
|
|
|
1330
|
0
|
2916
|
my ($self, $cv, $start_op) = @_; |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
# Sanity checks.. |
|
980
|
1330
|
50
|
33
|
|
|
10288
|
Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL"); |
|
981
|
1330
|
50
|
|
|
|
5267
|
Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL"); |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
# First get protype and sub attribute information |
|
984
|
1330
|
|
|
|
|
3868
|
local $self->{'curcop'} = $self->{'curcop'}; |
|
985
|
1330
|
|
|
|
|
2434
|
my $proto = ''; |
|
986
|
1330
|
50
|
|
|
|
5044
|
if ($cv->FLAGS & SVf_POK) { |
|
987
|
0
|
|
|
|
|
0
|
$proto .= "(". $cv->PV . ")"; |
|
988
|
|
|
|
|
|
|
} |
|
989
|
1330
|
100
|
|
|
|
4857
|
if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE)) { |
|
990
|
2
|
|
|
|
|
12
|
$proto .= ":"; |
|
991
|
2
|
100
|
|
|
|
10
|
$proto .= " lvalue" if $cv->CvFLAGS & CVf_LVALUE; |
|
992
|
2
|
50
|
|
|
|
7
|
$proto .= " locked" if $cv->CvFLAGS & CVf_LOCKED; |
|
993
|
2
|
100
|
|
|
|
8
|
$proto .= " method" if $cv->CvFLAGS & CVf_METHOD; |
|
994
|
|
|
|
|
|
|
} |
|
995
|
|
|
|
|
|
|
|
|
996
|
1330
|
|
|
|
|
3568
|
local($self->{'curcv'}) = $cv; |
|
997
|
1330
|
|
|
|
|
3392
|
local($self->{'curcvlex'}); |
|
998
|
|
|
|
|
|
|
local(@$self{qw'curstash warnings hints hinthash'}) |
|
999
|
1330
|
|
|
|
|
5687
|
= @$self{qw'curstash warnings hints hinthash'}; |
|
1000
|
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
# Now deparse subroutine body |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
1330
|
|
|
|
|
4840
|
my $root = $cv->ROOT; |
|
1004
|
1330
|
|
|
|
|
2533
|
my ($body, $node); |
|
1005
|
|
|
|
|
|
|
|
|
1006
|
1330
|
|
|
|
|
2571
|
local $B::overlay = {}; |
|
1007
|
1330
|
50
|
|
|
|
14255
|
if (not B::Deparse::null $root) { |
|
1008
|
1330
|
|
|
|
|
7290
|
$self->pessimise($root, $cv->START); |
|
1009
|
1330
|
|
|
|
|
5972
|
my $lineseq = $root->first; |
|
1010
|
1330
|
50
|
|
|
|
5088
|
if ($lineseq->name eq "lineseq") { |
|
|
|
0
|
|
|
|
|
|
|
1011
|
1330
|
|
|
|
|
2050
|
my @ops; |
|
1012
|
1330
|
|
|
|
|
5758
|
for(my $o=$lineseq->first; $$o; $o=$o->sibling) { |
|
1013
|
4148
|
|
|
|
|
13631
|
push @ops, $o; |
|
1014
|
|
|
|
|
|
|
} |
|
1015
|
1330
|
|
|
|
|
4142
|
$body = $self->lineseq($root, 0, @ops); |
|
1016
|
1330
|
|
|
|
|
38848
|
my $scope_en = $self->find_scope_en($lineseq); |
|
1017
|
|
|
|
|
|
|
} |
|
1018
|
|
|
|
|
|
|
elsif ($start_op) { |
|
1019
|
0
|
|
|
|
|
0
|
$body = $self->deparse($start_op, 0, $lineseq); |
|
1020
|
|
|
|
|
|
|
} else { |
|
1021
|
0
|
|
|
|
|
0
|
$body = $self->deparse($root->first, 0, $lineseq); |
|
1022
|
|
|
|
|
|
|
} |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
1330
|
|
|
|
|
7911
|
my $fn_name = $cv->GV->NAME; |
|
1025
|
1330
|
|
|
|
|
8710
|
$node = $self->info_from_template("sub $fn_name$proto", |
|
1026
|
|
|
|
|
|
|
$lineseq, |
|
1027
|
|
|
|
|
|
|
"$proto\n%|{\n%+%c\n%-}", |
|
1028
|
|
|
|
|
|
|
[0], [$body]); |
|
1029
|
1330
|
|
|
|
|
3682
|
$body->{parent} = $$lineseq; |
|
1030
|
1330
|
|
|
|
|
4733
|
$self->{optree}{$$lineseq} = $node; |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
} else { |
|
1033
|
0
|
|
|
|
|
0
|
my $sv = $cv->const_sv; |
|
1034
|
0
|
0
|
|
|
|
0
|
if ($$sv) { |
|
1035
|
|
|
|
|
|
|
# uh-oh. inlinable sub... format it differently |
|
1036
|
0
|
|
|
|
|
0
|
$node = $self->info_from_template('inline sub', $sv, |
|
1037
|
|
|
|
|
|
|
"$proto\n%|{\n%+%c\n%-}", |
|
1038
|
|
|
|
|
|
|
[0], [$self->const($sv, 0)]); |
|
1039
|
|
|
|
|
|
|
} else { |
|
1040
|
|
|
|
|
|
|
# XSUB? (or just a declaration) |
|
1041
|
0
|
|
|
|
|
0
|
$node = $self->info_from_string("XSUB or sub declaration", $proto); |
|
1042
|
|
|
|
|
|
|
} |
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
# Should we create a real node for this instead of the copy? |
|
1047
|
1330
|
|
|
|
|
4174
|
$self->{optree}{$$root} = $node; |
|
1048
|
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
# Add additional DeparseTree tracking info |
|
1050
|
1330
|
50
|
|
|
|
2989
|
if ($start_op) { |
|
1051
|
0
|
|
|
|
|
0
|
$node->{op} = $start_op; |
|
1052
|
0
|
|
|
|
|
0
|
$self->{'optree'}{$$start_op} = $node; |
|
1053
|
|
|
|
|
|
|
} |
|
1054
|
1330
|
|
|
|
|
2831
|
$node->{cop} = undef; |
|
1055
|
1330
|
|
|
|
|
2201
|
$node->{'parent'} = $cv; |
|
1056
|
1330
|
|
|
|
|
36575
|
return $node; |
|
1057
|
|
|
|
|
|
|
} |
|
1058
|
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
# We have a TODO list of things that must be handled |
|
1060
|
|
|
|
|
|
|
# at the top level. There are things like |
|
1061
|
|
|
|
|
|
|
# format statements, "BEGIN" and "use" statements. |
|
1062
|
|
|
|
|
|
|
# Here we handle the next one. |
|
1063
|
|
|
|
|
|
|
sub next_todo |
|
1064
|
|
|
|
|
|
|
{ |
|
1065
|
0
|
|
|
0
|
0
|
0
|
my ($self, $parent) = @_; |
|
1066
|
0
|
|
|
|
|
0
|
my $ent = shift @{$self->{'subs_todo'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
1067
|
0
|
|
|
|
|
0
|
my ($seq, $cv, $is_form, $name) = @$ent; |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
# any 'use strict; package foo' that should come before the sub |
|
1070
|
|
|
|
|
|
|
# declaration to sync with the first COP of the sub |
|
1071
|
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
## FIXME: $self->pragmata messes scoping up, although I don't know |
|
1073
|
|
|
|
|
|
|
## how it does that. |
|
1074
|
|
|
|
|
|
|
# my $pragmata = ''; |
|
1075
|
|
|
|
|
|
|
# if ($cv and !B::Deparse::null($cv->START) and B::Deparse::is_state($cv->START)) { |
|
1076
|
|
|
|
|
|
|
# $pragmata = $self->B::Deparse::pragmata($cv->START); |
|
1077
|
|
|
|
|
|
|
# } |
|
1078
|
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
# if (ref $name) { # lexical sub |
|
1080
|
|
|
|
|
|
|
# # emit the sub. |
|
1081
|
|
|
|
|
|
|
# my @text; |
|
1082
|
|
|
|
|
|
|
# my $flags = $name->FLAGS; |
|
1083
|
|
|
|
|
|
|
# push @text, |
|
1084
|
|
|
|
|
|
|
# !$cv || $seq <= $name->COP_SEQ_RANGE_LOW |
|
1085
|
|
|
|
|
|
|
# ? $self->keyword($flags & B::SVpad_OUR |
|
1086
|
|
|
|
|
|
|
# ? "our" |
|
1087
|
|
|
|
|
|
|
# : $flags & SVpad_STATE |
|
1088
|
|
|
|
|
|
|
# ? "state" |
|
1089
|
|
|
|
|
|
|
# : "my") . " " |
|
1090
|
|
|
|
|
|
|
# : ""; |
|
1091
|
|
|
|
|
|
|
# # XXX We would do $self->keyword("sub"), but ‘my CORE::sub’ |
|
1092
|
|
|
|
|
|
|
# # doesn’t work and ‘my sub’ ignores a &sub in scope. I.e., |
|
1093
|
|
|
|
|
|
|
# # we have a core bug here. |
|
1094
|
|
|
|
|
|
|
# push @text, "sub " . substr $name->PVX, 1; |
|
1095
|
|
|
|
|
|
|
# my $text = join('', @text); |
|
1096
|
|
|
|
|
|
|
# if ($cv) { |
|
1097
|
|
|
|
|
|
|
# # my sub foo { } |
|
1098
|
|
|
|
|
|
|
# my $cv_node = $self->deparse_sub($cv); |
|
1099
|
|
|
|
|
|
|
# my $fmt = sprintf("%s%s%%c", $pragmata, $text); |
|
1100
|
|
|
|
|
|
|
# return $self->info_from_template("sub", $cv, |
|
1101
|
|
|
|
|
|
|
# $fmt, undef, |
|
1102
|
|
|
|
|
|
|
# [$cv_node]); |
|
1103
|
|
|
|
|
|
|
# } else { |
|
1104
|
|
|
|
|
|
|
# return $self->info_from_string("sub no body", $cv, $text); |
|
1105
|
|
|
|
|
|
|
# } |
|
1106
|
|
|
|
|
|
|
# } |
|
1107
|
|
|
|
|
|
|
|
|
1108
|
0
|
|
|
|
|
0
|
my $gv = $cv->GV; |
|
1109
|
0
|
|
0
|
|
|
0
|
$name //= $self->gv_name($gv); |
|
1110
|
0
|
0
|
|
|
|
0
|
if ($is_form) { |
|
1111
|
0
|
|
|
|
|
0
|
my $node = $self->deparse_format($ent->[1], $cv); |
|
1112
|
0
|
|
|
|
|
0
|
return $self->info_from_template("format $name", |
|
1113
|
|
|
|
|
|
|
"format $name = %c", |
|
1114
|
|
|
|
|
|
|
undef, [$node]) |
|
1115
|
|
|
|
|
|
|
} else { |
|
1116
|
0
|
|
|
|
|
0
|
my ($fmt, $type); |
|
1117
|
0
|
|
|
|
|
0
|
$self->{'subs_declared'}{$name} = 1; |
|
1118
|
0
|
0
|
|
|
|
0
|
if ($name eq "BEGIN") { |
|
1119
|
0
|
|
|
|
|
0
|
my $use_dec = $self->begin_is_use($cv); |
|
1120
|
0
|
0
|
0
|
|
|
0
|
if (defined ($use_dec) and $self->{'expand'} < 5) { |
|
1121
|
0
|
0
|
|
|
|
0
|
if (0 == length($use_dec)) { |
|
1122
|
0
|
|
|
|
|
0
|
$self->info_from_string('BEGIN', $cv, ''); |
|
1123
|
|
|
|
|
|
|
} else { |
|
1124
|
0
|
|
|
|
|
0
|
$self->info_from_string('use', $cv, $use_dec); |
|
1125
|
|
|
|
|
|
|
} |
|
1126
|
|
|
|
|
|
|
} |
|
1127
|
|
|
|
|
|
|
} |
|
1128
|
0
|
|
|
|
|
0
|
my $l = ''; |
|
1129
|
0
|
0
|
|
|
|
0
|
if ($self->{'linenums'}) { |
|
1130
|
0
|
|
|
|
|
0
|
my $line = $gv->LINE; |
|
1131
|
0
|
|
|
|
|
0
|
my $file = $gv->FILE; |
|
1132
|
0
|
|
|
|
|
0
|
$l = "\n# line $line \"$file\"\n"; |
|
1133
|
|
|
|
|
|
|
} |
|
1134
|
0
|
0
|
|
|
|
0
|
if (class($cv->STASH) ne "SPECIAL") { |
|
1135
|
0
|
|
|
|
|
0
|
my $stash = $cv->STASH->NAME; |
|
1136
|
0
|
0
|
|
|
|
0
|
if ($stash ne $self->{'curstash'}) { |
|
1137
|
0
|
|
|
|
|
0
|
$fmt = "package $stash;\n"; |
|
1138
|
0
|
|
|
|
|
0
|
$type = "package $stash"; |
|
1139
|
0
|
0
|
|
|
|
0
|
$name = "$self->{'curstash'}::$name" unless $name =~ /::/; |
|
1140
|
0
|
|
|
|
|
0
|
$self->{'curstash'} = $stash; |
|
1141
|
|
|
|
|
|
|
} |
|
1142
|
0
|
|
|
|
|
0
|
$name =~ s/^\Q$stash\E::(?!\z|.*::)//; |
|
1143
|
0
|
|
|
|
|
0
|
$fmt .= "sub $name"; |
|
1144
|
0
|
|
|
|
|
0
|
$type .= "sub $name"; |
|
1145
|
|
|
|
|
|
|
} |
|
1146
|
0
|
|
|
|
|
0
|
my $node = $self->deparse_sub($cv, $parent); |
|
1147
|
0
|
|
|
|
|
0
|
$fmt .= '%c'; |
|
1148
|
0
|
|
|
|
|
0
|
my $sub_node = $self->info_from_template($type, $cv, $fmt, [0], [$node]); |
|
1149
|
0
|
|
|
|
|
0
|
$node->{parent} = $sub_node->{addr}; |
|
1150
|
0
|
|
|
|
|
0
|
$self->{optree}{$$cv} = $sub_node; |
|
1151
|
0
|
|
|
|
|
0
|
return $sub_node; |
|
1152
|
|
|
|
|
|
|
} |
|
1153
|
|
|
|
|
|
|
} |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
# Deparse a subroutine by name |
|
1156
|
|
|
|
|
|
|
sub deparse_subname($$) |
|
1157
|
|
|
|
|
|
|
{ |
|
1158
|
0
|
|
|
0
|
0
|
0
|
my ($self, $funcname) = @_; |
|
1159
|
0
|
|
|
|
|
0
|
my $cv = svref_2object(\&$funcname); |
|
1160
|
0
|
|
|
|
|
0
|
my $info = $self->deparse_sub($cv); |
|
1161
|
0
|
|
|
|
|
0
|
my $sub_node = $self->info_from_template("sub $funcname", $cv, "sub $funcname %c", |
|
1162
|
|
|
|
|
|
|
undef, [$info]); |
|
1163
|
0
|
|
|
|
|
0
|
$self->{optree}{$$cv} = $sub_node; |
|
1164
|
0
|
|
|
|
|
0
|
return $sub_node; |
|
1165
|
|
|
|
|
|
|
} |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
# Return a list of info nodes for "use" and "no" pragmas. |
|
1168
|
|
|
|
|
|
|
sub declare_hints |
|
1169
|
|
|
|
|
|
|
{ |
|
1170
|
1321
|
|
|
1321
|
0
|
3016
|
my ($self, $from, $to) = @_; |
|
1171
|
1321
|
|
|
|
|
2558
|
my $use = $to & ~$from; |
|
1172
|
1321
|
|
|
|
|
2164
|
my $no = $from & ~$to; |
|
1173
|
|
|
|
|
|
|
|
|
1174
|
1321
|
|
|
|
|
2142
|
my @decls = (); |
|
1175
|
1321
|
|
|
|
|
20656
|
for my $pragma (B::Deparse::hint_pragmas($use)) { |
|
1176
|
1266
|
|
|
|
|
27849
|
my $type = $self->keyword("use") . " $pragma"; |
|
1177
|
1266
|
|
|
|
|
6353
|
push @decls, $self->info_from_template($type, undef, "$type", [], []); |
|
1178
|
|
|
|
|
|
|
} |
|
1179
|
1321
|
|
|
|
|
8720
|
for my $pragma (B::Deparse::hint_pragmas($no)) { |
|
1180
|
0
|
|
|
|
|
0
|
my $type = $self->keyword("no") . " $pragma"; |
|
1181
|
0
|
|
|
|
|
0
|
push @decls, $self->info_from_template($type, undef, "$type", [], []); |
|
1182
|
|
|
|
|
|
|
} |
|
1183
|
1321
|
|
|
|
|
3754
|
return @decls; |
|
1184
|
|
|
|
|
|
|
} |
|
1185
|
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
# Internal implementation hints that the core sets automatically, so don't need |
|
1187
|
|
|
|
|
|
|
# (or want) to be passed back to the user |
|
1188
|
|
|
|
|
|
|
my %ignored_hints = ( |
|
1189
|
|
|
|
|
|
|
'open<' => 1, |
|
1190
|
|
|
|
|
|
|
'open>' => 1, |
|
1191
|
|
|
|
|
|
|
':' => 1, |
|
1192
|
|
|
|
|
|
|
'strict/refs' => 1, |
|
1193
|
|
|
|
|
|
|
'strict/subs' => 1, |
|
1194
|
|
|
|
|
|
|
'strict/vars' => 1, |
|
1195
|
|
|
|
|
|
|
); |
|
1196
|
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
my %rev_feature; |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
sub declare_hinthash { |
|
1200
|
2087
|
|
|
2087
|
0
|
4615
|
my ($self, $from, $to, $indent, $hints) = @_; |
|
1201
|
2087
|
|
|
|
|
2859
|
my $doing_features; |
|
1202
|
2087
|
50
|
|
|
|
3544
|
if ($] >= 5.016) { |
|
1203
|
2087
|
|
|
|
|
3456
|
$doing_features = ($hints & $feature::hint_mask) == $feature::hint_mask; |
|
1204
|
|
|
|
|
|
|
} else { |
|
1205
|
0
|
|
|
|
|
0
|
$doing_features = 0; |
|
1206
|
|
|
|
|
|
|
} |
|
1207
|
2087
|
|
|
|
|
4249
|
my @decls; |
|
1208
|
|
|
|
|
|
|
my @features; |
|
1209
|
2087
|
|
|
|
|
0
|
my @unfeatures; # bugs? |
|
1210
|
2087
|
|
|
|
|
7827
|
for my $key (sort keys %$to) { |
|
1211
|
67
|
50
|
|
|
|
109
|
next if $ignored_hints{$key}; |
|
1212
|
67
|
|
33
|
|
|
406
|
my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6; |
|
1213
|
67
|
100
|
66
|
|
|
226
|
next if $is_feature and not $doing_features; |
|
1214
|
54
|
100
|
66
|
|
|
161
|
if (!exists $from->{$key} or $from->{$key} ne $to->{$key}) { |
|
1215
|
12
|
50
|
|
|
|
16
|
if ($is_cperl){ |
|
1216
|
0
|
0
|
|
|
|
0
|
next if $key eq 'feature_lexsubs'; |
|
1217
|
0
|
0
|
|
|
|
0
|
next if $key eq 'feature_signatures'; |
|
1218
|
|
|
|
|
|
|
} |
|
1219
|
12
|
50
|
|
|
|
27
|
push(@features, $key), next if $is_feature; |
|
1220
|
|
|
|
|
|
|
push @decls, |
|
1221
|
|
|
|
|
|
|
qq(\$^H{) . single_delim($self, "q", "'", $key, "'") . qq(} = ) |
|
1222
|
|
|
|
|
|
|
. ( |
|
1223
|
|
|
|
|
|
|
defined $to->{$key} |
|
1224
|
0
|
0
|
|
|
|
0
|
? single_delim($self, "q", "'", $to->{$key}, "'") |
|
1225
|
|
|
|
|
|
|
: 'undef' |
|
1226
|
|
|
|
|
|
|
) |
|
1227
|
|
|
|
|
|
|
. qq(;); |
|
1228
|
|
|
|
|
|
|
} |
|
1229
|
|
|
|
|
|
|
} |
|
1230
|
2087
|
|
|
|
|
5169
|
for my $key (sort keys %$from) { |
|
1231
|
55
|
50
|
|
|
|
85
|
next if $ignored_hints{$key}; |
|
1232
|
55
|
|
33
|
|
|
278
|
my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6; |
|
1233
|
55
|
100
|
66
|
|
|
178
|
next if $is_feature and not $doing_features; |
|
1234
|
42
|
50
|
|
|
|
100
|
if (!exists $to->{$key}) { |
|
1235
|
0
|
0
|
|
|
|
0
|
push(@unfeatures, $key), next if $is_feature; |
|
1236
|
0
|
|
|
|
|
0
|
push @decls, qq(delete \$^H{'$key'};); |
|
1237
|
|
|
|
|
|
|
} |
|
1238
|
|
|
|
|
|
|
} |
|
1239
|
2087
|
|
|
|
|
2892
|
my @ret; |
|
1240
|
2087
|
100
|
66
|
|
|
7598
|
if (@features || @unfeatures) { |
|
1241
|
3
|
100
|
|
|
|
8
|
if (!%rev_feature) { %rev_feature = reverse %feature::feature } |
|
|
1
|
|
|
|
|
7
|
|
|
1242
|
|
|
|
|
|
|
} |
|
1243
|
2087
|
100
|
|
|
|
4139
|
if (@features) { |
|
1244
|
3
|
|
|
|
|
1141
|
push @ret, $self->keyword("use") . " feature " |
|
1245
|
|
|
|
|
|
|
. join(", ", map "'$rev_feature{$_}'", @features) . ";\n"; |
|
1246
|
|
|
|
|
|
|
} |
|
1247
|
2087
|
50
|
|
|
|
3805
|
if (@unfeatures) { |
|
1248
|
0
|
|
|
|
|
0
|
push @ret, $self->keyword("no") . " feature " |
|
1249
|
|
|
|
|
|
|
. join(", ", map "'$rev_feature{$_}'", @unfeatures) |
|
1250
|
|
|
|
|
|
|
. ";\n"; |
|
1251
|
|
|
|
|
|
|
} |
|
1252
|
|
|
|
|
|
|
@decls and |
|
1253
|
2087
|
50
|
|
|
|
3703
|
push @ret, |
|
1254
|
|
|
|
|
|
|
join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n"; |
|
1255
|
2087
|
|
|
|
|
5293
|
return @ret; |
|
1256
|
|
|
|
|
|
|
} |
|
1257
|
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
# generate any pragmas, 'package foo' etc needed to synchronise |
|
1259
|
|
|
|
|
|
|
# with the given cop |
|
1260
|
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
sub pragmata { |
|
1262
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1263
|
0
|
|
|
|
|
0
|
my($op) = @_; |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
0
|
|
|
|
|
0
|
my @text; |
|
1266
|
|
|
|
|
|
|
|
|
1267
|
0
|
|
|
|
|
0
|
my $stash = $op->stashpv; |
|
1268
|
0
|
0
|
|
|
|
0
|
if ($stash ne $self->{'curstash'}) { |
|
1269
|
0
|
|
|
|
|
0
|
push @text, $self->keyword("package") . " $stash;\n"; |
|
1270
|
0
|
|
|
|
|
0
|
$self->{'curstash'} = $stash; |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
0
|
|
|
|
|
0
|
if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) { |
|
1274
|
|
|
|
|
|
|
push @text, '$[ = '. $op->arybase .";\n"; |
|
1275
|
|
|
|
|
|
|
$self->{'arybase'} = $op->arybase; |
|
1276
|
|
|
|
|
|
|
} |
|
1277
|
|
|
|
|
|
|
|
|
1278
|
0
|
|
|
|
|
0
|
my $warnings = $op->warnings; |
|
1279
|
0
|
|
|
|
|
0
|
my $warning_bits; |
|
1280
|
0
|
0
|
0
|
|
|
0
|
if ($warnings->isa("B::SPECIAL") && $$warnings == 4) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1281
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings::Bits{"all"} & WARN_MASK; |
|
1282
|
|
|
|
|
|
|
} |
|
1283
|
|
|
|
|
|
|
elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) { |
|
1284
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings::NONE; |
|
1285
|
|
|
|
|
|
|
} |
|
1286
|
|
|
|
|
|
|
elsif ($warnings->isa("B::SPECIAL")) { |
|
1287
|
0
|
|
|
|
|
0
|
$warning_bits = undef; |
|
1288
|
|
|
|
|
|
|
} |
|
1289
|
|
|
|
|
|
|
else { |
|
1290
|
0
|
|
|
|
|
0
|
$warning_bits = $warnings->PV & WARN_MASK; |
|
1291
|
|
|
|
|
|
|
} |
|
1292
|
|
|
|
|
|
|
|
|
1293
|
0
|
0
|
0
|
|
|
0
|
if (defined ($warning_bits) and |
|
|
|
|
0
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
!defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) { |
|
1295
|
|
|
|
|
|
|
push @text, |
|
1296
|
0
|
|
|
|
|
0
|
$self->declare_warnings($self->{'warnings'}, $warning_bits); |
|
1297
|
0
|
|
|
|
|
0
|
$self->{'warnings'} = $warning_bits; |
|
1298
|
|
|
|
|
|
|
} |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
0
|
0
|
|
|
|
0
|
my $hints = $] < 5.008009 ? $op->private : $op->hints; |
|
1301
|
0
|
|
|
|
|
0
|
my $old_hints = $self->{'hints'}; |
|
1302
|
0
|
0
|
|
|
|
0
|
if ($self->{'hints'} != $hints) { |
|
1303
|
0
|
|
|
|
|
0
|
push @text, $self->declare_hints($self->{'hints'}, $hints); |
|
1304
|
0
|
|
|
|
|
0
|
$self->{'hints'} = $hints; |
|
1305
|
|
|
|
|
|
|
} |
|
1306
|
|
|
|
|
|
|
|
|
1307
|
0
|
|
|
|
|
0
|
my $newhh; |
|
1308
|
0
|
0
|
|
|
|
0
|
if ($] > 5.009) { |
|
1309
|
0
|
|
|
|
|
0
|
$newhh = $op->hints_hash->HASH; |
|
1310
|
|
|
|
|
|
|
} |
|
1311
|
|
|
|
|
|
|
|
|
1312
|
0
|
0
|
|
|
|
0
|
if ($] >= 5.015006) { |
|
1313
|
|
|
|
|
|
|
# feature bundle hints |
|
1314
|
0
|
|
|
|
|
0
|
my $from = $old_hints & $feature::hint_mask; |
|
1315
|
0
|
|
|
|
|
0
|
my $to = $ hints & $feature::hint_mask; |
|
1316
|
0
|
0
|
|
|
|
0
|
if ($from != $to) { |
|
1317
|
0
|
0
|
|
|
|
0
|
if ($to == $feature::hint_mask) { |
|
1318
|
0
|
0
|
|
|
|
0
|
if ($self->{'hinthash'}) { |
|
1319
|
|
|
|
|
|
|
delete $self->{'hinthash'}{$_} |
|
1320
|
0
|
|
|
|
|
0
|
for grep /^feature_/, keys %{$self->{'hinthash'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
1321
|
|
|
|
|
|
|
} |
|
1322
|
0
|
|
|
|
|
0
|
else { $self->{'hinthash'} = {} } |
|
1323
|
|
|
|
|
|
|
$self->{'hinthash'} |
|
1324
|
0
|
|
|
|
|
0
|
= _features_from_bundle($from, $self->{'hinthash'}); |
|
1325
|
|
|
|
|
|
|
} |
|
1326
|
|
|
|
|
|
|
else { |
|
1327
|
0
|
|
|
|
|
0
|
my $bundle = |
|
1328
|
|
|
|
|
|
|
$feature::hint_bundles[$to >> $feature::hint_shift]; |
|
1329
|
0
|
|
|
|
|
0
|
$bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12 |
|
|
0
|
|
|
|
|
0
|
|
|
1330
|
0
|
|
|
|
|
0
|
push @text, |
|
1331
|
|
|
|
|
|
|
$self->keyword("no") . " feature ':all';\n", |
|
1332
|
|
|
|
|
|
|
$self->keyword("use") . " feature ':$bundle';\n"; |
|
1333
|
|
|
|
|
|
|
} |
|
1334
|
|
|
|
|
|
|
} |
|
1335
|
|
|
|
|
|
|
} |
|
1336
|
|
|
|
|
|
|
|
|
1337
|
0
|
0
|
|
|
|
0
|
if ($] > 5.009) { |
|
1338
|
|
|
|
|
|
|
push @text, $self->declare_hinthash( |
|
1339
|
|
|
|
|
|
|
$self->{'hinthash'}, $newhh, |
|
1340
|
|
|
|
|
|
|
$self->{indent_size}, $self->{hints}, |
|
1341
|
0
|
|
|
|
|
0
|
); |
|
1342
|
0
|
|
|
|
|
0
|
$self->{'hinthash'} = $newhh; |
|
1343
|
|
|
|
|
|
|
} |
|
1344
|
|
|
|
|
|
|
|
|
1345
|
0
|
|
|
|
|
0
|
return join("", @text); |
|
1346
|
|
|
|
|
|
|
} |
|
1347
|
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
# Create a "use", "no", or "BEGIN" block to set warnings. |
|
1350
|
|
|
|
|
|
|
sub declare_warnings |
|
1351
|
|
|
|
|
|
|
{ |
|
1352
|
1266
|
|
|
1266
|
0
|
3028
|
my ($self, $from, $to) = @_; |
|
1353
|
1266
|
100
|
|
|
|
3257
|
if (($to & WARN_MASK) eq (warnings::bits("all") & WARN_MASK)) { |
|
|
|
50
|
|
|
|
|
|
|
1354
|
2
|
|
|
|
|
1011
|
my $type = $self->keyword("use") . " warnings"; |
|
1355
|
2
|
|
|
|
|
26
|
return $self->info_from_string($type, undef, "$type"); |
|
1356
|
|
|
|
|
|
|
} |
|
1357
|
|
|
|
|
|
|
elsif (($to & WARN_MASK) eq ("\0"x length($to) & WARN_MASK)) { |
|
1358
|
1264
|
|
|
|
|
26894
|
my $type = $self->keyword("no") . " warnings"; |
|
1359
|
1264
|
|
|
|
|
6122
|
return $self->info_from_string($type, undef, "$type"); |
|
1360
|
|
|
|
|
|
|
} |
|
1361
|
0
|
|
|
|
|
0
|
my $bit_expr = join('', map { sprintf("\\x%02x", ord $_) } split "", $to); |
|
|
0
|
|
|
|
|
0
|
|
|
1362
|
0
|
|
|
|
|
0
|
my $str = "BEGIN {\n%+\${^WARNING_BITS} = \"$bit_expr;\n%-"; |
|
1363
|
0
|
|
|
|
|
0
|
return $self->info_from_template('warning bits begin', undef, |
|
1364
|
|
|
|
|
|
|
"$str", [], [], {omit_next_semicolon=>1}); |
|
1365
|
|
|
|
|
|
|
} |
|
1366
|
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
# Iterate over $self->{subs_todo} picking up the |
|
1368
|
|
|
|
|
|
|
# text of of $self->next_todo. |
|
1369
|
|
|
|
|
|
|
# We return an array of strings. The calling |
|
1370
|
|
|
|
|
|
|
# routine will join these together |
|
1371
|
|
|
|
|
|
|
sub seq_subs { |
|
1372
|
2087
|
|
|
2087
|
0
|
4235
|
my ($self, $seq) = @_; |
|
1373
|
2087
|
|
|
|
|
3053
|
my @texts; |
|
1374
|
|
|
|
|
|
|
|
|
1375
|
2087
|
50
|
|
|
|
3872
|
return () if !defined $seq; |
|
1376
|
2087
|
|
|
|
|
2713
|
my @pending; |
|
1377
|
2087
|
|
33
|
|
|
2804
|
while (scalar(@{$self->{'subs_todo'}}) |
|
|
2087
|
|
|
|
|
6161
|
|
|
1378
|
|
|
|
|
|
|
and $seq > $self->{'subs_todo'}[0][0]) { |
|
1379
|
0
|
|
|
|
|
0
|
my $cv = $self->{'subs_todo'}[0][1]; |
|
1380
|
|
|
|
|
|
|
# Skip the OUTSIDE check for lexical subs. We may be deparsing a |
|
1381
|
|
|
|
|
|
|
# cloned anon sub with lexical subs declared in it, in which case |
|
1382
|
|
|
|
|
|
|
# the OUTSIDE pointer points to the anon protosub. |
|
1383
|
0
|
|
|
|
|
0
|
my $lexical = ref $self->{'subs_todo'}[0][3]; |
|
1384
|
0
|
|
0
|
|
|
0
|
my $outside = !$lexical && $cv && $cv->OUTSIDE; |
|
1385
|
0
|
0
|
0
|
|
|
0
|
if (!$lexical and $cv |
|
|
|
|
0
|
|
|
|
|
|
1386
|
0
|
0
|
|
|
|
0
|
and ${$cv->OUTSIDE || \0} != ${$self->{'curcv'}}) |
|
|
0
|
|
|
|
|
0
|
|
|
1387
|
|
|
|
|
|
|
{ |
|
1388
|
|
|
|
|
|
|
# rocky: What do we do with @pending? |
|
1389
|
0
|
|
|
|
|
0
|
push @pending, shift @{$self->{'subs_todo'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
1390
|
0
|
|
|
|
|
0
|
next; |
|
1391
|
|
|
|
|
|
|
} |
|
1392
|
0
|
|
|
|
|
0
|
push @texts, $self->next_todo; |
|
1393
|
|
|
|
|
|
|
} |
|
1394
|
2087
|
|
|
|
|
5078
|
return @texts; |
|
1395
|
|
|
|
|
|
|
} |
|
1396
|
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
# FIXME: this code has to be here. Find out why and fix. |
|
1398
|
|
|
|
|
|
|
# Truncate is special because OPf_SPECIAL makes a bareword first arg |
|
1399
|
|
|
|
|
|
|
# be a filehandle. This could probably be better fixed in the core |
|
1400
|
|
|
|
|
|
|
# by moving the GV lookup into ck_truc. |
|
1401
|
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
# Demo code |
|
1403
|
|
|
|
|
|
|
unless(caller) { |
|
1404
|
|
|
|
|
|
|
my @texts = ('a', 'b', 'c'); |
|
1405
|
|
|
|
|
|
|
my $deparse = __PACKAGE__->new(); |
|
1406
|
|
|
|
|
|
|
my $info = info_from_list('op', $deparse, \@texts, ', ', 'test', {}); |
|
1407
|
|
|
|
|
|
|
|
|
1408
|
8
|
|
|
8
|
|
84
|
use Data::Printer; |
|
|
8
|
|
|
|
|
55
|
|
|
|
8
|
|
|
|
|
40
|
|
|
1409
|
|
|
|
|
|
|
my $str = $deparse->template_engine("%c", [0], ["16"]); |
|
1410
|
|
|
|
|
|
|
p $str; |
|
1411
|
|
|
|
|
|
|
my $str2 = $deparse->template_engine("%F", [[0, sub {'0x' . sprintf "%x", shift}]], [$str]); |
|
1412
|
|
|
|
|
|
|
p $str2; |
|
1413
|
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
# print $deparse->template_engine("100%% "), "\n"; |
|
1415
|
|
|
|
|
|
|
# print $deparse->template_engine("%c,\n%+%c\n%|%c %c!", |
|
1416
|
|
|
|
|
|
|
# [1, 0, 2, 3], |
|
1417
|
|
|
|
|
|
|
# ["is", "now", "the", "time"]), "\n"; |
|
1418
|
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("demo", undef, "%C", |
|
1420
|
|
|
|
|
|
|
# [[0, 1, ";\n%|"]], |
|
1421
|
|
|
|
|
|
|
# ['$x=1', '$y=2']); |
|
1422
|
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
# @texts = ("use warnings;", "use strict", "my(\$a)"); |
|
1424
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("demo", undef, "%;", [], \@texts); |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
# $info = $deparse->info_from_template("list", undef, |
|
1427
|
|
|
|
|
|
|
# "%C", [[0, $#texts, ', ']], |
|
1428
|
|
|
|
|
|
|
# \@texts); |
|
1429
|
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
# p $info; |
|
1431
|
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
# @texts = (['a', 1], ['b', 2], 'c'); |
|
1434
|
|
|
|
|
|
|
# $info = info_from_list('op', $deparse, \@texts, ', ', 'test', {}); |
|
1435
|
|
|
|
|
|
|
# p $info; |
|
1436
|
|
|
|
|
|
|
} |
|
1437
|
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
1; |