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