为什么要在Perl 6语法中使用原型规则?

时间:2017-01-20 17:23:27

标签: grammar perl6

这是两个语法。一个使用proto token而一个不使用proto。他们都完成了同样的事情。这些基本上是S05 under "Variable (non-)interpolation"中的示例。在这个简单的例子中,他们都能够做同样的事情。

哪种情况可以证明所有额外的打字? proto令牌在动作类中有不同的方法,也许在那里有一个小的好处。但是,您必须输入一些额外的东西才能获得这些好处。

是否有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), ); 的某些功能使语法的其他部分更容易?

proto

输出显示------No proto parsing found sigil: $ found identifier: butterfuly found variable: $butterfuly ------Yes proto parsing found sym sigil: $ found identifier: butterfuly found variable: $butterfuly 在操作类中调用不同的方法:

/content/geometrixx/en/toolbar/

3 个答案:

答案 0 :(得分:8)

从技术上讲,如果您未自行指定,则会为您制作proto。它基本上为特定的token创建了多方法调度处理程序(就像它与submethod一样)。你通常不需要关心。

为什么要指定proto?我可以想到很多原因:

  1. 因为您希望token分享一些特征
  2. 因为你想在发送之前或之后执行一些代码
  3. 是的,{ * }可能包含可执行代码。裸Whatever表示向适当的候选人发送。使用sub

    在更简单的情况下显示此信息
    proto a(|) { say "before"; {*}; say "after" }
    multi a(Int) { say "Int" }
    multi a(Str) { say "Str" }
    a 42; a "42"
    

    所示:

    before
    Int
    after
    before
    Str
    after
    

    希望这会有所帮助: - )

答案 1 :(得分:7)

在动作类中调用它可以用于分离逻辑。除了语法之外,它与多方法基本相同。

(我wrote this用于评估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   }

}

它还使得子类化语法可以将其标记与已存在的标记一起添加,并且子类化动作类可以执行相同的操作。 (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 }
}

答案 2 :(得分:7)

将您的替代品拆分为proto和multis的一个好处是您可以更可靠地扩展它。您可以在语法中将multis添加到语法中,该语法继承了声明proto的语法,并且您不需要列出所有可能的替代方案(如果是a,则必须执行此操作单一规则)。

这意味着您甚至可以对同一语法进行多次独立扩展,例如通过混合使用多个规则来为不同的符号提供匹配。

这基本上是Perl 6在定义自定义运算符时使用的机制:有匹配不同类型运算符的规则(如中缀,前缀,后缀,...),并声明新运算符派生来自当前活动的新语法,为新运算符添加了多个候选语法。由于proto令牌机制的可扩展性,脚本可以从几个彼此不了解的模块中导入操作符。