Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't anything go in the body of a Perl 6 grammar proto?

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:nameand 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.

like image 619
user0721090601 Avatar asked Jul 30 '19 21:07

user0721090601


1 Answers

As a matter of fact, proto regexes are little more than a grouping device for several tokens. The documentation says:

the name of a group of values we'll create

They don't really declare a routine multi, and in fact, tokens that follow that proto are not declared as multis, they're simply tokens (which are regexes, which are methods) with funny names.

In your case, you can simply avoid the additional proto token by using alternation, which is actually what protos in grammars stand for:

grammar Bar { 
    token TOP { <meta>* }
    token metastart { '#' }
    token meta { <metastart> [ <name> | <date> ] }
    token name {  \w*  }
    token date { \d**6 }
}

say Bar.parse( "#Hey" );
say Bar.parse( "#3333" );
like image 188
jjmerelo Avatar answered Oct 18 '22 04:10

jjmerelo