6

本期所示,某些标记名称与 Grammar 的类层次结构中的方法名称发生冲突(包括MatchCaptureCoolAnyMy .)。例如,`Mu.item

grammar g {
    token TOP { <item> };
    token item { 'defined' }
};
say g.parse('defined');

发出这样的错误:

Too many positionals passed; expected 1 argument but got 2␤  
in regex item at xxx

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

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

Cannot find method 'match': no method cache and no .^find_method␤
at xxx

但是,其他子方法FALLBACK完全没有问题:

grammar g { 
  token TOP { <FALLBACK> }; 
  token FALLBACK { 'defined' } 
}; 
say g.parse('defined') # OUTPUT: «「defined」␤ FALLBACK => 「defined」␤»  

同样适用于 Grammar 类层次结构中的其他一些方法,例如,rand或者一般来说,大多数方法都是这样定义的。

有问题的名称似乎有一个共同点,即它们被声明为sub但并非总是如此:CREATE最初导致整个问题的 . 被声明为method. 因此,我完全不清楚要避免使用哪些名称,以及可以合法使用哪些名称。有人可以澄清吗?

4

3 回答 3

6

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

稍微改变一下你的例子:

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

生产

blah called
「defined」
blah => 「defined」
于 2018-05-26T21:35:49.593 回答
5

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

item等等

请参阅RT#127945 -Mu由于默认 Actions 类,方法不能用作语法标记令牌名称也与内部名称冲突?. 不幸的是,这并不容易解决。

下面是对该错误及其影响的解释。

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

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

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

grammar g           { rule all { all } };
class actions       { }
g.parse: 'all',
         rule    => 'all',
         actions => actions, 

这会产生与 类似的错误item,只是这次all方法来自Any。这是因为动作类的 MRO 包括Any

say class actions   { }.^mro ; # ((actions) (Any) (Mu))

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

grammar g           { rule all { all } };
class actions is Mu { }
g.parse: 'all',
         rule    => 'all',
         actions => actions, 

这很好用,因为现在操作仅继承自Mu-- 并且Mu没有all方法。

如果您可以从无继承,那就太好了,但您不能;is Mu尽可能小。

关于第一个错误,我们可以得出什么结论?

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

TWEAK等等

如果我找不到现有的错误,我将提交一个关于此的 RT 错误。

打高尔夫球:

grammar g { rule TWEAK {} }

这在编译时会爆炸(在解析语法声明的右花括号之后立即)。所以这绝对不是同一个item错误——因为后者是由于运行时动作机制造成的,它只在规则匹配后才会启动。

这不会爆炸:

grammar g { method TWEAK {} }

也许,作为创建/最终确定语法包的一部分,一些代码TWEAK会以一种在普通方法时可以正常工作但如果不是普通方法则崩溃的方式自省和/或操作在新语法包中找到的任何“方法”。

但是,像其他子方法FALLBACK完全没有问题

TWEAK类中的BUILD方法或子方法是标准对象构造的一部分。它们扮演的角色与FALLBACK(如果缺少方法,则调用它)非常不同。

关于第二个错误,我们可以得出什么结论?

显然有一些非常具体的事情正在发生,TWEAK并且BUILD它们很可能是仅有的两个具有它们所表现出的问题的规则名称。所以只要避免这两个名字,你就有望摆脱这个错误。

不小心使用了内置规则名称

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

您只需指定自己的版本即可覆盖内置规则。

正如矮人所说:“如果您不小心声明了与内置规则同名的 [规则],肯定会引起混乱。”。

所以关键问题是,了解内置规则的最终来源是什么?考虑到它们可能会随着时间的推移而发生变化,人们如何管理它们?

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

其他相关错误

另见莫里茨的回答。

于 2018-05-26T21:14:23.597 回答
4

该规则似乎是“如果语法引擎本身调用一个方法,则不能将其重新定义为正则表达式/令牌”。

可悲的是,没有关于此的文档,而且很可能它非常依赖于实现。

于 2018-05-27T08:07:47.803 回答