File Coverage

blib/lib/Kavorka/Sub.pm
Criterion Covered Total %
statement 232 244 95.0
branch 61 90 67.7
condition 15 31 48.3
subroutine 40 48 83.3
pod 17 19 89.4
total 365 432 84.4


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