Raku:相互递归标记导致 "method not found" 错误

Raku: Mutually recursive tokens cause a "method not found" error

我已经简化了一个更复杂的模式,我试图匹配到以下程序:

my token paren { '(' <tok> ')' }
my token tok { <paren>? foo }

say "(foo)foo" ~~ /<tok>/;

这对我来说似乎很简单,但我得到了这个错误:

No such method 'tok' for invocant of type 'Match'.  Did you mean 'to'?
  in regex paren at a.p6 line 1
  in regex tok at a.p6 line 2
  in block <unit> at a.p6 line 4

出现此错误的原因是什么?

如果我将第一个 <tok> 更改为 <&tok>,则模式匹配没有错误,但是我没有捕获到那个命名模式,在我的原始模式中,它更复杂案例,我需要

问题是 tok 还不在当前的词法命名空间中,因此 <tok> 被编译为方法调用。

如果你用 & 强制它成为词法调用,它会起作用。

my token paren { '(' <&tok> ')' }
my token tok { <paren>? foo }

say "(foo)foo" ~~ /<tok>/;

如果 <…> 以任何非字母开头,它不会捕获。

所以要以名称 tok 捕获它,我们将 tok= 添加到 <…>

my token paren { '(' <tok=&tok> ')' }
my token tok { <paren>? foo }

say "(foo)foo" ~~ /<tok>/;

Brad 的回答是正确的,但我想提供另一种可能的解决方案:您可以使用特殊的 <~~> token 在单个正则表达式中递归。使用它,加上一个常规的命名捕获,将在您的问题的简化示例中创建您想要的捕获;这是它的样子:

my token paren { $<tok> = ['(' <~~> ')']? foo }

我不确定您的更复杂的案例是否可以很容易地重写为递归自身而不是使用两个相互递归的标记。但是,当这种模式起作用时,它可以大大简化代码。