| 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; |