When declaring a proto, it's possible to surround the multimethod/sub code with additional code. For a silly example:
proto sub foo(|) { 'Camelia says “' ~ {*} ~ '!”' }
multi sub foo(1) { "hi" }
multi sub foo($) { "bye" }
say foo(1) # Camelia says “hi!”
I haven't come across any times (yet) where I've felt that's hugely useful, but on the flipside, I have come across some where in regex/Grammar world where I occasionally find myself repeating myself throughout all of the proto tokens — it's not that I can't shift into a separate token, but that adds an extra layer of hierarchy and actions. Compare a hypothetical
grammar Bar {
token TOP { <meta>* }
token metastart { '#' }
proto token meta { <metastart> {*} }
token meta:name { ( \w* ) }
token meta:date { (\d**6) }
}
Where they only action methods necessary besides TOP
would be meta:name
and meta:date
to
grammar Bar {
token TOP { <meta>* }
token metastart { '#' }
token meta { <metastart> <metacontent> }
proto token metacontent { * }
token metacontent:name { \w* }
token metacontent:date { \d**6 }
}
This now requires three methods: metacontent:name
, metacontent:date
and then a fairly superfluous meta
whose entire body would just be make $<metacontent>.made
.
Although I've seen documentation / comments floating around saying you can toss in code in the protos inside of a grammar, if anything is placed in the body of a proto token/regex/rule other than a single *
, then the compiler complains: Proto regex body must be {*} (or <*> or <...>, which are deprecated)
Is this an as-yet unimplemented features or is the plan to no longer allow anything in the proto? And if it's the latter, why should the proto
designator be required? (I'm guessing it's because there's something special about how proto token/regex/rule dispatches, since removing proto inside of a grammar results in runtime failures unlike in the sub/method world.
proto sub foo(|) { say "Do some init task"; my $ret = {*}.IO; #`(Coerce all returns to IO::path); say "Do some cleanup task"; return $ret; }; multi sub foo(Str $a) { return $a }; multi sub foo(IO::Path $a) { return $a };
– Lacrosse