什么是命名语法规则的元对象规则

jjm*_*elo 6 grammar perl6 meta-object-protocol

本期所述,某些令牌名称与语法的类层次结构中的方法名称冲突(包括Match,Capture,Cool,Any和显然是My.).例如,'Mu.item

grammar g {
    token TOP { <item> };
    token item { 'defined' }
};
say g.parse('defined');
Run Code Online (Sandbox Code Playgroud)

发出如下错误:

Too many positionals passed; expected 1 argument but got 2?  
in regex item at xxx
Run Code Online (Sandbox Code Playgroud)

item也是Anys方法的一部分 ; 我没有在其他类中找到任何其他类,其名称通常失败,但是没有定义的子类(除了item); 大多数是multis或实际定义为method.

当类似TWEAKBUILD子方法用于标记名称时也会发生这种情况,但在这种情况下的错误是不同的:

Cannot find method 'match': no method cache and no .^find_method?
at xxx
Run Code Online (Sandbox Code Playgroud)

但是,其他类似的方法FALLBACK完全没有问题:

grammar g { 
  token TOP { <FALLBACK> }; 
  token FALLBACK { 'defined' } 
}; 
say g.parse('defined') # OUTPUT: «?defined?? FALLBACK => ?defined??»  
Run Code Online (Sandbox Code Playgroud)

并且对于语法的类层次结构中的一些其他方法也是同上的,例如,rand或者,通常,大多数方法都是这样定义的.

有问题的名字似乎有一个共同点,就是它们被声明为sub但事实并非总是这样:CREATE最初引起整个问题的事实被宣布为method.因此,我不清楚要避免哪些名称,以及哪些名称可以合法使用.有人可以澄清吗?

dwa*_*ing 6

另请注意,语法中的FALLBACK标记在类中执行与FALLBACK方法类似的功能.当在语法中遇到未知令牌时,使用令牌名称调用它.

稍微改变你的例子:

grammar g { 
  token TOP { <blah> }; 
  token FALLBACK($name) { {note "$name called" } 'defined' } 
}; 
say g.parse('defined')
Run Code Online (Sandbox Code Playgroud)

产生

blah called
?defined?
blah => ?defined?
Run Code Online (Sandbox Code Playgroud)

  • 太好了!有一个upvote.:)我无法从JJ的问题标题中看出他真正追求的是什么,所以我只是写了一本书...... (2认同)
  • 这只是一个太大而不适合SO评论格式的评论:-) (2认同)
  • 我的书长"答案"的原始版本首先说它不是一个答案,但不适合评论.然后我想出足以删除那一位.我发现你提交了[Grammar'ident'覆盖行为](https://rt.perl.org/Public/Bug/Display.html?id=120146),我仍然想知道这是否也是混合的一部分.嗯.可能不是. (2认同)
  • 该RT涉及内置规则"ident"的覆盖.如果您不小心声明与内置规则同名的令牌,它肯定会引起混淆. (2认同)

rai*_*iph 5

这几乎完全是关于多个尴尬的错误.

item 等等

请参阅RT#127945 - Mu由于默认的Actions类,方法不能用作语法标记.还有令牌名称与内部名称混淆?.不幸的是,这不容易修复.

下面是对这个bug及其影响的解释.

根据Actions机制,如果语法规则匹配,则.parse调用立即尝试调用相应命名的操作方法.

如果您没有将操作类/对象显式传递给.parse方法,那么它将使用默认值,即Mu.然后,当您的语法中的规则匹配时,它会查找Mu具有相同名称的方法.如果找不到,一切都很好.但是如果它找到一个,那么它将Mu当前Match对象作为第一个也是唯一的参数调用该方法.在几乎所有情况下都会变坏.item就是一个例子.

如果您确实告诉该.parse方法使用特定的动作类/对象,则会出现另一个问题:

grammar g           { rule all { all } };
class actions       { }
g.parse: 'all',
         rule    => 'all',
         actions => actions, 
Run Code Online (Sandbox Code Playgroud)

这产生了类似的错误item,除了这个all方法来自Any.这是因为动作类的MRO包括Any:

say class actions   { }.^mro ; # ((actions) (Any) (Mu))
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式声明您的操作类来消除这种皱纹is Mu:

grammar g           { rule all { all } };
class actions is Mu { }
g.parse: 'all',
         rule    => 'all',
         actions => actions, 
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作,因为现在这些操作只继承自Mu- 并且Mu没有all方法.

如果你能从无所不能中继承,那就太棒了,但你做不到; is Mu尽可能小.

关于这个第一个bug,我们能得出什么结论?

因为Perl 6和/或Rakudo的较新版本可能附带新Mu方法,所以要防范此错误最安全的做法是始终声明一个操作类,并始终声明一个与语法中每个规则相对应的方法.如果您这样做,您不需要遵循任何命名规则来避免此错误.

TWEAK 等等

如果我找不到现有的错误,我会提交RT错误.

Golfed:

grammar g { rule TWEAK {} }
Run Code Online (Sandbox Code Playgroud)

这在编译时爆炸(在解析语法声明的结束大括号后立即).所以这肯定不是和bug一样的itembug - 因为后者是由于运行时的 Actions机制只能在规则匹配后启动.

这不会爆炸:

grammar g { method TWEAK {} }
Run Code Online (Sandbox Code Playgroud)

也许,作为创建/完成语法包的一部分,一些代码TWEAK以一种普通方法可以正常工作的方式内省和/或操纵新语法包中的任何"方法",但如果不是,则会爆炸.

但是,其他类似的方法FALLBACK根本没有问题

TWEAKBUILD在一个类中的方法或子方法是标准的对象的构造的一部分.它们扮演的角色非常不同FALLBACK(如果缺少某种方法,则会调用它).

关于第二个bug我们能得出什么结论?

显然有一些非常具体的内容,TWEAK并且BUILD它们很可能是他们展示的问题的唯一两个规则名称.所以只要避免这两个名字,你就可以清楚地知道这个bug.

意外使用内置规则名称

请参阅RT#125518 - 语法'ident'覆盖行为.

您可以通过指定自己的版本来覆盖内置规则.

正如相反的暗示 "如果你不小心宣布[规则]与内置规则同名,那肯定会引起混淆."

因此,关键问题是,了解内置规则的最终来源是什么?如果管理事物可能会随着时间的推移而改变,那么它们如何管理?

(是的,非常模糊,我知道.另外,我认为Perl 6的内置插件必须扩展NQP,这似乎可能是相关的.而且,每种整体语言中都有多个俚语,也许这是相关的.我打算讨论这个问题.在以后的编辑中更充分地发布.)

其他相关的错误

另见Moritz的回答.