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.
当类似TWEAK的BUILD子方法用于标记名称时也会发生这种情况,但在这种情况下的错误是不同的:
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.因此,我不清楚要避免哪些名称,以及哪些名称可以合法使用.有人可以澄清吗?
另请注意,语法中的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)
这几乎完全是关于多个尴尬的错误.
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根本没有问题
TWEAK和BUILD在一个类中的方法或子方法是标准的对象的构造的一部分.它们扮演的角色非常不同FALLBACK(如果缺少某种方法,则会调用它).
关于第二个bug我们能得出什么结论?
显然有一些非常具体的内容,TWEAK并且BUILD它们很可能是他们展示的问题的唯一两个规则名称.所以只要避免这两个名字,你就可以清楚地知道这个bug.
您可以通过指定自己的版本来覆盖内置规则.
正如相反的暗示 "如果你不小心宣布[规则]与内置规则同名,那肯定会引起混淆."
因此,关键问题是,了解内置规则的最终来源是什么?如果管理事物可能会随着时间的推移而改变,那么它们如何管理?
(是的,非常模糊,我知道.另外,我认为Perl 6的内置插件必须扩展NQP,这似乎可能是相关的.而且,每种整体语言中都有多个俚语,也许这是相关的.我打算讨论这个问题.在以后的编辑中更充分地发布.)
另见Moritz的回答.