使用 Perl 6 语法在原始正则表达式中传递变量
Passing variables in proto regex with Perl 6 grammar
将变量传递给 token
或 regex
或 rule
相当简单。例如
的输出
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
这是一个错误。见 [BUG] Proto regex with params isn't called correctly (possibly NYI) in Rakudo.
我有另一种方法可用于传递非动态参数。但是请看下一点。
你的后续评论解释了你打高尔夫球的原因表明你的动态变量替代方案可能更好。我也会讨论这个。
另一种可行的方法
将 proto token...
切换为 proto method...
,将 token foo:sym<...>
s 切换为 multi token
s,不带 :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")
但我不确定您是否真的可以结合符号和参数使其工作。 sym
s 已经有一个参数:副词中使用的那个。它不仅仅是一个符号,它是要在那里匹配的东西(如果你使用预定义的标记 <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")
所以我会说 是你想去的地方; sym
s 似乎不是实现该目标的正确方法,因为它们有一个内置变量(sym
的参数),但您必须指定每个案例。
将变量传递给 token
或 regex
或 rule
相当简单。例如
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
这是一个错误。见 [BUG] Proto regex with params isn't called correctly (possibly NYI) in Rakudo.
我有另一种方法可用于传递非动态参数。但是请看下一点。
你的后续评论解释了你打高尔夫球的原因表明你的动态变量替代方案可能更好。我也会讨论这个。
另一种可行的方法
将 proto token...
切换为 proto method...
,将 token foo:sym<...>
s 切换为 multi token
s,不带 :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")
但我不确定您是否真的可以结合符号和参数使其工作。 sym
s 已经有一个参数:副词中使用的那个。它不仅仅是一个符号,它是要在那里匹配的东西(如果你使用预定义的标记 <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")
所以我会说 sym
s 似乎不是实现该目标的正确方法,因为它们有一个内置变量(sym
的参数),但您必须指定每个案例。