1Devel::Declare(3)     User Contributed Perl Documentation    Devel::Declare(3)
2
3
4

NAME

6       Devel::Declare - (DEPRECATED) Adding keywords to perl, in perl
7

SYNOPSIS

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

DESCRIPTION

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

WARNING

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

USAGE

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

SEE ALSO

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

AUTHORS

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.32.1                      2021-01-27                 Devel::Declare(3)
Impressum