1Devel::Declare(3) User Contributed Perl Documentation Devel::Declare(3)
2
3
4
6 Devel::Declare - (DEPRECATED) Adding keywords to perl, in perl
7
9 use Method::Signatures;
10 # or ...
11 use MooseX::Declare;
12 # etc.
13
14 # Use some new and exciting syntax like:
15 method hello (Str :$who, Int :$age where { $_ > 0 }) {
16 $self->say("Hello ${who}, I am ${age} years old!");
17 }
18
20 Devel::Declare can install subroutines called declarators which locally
21 take over Perl's parser, allowing the creation of new syntax.
22
23 This document describes how to create a simple declarator.
24
26 Warning: Devel::Declare is a giant bag of crack originally implemented
27 by mst with the goal of upsetting the perl core developers so much by
28 its very existence that they implemented proper keyword handling in the
29 core.
30
31 As of perl5 version 14, this goal has been achieved, and modules such
32 as Devel::CallParser, Function::Parameters, and Keyword::Simple provide
33 mechanisms to mangle perl syntax that don't require hallucinogenic
34 drugs to interpret the error messages they produce.
35
36 If you are using something that uses Devel::Declare, please for the
37 love of kittens use something else:
38
39 • Instead of TryCatch, use Try::Tiny
40
41 • Instead of Method::Signatures, use real subroutine signatures
42 (requires perl 5.22) or Moops
43
45 We'll demonstrate the usage of "Devel::Declare" with a motivating
46 example: a new "method" keyword, which acts like the builtin "sub", but
47 automatically unpacks $self and the other arguments.
48
49 package My::Methods;
50 use Devel::Declare;
51
52 Creating a declarator with "setup_for"
53 You will typically create
54
55 sub import {
56 my $class = shift;
57 my $caller = caller;
58
59 Devel::Declare->setup_for(
60 $caller,
61 { method => { const => \&parser } }
62 );
63 no strict 'refs';
64 *{$caller.'::method'} = sub (&) {};
65 }
66
67 Starting from the end of this import routine, you'll see that we're
68 creating a subroutine called "method" in the caller's namespace. Yes,
69 that's just a normal subroutine, and it does nothing at all (yet!)
70 Note the prototype "(&)" which means that the caller would call it like
71 so:
72
73 method {
74 my ($self, $arg1, $arg2) = @_;
75 ...
76 }
77
78 However we want to be able to call it like this
79
80 method foo ($arg1, $arg2) {
81 ...
82 }
83
84 That's why we call "setup_for" above, to register the declarator
85 'method' with a custom parser, as per the next section. It acts on an
86 optype, usually 'const' as above. (Other valid values are 'check' and
87 'rv2cv').
88
89 For a simpler way to install new methods, see also
90 Devel::Declare::MethodInstaller::Simple
91
92 Writing a parser subroutine
93 This subroutine is called at compilation time, and allows you to read
94 the custom syntaxes that we want (in a syntax that may or may not be
95 valid core Perl 5) and munge it so that the result will be parsed by
96 the "perl" compiler.
97
98 For this example, we're defining some globals for convenience:
99
100 our ($Declarator, $Offset);
101
102 Then we define a parser subroutine to handle our declarator. We'll
103 look at this in a few chunks.
104
105 sub parser {
106 local ($Declarator, $Offset) = @_;
107
108 "Devel::Declare" provides some very low level utility methods to parse
109 character strings. We'll define some useful higher level routines
110 below for convenience, and we can use these to parse the various
111 elements in our new syntax.
112
113 Notice how our parser subroutine is invoked at compile time, when the
114 "perl" parser is pointed just before the declarator name.
115
116 skip_declarator; # step past 'method'
117 my $name = strip_name; # strip out the name 'foo', if present
118 my $proto = strip_proto; # strip out the prototype '($arg1, $arg2)', if present
119
120 Now we can prepare some code to 'inject' into the new subroutine. For
121 example we might want the method as above to have "my ($self, $arg1,
122 $arg2) = @_" injected at the beginning of it. We also do some clever
123 stuff with scopes that we'll look at shortly.
124
125 my $inject = make_proto_unwrap($proto);
126 if (defined $name) {
127 $inject = scope_injector_call().$inject;
128 }
129 inject_if_block($inject);
130
131 We've now managed to change "method ($arg1, $arg2) { ... }" into
132 "method { injected_code; ... }". This will compile... but we've lost
133 the name of the method!
134
135 In a cute (or horrifying, depending on your perspective) trick, we
136 temporarily change the definition of the subroutine "method" itself, to
137 specialise it with the $name we stripped, so that it assigns the code
138 block to that name.
139
140 Even though the next time "method" is compiled, it will be redefined
141 again, "perl" caches these definitions in its parse tree, so we'll
142 always get the right one!
143
144 Note that we also handle the case where there was no name, allowing an
145 anonymous method analogous to an anonymous subroutine.
146
147 if (defined $name) {
148 $name = join('::', Devel::Declare::get_curstash_name(), $name)
149 unless ($name =~ /::/);
150 shadow(sub (&) { no strict 'refs'; *{$name} = shift; });
151 } else {
152 shadow(sub (&) { shift });
153 }
154 }
155
156 Parser utilities in detail
157 For simplicity, we're using global variables like $Offset in these
158 examples. You may prefer to look at Devel::Declare::Context::Simple,
159 which encapsulates the context much more cleanly.
160
161 "skip_declarator"
162
163 This simple parser just moves across a 'token'. The common case is to
164 skip the declarator, i.e. to move to the end of the string 'method'
165 and before the prototype and code block.
166
167 sub skip_declarator {
168 $Offset += Devel::Declare::toke_move_past_token($Offset);
169 }
170
171 "toke_move_past_token"
172
173 This builtin parser simply moves past a 'token' (matching
174 "/[a-zA-Z_]\w*/") It takes an offset into the source document, and
175 skips past the token. It returns the number of characters skipped.
176
177 "strip_name"
178
179 This parser skips any whitespace, then scans the next word (again
180 matching a 'token'). We can then analyse the current line, and
181 manipulate it (using pure Perl). In this case we take the name of the
182 method out, and return it.
183
184 sub strip_name {
185 skipspace;
186 if (my $len = Devel::Declare::toke_scan_word($Offset, 1)) {
187 my $linestr = Devel::Declare::get_linestr();
188 my $name = substr($linestr, $Offset, $len);
189 substr($linestr, $Offset, $len) = '';
190 Devel::Declare::set_linestr($linestr);
191 return $name;
192 }
193 return;
194 }
195
196 "toke_scan_word"
197
198 This builtin parser, given an offset into the source document, matches
199 a 'token' as above but does not skip. It returns the length of the
200 token matched, if any.
201
202 "get_linestr"
203
204 This builtin returns the full text of the current line of the source
205 document.
206
207 "set_linestr"
208
209 This builtin sets the full text of the current line of the source
210 document. Beware that injecting a newline into the middle of the line
211 is likely to fail in surprising ways. Generally, Perl's parser can
212 rely on the `current line' actually being only a single line. Use
213 other kinds of whitespace instead, in the code that you inject.
214
215 "skipspace"
216
217 This parser skips whitsepace.
218
219 sub skipspace {
220 $Offset += Devel::Declare::toke_skipspace($Offset);
221 }
222
223 "toke_skipspace"
224
225 This builtin parser, given an offset into the source document, skips
226 over any whitespace, and returns the number of characters skipped.
227
228 "strip_proto"
229
230 This is a more complex parser that checks if it's found something that
231 starts with '(' and returns everything till the matching ')'.
232
233 sub strip_proto {
234 skipspace;
235
236 my $linestr = Devel::Declare::get_linestr();
237 if (substr($linestr, $Offset, 1) eq '(') {
238 my $length = Devel::Declare::toke_scan_str($Offset);
239 my $proto = Devel::Declare::get_lex_stuff();
240 Devel::Declare::clear_lex_stuff();
241 $linestr = Devel::Declare::get_linestr();
242 substr($linestr, $Offset, $length) = '';
243 Devel::Declare::set_linestr($linestr);
244 return $proto;
245 }
246 return;
247 }
248
249 "toke_scan_str"
250
251 This builtin parser uses Perl's own parsing routines to match a
252 "stringlike" expression. Handily, this includes bracketed expressions
253 (just think about things like "q(this is a quote)").
254
255 Also it Does The Right Thing with nested delimiters (like "q(this (is
256 (a) quote))").
257
258 It returns the effective length of the expression matched. Really,
259 what it returns is the difference in position between where the string
260 started, within the buffer, and where it finished. If the string
261 extended across multiple lines then the contents of the buffer may have
262 been completely replaced by the new lines, so this position difference
263 is not the same thing as the actual length of the expression matched.
264 However, because moving backward in the buffer causes problems, the
265 function arranges for the effective length to always be positive,
266 padding the start of the buffer if necessary.
267
268 Use "get_lex_stuff" to get the actual matched text, the content of the
269 string. Because of the behaviour around multiline strings, you can't
270 reliably get this from the buffer. In fact, after the function
271 returns, you can't rely on any content of the buffer preceding the end
272 of the string.
273
274 If the string being scanned is not well formed (has no closing
275 delimiter), "toke_scan_str" returns "undef". In this case you cannot
276 rely on the contents of the buffer.
277
278 "get_lex_stuff"
279
280 This builtin returns what was matched by "toke_scan_str". To avoid
281 segfaults, you should call "clear_lex_stuff" immediately afterwards.
282
283 Munging the subroutine
284 Let's look at what we need to do in detail.
285
286 "make_proto_unwrap"
287
288 We may have defined our method in different ways, which will result in
289 a different value for our prototype, as parsed above. For example:
290
291 method foo { # undefined
292 method foo () { # ''
293 method foo ($arg1) { # '$arg1'
294
295 We deal with them as follows, and return the appropriate "my ($self,
296 ...) = @_;" string.
297
298 sub make_proto_unwrap {
299 my ($proto) = @_;
300 my $inject = 'my ($self';
301 if (defined $proto) {
302 $inject .= ", $proto" if length($proto);
303 $inject .= ') = @_; ';
304 } else {
305 $inject .= ') = shift;';
306 }
307 return $inject;
308 }
309
310 "inject_if_block"
311
312 Now we need to inject it after the opening '{' of the method body. We
313 can do this with the building blocks we defined above like "skipspace"
314 and "get_linestr".
315
316 sub inject_if_block {
317 my $inject = shift;
318 skipspace;
319 my $linestr = Devel::Declare::get_linestr;
320 if (substr($linestr, $Offset, 1) eq '{') {
321 substr($linestr, $Offset+1, 0) = $inject;
322 Devel::Declare::set_linestr($linestr);
323 }
324 }
325
326 "scope_injector_call"
327
328 We want to be able to handle both named and anonymous methods. i.e.
329
330 method foo () { ... }
331 my $meth = method () { ... };
332
333 These will then get rewritten as
334
335 method { ... }
336 my $meth = method { ... };
337
338 where 'method' is a subroutine that takes a code block. Spot the
339 problem? The first one doesn't have a semicolon at the end of it!
340 Unlike 'sub' which is a builtin, this is just a normal statement, so we
341 need to terminate it. Luckily, using "B::Hooks::EndOfScope", we can do
342 this!
343
344 use B::Hooks::EndOfScope;
345
346 We'll add this to what gets 'injected' at the beginning of the method
347 source.
348
349 sub scope_injector_call {
350 return ' BEGIN { MethodHandlers::inject_scope }; ';
351 }
352
353 So at the beginning of every method, we are passing a callback that
354 will get invoked at the end of the method's compilation... i.e. exactly
355 then the closing '}' is compiled.
356
357 sub inject_scope {
358 on_scope_end {
359 my $linestr = Devel::Declare::get_linestr;
360 my $offset = Devel::Declare::get_linestr_offset;
361 substr($linestr, $offset, 0) = ';';
362 Devel::Declare::set_linestr($linestr);
363 };
364 }
365
366 Shadowing each method.
367 "shadow"
368
369 We override the current definition of 'method' using "shadow".
370
371 sub shadow {
372 my $pack = Devel::Declare::get_curstash_name;
373 Devel::Declare::shadow_sub("${pack}::${Declarator}", $_[0]);
374 }
375
376 For a named method we invoked like this:
377
378 shadow(sub (&) { no strict 'refs'; *{$name} = shift; });
379
380 So in the case of a "method foo { ... }", this call would redefine
381 "method" to be a subroutine that exports 'sub foo' as the (munged)
382 contents of "{...}".
383
384 The case of an anonymous method is also cute:
385
386 shadow(sub (&) { shift });
387
388 This means that
389
390 my $meth = method () { ... };
391
392 is rewritten with "method" taking the codeblock, and returning it as is
393 to become the value of $meth.
394
395 "get_curstash_name"
396
397 This returns the package name currently being compiled.
398
399 "shadow_sub"
400
401 Handles the details of redefining the subroutine.
402
404 One of the best ways to learn "Devel::Declare" is still to look at
405 modules that use it:
406
407 <http://cpants.perl.org/dist/used_by/Devel-Declare>.
408
410 Matt S Trout - <mst@shadowcat.co.uk> - original author
411
412 Company: http://www.shadowcat.co.uk/ Blog:
413 http://chainsawblues.vox.com/
414
415 Florian Ragwitz <rafl@debian.org> - maintainer
416
417 osfameron <osfameron@cpan.org> - first draft of documentation
418
420 This library is free software under the same terms as perl itself
421
422 Copyright (c) 2007, 2008, 2009 Matt S Trout
423
424 Copyright (c) 2008, 2009 Florian Ragwitz
425
426 stolen_chunk_of_toke.c based on toke.c from the perl core, which is
427
428 Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
429 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
430
431
432
433perl v5.36.0 2023-01-20 Devel::Declare(3)