如何在 Raku 语法中使用 :global 进行匹配?
How do I match using :global in Raku grammar?
我正在尝试编写一个 Raku 语法,它可以解析要求编程难题的命令。
这是针对我的问题的简化版本,但这些命令结合了难度级别和可选的语言列表。
有效输入示例:
- 无语言:
easy
- 一种语言:
hard javascript
- 多种语言:
medium javascript python raku
我可以让它匹配一种语言,但不能匹配多种语言。我不确定在哪里添加 :g
.
这是我目前所拥有的示例:
grammar Command {
rule TOP { <difficulty> <languages>? }
token difficulty { 'easy' | 'medium' | 'hard' }
rule languages { <language>+ }
token language { \w+ }
}
multi sub MAIN(Bool :$test) {
use Test;
plan 5;
# These first 3 pass.
ok Command.parse('hard', :token<difficulty>), '<difficulty> can parse a difficulty';
nok Command.parse('no', :token<difficulty>), '<difficulty> should not parse random words';
# Why does this parse <languages>, but <language> fails below?
ok Command.parse('js', :rule<languages>), '<languages> can parse a language';
# These last 2 fail.
ok Command.parse('js', :token<language>), '<language> can parse a language';
# Why does this not match both words? Can I use :g somewhere?
ok Command.parse('js python', :rule<languages>), '<languages> can parse multiple languages';
}
即使我的测试 #4 失败了,这仍然有效:
my token wrd { \w+ }
'js' ~~ &wrd; #=> 「js」
提取多种语言与使用此语法的正则表达式一起工作,但我不确定如何在语法中使用它:
'js python' ~~ m:g/ \w+ /; #=> (「js」 「python」)
此外,是否有一种理想的方法可以使顺序不重要,以便 difficulty
可以出现在字符串中的任何位置?示例:
rule TOP { <languages>* <difficulty> <languages>? }
理想情况下,我希望任何不是 difficulty
的内容都被解读为 language
。示例:raku python medium js
应将 medium
读作 difficulty
,其余读作 language
s。
这里有两个问题。
要在语法分析中指定子规则,命名参数总是:rule
,无论在语法中它是否是rule
、token
、method
或 regex
。您的前两个测试通过了,因为它们代表了有效的全语法分析(即 TOP
),因为 :token
命名参数因为未知而被忽略。
这让我们:
ok Command.parse('hard', :rule<difficulty>), '<difficulty> can parse a difficulty';
nok Command.parse('no', :rule<difficulty>), '<difficulty> should not parse random words';
ok Command.parse('js', :rule<languages> ), '<languages> can parse a language';
ok Command.parse('js', :rule<language> ), '<language> can parse a language';
ok Command.parse('js python', :rule<languages> ), '<languages> can parse multiple languages';
# Output
ok 1 - <difficulty> can parse a difficulty
ok 2 - <difficulty> should not parse random words
ok 3 - <languages> can parse a language
ok 4 - <language> can parse a language
not ok 5 - <languages> can parse multiple languages
第二个问题是如何在 rule
中处理隐含的空格。在token
中,以下是等价的:
token foo { <alpha>+ }
token bar { <alpha> + }
但在 rule
中,它们会有所不同。比较以下规则的令牌等价物:
rule foo { <alpha>+ }
token foo { <alpha>+ <.ws> }
rule bar { <alpha> + }
token bar { [<alpha> <.ws>] + }
在你的情况下,你有 <language>+
,并且由于 language
是 \w+
,所以不可能匹配两个(因为第一个会消耗所有 \w
).简单的解决方案,只需将 <language>+
更改为 <language> +
.
为了让 <difficulty>
令牌四处浮动,我想到的第一个解决方案是匹配它并保释 <language>
令牌:
token language { <!difficulty> \w+ }
<!foo>
如果在那个位置可以匹配 <foo>
将失败。在你得到像 'easyFoo' 这样的语言之前,这几乎可以完美地工作。简单的解决方法是确保难度标记始终出现在单词边界处:
token difficulty {
[
| easy
| medium
| hard
]
>>
}
其中 >>
断言右侧的单词边界。
我正在尝试编写一个 Raku 语法,它可以解析要求编程难题的命令。
这是针对我的问题的简化版本,但这些命令结合了难度级别和可选的语言列表。
有效输入示例:
- 无语言:
easy
- 一种语言:
hard javascript
- 多种语言:
medium javascript python raku
我可以让它匹配一种语言,但不能匹配多种语言。我不确定在哪里添加 :g
.
这是我目前所拥有的示例:
grammar Command {
rule TOP { <difficulty> <languages>? }
token difficulty { 'easy' | 'medium' | 'hard' }
rule languages { <language>+ }
token language { \w+ }
}
multi sub MAIN(Bool :$test) {
use Test;
plan 5;
# These first 3 pass.
ok Command.parse('hard', :token<difficulty>), '<difficulty> can parse a difficulty';
nok Command.parse('no', :token<difficulty>), '<difficulty> should not parse random words';
# Why does this parse <languages>, but <language> fails below?
ok Command.parse('js', :rule<languages>), '<languages> can parse a language';
# These last 2 fail.
ok Command.parse('js', :token<language>), '<language> can parse a language';
# Why does this not match both words? Can I use :g somewhere?
ok Command.parse('js python', :rule<languages>), '<languages> can parse multiple languages';
}
即使我的测试 #4 失败了,这仍然有效:
my token wrd { \w+ }
'js' ~~ &wrd; #=> 「js」
提取多种语言与使用此语法的正则表达式一起工作,但我不确定如何在语法中使用它:
'js python' ~~ m:g/ \w+ /; #=> (「js」 「python」)
此外,是否有一种理想的方法可以使顺序不重要,以便 difficulty
可以出现在字符串中的任何位置?示例:
rule TOP { <languages>* <difficulty> <languages>? }
理想情况下,我希望任何不是 difficulty
的内容都被解读为 language
。示例:raku python medium js
应将 medium
读作 difficulty
,其余读作 language
s。
这里有两个问题。
要在语法分析中指定子规则,命名参数总是:rule
,无论在语法中它是否是rule
、token
、method
或 regex
。您的前两个测试通过了,因为它们代表了有效的全语法分析(即 TOP
),因为 :token
命名参数因为未知而被忽略。
这让我们:
ok Command.parse('hard', :rule<difficulty>), '<difficulty> can parse a difficulty';
nok Command.parse('no', :rule<difficulty>), '<difficulty> should not parse random words';
ok Command.parse('js', :rule<languages> ), '<languages> can parse a language';
ok Command.parse('js', :rule<language> ), '<language> can parse a language';
ok Command.parse('js python', :rule<languages> ), '<languages> can parse multiple languages';
# Output
ok 1 - <difficulty> can parse a difficulty
ok 2 - <difficulty> should not parse random words
ok 3 - <languages> can parse a language
ok 4 - <language> can parse a language
not ok 5 - <languages> can parse multiple languages
第二个问题是如何在 rule
中处理隐含的空格。在token
中,以下是等价的:
token foo { <alpha>+ }
token bar { <alpha> + }
但在 rule
中,它们会有所不同。比较以下规则的令牌等价物:
rule foo { <alpha>+ }
token foo { <alpha>+ <.ws> }
rule bar { <alpha> + }
token bar { [<alpha> <.ws>] + }
在你的情况下,你有 <language>+
,并且由于 language
是 \w+
,所以不可能匹配两个(因为第一个会消耗所有 \w
).简单的解决方案,只需将 <language>+
更改为 <language> +
.
为了让 <difficulty>
令牌四处浮动,我想到的第一个解决方案是匹配它并保释 <language>
令牌:
token language { <!difficulty> \w+ }
<!foo>
如果在那个位置可以匹配 <foo>
将失败。在你得到像 'easyFoo' 这样的语言之前,这几乎可以完美地工作。简单的解决方法是确保难度标记始终出现在单词边界处:
token difficulty {
[
| easy
| medium
| hard
]
>>
}
其中 >>
断言右侧的单词边界。