1 package Function::Parameters;
9 use B::Hooks::EndOfScope;
16 my $defcaller = (caller $start)[0];
17 my $caller = $defcaller;
19 for (my $level = $start; ; ++$level) {
20 my ($pkg, $function) = (caller $level)[0, 3] or last;
21 #warn "? $pkg, $function";
22 $function =~ /::import\z/ or return $caller;
28 sub _fun ($) { $_[0] }
33 no warnings qw(redefine);
34 *_croak = \&Carp::croak;
41 my $keyword = @_ ? shift : 'fun';
43 _croak qq["$_" is not exported by the ${\__PACKAGE__} module] for @_;
45 $keyword =~ /^[[:alpha:]_]\w*\z/ or _croak qq{"$keyword" does not look like a valid identifier};
47 Devel::Declare->setup_for(
49 { $keyword => { const => \&parser } }
53 *{$victim . '::' . $keyword} = \&_fun;
59 my $caller = guess_caller;
60 #warn "caller = $caller";
62 import_into $caller, @_;
66 my ($offset, $name) = @_;
68 my $line = Devel::Declare::get_linestr();
69 substr $line, $offset + 1, 0, "\x{20de}\e[m";
70 substr $line, $offset, 0, "\e[31;1m";
71 print STDERR "$name($offset)>> $line\n";
76 $str =~ s/([\$\@\\"])/\\$1/g;
82 my ($declarator, $start) = @_;
84 my $line = Devel::Declare::get_linestr();
87 my $_file = PL_compiling->file;
88 my $_line = PL_compiling->line;
90 my $n = $_line + substr($line, $start, $offset - $start) =~ tr[\n][];
91 die join('', @_) . " at $_file line $n\n";
95 my $atomically = sub {
99 my @ret = eval { $pars->(@_) };
104 wantarray ? @ret : $ret[0]
110 my @ret = eval { $pars->() };
114 wantarray ? @ret : $ret[0]
119 my $skip = Devel::Declare::toke_skipspace($offset);
121 $skip == -$offset or die "Internal error: offset=$offset, skip=$skip";
122 Devel::Declare::set_linestr($line);
125 $line = Devel::Declare::get_linestr();
126 #warn "toke_skipspace($offset) = $skip\n== $line";
130 $offset += Devel::Declare::toke_move_past_token($offset);
132 my $manip_start = $offset;
135 if (my $len = Devel::Declare::toke_scan_word($offset, 1)) {
136 $name = substr $line, $offset, $len;
143 my $len = length $str;
144 substr($line, $offset, $len) eq $str
147 my $scan_token = sub {
149 my $len = length $str;
150 substr($line, $offset, $len) eq $str or $fail->(qq{Missing "$str"});
156 my $len = Devel::Declare::toke_scan_word($offset, 0) or $fail->('Missing identifier');
157 my $name = substr $line, $offset, $len;
163 my $scan_var = $atomically->(sub {
164 (my $sigil = substr($line, $offset, 1)) =~ /^[\$\@%]\z/ or $fail->('Missing [$@%]');
167 my $name = $scan_id->();
171 my $separated_by = $atomically->(sub {
172 my ($sep, $pars) = @_;
173 my $len = length $sep;
174 defined(my $x = $try->($pars)) or return;
177 substr($line, $offset, $len) eq $sep or return @res;
180 push @res, $pars->();
184 my $many_till = $atomically->(sub {
185 my ($end, $pars) = @_;
186 my $len = length $end;
188 until (substr($line, $offset, $len) eq $end) {
189 push @res, $pars->();
194 my $scan_params = $atomically->(sub {
195 if ($try->(sub { $scan_token->('('); 1 })) {
196 my @param = $separated_by->(',', $scan_var);
203 #report_pos $offset, "param";
204 my @param = $scan_params->();
206 #report_pos $offset, "extra";
207 while ($peek_str->('(')) {
208 push @extra, [$scan_params->()];
209 #report_pos $offset, "extra";
212 my $scan_pargroup_opt = sub {
213 substr($line, $offset, 1) eq '(' or return '';
214 my $len = Devel::Declare::toke_scan_str($offset);
215 my $res = Devel::Declare::get_lex_stuff();
216 Devel::Declare::clear_lex_stuff();
217 $res eq '' and $fail->(qq{Can't find ")" anywhere before EOF});
223 my $scan_attr = sub {
224 my $name = $scan_id->();
225 my $param = $scan_pargroup_opt->() || '';
229 my $scan_attributes = $atomically->(sub {
230 $try->(sub { $scan_token->(':'); 1 }) or return '', [];
231 my $proto = $scan_pargroup_opt->();
232 my @attrs = $many_till->('{', $scan_attr);
233 ' ' . $proto, \@attrs
236 #report_pos $offset, "attr";
237 my ($proto, $attributes) = $scan_attributes->();
238 my $attr = @$attributes ? ' : ' . join(' ', @$attributes) : '';
240 #report_pos $offset, "'{'";
243 my $manip_end = $offset;
244 my $manip_len = $manip_end - $manip_start;
245 #print STDERR "($manip_start:$manip_len:$manip_end)\n";
247 my $params = @param ? 'my (' . join(', ', @param) . ') = @_; ' : '';
248 my $extra_a = join '', map 'sub { ' . (@$_ ? 'my (' . join(', ', @$_) . ') = @_; ' : ''), @extra;
249 my $extra_z = '}' x @extra;
255 $str eq '' and return '';
256 'BEGIN { ' . __PACKAGE__ . '::_terminate_me(' . _quote($str) . '); } '
260 #print STDERR "($manip_start:$manip_len) [$line]\n";
261 substr $line, $manip_start, $manip_len, " do { sub $name$proto; sub $name$proto$attr { $params$extra_a${\$term->(qq[$extra_z \\&$name };])}";
263 substr $line, $manip_start, $manip_len, " sub$proto$attr { $params$extra_a${\$term->(qq[$extra_z])}";
265 print STDERR ".> $line\n";
266 Devel::Declare::set_linestr($line);
267 print STDERR ".< $line\n";
271 print STDERR "..>\n";
274 my $line = Devel::Declare::get_linestr();
275 print STDERR "~~> $line\n";
276 my $offset = Devel::Declare::get_linestr_offset();
277 substr $line, $offset, 0, $str;
278 Devel::Declare::set_linestr($line);
279 print STDERR "??> $line\n";
289 Function::Parameters - subroutine definitions with parameter lists
293 use Function::Parameters;
305 fun mymap($fun, @args) :(&@) {
308 push @res, $fun->($_);
313 print "$_\n" for mymap { $_ * 2 } 1 .. 4;
315 use Function::Parameters 'proc';
316 my $f = proc ($x) { $x * 2 };
320 This module lets you use parameter lists in your subroutines. Thanks to
321 L<Devel::Declare> it works without source filters.
323 WARNING: This is my first attempt at using L<Devel::Declare> and I have
324 almost no experience with perl's internals. So while this module might
325 appear to work, it could also conceivably make your programs segfault.
326 Consider this module alpha quality.
330 To use this new functionality, you have to use C<fun> instead of C<sub> -
331 C<sub> continues to work as before. The syntax is almost the same as for
332 C<sub>, but after the subroutine name (or directly after C<fun> if you're
333 writing an anonymous sub) you can write a parameter list in parens. This
334 list consists of comma-separated variables.
336 The effect of C<fun foo($bar, $baz) {> is as if you'd written
337 C<sub foo { my ($bar, $baz) = @_; >, i.e. the parameter list is simply
338 copied into C<my> and initialized from L<@_|perlvar/"@_">.
342 You can actually use multiple parameter lists:
343 C<fun foo(LIST1)(LIST2)(LIST3)...> is valid (and the parameter lists
344 are completely separate). You use the same syntax to call the function:
345 C<foo(1)(2, 3)(4, 5, 6)>.
347 What this actually does is to generate nested subs, each returning a reference
348 to the next, as if you'd written
349 C<fun foo(LIST1) { fun (LIST2) { fun (LIST3) { ... } } }>.
351 =head2 Advanced stuff
353 You can change the name of the new keyword from C<fun> to anything you want by
354 specifying it in the import list, i.e. C<use Function::Parameters 'spork'> lets
355 you write C<spork> instead of C<fun>.
357 If you need L<subroutine attributes|perlsub/"Subroutine Attributes">, you can
358 put them after the parameter list with their usual syntax. There's one
359 exception, though: you can only use one colon (to start the attribute list);
360 multiple attributes have to be separated by spaces.
362 Syntactically, these new parameter lists live in the spot normally occupied
363 by L<prototypes|perlsub/"Prototypes">. However, you can include a prototype by
364 specifying it as the first attribute (this is syntactically unambiguous
365 because normal attributes have to start with a letter).
367 Normally, Perl subroutines are not in scope in their own body, meaning the
368 parser doesn't know the name C<foo> or its prototype when processing
369 C<sub foo ($) { foo $bar[1], $bar[0]; }>, parsing it as
370 C<$bar-E<gt>foo([1], $bar[0])>. Yes. You can add parens to change the
371 interpretation of this code, but C<foo($bar[1], $bar[0])> will only trigger
372 a I<foo() called too early to check prototype> warning. This module attempts
373 to fix all of this by adding a subroutine declaration before the definition,
374 so the parser knows the name (and possibly prototype) while it processes the
375 body. Thus C<fun foo($x) :($) { $x }> really turns into
376 C<sub foo ($); sub foo ($) { my ($x) = @_; $x }>.
378 If you want to wrap C<Function::Parameters>, you may find C<import_into>
379 helpful. It lets you specify a target package for the syntax magic, as in:
381 package Some::Wrapper;
382 use Function::Parameters ();
385 Function::Parameters::import_into $caller;
386 # or Function::Parameters::import_into $caller, 'other_keyword';
389 C<import_into> is not exported by this module, so you have to use a fully
390 qualified name to call it.
394 Lukas Mai, C<< <l.mai at web.de> >>
396 =head1 COPYRIGHT & LICENSE
398 Copyright 2010 Lukas Mai.
400 This program is free software; you can redistribute it and/or modify it
401 under the terms of either: the GNU General Public License as published
402 by the Free Software Foundation; or the Artistic License.
404 See http://dev.perl.org/licenses/ for more information.