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

Passing variables in proto regex with Perl 6 grammar

将变量传递给 tokenregexrule 相当简单。例如

的输出
grammar Foo {
    token TOP     { (.) {} <bar([=10=])> }
    token bar($s) { {say ~$s} .+ }
}
Foo.parse("xyz")

就是x。但是在使用 proto 时事情会出错。例如,1 让我们做一个简单的原型来区分字符串的其余部分是字母还是数字:

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

Foo.parse("xyz")

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

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

Foo.parse("xyz")

现在我们得到相反的结果:expected 2 arguments but got 1。嗯,也许这意味着原型声明正在吃掉价值而不传递任何东西。所以我试着把它塞进去:

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

Foo.parse("xyz")

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

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

Foo.parse("xyz")

但这似乎不是一个完全直观的步骤。如何以非动态方式将变量直接传递给原型,以便候选人接收它?


[1] 请注意,以上所有代码都经过精心设计以专注于传递变量。实际使用的令牌与我的真实代码没有任何相似之处。
[2] 我也开始怀疑这是否(一般而言)是 LTA 错误消息。虽然我知道它是基于第一个 arg = invocant,但它仍然让人感觉不对。也许它应该说 "Expected invocant and one argument, only received invocant" 或类似的东西。

TL;DR

另一种可行的方法

proto token... 切换为 proto method...,将 token foo:sym<...>s 切换为 multi tokens,不带 :sym<...> 词缀:

grammar Foo {
  token TOP { (.) {} <bar([=10=])> }
  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")

显示:

alpha start 「x」
「xyz」
 0 => 「x」
 bar => 「yz」

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

In my actual code, the variable is passed along to block certain matches (mainly to avoid certain types of recursion)

听起来你可以有一个动态变量(比如 $*nope),设置为你想要的任何值,然后系统地使用它。或者也许是一对。动态变量正是为这类事情而设计的。除了对动态变量的意识形态不满(在某种程度上,它们被粗心地用作不受约束的全局变量,它们 坏消息),还有什么不喜欢的?

第一件事是我真的不明白你在这里打算做什么。我的印象是您希望令牌的第二部分是第一部分的函数。我不明白你为什么在这里使用原型。您可以通过以下方式立即执行此操作:

grammar Foo {
    token TOP     { (.) {} <bar([=10=])> }
    token bar( $s )  { {say ~$s} $s <alpha>+ }
}

say Foo.parse("xxz")

但我不确定您是否真的可以结合符号和参数使其工作。 syms 已经有一个参数:副词中使用的那个。它不仅仅是一个符号,它是要在那里匹配的东西(如果你使用预定义的标记 <sym>;你也可以简单地将它用作子匹配:

grammar Foo {
    token TOP     { (.) {} <bar> }
    proto token bar {*}
    token bar:sym<alpha>  { <alpha>+ }
    token bar:sym<digit>  { <digit>+ }
}

say Foo.parse("xxz");
say Foo.parse("x01")

或者简单地使用字符串作为 sym 匹配:

grammar Foo {
    token TOP     { (.) {} <bar>+ }
    proto token bar {*}
    token bar:sym<x>  { <sym>+ }
    token bar:sym<z>  { <sym>+ }
    token bar:sym<1>  { <sym>+ }
    token bar:sym<0>  { <sym>+ }
}

say Foo.parse("xxz");
say Foo.parse("x01")

所以我会说 是你想去的地方; syms 似乎不是实现该目标的正确方法,因为它们有一个内置变量(sym 的参数),但您必须指定每个案例。