Version 0.006005
[p5sagit/Devel-Declare.git] / lib / Devel / Declare.pm
CommitLineData
94caac6e 1package Devel::Declare;
2
3use strict;
4use warnings;
5use 5.008001;
6
5c82d547 7our $VERSION = '0.006005';
0ba8c7aa 8
9use constant DECLARE_NAME => 1;
10use constant DECLARE_PROTO => 2;
53e3ab32 11use constant DECLARE_NONE => 4;
15d0d014 12use constant DECLARE_PACKAGE => 8+1; # name implicit
0ba8c7aa 13
86c3de80 14use vars qw(%declarators %declarator_handlers @ISA);
94caac6e 15use base qw(DynaLoader);
323ae557 16use Scalar::Util 'set_prototype';
b15aa864 17use B::Hooks::OP::Check;
94caac6e 18
19bootstrap Devel::Declare;
20
86c3de80 21@ISA = ();
22
94caac6e 23sub import {
0ba8c7aa 24 my ($class, %args) = @_;
94caac6e 25 my $target = caller;
0ba8c7aa 26 if (@_ == 1) { # "use Devel::Declare;"
27 no strict 'refs';
15d0d014 28 foreach my $name (qw(NAME PROTO NONE PACKAGE)) {
53e3ab32 29 *{"${target}::DECLARE_${name}"} = *{"DECLARE_${name}"};
0ba8c7aa 30 }
31 } else {
32 $class->setup_for($target => \%args);
33 }
94caac6e 34}
35
36sub unimport {
37 my ($class) = @_;
38 my $target = caller;
39 $class->teardown_for($target);
40}
41
42sub setup_for {
43 my ($class, $target, $args) = @_;
44 setup();
0ba8c7aa 45 foreach my $key (keys %$args) {
46 my $info = $args->{$key};
47 my ($flags, $sub);
48 if (ref($info) eq 'ARRAY') {
49 ($flags, $sub) = @$info;
50 } elsif (ref($info) eq 'CODE') {
51 $flags = DECLARE_NAME;
52 $sub = $info;
840ebcbb 53 } elsif (ref($info) eq 'HASH') {
54 $flags = 1;
55 $sub = $info;
0ba8c7aa 56 } else {
840ebcbb 57 die "Info for sub ${key} must be [ \$flags, \$sub ] or \$sub or handler hashref";
0ba8c7aa 58 }
59 $declarators{$target}{$key} = $flags;
60 $declarator_handlers{$target}{$key} = $sub;
61 }
94caac6e 62}
63
64sub teardown_for {
65 my ($class, $target) = @_;
66 delete $declarators{$target};
0ba8c7aa 67 delete $declarator_handlers{$target};
94caac6e 68}
69
94caac6e 70my $temp_name;
0ba8c7aa 71my $temp_save;
94caac6e 72
73sub init_declare {
0f070758 74 my ($usepack, $use, $inpack, $name, $proto, $traits) = @_;
53e3ab32 75 my ($name_h, $XX_h, $extra_code)
9026391e 76 = $declarator_handlers{$usepack}{$use}->(
0f070758 77 $usepack, $use, $inpack, $name, $proto, defined(wantarray), $traits
53e3ab32 78 );
15d0d014 79 ($temp_name, $temp_save) = ([], []);
0ba8c7aa 80 if ($name) {
9026391e 81 $name = "${inpack}::${name}" unless $name =~ /::/;
840ebcbb 82 shadow_sub($name, $name_h);
0ba8c7aa 83 }
84 if ($XX_h) {
840ebcbb 85 shadow_sub("${inpack}::X", $XX_h);
0ba8c7aa 86 }
53e3ab32 87 if (defined wantarray) {
88 return $extra_code || '0;';
89 } else {
90 return;
91 }
94caac6e 92}
93
840ebcbb 94sub shadow_sub {
95 my ($name, $cr) = @_;
96 push(@$temp_name, $name);
97 no strict 'refs';
98 my ($pack, $pname) = ($name =~ m/(.+)::([^:]+)/);
99 push(@$temp_save, $pack->can($pname));
840ebcbb 100 no warnings 'redefine';
101 no warnings 'prototype';
102 *{$name} = $cr;
103 set_in_declare(~~@{$temp_name||[]});
104}
105
94caac6e 106sub done_declare {
107 no strict 'refs';
86c3de80 108 my $name = shift(@{$temp_name||[]});
0ba8c7aa 109 die "done_declare called with no temp_name stack" unless defined($name);
86c3de80 110 my $saved = shift(@$temp_save);
15d0d014 111 $name =~ s/(.*):://;
112 my $temp_pack = $1;
0ba8c7aa 113 delete ${"${temp_pack}::"}{$name};
114 if ($saved) {
115 no warnings 'prototype';
116 *{"${temp_pack}::${name}"} = $saved;
117 }
840ebcbb 118 set_in_declare(~~@{$temp_name||[]});
94caac6e 119}
120
323ae557 121sub build_sub_installer {
122 my ($class, $pack, $name, $proto) = @_;
123 return eval "
124 package ${pack};
125 my \$body;
126 sub ${name} (${proto}) :lvalue {\n"
003ac394 127 .' if (wantarray) {
c5912dc7 128 goto &$body;
003ac394 129 }
130 my $ret = $body->(@_);
86c3de80 131 return $ret;
323ae557 132 };
133 sub { ($body) = @_; };';
134}
135
136sub setup_declarators {
137 my ($class, $pack, $to_setup) = @_;
86c3de80 138 die "${class}->setup_declarators(\$pack, \\\%to_setup)"
139 unless defined($pack) && ref($to_setup) eq 'HASH';
140 my %setup_for_args;
323ae557 141 foreach my $name (keys %$to_setup) {
142 my $info = $to_setup->{$name};
143 my $flags = $info->{flags} || DECLARE_NAME;
144 my $run = $info->{run};
145 my $compile = $info->{compile};
146 my $proto = $info->{proto} || '&';
147 my $sub_proto = $proto;
148 # make all args optional to enable lvalue for DECLARE_NONE
149 $sub_proto =~ s/;//; $sub_proto = ';'.$sub_proto;
86c3de80 150 #my $installer = $class->build_sub_installer($pack, $name, $proto);
151 my $installer = $class->build_sub_installer($pack, $name, '@');
86c3de80 152 $installer->(sub :lvalue {
003ac394 153#{ no warnings 'uninitialized'; warn 'INST: '.join(', ', @_)."\n"; }
c5534496 154 if (@_) {
155 if (ref $_[0] eq 'HASH') {
156 shift;
003ac394 157 if (wantarray) {
158 my @ret = $run->(undef, undef, @_);
159 return @ret;
160 }
c5534496 161 my $r = $run->(undef, undef, @_);
162 return $r;
163 } else {
003ac394 164 return @_[1..$#_];
c5534496 165 }
86c3de80 166 }
167 return my $sv;
168 });
169 $setup_for_args{$name} = [
170 $flags,
171 sub {
0f070758 172 my ($usepack, $use, $inpack, $name, $proto, $shift_hashref, $traits) = @_;
173 my $extra_code = $compile->($name, $proto, $traits);
003ac394 174 my $main_handler = sub { shift if $shift_hashref;
c5534496 175 ("DONE", $run->($name, $proto, @_));
003ac394 176 };
86c3de80 177 my ($name_h, $XX);
178 if (defined $proto) {
179 $name_h = sub :lvalue { return my $sv; };
180 $XX = $main_handler;
c5534496 181 } elsif (defined $name && length $name) {
86c3de80 182 $name_h = $main_handler;
183 }
003ac394 184 $extra_code ||= '';
185 $extra_code = '}, sub {'.$extra_code;
86c3de80 186 return ($name_h, $XX, $extra_code);
187 }
188 ];
323ae557 189 }
86c3de80 190 $class->setup_for($pack, \%setup_for_args);
191}
192
193sub install_declarator {
194 my ($class, $target_pack, $target_name, $flags, $filter, $handler) = @_;
195 $class->setup_declarators($target_pack, {
196 $target_name => {
197 flags => $flags,
198 compile => $filter,
199 run => $handler,
200 }
201 });
323ae557 202}
203
04a8a223 204sub linestr_callback_rv2cv {
205 my ($name, $offset) = @_;
206 $offset += toke_move_past_token($offset);
207 my $pack = get_curstash_name();
208 my $flags = $declarators{$pack}{$name};
209 my ($found_name, $found_proto);
04a8a223 210 if ($flags & DECLARE_NAME) {
211 $offset += toke_skipspace($offset);
212 my $linestr = get_linestr();
213 if (substr($linestr, $offset, 2) eq '::') {
214 substr($linestr, $offset, 2) = '';
215 set_linestr($linestr);
216 }
217 if (my $len = toke_scan_word($offset, $flags & DECLARE_PACKAGE)) {
218 $found_name = substr($linestr, $offset, $len);
219 $offset += $len;
04a8a223 220 }
221 }
222 if ($flags & DECLARE_PROTO) {
223 $offset += toke_skipspace($offset);
224 my $linestr = get_linestr();
225 if (substr($linestr, $offset, 1) eq '(') {
226 my $length = toke_scan_str($offset);
227 $found_proto = get_lex_stuff();
228 clear_lex_stuff();
229 my $replace =
230 ($found_name ? ' ' : '=')
231 .'X'.(' ' x length($found_proto));
232 $linestr = get_linestr();
233 substr($linestr, $offset, $length) = $replace;
234 set_linestr($linestr);
235 $offset += $length;
04a8a223 236 }
237 }
238 my @args = ($pack, $name, $pack, $found_name, $found_proto);
04a8a223 239 $offset += toke_skipspace($offset);
240 my $linestr = get_linestr();
241 if (substr($linestr, $offset, 1) eq '{') {
242 my $ret = init_declare(@args);
243 $offset++;
244 if (defined $ret && length $ret) {
245 substr($linestr, $offset, 0) = $ret;
246 set_linestr($linestr);
247 }
248 } else {
249 init_declare(@args);
250 }
251 #warn "linestr now ${linestr}";
252}
253
569ac469 254sub linestr_callback_const {
04a8a223 255 my ($name, $offset) = @_;
256 my $pack = get_curstash_name();
257 my $flags = $declarators{$pack}{$name};
258 if ($flags & DECLARE_NAME) {
259 $offset += toke_move_past_token($offset);
260 $offset += toke_skipspace($offset);
261 if (toke_scan_word($offset, $flags & DECLARE_PACKAGE)) {
262 my $linestr = get_linestr();
263 substr($linestr, $offset, 0) = '::';
264 set_linestr($linestr);
265 }
266 }
569ac469 267}
268
269sub linestr_callback {
270 my $type = shift;
840ebcbb 271 my $name = $_[0];
272 my $pack = get_curstash_name();
273 my $handlers = $declarator_handlers{$pack}{$name};
274 if (ref $handlers eq 'CODE') {
275 my $meth = "linestr_callback_${type}";
276 __PACKAGE__->can($meth)->(@_);
277 } elsif (ref $handlers eq 'HASH') {
278 if ($handlers->{$type}) {
279 $handlers->{$type}->(@_);
280 }
281 } else {
282 die "PANIC: unknown thing in handlers for $pack $name: $handlers";
283 }
569ac469 284}
285
94caac6e 286=head1 NAME
287
7e31b6e3 288Devel::Declare - Adding keywords to perl, in perl
94caac6e 289
290=head1 SYNOPSIS
291
1795217c 292 use Method::Signatures;
293 # or ...
294 use MooseX::Declare;
295 # etc.
296
297 # Use some new and exciting syntax like:
298 method hello (Str :$who, Int :$age where { $_ > 0 }) {
299 $self->say("Hello ${who}, I am ${age} years old!");
300 }
301
302=head1 DESCRIPTION
303
304L<Devel::Declare> can install subroutines called declarators which locally take
305over Perl's parser, allowing the creation of new syntax.
306
307This document describes how to create a simple declarator.
308
309=head1 USAGE
310
311We'll demonstrate the usage of C<Devel::Declare> with a motivating example: a new
312C<method> keyword, which acts like the builtin C<sub>, but automatically unpacks
313C<$self> and the other arguments.
314
315 package My::Methods;
316 use Devel::Declare;
317
318=head2 Creating a declarator with C<setup_for>
319
320You will typically create
321
322 sub import {
323 my $class = shift;
324 my $caller = caller;
325
326 Devel::Declare->setup_for(
327 $caller,
328 { method => { const => \&parser } }
329 );
330 no strict 'refs';
331 *{$caller.'::method'} = sub (&) {};
332 }
333
334Starting from the end of this import routine, you'll see that we're creating a
335subroutine called C<method> in the caller's namespace. Yes, that's just a normal
336subroutine, and it does nothing at all (yet!) Note the prototype C<(&)> which means
337that the caller would call it like so:
338
339 method {
340 my ($self, $arg1, $arg2) = @_;
341 ...
342 }
343
344However we want to be able to call it like this
345
346 method foo ($arg1, $arg2) {
347 ...
348 }
349
350That's why we call C<setup_for> above, to register the declarator 'method' with a custom
351parser, as per the next section. It acts on an optype, usually C<'const'> as above.
352(Other valid values are C<'check'> and C<'rv2cv'>).
353
354For a simpler way to install new methods, see also L<Devel::Declare::MethodInstaller::Simple>
355
356=head2 Writing a parser subroutine
357
358This subroutine is called at I<compilation> time, and allows you to read the custom
359syntaxes that we want (in a syntax that may or may not be valid core Perl 5) and
360munge it so that the result will be parsed by the C<perl> compiler.
361
362For this example, we're defining some globals for convenience:
363
2ee34f20 364 our ($Declarator, $Offset);
1795217c 365
366Then we define a parser subroutine to handle our declarator. We'll look at this in
367a few chunks.
368
369 sub parser {
370 local ($Declarator, $Offset) = @_;
371
372C<Devel::Declare> provides some very low level utility methods to parse character
373strings. We'll define some useful higher level routines below for convenience,
374and we can use these to parse the various elements in our new syntax.
375
376Notice how our parser subroutine is invoked at compile time,
377when the C<perl> parser is pointed just I<before> the declarator name.
378
379 skip_declarator; # step past 'method'
380 my $name = strip_name; # strip out the name 'foo', if present
381 my $proto = strip_proto; # strip out the prototype '($arg1, $arg2)', if present
382
383Now we can prepare some code to 'inject' into the new subroutine. For example we
384might want the method as above to have C<my ($self, $arg1, $arg2) = @_> injected at
385the beginning of it. We also do some clever stuff with scopes that we'll look
386at shortly.
387
388 my $inject = make_proto_unwrap($proto);
389 if (defined $name) {
390 $inject = scope_injector_call().$inject;
391 }
392 inject_if_block($inject);
393
394We've now managed to change C<method ($arg1, $arg2) { ... }> into C<method {
395injected_code; ... }>. This will compile... but we've lost the name of the
396method!
397
398In a cute (or horrifying, depending on your perspective) trick, we temporarily
399change the definition of the subroutine C<method> itself, to specialise it with
400the C<$name> we stripped, so that it assigns the code block to that name.
401
402Even though the I<next> time C<method> is compiled, it will be
403redefined again, C<perl> caches these definitions in its parse
404tree, so we'll always get the right one!
405
406Note that we also handle the case where there was no name, allowing
407an anonymous method analogous to an anonymous subroutine.
408
409 if (defined $name) {
410 $name = join('::', Devel::Declare::get_curstash_name(), $name)
411 unless ($name =~ /::/);
412 shadow(sub (&) { no strict 'refs'; *{$name} = shift; });
413 } else {
414 shadow(sub (&) { shift });
415 }
416 }
417
418
419=head2 Parser utilities in detail
420
421For simplicity, we're using global variables like C<$Offset> in these examples.
422You may prefer to look at L<Devel::Declare::Context::Simple>, which
423encapsulates the context much more cleanly.
424
425=head3 C<skip_declarator>
426
427This simple parser just moves across a 'token'. The common case is
428to skip the declarator, i.e. to move to the end of the string
429'method' and before the prototype and code block.
430
2ee34f20 431 sub skip_declarator {
432 $Offset += Devel::Declare::toke_move_past_token($Offset);
433 }
1795217c 434
435=head4 C<toke_move_past_token>
436
437This builtin parser simply moves past a 'token' (matching C</[a-zA-Z_]\w*/>)
438It takes an offset into the source document, and skips past the token.
439It returns the number of characters skipped.
440
441=head3 C<strip_name>
442
443This parser skips any whitespace, then scans the next word (again matching a
444'token'). We can then analyse the current line, and manipulate it (using pure
445Perl). In this case we take the name of the method out, and return it.
446
2ee34f20 447 sub strip_name {
448 skipspace;
449 if (my $len = Devel::Declare::toke_scan_word($Offset, 1)) {
450 my $linestr = Devel::Declare::get_linestr();
451 my $name = substr($linestr, $Offset, $len);
452 substr($linestr, $Offset, $len) = '';
453 Devel::Declare::set_linestr($linestr);
454 return $name;
455 }
456 return;
457 }
1795217c 458
459=head4 C<toke_scan_word>
460
461This builtin parser, given an offset into the source document,
462matches a 'token' as above but does not skip. It returns the
463length of the token matched, if any.
464
465=head4 C<get_linestr>
466
467This builtin returns the full text of the current line of the source document.
468
469=head4 C<set_linestr>
470
471This builtin sets the full text of the current line of the source document.
472
473=head3 C<skipspace>
474
475This parser skips whitsepace.
476
477 sub skipspace {
478 $Offset += Devel::Declare::toke_skipspace($Offset);
479 }
480
481=head4 C<toke_skipspace>
482
483This builtin parser, given an offset into the source document,
484skips over any whitespace, and returns the number of characters
485skipped.
486
487=head3 C<strip_proto>
488
489This is a more complex parser that checks if it's found something that
490starts with C<'('> and returns everything till the matching C<')'>.
491
2ee34f20 492 sub strip_proto {
493 skipspace;
1795217c 494
2ee34f20 495 my $linestr = Devel::Declare::get_linestr();
496 if (substr($linestr, $Offset, 1) eq '(') {
497 my $length = Devel::Declare::toke_scan_str($Offset);
498 my $proto = Devel::Declare::get_lex_stuff();
499 Devel::Declare::clear_lex_stuff();
500 $linestr = Devel::Declare::get_linestr();
501 substr($linestr, $Offset, $length) = '';
502 Devel::Declare::set_linestr($linestr);
503 return $proto;
504 }
505 return;
506 }
1795217c 507
508=head4 C<toke_scan_str>
509
510This builtin parser uses Perl's own parsing routines to match a "stringlike"
511expression. Handily, this includes bracketed expressions (just think about
512things like C<q(this is a quote)>).
513
514Also it Does The Right Thing with nested delimiters (like C<q(this (is (a) quote))>).
515
516It returns the length of the expression matched. Use C<get_lex_stuff> to
517get the actual matched text.
518
519=head4 C<get_lex_stuff>
520
521This builtin returns what was matched by C<toke_scan_str>. To avoid segfaults,
522you should call C<clear_lex_stuff> immediately afterwards.
523
524=head2 Munging the subroutine
525
526Let's look at what we need to do in detail.
527
528=head3 C<make_proto_unwrap>
529
530We may have defined our method in different ways, which will result
531in a different value for our prototype, as parsed above. For example:
532
533 method foo { # undefined
534 method foo () { # ''
535 method foo ($arg1) { # '$arg1'
536
537We deal with them as follows, and return the appropriate C<my ($self, ...) = @_;>
538string.
539
2ee34f20 540 sub make_proto_unwrap {
541 my ($proto) = @_;
542 my $inject = 'my ($self';
543 if (defined $proto) {
544 $inject .= ", $proto" if length($proto);
545 $inject .= ') = @_; ';
546 } else {
547 $inject .= ') = shift;';
548 }
549 return $inject;
550 }
1795217c 551
552=head3 C<inject_if_block>
553
554Now we need to inject it after the opening C<'{'> of the method body.
555We can do this with the building blocks we defined above like C<skipspace>
556and C<get_linestr>.
557
2ee34f20 558 sub inject_if_block {
559 my $inject = shift;
560 skipspace;
561 my $linestr = Devel::Declare::get_linestr;
562 if (substr($linestr, $Offset, 1) eq '{') {
563 substr($linestr, $Offset+1, 0) = $inject;
564 Devel::Declare::set_linestr($linestr);
565 }
566 }
94caac6e 567
1795217c 568=head3 C<scope_injector_call>
569
570We want to be able to handle both named and anonymous methods. i.e.
571
572 method foo () { ... }
573 my $meth = method () { ... };
574
575These will then get rewritten as
576
577 method { ... }
578 my $meth = method { ... };
579
580where 'method' is a subroutine that takes a code block. Spot the problem?
581The first one doesn't have a semicolon at the end of it! Unlike 'sub' which
582is a builtin, this is just a normal statement, so we need to terminate it.
6c1cecd4 583Luckily, using C<B::Hooks::EndOfScope>, we can do this!
1795217c 584
6c1cecd4 585 use B::Hooks::EndOfScope;
1795217c 586
587We'll add this to what gets 'injected' at the beginning of the method source.
588
589 sub scope_injector_call {
590 return ' BEGIN { MethodHandlers::inject_scope }; ';
2ee34f20 591 }
1795217c 592
5bcdf810 593So at the beginning of every method, we are passing a callback that will get invoked
1795217c 594at the I<end> of the method's compilation... i.e. exactly then the closing C<'}'>
595is compiled.
596
597 sub inject_scope {
6c1cecd4 598 on_scope_end {
1795217c 599 my $linestr = Devel::Declare::get_linestr;
600 my $offset = Devel::Declare::get_linestr_offset;
601 substr($linestr, $offset, 0) = ';';
602 Devel::Declare::set_linestr($linestr);
6c1cecd4 603 };
2ee34f20 604 }
94caac6e 605
1795217c 606=head2 Shadowing each method.
607
608=head3 C<shadow>
94caac6e 609
1795217c 610We override the current definition of 'method' using C<shadow>.
94caac6e 611
1795217c 612 sub shadow {
613 my $pack = Devel::Declare::get_curstash_name;
614 Devel::Declare::shadow_sub("${pack}::${Declarator}", $_[0]);
2ee34f20 615 }
94caac6e 616
1795217c 617For a named method we invoked like this:
618
619 shadow(sub (&) { no strict 'refs'; *{$name} = shift; });
620
621So in the case of a C<method foo { ... }>, this call would redefine C<method>
622to be a subroutine that exports 'sub foo' as the (munged) contents of C<{...}>.
623
624The case of an anonymous method is also cute:
625
626 shadow(sub (&) { shift });
627
628This means that
629
630 my $meth = method () { ... };
631
632is rewritten with C<method> taking the codeblock, and returning it as is to become
633the value of C<$meth>.
634
635=head4 C<get_curstash_name>
636
637This returns the package name I<currently being compiled>.
638
639=head4 C<shadow_sub>
640
641Handles the details of redefining the subroutine.
642
643=head1 SEE ALSO
644
645One of the best ways to learn C<Devel::Declare> is still to look at
646modules that use it:
647
648L<http://cpants.perl.org/dist/used_by/Devel-Declare>.
94caac6e 649
dcf29eb6 650=head1 AUTHORS
94caac6e 651
502ba90e 652Matt S Trout - E<lt>mst@shadowcat.co.ukE<gt> - original author
94caac6e 653
02f5a508 654Company: http://www.shadowcat.co.uk/
94caac6e 655Blog: http://chainsawblues.vox.com/
656
1795217c 657Florian Ragwitz E<lt>rafl@debian.orgE<gt> - maintainer
658
0df492b9 659osfameron E<lt>osfameron@cpan.orgE<gt> - first draft of documentation
dcf29eb6 660
107322d1 661=head1 COPYRIGHT AND LICENSE
662
09addf7a 663This library is free software under the same terms as perl itself
664
107322d1 665Copyright (c) 2007, 2008, 2009 Matt S Trout
666
667Copyright (c) 2008, 2009 Florian Ragwitz
94caac6e 668
09addf7a 669stolen_chunk_of_toke.c based on toke.c from the perl core, which is
670
671Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
6722000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
94caac6e 673
674=cut
675
6761;