enable default arguments by default
[p5sagit/Function-Parameters.git] / lib / Function / Parameters.pm
CommitLineData
7a63380c 1package Function::Parameters;
2
7dd35535 3use v5.14.0;
4
7a63380c 5use strict;
6use warnings;
7
63915d26 8use Carp qw(confess);
9
db81d362 10use XSLoader;
11BEGIN {
1d143321 12 our $VERSION = '0.06';
db81d362 13 XSLoader::load;
7a63380c 14}
15
2d5cf47a 16sub _assert_valid_identifier {
17 my ($name, $with_dollar) = @_;
18 my $bonus = $with_dollar ? '\$' : '';
19 $name =~ /^${bonus}[^\W\d]\w*\z/
20 or confess qq{"$name" doesn't look like a valid identifier};
21}
22
b72eb6ee 23sub _assert_valid_attributes {
24 my ($attrs) = @_;
25 $attrs =~ /^\s*:\s*[^\W\d]\w*\s*(?:(?:\s|:\s*)[^\W\d]\w*\s*)*(?:\(|\z)/
26 or confess qq{"$attrs" doesn't look like valid attributes};
27}
28
125c067e 29my @bare_arms = qw(function method);
2d5cf47a 30my %type_map = (
63915d26 31 function => {
32 name => 'optional',
33 default_arguments => 1,
34 check_argument_count => 0,
35 },
7947f7ce 36 method => {
37 name => 'optional',
63915d26 38 default_arguments => 1,
39 check_argument_count => 0,
7947f7ce 40 attrs => ':method',
63915d26 41 shift => '$self',
7947f7ce 42 },
a23979e1 43 classmethod => {
44 name => 'optional',
63915d26 45 default_arguments => 1,
46 check_argument_count => 0,
a23979e1 47 attrs => ':method',
63915d26 48 shift => '$class',
a23979e1 49 },
2d5cf47a 50);
c9a39f6b 51
db81d362 52sub import {
53 my $class = shift;
7a63380c 54
b72eb6ee 55 @_ or @_ = {
56 fun => 'function',
57 method => 'method',
58 };
125c067e 59 if (@_ == 1 && ref($_[0]) eq 'HASH') {
60 @_ = map [$_, $_[0]{$_}], keys %{$_[0]}
61 or return;
62 }
7a63380c 63
125c067e 64 my %spec;
65
66 my $bare = 0;
67 for my $proto (@_) {
68 my $item = ref $proto
69 ? $proto
70 : [$proto, $bare_arms[$bare++] || confess(qq{Don't know what to do with "$proto"})]
71 ;
ae6e00b5 72 my ($name, $proto_type) = @$item;
2d5cf47a 73 _assert_valid_identifier $name;
74
ae6e00b5 75 unless (ref $proto_type) {
76 # use '||' instead of 'or' to preserve $proto_type in the error message
77 $proto_type = $type_map{$proto_type}
78 || confess qq["$proto_type" doesn't look like a valid type (one of ${\join ', ', sort keys %type_map})];
2d5cf47a 79 }
b72eb6ee 80
ae6e00b5 81 my %type = %$proto_type;
82 my %clean;
10acc8b1 83
ae6e00b5 84 $clean{name} = delete $type{name} || 'optional';
85 $clean{name} =~ /^(?:optional|required|prohibited)\z/
86 or confess qq["$clean{name}" doesn't look like a valid name attribute (one of optional, required, prohibited)];
10acc8b1 87
ae6e00b5 88 $clean{shift} = delete $type{shift} || '';
10acc8b1 89 _assert_valid_identifier $clean{shift}, 1 if $clean{shift};
90
91 $clean{attrs} = delete $type{attrs} || '';
92 _assert_valid_attributes $clean{attrs} if $clean{attrs};
125c067e 93
59f51b8b 94 $clean{default_arguments} =
95 exists $type{default_arguments}
96 ? !!delete $type{default_arguments}
97 : 1
98 ;
63915d26 99 $clean{check_argument_count} = !!delete $type{check_argument_count};
100
ae6e00b5 101 %type and confess "Invalid keyword property: @{[keys %type]}";
102
103 $spec{$name} = \%clean;
125c067e 104 }
105
db81d362 106 for my $kw (keys %spec) {
107 my $type = $spec{$kw};
108
63915d26 109 my $flags =
110 $type->{name} eq 'prohibited' ? FLAG_ANON_OK :
111 $type->{name} eq 'required' ? FLAG_NAME_OK :
112 FLAG_ANON_OK | FLAG_NAME_OK
113 ;
114 $flags |= FLAG_DEFAULT_ARGS if $type->{default_arguments};
115 $flags |= FLAG_CHECK_NARGS if $type->{check_argument_count};
116 $^H{HINTK_FLAGS_ . $kw} = $flags;
ae6e00b5 117 $^H{HINTK_SHIFT_ . $kw} = $type->{shift};
10acc8b1 118 $^H{HINTK_ATTRS_ . $kw} = $type->{attrs};
db81d362 119 $^H{+HINTK_KEYWORDS} .= "$kw ";
125c067e 120 }
eeb7df5f 121}
122
db81d362 123sub unimport {
eeb7df5f 124 my $class = shift;
125c067e 125
db81d362 126 if (!@_) {
127 delete $^H{+HINTK_KEYWORDS};
125c067e 128 return;
129 }
130
db81d362 131 for my $kw (@_) {
132 $^H{+HINTK_KEYWORDS} =~ s/(?<![^ ])\Q$kw\E //g;
125c067e 133 }
134}
135
db81d362 136
125c067e 137'ok'
7a63380c 138
139__END__
140
f2541b7d 141=encoding UTF-8
142
7a63380c 143=head1 NAME
144
145Function::Parameters - subroutine definitions with parameter lists
146
147=head1 SYNOPSIS
148
149 use Function::Parameters;
150
151 fun foo($bar, $baz) {
152 return $bar + $baz;
153 }
154
155 fun mymap($fun, @args) :(&@) {
156 my @res;
157 for (@args) {
158 push @res, $fun->($_);
159 }
160 @res
161 }
162
163 print "$_\n" for mymap { $_ * 2 } 1 .. 4;
125c067e 164
165 method set_name($name) {
166 $self->{name} = $name;
167 }
7a63380c 168
125c067e 169=cut
170
171=pod
172
63a24d7c 173 use Function::Parameters {
174 proc => 'function',
175 meth => 'method',
176 };
c9a39f6b 177
125c067e 178 my $f = proc ($x) { $x * 2 };
179 meth get_age() {
180 return $self->{age};
181 }
182
7a63380c 183=head1 DESCRIPTION
184
185This module lets you use parameter lists in your subroutines. Thanks to
63a24d7c 186L<PL_keyword_plugin|perlapi/PL_keyword_plugin> it works without source filters.
7a63380c 187
db81d362 188WARNING: This is my first attempt at writing L<XS code|perlxs> and I have
7a63380c 189almost no experience with perl's internals. So while this module might
190appear to work, it could also conceivably make your programs segfault.
191Consider this module alpha quality.
192
193=head2 Basic stuff
194
195To use this new functionality, you have to use C<fun> instead of C<sub> -
196C<sub> continues to work as before. The syntax is almost the same as for
197C<sub>, but after the subroutine name (or directly after C<fun> if you're
125c067e 198writing an anonymous sub) you can write a parameter list in parentheses. This
7a63380c 199list consists of comma-separated variables.
200
201The effect of C<fun foo($bar, $baz) {> is as if you'd written
202C<sub foo { my ($bar, $baz) = @_; >, i.e. the parameter list is simply
203copied into C<my> and initialized from L<@_|perlvar/"@_">.
204
125c067e 205In addition you can use C<method>, which understands the same syntax as C<fun>
206but automatically creates a C<$self> variable for you. So by writing
207C<method foo($bar, $baz) {> you get the same effect as
208C<sub foo { my $self = shift; my ($bar, $baz) = @_; >.
7a63380c 209
125c067e 210=head2 Customizing the generated keywords
c9a39f6b 211
63a24d7c 212You can customize the names of the keywords injected into your scope. To do
213that you pass a hash reference in the import list:
7a63380c 214
125c067e 215 use Function::Parameters { proc => 'function', meth => 'method' }; # -or-
216 use Function::Parameters { proc => 'function' }; # -or-
a23979e1 217 use Function::Parameters { meth => 'method' }; # etc.
125c067e 218
219The first line creates two keywords, C<proc> and C<meth> (for defining
220functions and methods, respectively). The last two lines only create one
221keyword. Generally the hash keys can be any identifiers you want while the
a23979e1 222values have to be either C<function>, C<method>, C<classmethod> or a hash
223reference (see below). The difference between C<function> and C<method> is that
224C<method>s automatically L<shift|perlfunc/shift> their first argument into
225C<$self> (C<classmethod>s are similar but shift into C<$class>).
125c067e 226
227The following shortcuts are available:
228
229 use Function::Parameters;
230 # is equivalent to #
231 use Function::Parameters { fun => 'function', method => 'method' };
232
233=cut
234
235=pod
236
63a24d7c 237The following shortcuts are deprecated and may be removed from a future version
238of the module:
239
240 # DEPRECATED
125c067e 241 use Function::Parameters 'foo';
242 # is equivalent to #
243 use Function::Parameters { 'foo' => 'function' };
244
245=cut
246
247=pod
248
63a24d7c 249 # DEPRECATED
125c067e 250 use Function::Parameters 'foo', 'bar';
251 # is equivalent to #
252 use Function::Parameters { 'foo' => 'function', 'bar' => 'method' };
253
63a24d7c 254That is, if you want to pass arguments to L<Function::Parameters>, use a
255hashref, not a list of strings.
256
ce052c57 257You can customize things even more by passing a hashref instead of C<function>
258or C<method>. This hash can have the following keys:
259
260=over
261
262=item C<name>
263
264Valid values: C<optional> (default), C<required> (all uses of this keyword must
265specify a function name), and C<prohibited> (all uses of this keyword must not
266specify a function name). This means a C<< name => 'prohibited' >> keyword can
267only be used for defining anonymous functions.
268
269=item C<shift>
270
271Valid values: strings that look like a scalar variable. Any function created by
272this keyword will automatically L<shift|perlfunc/shift> its first argument into
63a24d7c 273a local variable whose name is specified here.
ce052c57 274
273c6544 275=item C<attrs>
276
277Valid values: strings that are valid source code for attributes. Any value
278specified here will be inserted as a subroutine attribute in the generated
279code. Thus:
280
281 use Function::Parameters { sub_l => { attrs => ':lvalue' } };
282 sub_l foo() {
283 ...
284 }
285
286turns into
287
288 sub foo :lvalue {
289 ...
290 }
291
ce052c57 292=back
293
a23979e1 294Plain C<'function'> is equivalent to C<< { name => 'optional' } >>, plain
273c6544 295C<'method'> is equivalent to
a23979e1 296C<< { name => 'optional', shift => '$self', attrs => ':method' } >>, and plain
297C<'classmethod'> is equivalent to
298C<< { name => 'optional', shift => '$class', attrs => ':method' } >>.
ce052c57 299
63a24d7c 300=head2 Syntax and generated code
7a63380c 301
302Normally, Perl subroutines are not in scope in their own body, meaning the
63a24d7c 303parser doesn't know the name C<foo> or its prototype while processing the body
304of C<sub foo ($) { foo $bar[1], $bar[0]; }>, parsing it as
7a63380c 305C<$bar-E<gt>foo([1], $bar[0])>. Yes. You can add parens to change the
306interpretation of this code, but C<foo($bar[1], $bar[0])> will only trigger
307a I<foo() called too early to check prototype> warning. This module attempts
308to fix all of this by adding a subroutine declaration before the definition,
309so the parser knows the name (and possibly prototype) while it processes the
310body. Thus C<fun foo($x) :($) { $x }> really turns into
311C<sub foo ($); sub foo ($) { my ($x) = @_; $x }>.
312
125c067e 313If you need L<subroutine attributes|perlsub/"Subroutine Attributes">, you can
314put them after the parameter list with their usual syntax.
315
316Syntactically, these new parameter lists live in the spot normally occupied
317by L<prototypes|perlsub/"Prototypes">. However, you can include a prototype by
318specifying it as the first attribute (this is syntactically unambiguous
63a24d7c 319because normal attributes have to start with a letter while a prototype starts
320with C<(>).
321
322As an example, the following declaration uses every feature available
323(subroutine name, parameter list, prototype, attributes, and implicit
324C<$self>):
325
326 method foo($x, $y, @z) :($;$@) :lvalue :Banana(2 + 2) {
327 ...
328 }
329
330And here's what it turns into:
331
332 sub foo ($;$@); sub foo ($;$@) :lvalue :Banana(2 + 2) { my $self = shift; my ($x, $y, @z) = @_;
333 ...
334 }
335
336Another example:
337
338 my $coderef = fun ($p, $q) :(;$$)
339 :lvalue
340 :Gazebo((>:O)) {
341 ...
342 };
343
344And the generated code:
345
346 my $coderef = sub (;$$) :lvalue :Gazebo((>:O)) { my ($p, $q) = @_;
347 ...
348 };
349
350=head2 Wrapping Function::Parameters
125c067e 351
db81d362 352If you want to wrap L<Function::Parameters>, you just have to call its
353C<import> method. It always applies to the file that is currently being parsed
63a24d7c 354and its effects are lexical (i.e. it works like L<warnings> or L<strict>):
355
356 package Some::Wrapper;
357 use Function::Parameters ();
358 sub import {
359 Function::Parameters->import;
360 # or Function::Parameters->import(@other_import_args);
361 }
eeb7df5f 362
7a63380c 363=head1 AUTHOR
364
365Lukas Mai, C<< <l.mai at web.de> >>
366
367=head1 COPYRIGHT & LICENSE
368
db81d362 369Copyright 2010, 2011, 2012 Lukas Mai.
7a63380c 370
371This program is free software; you can redistribute it and/or modify it
372under the terms of either: the GNU General Public License as published
373by the Free Software Foundation; or the Artistic License.
374
375See http://dev.perl.org/licenses/ for more information.
376
377=cut