Raku:相互递归令牌导致“找不到方法”错误

Sea*_*ean 9 regex raku

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

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

say "(foo)foo" ~~ /<tok>/;
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

这个错误的原因是什么?

如果我将第一个更改<tok><&tok>,则模式匹配而不会出错,但随后我没有捕获该命名模式,在我原来的更复杂的情况下,我需要它。

Bra*_*ert 9

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

如果你强制它是一个词法调用&,它会起作用。

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

say "(foo)foo" ~~ /<tok>/;
Run Code Online (Sandbox Code Playgroud)

如果<…>以字母以外的任何内容开头,则不会捕获。

所以为了在名称下捕获它tok,我们添加tok=<…>

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

say "(foo)foo" ~~ /<tok>/;
Run Code Online (Sandbox Code Playgroud)


cod*_*ons 9

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

my token paren { $<tok> = ['(' <~~> ')']? foo }
Run Code Online (Sandbox Code Playgroud)

我不确定您的更复杂的情况是否可以轻松地重新编写以递归自己而不是使用两个相互递归的令牌。但是,当这种模式起作用时,它可以大大简化代码。