line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
38
|
|
|
38
|
|
275441
|
use 5.014; |
|
38
|
|
|
|
|
90
|
|
2
|
38
|
|
|
38
|
|
139
|
use strict; |
|
38
|
|
|
|
|
46
|
|
|
38
|
|
|
|
|
805
|
|
3
|
38
|
|
|
38
|
|
123
|
use warnings; |
|
38
|
|
|
|
|
41
|
|
|
38
|
|
|
|
|
885
|
|
4
|
|
|
|
|
|
|
|
5
|
38
|
|
|
38
|
|
13123
|
use Kavorka::Signature (); |
|
38
|
|
|
|
|
85
|
|
|
38
|
|
|
|
|
1276
|
|
6
|
38
|
|
|
38
|
|
217
|
use Sub::Util (); |
|
38
|
|
|
|
|
51
|
|
|
38
|
|
|
|
|
2226
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Kavorka::Sub; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:TOBYINK'; |
11
|
|
|
|
|
|
|
our $VERSION = '0.037'; |
12
|
|
|
|
|
|
|
|
13
|
38
|
|
|
38
|
|
148
|
use Text::Balanced qw( extract_bracketed ); |
|
38
|
|
|
|
|
40
|
|
|
38
|
|
|
|
|
1882
|
|
14
|
38
|
|
|
38
|
|
137
|
use Parse::Keyword {}; |
|
38
|
|
|
|
|
50
|
|
|
38
|
|
|
|
|
176
|
|
15
|
38
|
|
|
38
|
|
2975
|
use Parse::KeywordX; |
|
38
|
|
|
|
|
44
|
|
|
38
|
|
|
|
|
157
|
|
16
|
38
|
|
|
38
|
|
9848
|
use Carp; |
|
38
|
|
|
|
|
47
|
|
|
38
|
|
|
|
|
2572
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our @CARP_NOT = qw(Kavorka); |
19
|
|
|
|
|
|
|
|
20
|
38
|
|
|
38
|
|
169
|
use Moo::Role; |
|
38
|
|
|
|
|
51
|
|
|
38
|
|
|
|
|
296
|
|
21
|
38
|
|
|
38
|
|
17262
|
use namespace::sweep; |
|
38
|
|
|
|
|
50
|
|
|
38
|
|
|
|
|
155
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
use overload ( |
24
|
1
|
|
|
1
|
|
725
|
q[&{}] => sub { shift->body }, |
|
|
|
|
0
|
|
|
|
25
|
4
|
|
|
0
|
|
66
|
q[bool] => sub { 1 }, |
|
|
|
|
4
|
|
|
|
26
|
0
|
|
0
|
0
|
|
0
|
q[""] => sub { shift->qualified_name // '__ANON__' }, |
|
|
|
|
0
|
|
|
|
27
|
0
|
|
|
0
|
|
0
|
q[0+] => sub { 1 }, |
|
|
|
|
0
|
|
|
|
28
|
38
|
|
|
|
|
411
|
fallback => 1, |
29
|
38
|
|
|
38
|
|
5046
|
); |
|
38
|
|
|
|
|
53
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
has keyword => (is => 'ro'); |
32
|
|
|
|
|
|
|
has signature_class => (is => 'lazy', default => sub { 'Kavorka::Signature' }); |
33
|
|
|
|
|
|
|
has package => (is => 'ro'); |
34
|
|
|
|
|
|
|
has declared_name => (is => 'rwp'); |
35
|
|
|
|
|
|
|
has signature => (is => 'rwp'); |
36
|
|
|
|
|
|
|
has traits => (is => 'lazy', default => sub { +{} }); |
37
|
|
|
|
|
|
|
has prototype => (is => 'rwp'); |
38
|
|
|
|
|
|
|
has attributes => (is => 'lazy', default => sub { [] }); |
39
|
|
|
|
|
|
|
has body => (is => 'rwp'); |
40
|
|
|
|
|
|
|
has qualified_name => (is => 'rwp'); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
has _unwrapped_body => (is => 'rwp'); |
43
|
|
|
|
|
|
|
has _pads_to_poke => (is => 'lazy'); |
44
|
|
|
|
|
|
|
has _tmp_name => (is => 'lazy'); |
45
|
|
|
|
|
|
|
|
46
|
23
|
|
|
23
|
1
|
44
|
sub allow_anonymous { 1 } |
47
|
4
|
|
|
4
|
0
|
9
|
sub allow_lexical { 1 } |
48
|
902
|
|
|
902
|
1
|
2865
|
sub is_anonymous { !defined( shift->declared_name ) } |
49
|
802
|
|
50
|
802
|
0
|
4165
|
sub is_lexical { (shift->declared_name || '') =~ /\A\$/ } |
50
|
0
|
|
|
0
|
1
|
0
|
sub invocation_style { +undef } |
51
|
132
|
|
|
132
|
1
|
220
|
sub default_attributes { return; } |
52
|
111
|
|
|
111
|
1
|
175
|
sub default_invocant { return; } |
53
|
161
|
|
|
161
|
1
|
187
|
sub forward_declare_sub { return; } |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub bypass_custom_parsing |
56
|
|
|
|
|
|
|
{ |
57
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
58
|
0
|
|
|
|
|
0
|
my ($keyword, $caller, $args) = @_; |
59
|
0
|
|
|
|
|
0
|
croak("Attempt to call keyword '$keyword' bypassing prototype not supported"); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub install_sub |
63
|
|
|
|
|
|
|
{ |
64
|
160
|
|
|
160
|
1
|
256
|
my $self = shift; |
65
|
160
|
|
|
|
|
197
|
my $code = $self->body; |
66
|
|
|
|
|
|
|
|
67
|
160
|
100
|
|
|
|
258
|
if ($self->is_anonymous) |
|
|
100
|
|
|
|
|
|
68
|
|
|
|
|
|
|
{ |
69
|
|
|
|
|
|
|
# no installation |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
elsif ($self->is_lexical) |
72
|
|
|
|
|
|
|
{ |
73
|
6
|
|
|
|
|
32
|
require PadWalker; |
74
|
6
|
|
|
|
|
37
|
PadWalker::peek_my(2)->{ $self->declared_name } = \$code; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
else |
77
|
|
|
|
|
|
|
{ |
78
|
125
|
|
|
|
|
200
|
my $name = $self->qualified_name; |
79
|
38
|
|
|
38
|
|
18130
|
no strict 'refs'; |
|
38
|
|
|
|
|
44
|
|
|
38
|
|
|
|
|
2856
|
|
80
|
125
|
|
|
|
|
115
|
*{$name} = $code; |
|
125
|
|
|
|
|
398
|
|
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
160
|
|
|
|
|
380
|
$code; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub inject_attributes |
87
|
|
|
|
|
|
|
{ |
88
|
165
|
|
|
165
|
1
|
242
|
my $self = shift; |
89
|
38
|
|
|
38
|
|
153
|
no warnings; # Perl 5.21+ sprintf emits warnings for redundant arguments |
|
38
|
|
|
|
|
45
|
|
|
38
|
|
|
|
|
80431
|
|
90
|
165
|
50
|
|
|
|
203
|
join(' ', map sprintf($_->[1] ? ':%s(%s)' : ':%s', @$_), @{ $self->attributes }), |
|
165
|
|
|
|
|
332
|
|
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub inject_prelude |
94
|
|
|
|
|
|
|
{ |
95
|
188
|
|
|
188
|
1
|
3698
|
my $self = shift; |
96
|
188
|
|
|
|
|
643
|
$self->signature->injection; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub parse |
100
|
|
|
|
|
|
|
{ |
101
|
188
|
|
|
188
|
1
|
273
|
my $class = shift; |
102
|
188
|
|
|
|
|
4218
|
my $self = $class->new(@_, package => compiling_package); |
103
|
|
|
|
|
|
|
|
104
|
188
|
|
|
|
|
7287
|
lex_read_space; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# sub name |
107
|
188
|
|
|
|
|
675
|
$self->parse_subname; |
108
|
188
|
100
|
100
|
|
|
707
|
unless ($self->is_anonymous or $self->is_lexical) |
109
|
|
|
|
|
|
|
{ |
110
|
161
|
|
|
|
|
469
|
my $qualified = Kavorka::_fqname($self->declared_name); |
111
|
161
|
|
|
|
|
371
|
$self->_set_qualified_name($qualified); |
112
|
161
|
|
|
|
|
298
|
$self->forward_declare_sub; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Thanks to Perl 5.20 subs, we have to allow attributes before |
116
|
|
|
|
|
|
|
# the signature too. |
117
|
188
|
|
|
|
|
312
|
lex_read_space; |
118
|
188
|
0
|
0
|
|
|
415
|
$self->parse_attributes |
119
|
|
|
|
|
|
|
if lex_peek eq ':' |
120
|
|
|
|
|
|
|
&& lex_peek(2) ne ':('; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# signature |
123
|
188
|
|
|
|
|
717
|
$self->parse_signature; |
124
|
188
|
|
|
|
|
324
|
my $sig = $self->signature; |
125
|
188
|
100
|
|
|
|
430
|
unless ($sig->has_invocants) |
126
|
|
|
|
|
|
|
{ |
127
|
182
|
|
|
|
|
441
|
my @defaults = $self->default_invocant; |
128
|
182
|
|
|
|
|
356
|
unshift @{$sig->params}, @defaults; |
|
182
|
|
|
|
|
347
|
|
129
|
182
|
|
|
|
|
324
|
$sig->_set_has_invocants(scalar @defaults); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# traits |
133
|
188
|
|
|
|
|
398
|
$self->parse_traits; |
134
|
188
|
|
|
|
|
510
|
my $traits = $self->traits; |
135
|
188
|
100
|
|
|
|
714
|
if (keys %$traits) |
136
|
|
|
|
|
|
|
{ |
137
|
|
|
|
|
|
|
# traits handled natively (none so far) |
138
|
10
|
|
|
|
|
8
|
state $native_traits = {}; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
my @custom_traits = |
141
|
|
|
|
|
|
|
map "Kavorka::TraitFor::Sub::$_", |
142
|
10
|
|
|
|
|
45
|
grep !exists($native_traits->{$_}), |
143
|
|
|
|
|
|
|
keys %$traits; |
144
|
|
|
|
|
|
|
|
145
|
10
|
50
|
|
|
|
48
|
'Moo::Role'->apply_roles_to_object($self, @custom_traits) if @custom_traits; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# prototype and attributes |
149
|
188
|
|
|
|
|
3081
|
$self->parse_prototype; |
150
|
188
|
|
|
|
|
556
|
$self->parse_attributes; |
151
|
188
|
|
|
|
|
690
|
push @{$self->attributes}, $self->default_attributes; |
|
188
|
|
|
|
|
471
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# body |
154
|
188
|
|
|
|
|
372
|
$self->parse_body; |
155
|
|
|
|
|
|
|
|
156
|
188
|
|
|
|
|
466
|
$self; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub parse_subname |
160
|
|
|
|
|
|
|
{ |
161
|
188
|
|
|
188
|
1
|
275
|
my $self = shift; |
162
|
188
|
|
|
|
|
409
|
my $peek = lex_peek(2); |
163
|
|
|
|
|
|
|
|
164
|
188
|
|
|
|
|
217
|
my $saw_my = 0; |
165
|
|
|
|
|
|
|
|
166
|
188
|
100
|
|
|
|
621
|
if ($peek =~ /\A(?:\w|::)/) # normal sub |
167
|
|
|
|
|
|
|
{ |
168
|
165
|
|
|
|
|
507
|
my $name = parse_name('subroutine', 1); |
169
|
|
|
|
|
|
|
|
170
|
165
|
100
|
|
|
|
366
|
if ($name eq 'my') |
171
|
|
|
|
|
|
|
{ |
172
|
4
|
|
|
|
|
9
|
lex_read_space; |
173
|
4
|
0
|
|
|
|
10
|
$saw_my = 1 if lex_peek eq '$'; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
165
|
100
|
|
|
|
262
|
if ($saw_my) |
177
|
|
|
|
|
|
|
{ |
178
|
4
|
|
|
|
|
10
|
$peek = lex_peek(2); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
else |
181
|
|
|
|
|
|
|
{ |
182
|
161
|
|
|
|
|
441
|
$self->_set_declared_name($name); |
183
|
161
|
|
|
|
|
499
|
return; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
27
|
100
|
|
|
|
62
|
if ($peek =~ /\A\$[^\W0-9]/) # lexical sub |
188
|
|
|
|
|
|
|
{ |
189
|
4
|
50
|
|
|
|
11
|
carp("'${\ $self->keyword }' should be '${\ $self->keyword } my'") |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
190
|
|
|
|
|
|
|
unless $saw_my; |
191
|
|
|
|
|
|
|
|
192
|
4
|
|
|
|
|
7
|
lex_read(1); |
193
|
4
|
|
|
|
|
12
|
$self->_set_declared_name('$' . parse_name('lexical subroutine', 0)); |
194
|
|
|
|
|
|
|
|
195
|
4
|
50
|
|
|
|
11
|
croak("Keyword '${\ $self->keyword }' does not support defining lexical subs") |
|
0
|
|
|
|
|
0
|
|
196
|
|
|
|
|
|
|
unless $self->allow_lexical; |
197
|
|
|
|
|
|
|
|
198
|
4
|
|
|
|
|
5
|
return; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
23
|
50
|
|
|
|
45
|
croak("Keyword '${\ $self->keyword }' does not support defining anonymous subs") |
|
0
|
|
|
|
|
0
|
|
202
|
|
|
|
|
|
|
unless $self->allow_anonymous; |
203
|
|
|
|
|
|
|
|
204
|
23
|
|
|
|
|
29
|
(); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub parse_signature |
208
|
|
|
|
|
|
|
{ |
209
|
188
|
|
|
188
|
1
|
258
|
my $self = shift; |
210
|
188
|
|
|
|
|
255
|
lex_read_space; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# default signature |
213
|
188
|
|
|
|
|
503
|
my $dummy = 0; |
214
|
188
|
0
|
|
|
|
349
|
if (lex_peek ne '(') |
215
|
|
|
|
|
|
|
{ |
216
|
32
|
|
|
|
|
58
|
$dummy = 1; |
217
|
32
|
|
|
|
|
83
|
lex_stuff('(...)'); |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
188
|
|
|
|
|
401
|
lex_read(1); |
221
|
188
|
|
|
|
|
480
|
my $sig = $self->signature_class->parse(package => $self->package, _is_dummy => $dummy); |
222
|
188
|
0
|
|
|
|
460
|
lex_peek eq ')' or croak('Expected ")" after signature'); |
223
|
188
|
|
|
|
|
459
|
lex_read(1); |
224
|
188
|
|
|
|
|
251
|
lex_read_space; |
225
|
|
|
|
|
|
|
|
226
|
188
|
|
|
|
|
400
|
$self->_set_signature($sig); |
227
|
|
|
|
|
|
|
|
228
|
188
|
|
|
|
|
401
|
(); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub parse_prototype |
232
|
|
|
|
|
|
|
{ |
233
|
188
|
|
|
188
|
1
|
245
|
my $self = shift; |
234
|
188
|
|
|
|
|
286
|
lex_read_space; |
235
|
|
|
|
|
|
|
|
236
|
188
|
|
|
|
|
343
|
my $peek = lex_peek(1000); |
237
|
188
|
100
|
|
|
|
435
|
if ($peek =~ / \A \: \s* \( /xsm ) |
238
|
|
|
|
|
|
|
{ |
239
|
3
|
|
|
|
|
5
|
lex_read(1); |
240
|
3
|
|
|
|
|
5
|
lex_read_space; |
241
|
3
|
|
|
|
|
5
|
$peek = lex_peek(1000); |
242
|
|
|
|
|
|
|
|
243
|
3
|
|
|
|
|
11
|
my $extracted = extract_bracketed($peek, '()'); |
244
|
3
|
|
|
|
|
322
|
lex_read(length $extracted); |
245
|
3
|
|
|
|
|
10
|
$extracted =~ s/(?: \A\( | \)\z )//xgsm; |
246
|
|
|
|
|
|
|
|
247
|
3
|
|
|
|
|
11
|
$self->_set_prototype($extracted); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
188
|
|
|
|
|
214
|
(); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub parse_traits |
254
|
|
|
|
|
|
|
{ |
255
|
188
|
|
|
188
|
1
|
191
|
my $self = shift; |
256
|
188
|
|
|
|
|
273
|
lex_read_space; |
257
|
|
|
|
|
|
|
|
258
|
188
|
|
|
|
|
487
|
while (lex_peek(5) =~ m{ \A (is|does|but) \s }xsm) |
259
|
|
|
|
|
|
|
{ |
260
|
10
|
|
|
|
|
34
|
lex_read(length($1)); |
261
|
10
|
|
|
|
|
14
|
lex_read_space; |
262
|
10
|
|
|
|
|
22
|
my ($name, undef, $args) = parse_trait; |
263
|
10
|
|
|
|
|
40
|
$self->traits->{$name} = $args; |
264
|
10
|
|
|
|
|
35
|
lex_read_space; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
188
|
|
|
|
|
357
|
(); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub parse_attributes |
271
|
|
|
|
|
|
|
{ |
272
|
193
|
|
|
193
|
1
|
249
|
my $self = shift; |
273
|
193
|
|
|
|
|
247
|
lex_read_space; |
274
|
|
|
|
|
|
|
|
275
|
193
|
0
|
|
|
|
410
|
if (lex_peek eq ':') |
276
|
|
|
|
|
|
|
{ |
277
|
7
|
|
|
|
|
17
|
lex_read(1); |
278
|
7
|
|
|
|
|
10
|
lex_read_space; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
else |
281
|
|
|
|
|
|
|
{ |
282
|
186
|
|
|
|
|
541
|
return; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
7
|
|
|
|
|
27
|
while (lex_peek(4) =~ /\A([^\W0-9]\w+)/) |
286
|
|
|
|
|
|
|
{ |
287
|
7
|
|
|
|
|
27
|
my $parsed = [parse_trait]; |
288
|
7
|
|
|
|
|
15
|
lex_read_space; |
289
|
|
|
|
|
|
|
|
290
|
7
|
100
|
|
|
|
18
|
if ($parsed->[0] eq 'prototype') |
291
|
|
|
|
|
|
|
{ |
292
|
3
|
|
|
|
|
6
|
$self->_set_prototype($parsed->[1]); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
else |
295
|
|
|
|
|
|
|
{ |
296
|
4
|
|
|
|
|
4
|
push @{$self->attributes}, $parsed; |
|
4
|
|
|
|
|
13
|
|
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
7
|
0
|
|
|
|
18
|
if (lex_peek eq ':') |
300
|
|
|
|
|
|
|
{ |
301
|
0
|
|
|
|
|
0
|
lex_read(1); |
302
|
0
|
|
|
|
|
0
|
lex_read_space; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
7
|
|
|
|
|
46
|
(); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub _build__tmp_name |
310
|
|
|
|
|
|
|
{ |
311
|
164
|
|
|
164
|
|
3578
|
state $i = 0; |
312
|
164
|
|
|
|
|
729
|
"Kavorka::Temp::f" . ++$i; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub parse_body |
316
|
|
|
|
|
|
|
{ |
317
|
188
|
|
|
188
|
1
|
185
|
my $self = shift; |
318
|
|
|
|
|
|
|
|
319
|
188
|
|
|
|
|
266
|
lex_read_space; |
320
|
188
|
0
|
|
|
|
415
|
lex_peek(1) eq '{' or croak("expected block!"); |
321
|
188
|
|
|
|
|
453
|
lex_read(1); |
322
|
|
|
|
|
|
|
|
323
|
188
|
100
|
|
|
|
328
|
if ($self->is_anonymous) |
324
|
|
|
|
|
|
|
{ |
325
|
23
|
|
|
|
|
42
|
lex_stuff(sprintf("{ %s", $self->inject_prelude)); |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Parse the actual code |
328
|
23
|
0
|
|
|
|
1670
|
my $code = parse_block(0) or Carp::croak("cannot parse block!"); |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Set up prototype |
331
|
23
|
|
|
|
|
296
|
&Scalar::Util::set_prototype($code, $self->prototype); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# Fix sub name |
334
|
23
|
|
|
|
|
140
|
$code = Sub::Util::set_subname(join('::', $self->package, '__ANON__'), $code); |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# Set up attributes - this doesn't much work |
337
|
23
|
|
|
|
|
57
|
my $attrs = $self->attributes; |
338
|
23
|
100
|
|
|
|
584
|
if (@$attrs) |
339
|
|
|
|
|
|
|
{ |
340
|
7
|
|
|
|
|
668
|
require attributes; |
341
|
38
|
|
|
38
|
|
199
|
no warnings; |
|
38
|
|
|
|
|
58
|
|
|
38
|
|
|
|
|
6812
|
|
342
|
7
|
|
|
|
|
1084
|
attributes->import( |
343
|
|
|
|
|
|
|
$self->package, |
344
|
|
|
|
|
|
|
$code, |
345
|
|
|
|
|
|
|
map($_->[0], @$attrs), |
346
|
|
|
|
|
|
|
); |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# And keep the coderef |
350
|
23
|
|
|
|
|
406
|
$self->_set_body($code); |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
else |
353
|
|
|
|
|
|
|
{ |
354
|
165
|
|
|
|
|
174
|
state $i = 0; |
355
|
|
|
|
|
|
|
|
356
|
165
|
|
|
|
|
159
|
my $lex = ''; |
357
|
165
|
100
|
|
|
|
257
|
if ($self->is_lexical) |
358
|
|
|
|
|
|
|
{ |
359
|
4
|
|
|
|
|
13
|
$lex = sprintf( |
360
|
|
|
|
|
|
|
'&Internals::SvREADONLY(\\(my %s = \&%s), 1);', |
361
|
|
|
|
|
|
|
$self->declared_name, |
362
|
|
|
|
|
|
|
$self->_tmp_name, |
363
|
|
|
|
|
|
|
); |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# Here instead of parsing the body we'll leave it to plain old |
367
|
|
|
|
|
|
|
# Perl. We'll pick it up later from this name in _post_parse |
368
|
|
|
|
|
|
|
lex_stuff( |
369
|
165
|
|
|
|
|
427
|
sprintf( |
370
|
|
|
|
|
|
|
"%s sub %s %s { no warnings 'closure'; %s", |
371
|
|
|
|
|
|
|
$lex, |
372
|
|
|
|
|
|
|
$self->_tmp_name, |
373
|
|
|
|
|
|
|
$self->inject_attributes, |
374
|
|
|
|
|
|
|
$self->inject_prelude, |
375
|
|
|
|
|
|
|
) |
376
|
|
|
|
|
|
|
); |
377
|
165
|
|
|
|
|
539
|
$self->{argh} = $self->_tmp_name; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
188
|
|
|
|
|
4031
|
(); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _post_parse |
384
|
|
|
|
|
|
|
{ |
385
|
196
|
|
|
196
|
|
191
|
my $self = shift; |
386
|
|
|
|
|
|
|
|
387
|
196
|
100
|
|
|
|
2630
|
if ($self->{argh}) |
388
|
|
|
|
|
|
|
{ |
389
|
38
|
|
|
38
|
|
169
|
no strict 'refs'; |
|
38
|
|
|
|
|
54
|
|
|
38
|
|
|
|
|
21119
|
|
390
|
167
|
100
|
|
|
|
349
|
my $code = $self->is_lexical ? \&{$self->{argh}} : \&{ delete $self->{argh} }; |
|
6
|
|
|
|
|
22
|
|
|
161
|
|
|
|
|
601
|
|
391
|
167
|
100
|
66
|
|
|
407
|
Sub::Util::set_subname( |
392
|
|
|
|
|
|
|
$self->is_anonymous || $self->is_lexical |
393
|
|
|
|
|
|
|
? join('::', $self->package, '__ANON__') |
394
|
|
|
|
|
|
|
: $self->qualified_name, |
395
|
|
|
|
|
|
|
$code, |
396
|
|
|
|
|
|
|
); |
397
|
167
|
|
|
|
|
722
|
&Scalar::Util::set_prototype($code, $self->prototype); |
398
|
167
|
|
|
|
|
371
|
$self->_set_body($code); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
196
|
|
|
|
|
360
|
$self->_apply_return_types; |
402
|
|
|
|
|
|
|
|
403
|
196
|
100
|
100
|
|
|
1226
|
$self->_set_signature(undef) |
404
|
|
|
|
|
|
|
if $self->signature && $self->signature->_is_dummy; |
405
|
|
|
|
|
|
|
|
406
|
196
|
|
|
|
|
273
|
(); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub _apply_return_types |
410
|
|
|
|
|
|
|
{ |
411
|
196
|
|
|
196
|
|
202
|
my $self = shift; |
412
|
|
|
|
|
|
|
|
413
|
196
|
100
|
|
|
|
169
|
my @rt = @{ $self->signature ? $self->signature->return_types : [] }; |
|
196
|
|
|
|
|
1070
|
|
414
|
|
|
|
|
|
|
|
415
|
196
|
100
|
|
|
|
418
|
if (@rt) |
416
|
|
|
|
|
|
|
{ |
417
|
3
|
|
|
|
|
18
|
my @scalar = grep !$_->list, @rt; |
418
|
3
|
|
|
|
|
11
|
my @list = grep $_->list, @rt; |
419
|
|
|
|
|
|
|
|
420
|
3
|
50
|
|
|
|
17
|
my $scalar = |
|
|
50
|
|
|
|
|
|
421
|
|
|
|
|
|
|
(@scalar == 0) ? undef : |
422
|
|
|
|
|
|
|
(@scalar == 1) ? $scalar[0] : |
423
|
|
|
|
|
|
|
croak("Multiple scalar context return types specified for function"); |
424
|
|
|
|
|
|
|
|
425
|
3
|
50
|
|
|
|
9
|
my $list = |
|
|
100
|
|
|
|
|
|
426
|
|
|
|
|
|
|
(@list == 0) ? undef : |
427
|
|
|
|
|
|
|
(@list == 1) ? $list[0] : |
428
|
|
|
|
|
|
|
croak("Multiple list context return types specified for function"); |
429
|
|
|
|
|
|
|
|
430
|
3
|
0
|
33
|
|
|
21
|
return if (!$scalar || $scalar->assumed) && (!$list || $list->assumed); |
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
431
|
|
|
|
|
|
|
|
432
|
3
|
|
|
|
|
763
|
require Return::Type; |
433
|
3
|
50
|
|
|
|
9352
|
my $wrapped = Return::Type->wrap_sub( |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
434
|
|
|
|
|
|
|
$self->body, |
435
|
|
|
|
|
|
|
scalar => ($scalar ? $scalar->_effective_type : undef), |
436
|
|
|
|
|
|
|
list => ($list ? $list->_effective_type : undef), |
437
|
|
|
|
|
|
|
coerce_scalar => ($scalar ? $scalar->coerce : 0), |
438
|
|
|
|
|
|
|
coerce_list => ($list ? $list->coerce : $scalar ? $scalar->coerce : 0), |
439
|
|
|
|
|
|
|
); |
440
|
3
|
|
|
|
|
10109
|
$self->_set__unwrapped_body($self->body); |
441
|
3
|
|
|
|
|
11
|
$self->_set_body($wrapped); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
196
|
|
|
|
|
217
|
(); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
sub _build__pads_to_poke |
448
|
|
|
|
|
|
|
{ |
449
|
179
|
|
|
179
|
|
5267
|
my $self = shift; |
450
|
|
|
|
|
|
|
|
451
|
179
|
|
66
|
|
|
929
|
my @pads = $self->_unwrapped_body // $self->body; |
452
|
|
|
|
|
|
|
|
453
|
179
|
100
|
|
|
|
172
|
for my $param (@{ $self->signature ? $self->signature->params : [] }) |
|
179
|
|
|
|
|
752
|
|
454
|
|
|
|
|
|
|
{ |
455
|
244
|
100
|
|
|
|
832
|
push @pads, $param->default if $param->default; |
456
|
244
|
|
|
|
|
199
|
push @pads, @{ $param->constraints }; |
|
244
|
|
|
|
|
530
|
|
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
179
|
|
|
|
|
529
|
\@pads; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub _poke_pads |
463
|
|
|
|
|
|
|
{ |
464
|
213
|
|
|
213
|
|
224
|
my $self = shift; |
465
|
213
|
|
|
|
|
227
|
my ($vars) = @_; |
466
|
|
|
|
|
|
|
|
467
|
213
|
|
|
|
|
174
|
for my $code (@{$self->_pads_to_poke}) |
|
213
|
|
|
|
|
560
|
|
468
|
|
|
|
|
|
|
{ |
469
|
239
|
|
|
|
|
1493
|
my $closed_over = PadWalker::closed_over($code); |
470
|
|
|
|
|
|
|
ref($vars->{$_}) && ($closed_over->{$_} = $vars->{$_}) |
471
|
239
|
|
66
|
|
|
576
|
for keys %$closed_over; |
472
|
239
|
|
|
|
|
540
|
PadWalker::set_closed_over($code, $closed_over); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
213
|
|
|
|
|
370
|
(); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
1; |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
__END__ |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=pod |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=encoding utf-8 |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=for stopwords invocant invocants lexicals unintuitive |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=head1 NAME |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
Kavorka::Sub - a function that has been declared |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head1 DESCRIPTION |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
Kavorka::Sub is a role which represents a function declared using |
495
|
|
|
|
|
|
|
L<Kavorka>. Classes implementing this role are used to parse functions, |
496
|
|
|
|
|
|
|
and also to inject Perl code into them. |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
Instances of classes implementing this role are also returned by |
499
|
|
|
|
|
|
|
Kavorka's function introspection API. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=head2 Introspection API |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
A function instance has the following methods. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=over |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=item C<keyword> |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
The keyword (e.g. C<method>) used to declare the function. |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=item C<package> |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
Returns the package name the parameter was declared in. Not necessarily |
514
|
|
|
|
|
|
|
the package it will be installed into... |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
package Foo; |
517
|
|
|
|
|
|
|
fun UNIVERSAL::quux { ... } # will be installed into UNIVERSAL |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=item C<is_anonymous> |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
Returns a boolean indicating whether this is an anonymous coderef. |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=item C<declared_name> |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
The declared name of the function (if any). |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=item C<qualified_name> |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
The name the function will be installed as, based on the package and |
530
|
|
|
|
|
|
|
declared name. |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=item C<signature> |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
An instance of L<Kavorka::Signature>, or undef. |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=item C<traits> |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
A hashref of traits. |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=item C<prototype> |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
The function prototype as a string. |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=item C<attributes> |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
The function attributes. The structure returned by this method is |
547
|
|
|
|
|
|
|
subject to change. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=item C<body> |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
The function body as a coderef. Note that this coderef I<will> have had |
552
|
|
|
|
|
|
|
the signature code injected into it. |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=back |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=head2 Other Methods |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
=over |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=item C<parse>, |
561
|
|
|
|
|
|
|
C<parse_subname>, |
562
|
|
|
|
|
|
|
C<parse_signature>, |
563
|
|
|
|
|
|
|
C<parse_traits>, |
564
|
|
|
|
|
|
|
C<parse_prototype>, |
565
|
|
|
|
|
|
|
C<parse_attributes>, |
566
|
|
|
|
|
|
|
C<parse_body> |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
Internal methods used to parse a subroutine. It only makes sense to call |
569
|
|
|
|
|
|
|
these from a L<Parse::Keyword> parser, but may make sense to override |
570
|
|
|
|
|
|
|
them in classes consuming the Kavorka::Sub role. |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
=item C<allow_anonymous> |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
Returns a boolean indicating whether this keyword allows functions to be |
575
|
|
|
|
|
|
|
anonymous. |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
The implementation defined in this role returns true. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=item C<signature_class> |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
A class to use for signatures. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=item C<default_attributes> |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
Returns a list of attributes to add to the sub when it is parsed. |
586
|
|
|
|
|
|
|
It would make sense to override this in classes implementing this role, |
587
|
|
|
|
|
|
|
however attributes don't currently work properly anyway. |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
The implementation defined in this role returns the empty list. |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=item C<default_invocant> |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
Returns a list invocant parameters to add to the signature if no |
594
|
|
|
|
|
|
|
invocants are specified in the signature. It makes sense to override |
595
|
|
|
|
|
|
|
this for keywords which have implicit invocants, such as C<method>. |
596
|
|
|
|
|
|
|
(See L<Kavorka::Sub::Method> for an example.) |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
The implementation defined in this role returns the empty list. |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
=item C<forward_declare_sub> |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
Method called at compile time to forward-declare the sub, if that |
603
|
|
|
|
|
|
|
behaviour is desired. |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
The implementation defined in this role does nothing, but |
606
|
|
|
|
|
|
|
L<Kavorka::Sub::Fun> actually does some forward declaration. |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=item C<install_sub> |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
Method called at run time to install the sub into the symbol table. |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
This makes sense to override if the sub shouldn't be installed in the |
613
|
|
|
|
|
|
|
normal Perlish way. For example L<Kavorka::MethodModifier> overrides |
614
|
|
|
|
|
|
|
it. |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=item C<invocation_style> |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Returns a string "fun" or "method" depending on whether subs are |
619
|
|
|
|
|
|
|
expected to be invoked as functions or methods. May return undef if |
620
|
|
|
|
|
|
|
neither is really the case (e.g. as with method modifiers). |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=item C<inject_attributes> |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
Returns a string of Perl code along the lines of ":foo :bar(1)" which |
625
|
|
|
|
|
|
|
is injected into the Perl token stream to be parsed as the sub's |
626
|
|
|
|
|
|
|
attributes. (Only used for named subs.) |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=item C<inject_prelude> |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Returns a string of Perl code to inject into the body of the sub. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=item C<bypass_custom_parsing> |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
A I<class method> that is called when people attempt to use the |
635
|
|
|
|
|
|
|
keyword while bypassing the Perl keyword API's custom parsing. |
636
|
|
|
|
|
|
|
Examples of how they can do that are: |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
use Kavorka 'method'; |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
&method(...); |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
__PACKAGE__->can("method")->(...); |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
The default implementation of C<bypass_custom_parsing> is to croak, |
645
|
|
|
|
|
|
|
but this can be overridden in cases where it may be possible to do |
646
|
|
|
|
|
|
|
something useful. (L<Kavorka::MethodModifier> does this.) |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
It is passed the name of the keyword, the name of the package that |
649
|
|
|
|
|
|
|
the keyword was installed into, and an arrayref representing C<< @_ >>. |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=back |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=head1 BUGS |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
Please report any bugs to |
656
|
|
|
|
|
|
|
L<http://rt.cpan.org/Dist/Display.html?Queue=Kavorka>. |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=head1 SEE ALSO |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
L<Kavorka::Manual::API>, |
661
|
|
|
|
|
|
|
L<Kavorka::Signature>. |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=head1 AUTHOR |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
Toby Inkster E<lt>tobyink@cpan.orgE<gt>. |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENCE |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
This software is copyright (c) 2013-2014, 2017 by Toby Inkster. |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
672
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=head1 DISCLAIMER OF WARRANTIES |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
677
|
|
|
|
|
|
|
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
678
|
|
|
|
|
|
|
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
679
|
|
|
|
|
|
|
|