File Coverage

blib/lib/Sublike/Extended.pm
Criterion Covered Total %
statement 13 18 72.2
branch 4 12 33.3
condition n/a
subroutine 4 5 80.0
pod n/a
total 21 35 60.0


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2023-2024 -- leonerd@leonerd.org.uk
5              
6             package Sublike::Extended 0.41;
7              
8 4     4   530206 use v5.14;
  4         25  
9 4     4   27 use warnings;
  4         25  
  4         1603  
10              
11 4     4   31 use Carp;
  4         8  
  4         2143  
12              
13             # XS code is part of XS::Parse::Sublike
14             require XS::Parse::Sublike;
15              
16             =head1 NAME
17              
18             C - enable extended features when parsing C-like syntax
19              
20             =head1 SYNOPSIS
21              
22             =for highlighter language=perl
23              
24             use v5.26;
25             use Sublike::Extended;
26             use experimental 'signatures';
27              
28             extended sub greet (:$name = "world") {
29             say "Hello, $name";
30             }
31              
32             greet( name => $ENV{USER} );
33              
34             Or, I
35              
36             use v5.26;
37             use Sublike::Extended 0.29 'sub';
38             use experimental 'signatures';
39              
40             sub greet (:$name = "world") {
41             say "Hello, $name";
42             }
43              
44             greet( name => $ENV{USER} );
45              
46             =head1 DESCRIPTION
47              
48             This module extends the syntax for declaring named or anonymous subroutines
49             using Perl's builtin C keyword, or other similar keywords provided by
50             third-party modules, to enable parsing of extra features.
51              
52             By default, this module provides a new keyword, L|/extended>,
53             which parses the extra syntax required. Optionally I, this
54             module can additionally take over the handling of the C keyword itself,
55             allowing this extra syntax to be used without the C prefix keyword.
56             As this ability may be surprising to unsuspecting readers, this is not done by
57             default and must be explicitly requested with the C import argument:
58              
59             use Sublike::Extended 'sub';
60              
61             On Perl 5.38 or above, this can also take over handling of the C
62             keyword when using C.
63              
64             use Sublike::Extended 'method';
65              
66             Currently, the only extended features that are provided are related to the
67             parsing of a subroutine signature. Since signatures are only available on Perl
68             version 5.26 or later, this module is unlikely to be useful in earlier
69             versions of Perl.
70              
71             =head2 Named Parameters
72              
73             Extended subroutines can declare named parameters in the signature, after any
74             positional ones. These take the form of a name prefixed by a colon character.
75             The caller of such a function should pass values for these parameters by the
76             usual name-value pair syntax that would be used for passing into a regular
77             hash. Within the body of the subroutine the values passed into these are
78             unpacked into regular lexical variables.
79              
80             sub colour (:$red, :$green, :$blue) {
81             ... # $red, $green and $blue are available as regular lexicals
82             }
83              
84             # argument order at the caller site is not important
85             colour(green => 1, blue => 2, red => 3);
86              
87             Positional parameters I be placed after optional positional ones, but in
88             order to make use of them the caller would have to pass a value for every
89             positional parameter including the optional ones first. This is unlikely to be
90             very useful; if you want to have optional parameters and named parameters, use
91             named optional ones after any I positional parameters.
92              
93             As with positional parameters, they are normally mandatory, but can be made
94             optional by supplying a defaulting expression. If the caller fails to pass a
95             value corresponding to an optional parameter, the default expression is
96             evaluated and used instead.
97              
98             sub f (:$x0, :$x1, :$x2 = 0) { ... }
99             # The caller must provide x0 and x1, but x2 is optional
100              
101             I named parameters can be given defaulting expressions
102             with the C or C<||=> operators, meaning their defaults apply also if the
103             caller passed a present-but-undef, or present-but-false value.
104              
105             sub f (:$x0, :$x1, :$x2 //= 0) { ... }
106             # $x2 will be set to 0 even if the caller passes x2 => undef
107              
108             An optional slurpy hash or (I) slurpy array is also
109             permitted after all of these. It will contain the values of any other
110             name-value pairs given by the caller, after those corresponding to named
111             parameters have already been extracted.
112              
113             sub g (:$alpha, :$beta, %rest) { ... }
114              
115             sub g (:$alpha, :$beta, @rest) { ... }
116              
117             In the case of a slurpy array, it will contain every argument value that was
118             not consumed as a named parameter pair, in the original order passed by the
119             caller, including any duplicates.
120              
121             This syntax is compatible with that proposed by
122             L,
123             which will become available in Perl version 5.43.5.
124              
125             =head2 Parameter Attributes
126              
127             Parameters to extended subroutines can use attribute syntax to apply extra
128             attributes to individual parameters.
129              
130             sub info ($x :Attribute) { ... }
131              
132             Any attributes that are available are ones that have been previously
133             registered with L using its XS-level API. The particular
134             behaviour of such an attribute would be defined by whatever module provided
135             the attribute.
136              
137             =head2 Refalias Parameters
138              
139             I
140              
141             Parameters to extended subroutines can use refalias syntax in order to create
142             lexical variables that alias, rather than contain copies of, variables that
143             callers pass in references.
144              
145             sub h (\@items) { ... }
146              
147             # The caller must provide an ARRAY reference
148             my @arr = (1, 2, 3, 4, 5);
149             h(\@arr);
150              
151             This syntax is similar to refalias assignment as provided by
152             L. This example creates a lexical array
153             variable within the body of the function, which aliases an array passed
154             I from the caller.
155              
156             Refaliased variables may be scalars, arrays, or hashes. For argument handling
157             purposes each will act like a positional scalar which consumes a reference to
158             a variable of the matching type. If the caller does not pass a reference, or a
159             reference to a mismatched type of variable, an exception is thrown as part of
160             argument handling in the signature.
161              
162             I named parameters may also use refalias assignment, using
163             the syntax C<:\VAR> - such as C<:\@items>.
164              
165             As with other parameters, a defaulting expression can be provided, which makes
166             the parameter optional for the caller. If the caller does not provide a
167             corresponding value, this value is used as if the caller passed it. In this
168             case, note that the defaulting expression must still yield a I a
169             container of the appropriate shape to match the declared parameter variable.
170             While all of the C<=>, C and C<||=> operators can be used here, because
171             the value must be a reference, it is unlikely that the distinction between
172             testing for definedness vs boolean truth will be useful.
173              
174             Note that I optional named refalias parameters are
175             allowed, but a limitation of the implementation means that if a corresponding
176             value for the parameter is not provided by the caller and the defaulting
177             expression yields a reference to an incompatible variable, the resulting
178             exception message fails to identify the name of the variable involved; instead
179             just quoting three questionmarks:
180              
181             =for highlighter
182              
183             $ perl -E 'use Sublike::Extended "sub"; sub f ( :\@arr = \undef ) {} f()'
184             refaliases are experimental at -e line 1.
185             Expected named argument '???' to main::f to be a reference to ARRAY at -e line 1.
186              
187             =for highlighter language=perl
188              
189             The body of the function can see the value stored by the referred variable
190             and make modifications to it. Any such modifications will be reflected in the
191             variable whose reference was passed by the caller, or the value created by the
192             defaulting expression if it was used.
193              
194             =head1 KEYWORDS
195              
196             =head2 extended
197              
198             extended sub NAME (SIGNATURE...) { BODY... }
199              
200             extended sub (SIGNATURE...) { BODY... };
201              
202             This prefix keyword enables extra parsing features when handling a C (or
203             other sub-like function keyword).
204              
205             This keyword can be freely mixed with other C-prefix keywords, such as
206             C from L
207              
208             async extended sub f (:$param) { ... }
209              
210             This can also be used with other keywords that provide C-like syntax,
211             such as C from L or the core C.
212              
213             extended method f (:$param) { ... }
214              
215             =cut
216              
217             sub import
218             {
219 8     8   6215 shift;
220 8         48 $^H{"Sublike::Extended/extended"}++;
221              
222             my @rest = grep {
223 8         24 $_ eq "sub" ? ( $^H{"Sublike::Extended/extended-sub"}++, 0 ) :
224 4 50       39 $_ eq "method" ? ( $^H{"Sublike::Extended/extended-method"}++, 0 ) :
    100          
225             1
226             } @_;
227              
228 8 50       7712 croak "Unrecognised import arguments: @rest" if @rest;
229             }
230              
231             sub unimport
232             {
233 0     0     shift;
234 0           delete $^H{"Sublike::Extended/extended"};
235              
236             my @rest = grep {
237 0           $_ eq "sub" ? ( delete $^H{"Sublike::Extended/extended-sub"}, 0 ) :
238 0 0         $_ eq "method" ? ( delete $^H{"Sublike::Extended/extended-method"}, 0 ) :
    0          
239             1
240             } @_;
241              
242 0 0         croak "Unrecognised unimport arguments: @rest" if @rest;
243             }
244              
245             =head1 TODO
246              
247             =over 4
248              
249             =item *
250              
251             Support defined-or and true-or positional parameters even on versions of Perl
252             before they were officially added (v5.38).
253              
254             =back
255              
256             =head1 AUTHOR
257              
258             Paul Evans
259              
260             =cut
261              
262             0x55AA;