使用Perl 6语法在原型正则表达式中传递变量

use*_*601 8 grammar perl6 raku

将变量传递给tokenor regexrule相当简单。例如,输出

grammar Foo {
    token TOP     { (.) {} <bar($0)> }
    token bar($s) { {say ~$s} .+ }
}
Foo.parse("xyz")
Run Code Online (Sandbox Code Playgroud)

很简单x。但是当使用原型时,事情变得很糟糕。例如,1让我们做一个简单的原型来区分字符为字母或数字的其余部分:

grammar Foo {
    token TOP     { (.) {} <bar($0)> }
    proto token bar { * }
          token bar:sym<a> ($s) { {say ~$s} <alpha>+ }
          token bar:sym<1> ($s) { {say ~$s} <digit>+ }
}

Foo.parse("xyz")
Run Code Online (Sandbox Code Playgroud)

这枚炸弹声称expected 1 argument but got 2bar。好的,在普通方法中,我们必须在proto声明中指定args,所以我们只声明一下:

grammar Foo {
    token TOP     { (.) {} <bar($0)> }
    proto token bar ($s) { * }
          token bar:sym<a> ($s) { {say ~$s} <alpha>+ }
          token bar:sym<1> ($s) { {say ~$s} <digit>+ }
}

Foo.parse("xyz")
Run Code Online (Sandbox Code Playgroud)

现在我们得到相反的结果:expected 2 arguments but got 1。嗯,也许这意味着原始声明正在消耗该值,并且没有传递任何东西。因此,我尝试将其插入:

grammar Foo {
    token TOP     { (.) {} <bar($0)> }
    proto token bar (|) { * }
          token bar:sym<a> ($s) { {say ~$s} <alpha>+ }
          token bar:sym<1> ($s) { {say ~$s} <digit>+ }
}

Foo.parse("xyz")
Run Code Online (Sandbox Code Playgroud)

同样的错误在这里。它声称expected 2 arguments, but got 12 不知何故,使用proto占用了争论。目前,我发现的唯一解决方案是使用动态变量,这使我认为可能存在一些隐藏步骤,其中变量没有从原型传递到候选对象。

grammar Foo {
    token TOP     { (.) {} <bar($0)> }
    proto token bar ($*s) { * }
          token bar:sym<a> { {say ~$*s} <alpha>+ }
          token bar:sym<1> { {say ~$*s} <digit>+ }
}

Foo.parse("xyz")
Run Code Online (Sandbox Code Playgroud)

但这似乎并不是一个非常直观的步骤。一个人将如何以一种非动态的方式将变量直接传递给原型,以使其被候选人接收?


[1]请注意,以上所有代码都集中于传递变量。实际使用的令牌与我的真实代码不相似。
[2]我也开始怀疑这是否通常是LTA错误消息。虽然我认为它是基于第一个arg = invocant的,但仍然感觉不佳。也许应该说出“期望的主诉者和一个论点,只有被接受的主诉者”之类的话。

rai*_*iph 6

TL; DR

一种可行的替代方法

proto token...在不带后缀的情况下切换到proto method...和切换到token foo:sym<...>s :multi token:sym<...>

grammar Foo {
  token TOP { (.) {} <bar($0)> }
  proto method bar ($s) {*}
  multi token bar ($s where /<alpha>+/) { {say 'alpha start ', $s} .. }
  multi token bar ($s where /<digit>+/) { {say 'digit start ', $s} .. }
}

say Foo.parse("xyz")
Run Code Online (Sandbox Code Playgroud)

显示:

alpha start ?x?
?xyz?
 0 => ?x?
 bar => ?yz?
Run Code Online (Sandbox Code Playgroud)

您的动态变量替代方法可能更好

在我的实际代码中,传递了该变量以阻止某些匹配(主要是为了避免某些类型的递归)

听起来您可以有一个动态变量(例如$*nope),将其设置为所需的任何值,然后系统地使用它。也许是一对。动态变量正是用于此类事情。除了在意识形态上与动态变量不符(在某种程度上,它们被无意用作不受约束的全局变量,这是个坏消息),还有什么不喜欢的呢?