Why are you using the proto rule in Perl 6 grammar?

Here are two grammars. One uses proto token , and the other does not. They both do the same. These are mainly examples in S05 in the section "Variable (non) interpolation" . In this simple example, both of them can do the same.

What situations justify all the extra typing? proto tokens have different methods in the action class, and perhaps there is a slight advantage. However, you need to recruit some additional materials to get this benefit.

Is there some proto feature that facilitates other parts of the grammar?

 grammar NoProto { token variable { <sigil> <identifier> } token identifier { <ident>+ } token sigil { < $ @ % & :: > } } grammar YesProto { token variable { <sigil> <identifier> } token identifier { <ident>+ } proto token sigil { * } token sigil:sym<$> { <sym> } token sigil:sym<@> { <sym> } token sigil:sym<%> { <sym> } token sigil:sym<&> { <sym> } token sigil:sym<::> { <sym> } } class Proto::Actions { method variable ($/) { say "found variable: " ~ $/; } method identifier ($/) { say "found identifier: " ~ $/; } method sigil ($/) { say "found sigil: " ~ $/; } method sigil:sym<$> ($/) { say "found sym sigil: " ~ $/; } } my $variable = '$butterfuly'; say "------No proto parsing"; my $no_proto_match = NoProto.parse( $variable, :rule<variable>, :actions(Proto::Actions), ); say "------Yes proto parsing"; my $yes_proto_match = YesProto.parse( $variable, :rule<variable>, :actions(Proto::Actions), ); 

The result shows that proto calls another method in the action class:

 ------No proto parsing found sigil: $ found identifier: butterfuly found variable: $butterfuly ------Yes proto parsing found sym sigil: $ found identifier: butterfuly found variable: $butterfuly 
+6
source share
3 answers

Technically, proto will be created for you if you do not specify it yourself. It basically creates a handler for sending multiple methods for this particular token (just like with sub and method ). What you usually don't need to care about.

Why do you need to specify proto ? I can think of several reasons:

  • because you want token share some features
  • because you want to execute some code before or after sending

Yes, { * } may contain executable code. Naked Whatever indicates sending to the appropriate candidate. Showing this in a simpler situation with sub :

 proto a(|) { say "before"; {*}; say "after" } multi a(Int) { say "Int" } multi a(Str) { say "Str" } a 42; a "42" 

shows:

 before Int after before Str after 

Hope this helps :-)

+7
source

Having a method that it calls in an action class can be useful for separating logic. This is basically the same idea as the ellipsis other than grammars.

(I wrote this to evaluate responses to Code Golf )

 grammar Mathemania { token TOP { <cmd-list> } token cmd-list { <cmd>+ } token cmd { <op> <argument>? } proto token op { * } token op:sym<exp> { e } # notice that the name doesn't have to match token op:sym<factorial> { f } token op:sym<root> { r } token op:sym<ceil> { c } token op:sym<floor> { l } token argument { '(' ~ ')' <cmd-list> } } class Calculate { method TOP ($/) { make $<cmd-list>.made } method argument ($/) { make $<cmd-list>.made } method cmd-list ($/) { my $result = 2; $result = .made.($result).narrow for @<cmd>; make $result; } method cmd ($/) { if $<argument> { make $<op>.made.assuming( *, $<argument>.made ); } else { make $<op>.made; } } method op:sym<exp> ($/) { make -> \n, \e = 2 { n ** e } } method op:sym<factorial> ($/) { make -> \n, \k = 2 { [*] n, n - k + 1 ...^ 0 } } method op:sym<root> ($/) { make -> \n, \r = 2 { n ** (1/r) } } method op:sym<ceil> ($/) { make &ceiling } method op:sym<floor> ($/) { make &floor } } 

It also makes it possible for a subclassical grammar to add its markers along one that already exists, and a class of subclassifying actions can do the same. ( try it )

 grammar Mathmania-Plus is Mathemania { token op:sym<negate> { n } token op:sym<abs> { a } } class Calculate-Plus is Calculate { method op:sym<negate> ($/) { make &prefix:<-> } method op:sym<abs> ($/) { make &abs } } 
+6
source

One of the advantages of dividing your alternatives into proto and multis is that you can more reliably expand it. You can add multis to an existing proto in a grammar that inherits a grammar declaring a proto, and you do not need to list all the possible alternatives (which you would need to do in the case of one rule).

This means that you can even have several independent extensions for the same grammar, for example, by mixing in several rules that provide multis for different characters.

This is basically the mechanism that Perl 6 uses when defining a user-defined operator: there are rules for matching different types of operators (for example, infix, prefix, postfix ...) and declaring a new operator a new grammar from the current active, with the addition of several candidates for the new operator . A script can import statements from several modules that are not aware of each other due to the extensibility of the flow label mechanism.

+5
source

Source: https://habr.com/ru/post/1014261/


All Articles