line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Sub::Quote; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
128
|
sub _clean_eval { eval $_[0] } |
|
5
|
|
|
40
|
|
17
|
|
|
5
|
|
|
1
|
|
184
|
|
|
40
|
|
|
1
|
|
6044
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
4
|
|
|
|
|
|
|
|
5
|
10
|
|
|
10
|
|
290080
|
use strict; |
|
9
|
|
|
|
|
66
|
|
|
9
|
|
|
|
|
308
|
|
6
|
10
|
|
|
10
|
|
55
|
use warnings; |
|
10
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
534
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '2.006008'; |
9
|
|
|
|
|
|
|
$VERSION =~ tr/_//d; |
10
|
|
|
|
|
|
|
|
11
|
10
|
|
|
10
|
|
2661
|
use Sub::Defer qw(defer_sub); |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
493
|
|
12
|
10
|
|
|
10
|
|
77
|
use Scalar::Util qw(weaken); |
|
10
|
|
|
|
|
20
|
|
|
10
|
|
|
|
|
449
|
|
13
|
10
|
|
|
10
|
|
58
|
use Exporter (); |
|
10
|
|
|
|
|
18
|
|
|
10
|
|
|
|
|
455
|
|
14
|
10
|
|
|
10
|
|
203
|
BEGIN { *import = \&Exporter::import } |
15
|
11
|
|
|
10
|
|
48
|
use Carp qw(croak); |
|
11
|
|
|
|
|
157
|
|
|
10
|
|
|
|
|
473
|
|
16
|
10
|
|
|
10
|
|
5038
|
BEGIN { our @CARP_NOT = qw(Sub::Defer) } |
17
|
|
|
|
|
|
|
BEGIN { |
18
|
11
|
|
|
10
|
|
90
|
my $TRUE = sub(){!!1}; |
19
|
11
|
|
|
|
|
155
|
my $FALSE = sub(){!!0}; |
20
|
10
|
50
|
|
|
|
163
|
*_HAVE_IS_UTF8 = defined &utf8::is_utf8 ? $TRUE : $FALSE; |
21
|
10
|
50
|
|
|
|
65
|
*_CAN_TRACK_BOOLEANS = defined &builtin::is_bool ? $TRUE : $FALSE; |
22
|
10
|
50
|
|
|
|
33
|
*_CAN_TRACK_NUMBERS = defined &builtin::created_as_number ? $TRUE : $FALSE; |
23
|
10
|
100
|
66
|
|
|
299
|
*_HAVE_HEX_FLOAT = !$ENV{SUB_QUOTE_NO_HEX_FLOAT} && "$]" >= 5.022 ? $TRUE : $FALSE; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# This may not be perfect, as we can't tell the format purely from the size |
26
|
|
|
|
|
|
|
# but it should cover the common cases, and other formats are more likely to |
27
|
|
|
|
|
|
|
# be less precise. |
28
|
10
|
|
|
|
|
155
|
my $nvsize = 8 * length pack 'F', 0; |
29
|
9
|
0
|
|
|
|
41
|
my $nvmantbits |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
30
|
|
|
|
|
|
|
= $nvsize == 16 ? 11 |
31
|
|
|
|
|
|
|
: $nvsize == 32 ? 24 |
32
|
|
|
|
|
|
|
: $nvsize == 64 ? 53 |
33
|
|
|
|
|
|
|
: $nvsize == 80 ? 64 |
34
|
|
|
|
|
|
|
: $nvsize == 128 ? 113 |
35
|
|
|
|
|
|
|
: $nvsize == 256 ? 237 |
36
|
|
|
|
|
|
|
: 237 # unknown float format |
37
|
|
|
|
|
|
|
; |
38
|
9
|
|
|
|
|
84
|
my $precision = int( log(2)/log(10)*$nvmantbits ); |
39
|
|
|
|
|
|
|
|
40
|
8
|
|
|
|
|
108
|
*_NVSIZE = sub(){ $nvsize }; |
|
1
|
|
|
|
|
7
|
|
41
|
8
|
|
|
|
|
36
|
*_NVMANTBITS = sub(){ $nvmantbits }; |
|
1
|
|
|
|
|
103
|
|
42
|
8
|
|
|
|
|
31
|
*_FLOAT_PRECISION = sub(){ $precision }; |
|
1
|
|
|
|
|
3
|
|
43
|
|
|
|
|
|
|
|
44
|
8
|
|
|
|
|
67
|
local $@; |
45
|
|
|
|
|
|
|
# if B is already loaded, just use its perlstring |
46
|
8
|
50
|
33
|
|
|
102
|
if ("$]" >= 5.008_000 && "$]" != 5.010_000 && defined &B::perlstring) { |
|
|
0
|
33
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
47
|
8
|
|
|
|
|
710
|
*_perlstring = \&B::perlstring; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
# XString is smaller than B, so prefer to use it. Buggy until 0.003. |
50
|
1
|
|
|
|
|
83
|
elsif (eval { require XString; XString->VERSION(0.003) }) { |
|
1
|
|
|
|
|
5
|
|
51
|
1
|
|
|
|
|
3
|
*_perlstring = \&XString::perlstring; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
# B::perlstring in perl 5.10 handles escaping incorrectly on utf8 strings |
54
|
|
|
|
|
|
|
elsif ("$]" == 5.010_000) { |
55
|
1
|
|
|
|
|
57
|
my %escape = ( |
56
|
|
|
|
|
|
|
(map +(chr($_) => sprintf '\x%02x', $_), 0 .. 0x31, 0x7f), |
57
|
|
|
|
|
|
|
"\t" => "\\t", |
58
|
|
|
|
|
|
|
"\n" => "\\n", |
59
|
|
|
|
|
|
|
"\r" => "\\r", |
60
|
|
|
|
|
|
|
"\f" => "\\f", |
61
|
|
|
|
|
|
|
"\b" => "\\b", |
62
|
|
|
|
|
|
|
"\a" => "\\a", |
63
|
|
|
|
|
|
|
"\e" => "\\e", |
64
|
|
|
|
|
|
|
(map +($_ => "\\$_"), qw(" \ $ @)), |
65
|
|
|
|
|
|
|
); |
66
|
|
|
|
|
|
|
*_perlstring = sub { |
67
|
1
|
|
|
|
|
2
|
my $value = shift; |
68
|
1
|
|
|
|
|
99
|
$value =~ s{(["\$\@\\[:cntrl:]]|[^\x00-\x7f])}{ |
69
|
1
|
0
|
|
|
|
5
|
$escape{$1} || sprintf('\x{%x}', ord($1)) |
70
|
|
|
|
|
|
|
}ge; |
71
|
1
|
|
|
|
|
2
|
qq["$value"]; |
72
|
1
|
|
|
|
|
8
|
}; |
73
|
|
|
|
|
|
|
} |
74
|
1
|
|
|
|
|
56
|
elsif ("$]" >= 5.008_000 && eval { require B; 1 } && defined &B::perlstring ) { |
|
1
|
|
|
|
|
7
|
|
75
|
1
|
|
|
|
|
2
|
*_perlstring = \&B::perlstring; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
# on perl 5.6, perlstring is not available. quotemeta will mostly serve as a |
78
|
|
|
|
|
|
|
# replacement. it quotes just by adding lots of backslashes though. if a |
79
|
|
|
|
|
|
|
# utf8 string was written out directly as bytes, it wouldn't get interpreted |
80
|
|
|
|
|
|
|
# correctly if not under 'use utf8'. this is mostly a theoretical concern, |
81
|
|
|
|
|
|
|
# but enough to stick with perlstring when possible. |
82
|
|
|
|
|
|
|
else { |
83
|
1
|
|
|
|
|
80
|
*_perlstring = sub { qq["\Q$_[0]\E"] }; |
|
1
|
|
|
|
|
5
|
|
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
our @EXPORT = qw(quote_sub unquote_sub quoted_from_sub qsub); |
88
|
|
|
|
|
|
|
our @EXPORT_OK = qw(quotify capture_unroll inlinify sanitize_identifier); |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
our %QUOTED; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub quotify { |
93
|
1875
|
|
|
1875
|
1
|
3422073
|
my $value = $_[0]; |
94
|
8
|
|
|
10
|
|
51
|
no warnings 'numeric'; |
|
8
|
|
|
|
|
71
|
|
|
8
|
|
|
|
|
409
|
|
95
|
|
|
|
|
|
|
BEGIN { |
96
|
8
|
|
|
10
|
|
18276
|
warnings->unimport(qw(experimental::builtin)) |
97
|
|
|
|
|
|
|
if _CAN_TRACK_BOOLEANS || _CAN_TRACK_NUMBERS; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
! defined $value ? 'undef()' |
100
|
|
|
|
|
|
|
: _CAN_TRACK_BOOLEANS && builtin::is_bool($value) ? ( |
101
|
|
|
|
|
|
|
$value ? '(!!1)' : '(!!0)' |
102
|
|
|
|
|
|
|
) |
103
|
|
|
|
|
|
|
# numeric detection |
104
|
|
|
|
|
|
|
: ( |
105
|
|
|
|
|
|
|
_CAN_TRACK_NUMBERS |
106
|
|
|
|
|
|
|
? builtin::created_as_number($value) |
107
|
|
|
|
|
|
|
: ( |
108
|
|
|
|
|
|
|
!(_HAVE_IS_UTF8 && utf8::is_utf8($value)) |
109
|
|
|
|
|
|
|
&& length( (my $dummy = '') & $value ) |
110
|
|
|
|
|
|
|
&& 0 + $value eq $value |
111
|
|
|
|
|
|
|
) |
112
|
|
|
|
|
|
|
) ? ( |
113
|
|
|
|
|
|
|
$value != $value ? ( |
114
|
|
|
|
|
|
|
$value eq (9**9**9*0) |
115
|
|
|
|
|
|
|
? '(9**9**9*0)' # nan |
116
|
|
|
|
|
|
|
: '(-(9**9**9*0))' # -nan |
117
|
|
|
|
|
|
|
) |
118
|
|
|
|
|
|
|
: $value == 9**9**9 ? '(9**9**9)' # inf |
119
|
|
|
|
|
|
|
: $value == -9**9**9 ? '(-9**9**9)' # -inf |
120
|
|
|
|
|
|
|
: $value == 0 ? ( |
121
|
|
|
|
|
|
|
sprintf('%g', $value) eq '-0' ? '-0.0' : '0', |
122
|
|
|
|
|
|
|
) |
123
|
|
|
|
|
|
|
: $value !~ /[e.]/i ? ( |
124
|
|
|
|
|
|
|
$value > 0 ? (sprintf '%u', $value) |
125
|
|
|
|
|
|
|
: (sprintf '%d', $value) |
126
|
|
|
|
|
|
|
) |
127
|
1875
|
100
|
100
|
|
|
24817
|
: do { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
128
|
180
|
|
|
|
|
404
|
my $float = $value; |
129
|
180
|
|
|
|
|
788
|
my $max_factor = int( log( abs($value) ) / log(2) ) - _NVMANTBITS; |
130
|
180
|
100
|
|
|
|
406
|
my $ex_sign = $max_factor > 0 ? 1 : -1; |
131
|
180
|
|
|
|
|
460
|
FACTOR: for my $ex (0 .. abs($max_factor)) { |
132
|
188
|
|
|
|
|
469
|
my $num = $value / 2**($ex_sign * $ex); |
133
|
188
|
|
|
|
|
302
|
for my $precision (_FLOAT_PRECISION .. _FLOAT_PRECISION+2) { |
134
|
289
|
|
|
|
|
1681
|
my $formatted = sprintf '%0.'.$precision.'g', $num; |
135
|
289
|
100
|
|
|
|
713
|
$float = $formatted |
136
|
|
|
|
|
|
|
if $ex == 0; |
137
|
289
|
100
|
|
|
|
968
|
if ($formatted == $num) { |
138
|
177
|
100
|
|
|
|
360
|
if ($ex) { |
139
|
5
|
50
|
|
|
|
24
|
$float |
|
|
50
|
|
|
|
|
|
140
|
|
|
|
|
|
|
= $formatted |
141
|
|
|
|
|
|
|
. ($ex_sign == 1 ? '*' : '/') |
142
|
|
|
|
|
|
|
. ( |
143
|
|
|
|
|
|
|
$ex > _NVMANTBITS |
144
|
|
|
|
|
|
|
? "2**$ex" |
145
|
|
|
|
|
|
|
: sprintf('%u', 2**$ex) |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
} |
148
|
177
|
|
|
|
|
539
|
last FACTOR; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
} |
151
|
16
|
|
|
|
|
46
|
if (_HAVE_HEX_FLOAT) { |
152
|
97
|
|
|
|
|
303
|
$float = sprintf '%a', $value; |
153
|
8
|
|
|
|
|
106
|
last FACTOR; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
93
|
|
|
|
|
269
|
"$float"; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
) |
159
|
|
|
|
|
|
|
: !_CAN_TRACK_BOOLEANS && !length($value) && length( (my $dummy2 = '') & $value ) ? '(!!0)' # false |
160
|
|
|
|
|
|
|
: _perlstring($value); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub sanitize_identifier { |
164
|
3
|
|
|
3
|
1
|
560
|
my $name = shift; |
165
|
3
|
|
|
|
|
92
|
$name =~ s/([_\W])/sprintf('_%x', ord($1))/ge; |
|
6
|
|
|
|
|
23
|
|
166
|
2
|
|
|
|
|
15
|
$name; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub capture_unroll { |
170
|
43
|
|
|
44
|
1
|
1682
|
my ($from, $captures, $indent) = @_; |
171
|
|
|
|
|
|
|
join( |
172
|
|
|
|
|
|
|
'', |
173
|
|
|
|
|
|
|
map { |
174
|
43
|
100
|
|
|
|
122
|
/^([\@\%\$])/ |
|
88
|
|
|
|
|
616
|
|
175
|
|
|
|
|
|
|
or croak "capture key should start with \@, \% or \$: $_"; |
176
|
86
|
|
|
|
|
319
|
(' ' x $indent).qq{my ${_} = ${1}{${from}->{${\quotify $_}}};\n}; |
|
86
|
|
|
|
|
160
|
|
177
|
|
|
|
|
|
|
} keys %$captures |
178
|
|
|
|
|
|
|
); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub inlinify { |
182
|
9
|
|
|
10
|
1
|
10430
|
my ($code, $args, $extra, $local) = @_; |
183
|
9
|
100
|
|
|
|
83
|
$args = '()' |
184
|
|
|
|
|
|
|
if !defined $args; |
185
|
9
|
|
100
|
|
|
33
|
my $do = 'do { '.($extra||''); |
186
|
9
|
100
|
|
|
|
40
|
if ($code =~ s/^(\s*package\s+([a-zA-Z0-9:]+);)//) { |
187
|
2
|
|
|
|
|
73
|
$do .= $1; |
188
|
|
|
|
|
|
|
} |
189
|
9
|
100
|
100
|
|
|
59
|
if ($code =~ s{ |
|
|
100
|
|
|
|
|
|
190
|
|
|
|
|
|
|
\A((?:\#\ BEGIN\ quote_sub\ PRELUDE\n.*?\#\ END\ quote_sub\ PRELUDE\n)?\s*) |
191
|
|
|
|
|
|
|
(^\s*) my \s* \(([^)]+)\) \s* = \s* \@_; |
192
|
|
|
|
|
|
|
}{}xms) { |
193
|
4
|
|
|
|
|
16
|
my ($pre, $indent, $code_args) = ($1, $2, $3); |
194
|
4
|
|
|
|
|
352
|
$do .= $pre; |
195
|
4
|
100
|
|
|
|
834
|
if ($code_args ne $args) { |
196
|
2
|
|
|
|
|
16
|
$do .= $indent . 'my ('.$code_args.') = ('.$args.'); '; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
elsif ($local || $args ne '@_') { |
200
|
3
|
100
|
|
|
|
10
|
$do .= ($local ? 'local ' : '').'@_ = ('.$args.'); '; |
201
|
|
|
|
|
|
|
} |
202
|
8
|
|
|
|
|
26
|
$do.$code.' }'; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub quote_sub { |
206
|
|
|
|
|
|
|
# HOLY DWIMMERY, BATMAN! |
207
|
|
|
|
|
|
|
# $name => $code => \%captures => \%options |
208
|
|
|
|
|
|
|
# $name => $code => \%captures |
209
|
|
|
|
|
|
|
# $name => $code |
210
|
|
|
|
|
|
|
# $code => \%captures => \%options |
211
|
|
|
|
|
|
|
# $code |
212
|
59
|
100
|
100
|
61
|
1
|
23661
|
my $options = |
213
|
|
|
|
|
|
|
(ref($_[-1]) eq 'HASH' and ref($_[-2]) eq 'HASH') |
214
|
|
|
|
|
|
|
? pop |
215
|
|
|
|
|
|
|
: {}; |
216
|
59
|
100
|
|
|
|
154
|
my $captures = ref($_[-1]) eq 'HASH' ? pop : undef; |
217
|
59
|
100
|
100
|
|
|
181
|
undef($captures) if $captures && !keys %$captures; |
218
|
59
|
|
|
|
|
133
|
my $code = pop; |
219
|
59
|
|
|
|
|
95
|
my $name = $_[0]; |
220
|
59
|
100
|
|
|
|
122
|
if ($name) { |
221
|
21
|
|
|
|
|
27
|
my $subname = $name; |
222
|
21
|
100
|
|
|
|
179
|
my $package = $subname =~ s/(.*)::// ? $1 : caller; |
223
|
21
|
|
|
|
|
65
|
$name = join '::', $package, $subname; |
224
|
21
|
100
|
|
|
|
399
|
croak qq{package name "$package" too long!} |
225
|
|
|
|
|
|
|
if length $package > 252; |
226
|
19
|
100
|
|
|
|
289
|
croak qq{package name "$package" is not valid!} |
227
|
|
|
|
|
|
|
unless $package =~ /^[^\d\W]\w*(?:::\w+)*$/; |
228
|
17
|
100
|
|
|
|
131
|
croak qq{sub name "$subname" too long!} |
229
|
|
|
|
|
|
|
if length $subname > 252; |
230
|
16
|
100
|
|
|
|
235
|
croak qq{sub name "$subname" is not valid!} |
231
|
|
|
|
|
|
|
unless $subname =~ /^[^\d\W]\w*$/; |
232
|
|
|
|
|
|
|
} |
233
|
52
|
|
|
|
|
314
|
my @caller = caller(0); |
234
|
52
|
|
|
|
|
97
|
my ($attributes, $file, $line) = @{$options}{qw(attributes file line)}; |
|
52
|
|
|
|
|
157
|
|
235
|
52
|
100
|
|
|
|
117
|
if ($attributes) { |
236
|
|
|
|
|
|
|
/\A\w+(?:\(.*\))?\z/s || croak "invalid attribute $_" |
237
|
3
|
|
66
|
|
|
118
|
for @$attributes; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
my $quoted_info = { |
240
|
|
|
|
|
|
|
name => $name, |
241
|
|
|
|
|
|
|
code => $code, |
242
|
|
|
|
|
|
|
captures => $captures, |
243
|
|
|
|
|
|
|
package => (exists $options->{package} ? $options->{package} : $caller[0]), |
244
|
|
|
|
|
|
|
hints => (exists $options->{hints} ? $options->{hints} : $caller[8]), |
245
|
|
|
|
|
|
|
warning_bits => (exists $options->{warning_bits} ? $options->{warning_bits} : $caller[9]), |
246
|
51
|
100
|
|
|
|
446
|
hintshash => (exists $options->{hintshash} ? $options->{hintshash} : $caller[10]), |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
247
|
|
|
|
|
|
|
($attributes ? (attributes => $attributes) : ()), |
248
|
|
|
|
|
|
|
($file ? (file => $file) : ()), |
249
|
|
|
|
|
|
|
($line ? (line => $line) : ()), |
250
|
|
|
|
|
|
|
}; |
251
|
51
|
|
|
|
|
86
|
my $unquoted; |
252
|
51
|
|
|
|
|
235
|
weaken($quoted_info->{unquoted} = \$unquoted); |
253
|
51
|
100
|
|
|
|
106
|
if ($options->{no_defer}) { |
254
|
4
|
|
|
|
|
6
|
my $fake = \my $var; |
255
|
4
|
|
|
|
|
13
|
local $QUOTED{$fake} = $quoted_info; |
256
|
4
|
|
|
|
|
9
|
my $sub = unquote_sub($fake); |
257
|
4
|
100
|
100
|
|
|
20
|
Sub::Defer::_install_coderef($name, $sub) if $name && !$options->{no_install}; |
258
|
4
|
|
|
|
|
22
|
return $sub; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
else { |
261
|
|
|
|
|
|
|
my $deferred = defer_sub( |
262
|
|
|
|
|
|
|
($options->{no_install} ? undef : $name), |
263
|
|
|
|
|
|
|
sub { |
264
|
30
|
|
|
32
|
|
39
|
$unquoted if 0; |
265
|
30
|
|
|
|
|
61
|
unquote_sub($quoted_info->{deferred}); |
266
|
|
|
|
|
|
|
}, |
267
|
|
|
|
|
|
|
{ |
268
|
|
|
|
|
|
|
($attributes ? ( attributes => $attributes ) : ()), |
269
|
47
|
100
|
|
|
|
310
|
($name ? () : ( package => $quoted_info->{package} )), |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
270
|
|
|
|
|
|
|
}, |
271
|
|
|
|
|
|
|
); |
272
|
47
|
|
|
|
|
144
|
weaken($quoted_info->{deferred} = $deferred); |
273
|
47
|
|
|
|
|
152
|
weaken($QUOTED{$deferred} = $quoted_info); |
274
|
47
|
|
|
|
|
226
|
return $deferred; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub _context { |
279
|
47
|
|
|
49
|
|
91
|
my $info = shift; |
280
|
47
|
|
66
|
|
|
138
|
$info->{context} ||= do { |
281
|
|
|
|
|
|
|
my ($package, $hints, $warning_bits, $hintshash, $file, $line) |
282
|
41
|
|
|
|
|
65
|
= @{$info}{qw(package hints warning_bits hintshash file line)}; |
|
41
|
|
|
|
|
111
|
|
283
|
|
|
|
|
|
|
|
284
|
41
|
100
|
50
|
|
|
85
|
$line ||= 1 |
285
|
|
|
|
|
|
|
if $file; |
286
|
|
|
|
|
|
|
|
287
|
41
|
|
|
|
|
64
|
my $line_mark = ''; |
288
|
41
|
100
|
|
|
|
83
|
if ($line) { |
289
|
2
|
|
|
|
|
5
|
$line_mark = "#line ".($line-1); |
290
|
2
|
100
|
|
|
|
8
|
if ($file) { |
291
|
1
|
|
|
|
|
3
|
$line_mark .= qq{ "$file"}; |
292
|
|
|
|
|
|
|
} |
293
|
2
|
|
|
|
|
3
|
$line_mark .= "\n"; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
$info->{context} |
297
|
|
|
|
|
|
|
="# BEGIN quote_sub PRELUDE\n" |
298
|
|
|
|
|
|
|
."package $package;\n" |
299
|
|
|
|
|
|
|
."BEGIN {\n" |
300
|
|
|
|
|
|
|
." \$^H = ".quotify($hints).";\n" |
301
|
|
|
|
|
|
|
." \${^WARNING_BITS} = ".quotify($warning_bits).";\n" |
302
|
|
|
|
|
|
|
." \%^H = (\n" |
303
|
|
|
|
|
|
|
. join('', map |
304
|
|
|
|
|
|
|
" ".quotify($_)." => ".quotify($hintshash->{$_}).",\n", |
305
|
41
|
|
33
|
|
|
136
|
grep !(ref $hintshash->{$_} && $hintshash->{$_} =~ /\A(?:\w+(?:::\w+)*=)?[A-Z]+\(0x[[0-9a-fA-F]+\)\z/), |
306
|
|
|
|
|
|
|
keys %$hintshash) |
307
|
|
|
|
|
|
|
." );\n" |
308
|
|
|
|
|
|
|
."}\n" |
309
|
|
|
|
|
|
|
.$line_mark |
310
|
|
|
|
|
|
|
."# END quote_sub PRELUDE\n"; |
311
|
|
|
|
|
|
|
}; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub quoted_from_sub { |
315
|
10
|
|
|
15
|
1
|
463
|
my ($sub) = @_; |
316
|
10
|
100
|
50
|
|
|
49
|
my $quoted_info = $QUOTED{$sub||''} or return undef; |
317
|
|
|
|
|
|
|
my ($name, $code, $captures, $unquoted, $deferred) |
318
|
8
|
|
|
|
|
19
|
= @{$quoted_info}{qw(name code captures unquoted deferred)}; |
|
8
|
|
|
|
|
26
|
|
319
|
8
|
|
|
|
|
17
|
$code = _context($quoted_info) . $code; |
320
|
8
|
|
66
|
|
|
52
|
$unquoted &&= $$unquoted; |
321
|
8
|
100
|
100
|
|
|
75
|
if (($deferred && $deferred eq $sub) |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
322
|
|
|
|
|
|
|
|| ($unquoted && $unquoted eq $sub)) { |
323
|
7
|
|
|
|
|
51
|
return [ $name, $code, $captures, $unquoted, $deferred ]; |
324
|
|
|
|
|
|
|
} |
325
|
1
|
|
|
|
|
7
|
return undef; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub unquote_sub { |
329
|
43
|
|
|
45
|
1
|
694
|
my ($sub) = @_; |
330
|
43
|
100
|
|
|
|
135
|
my $quoted_info = $QUOTED{$sub} or return undef; |
331
|
42
|
|
|
|
|
71
|
my $unquoted = $quoted_info->{unquoted}; |
332
|
42
|
100
|
66
|
|
|
155
|
unless ($unquoted && $$unquoted) { |
333
|
|
|
|
|
|
|
my ($name, $code, $captures, $package, $attributes) |
334
|
40
|
|
|
|
|
57
|
= @{$quoted_info}{qw(name code captures package attributes)}; |
|
40
|
|
|
|
|
111
|
|
335
|
|
|
|
|
|
|
|
336
|
40
|
100
|
|
|
|
135
|
($package, $name) = $name =~ /(.*)::(.*)/ |
337
|
|
|
|
|
|
|
if $name; |
338
|
|
|
|
|
|
|
|
339
|
40
|
100
|
|
|
|
91
|
my %captures = $captures ? %$captures : (); |
340
|
40
|
|
|
|
|
73
|
$captures{'$_UNQUOTED'} = \$unquoted; |
341
|
40
|
|
|
|
|
65
|
$captures{'$_QUOTED'} = \$quoted_info; |
342
|
|
|
|
|
|
|
|
343
|
40
|
100
|
|
|
|
86
|
my $make_sub |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
344
|
|
|
|
|
|
|
= "{\n" |
345
|
|
|
|
|
|
|
. capture_unroll("\$_[1]", \%captures, 2) |
346
|
|
|
|
|
|
|
. " package ${package};\n" |
347
|
|
|
|
|
|
|
. ( |
348
|
|
|
|
|
|
|
$name |
349
|
|
|
|
|
|
|
# disable the 'variable $x will not stay shared' warning since |
350
|
|
|
|
|
|
|
# we're not letting it escape from this scope anyway so there's |
351
|
|
|
|
|
|
|
# nothing trying to share it |
352
|
|
|
|
|
|
|
? " no warnings 'closure';\n sub ${name} " |
353
|
|
|
|
|
|
|
: " \$\$_UNQUOTED = sub " |
354
|
|
|
|
|
|
|
) |
355
|
|
|
|
|
|
|
. ($attributes ? join('', map ":$_ ", @$attributes) : '') . "{\n" |
356
|
|
|
|
|
|
|
. " (\$_QUOTED,\$_UNQUOTED) if 0;\n" |
357
|
|
|
|
|
|
|
. _context($quoted_info) |
358
|
|
|
|
|
|
|
. $code |
359
|
|
|
|
|
|
|
. " }".($name ? "\n \$\$_UNQUOTED = \\&${name}" : '') . ";\n" |
360
|
|
|
|
|
|
|
. "}\n" |
361
|
|
|
|
|
|
|
. "1;\n"; |
362
|
39
|
100
|
|
|
|
139
|
if (my $debug = $ENV{SUB_QUOTE_DEBUG}) { |
363
|
12
|
100
|
|
|
|
100
|
if ($debug =~ m{^([^\W\d]\w*(?:::\w+)*(?:::)?)$}) { |
|
|
100
|
|
|
|
|
|
364
|
9
|
|
|
|
|
29
|
my $filter = $1; |
365
|
9
|
100
|
50
|
|
|
55
|
my $match |
|
|
100
|
100
|
|
|
|
|
366
|
|
|
|
|
|
|
= $filter =~ /::$/ ? $package.'::' |
367
|
|
|
|
|
|
|
: $filter =~ /::/ ? $package.'::'.($name||'__ANON__') |
368
|
|
|
|
|
|
|
: ($name||'__ANON__'); |
369
|
9
|
100
|
|
|
|
47
|
warn $make_sub |
370
|
|
|
|
|
|
|
if $match eq $filter; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
elsif ($debug =~ m{\A/(.*)/\z}s) { |
373
|
2
|
|
|
|
|
5
|
my $filter = $1; |
374
|
2
|
100
|
|
|
|
25
|
warn $make_sub |
375
|
|
|
|
|
|
|
if $code =~ $filter; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
else { |
378
|
1
|
|
|
|
|
11
|
warn $make_sub; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
{ |
382
|
8
|
|
|
8
|
|
137
|
no strict 'refs'; |
|
8
|
|
|
|
|
19
|
|
|
8
|
|
|
|
|
2597
|
|
|
39
|
|
|
|
|
89
|
|
383
|
39
|
100
|
|
|
|
72
|
local *{"${package}::${name}"} if $name; |
|
13
|
|
|
|
|
59
|
|
384
|
39
|
|
|
|
|
96
|
my ($success, $e); |
385
|
|
|
|
|
|
|
{ |
386
|
39
|
|
|
|
|
51
|
local $@; |
|
39
|
|
|
|
|
52
|
|
387
|
39
|
|
|
|
|
102
|
$success = _clean_eval($make_sub, \%captures); |
388
|
39
|
|
|
|
|
117
|
$e = $@; |
389
|
|
|
|
|
|
|
} |
390
|
39
|
100
|
|
|
|
103
|
unless ($success) { |
391
|
2
|
|
|
|
|
12
|
my $space = length($make_sub =~ tr/\n//); |
392
|
2
|
|
|
|
|
4
|
my $line = 0; |
393
|
2
|
|
|
|
|
13
|
$make_sub =~ s/^/sprintf "%${space}d: ", ++$line/emg; |
|
39
|
|
|
|
|
113
|
|
394
|
2
|
|
|
|
|
210
|
croak "Eval went very, very wrong:\n\n${make_sub}\n\n$e"; |
395
|
|
|
|
|
|
|
} |
396
|
37
|
|
|
|
|
249
|
weaken($QUOTED{$$unquoted} = $quoted_info); |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
} |
399
|
39
|
|
|
|
|
144
|
$$unquoted; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub qsub ($) { |
403
|
1
|
|
|
2
|
1
|
555
|
goto "e_sub; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub CLONE { |
407
|
5
|
|
|
6
|
|
43
|
my @quoted = map { defined $_ ? ( |
408
|
2
|
|
|
|
|
10
|
$_->{unquoted} && ${$_->{unquoted}} ? (${ $_->{unquoted} } => $_) : (), |
409
|
8
|
100
|
100
|
|
|
26
|
$_->{deferred} ? ($_->{deferred} => $_) : (), |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
410
|
|
|
|
|
|
|
) : () } values %QUOTED; |
411
|
5
|
|
|
|
|
16
|
%QUOTED = @quoted; |
412
|
5
|
|
|
|
|
21
|
weaken($_) for values %QUOTED; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
1; |
416
|
|
|
|
|
|
|
__END__ |