TL;DR我将从一个精确且相对简洁的答案开始。此答案的其余部分适用于那些想要了解更多关于一般内置规则和/或特别是深入了解ident 的人。
<.ident> 函数/捕获
由于.、<.ident> 仅匹配,它不会捕获[1]。对于这个答案的其余部分,我通常会省略 .,因为除了捕获方面之外,它对规则的含义没有任何影响。
正如您可以在编程语言的声明中调用(也称为“调用”)一个函数一样,您也可以调用规则/令牌/正则表达式/方法(此后我通常只使用术语“规则") 在另一个规则的声明中。 <foo> 是用于调用名为 foo 的规则的语法;所以<ident> 调用了一个名为ident 的(方法)。
在我写这篇文章的时候,XML::Grammar 语法本身并没有定义/声明一个名为 ident 的规则。这意味着调用最终被分派到具有该名称的内置声明。
内置的ident 规则与声明为:
token ident {
[ <alpha> ]
[ <alnum> ]*
}
official Predefined character classes doc 应提供<alpha> 和<alnum> 的精确定义。或者,相关详细信息也包含在此答案的后面。
底线是ident 匹配一个或多个“字母数字”字符的字符串,但第一个字符不能是“数字”。
因此abc 或def123 都匹配,而123abc 不匹配。
这个答案的其余部分
对于那些对细节感兴趣的人,我写了以下部分:
Raku(标准语言和课程详情)
XML::Grammar 是用户定义的 Raku 语法。 Raku 语法是一个类。 ("Grammars are really just slightly specialized classes".)
Raku rule 是一个正则表达式是一个方法:
grammar foo { rule ident { ... } }
say foo.^lookup('ident').WHAT; # (Regex)
say Regex ~~ Method; # True
规则调用,如语法中的<ident>,通常作为调用.parse 或类似语法的结果而被调用。 .parse 调用根据语法中的规则匹配输入字符串。
当在匹配期间评估 XML::Grammar 中出现的 <ident> 时,结果是对 XML::Grammar 实例的 ident 方法(规则)调用(.parse 调用创建其实例如果它只是一个类型对象,则调用者)。
因为XML::Grammar 本身并没有定义该名称的规则/方法,所以ident 调用是根据标准方法解析,呃,规则来调度的。 (我在这里使用通用的非 Raku 特定意义上的“规则”一词。啊,语言。)
在 Raku 中,使用 grammar foo { ... } 形式的声明创建的任何类都会自动继承自 Grammar 类,而 Grammar 类又继承自 Match 类:
say .^mro given grammar foo {} # ((foo) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))
ident 可以在内置的Match 类中找到。
Rakudo(高级实现)
在 Rakudo 编译器中,the Match class does role NQPMatchRole。
这个NQPMatchRole 是找到ident 的最高级别实现的地方。
NQP(中级实施)
NQPMatchRole 是用 nqp 语言编写的,它是 Raku 的一个子集,用于引导完整的 Raku,也是编译器工具包 NQP 的核心。
仅从the ident declaration 中摘录并重新格式化最显着的代码,first 字符的匹配归结为:
nqp::ord($target, $!pos) == 95
|| nqp::iscclass(nqp::const::CCLASS_ALPHABETIC, $target, $!pos)
如果 first 字符是 either 则匹配 _(95 是下划线的 ASCII 代码/Unicode 代码点)或 em> 一个与 NQP 中定义的字符类匹配的字符,称为 CCLASS_ALPHABETIC。
另一个显着的代码是:
nqp::findnotcclass( nqp::const::CCLASS_WORD
这匹配字符类CCLASS_WORD中的零个或多个后续个字符。
search of NQP for CCLASS_ALPHABETIC 显示多个匹配项。最有用的似乎是an NQP test file。虽然此文件明确指出 CCLASS_WORD 是 CCLASS_ALPHABETIC 的超集,但并没有明确说明这些类实际匹配的内容。
NQP 以多个“后端”或具体虚拟机为目标。鉴于 Rakudo/NQP 文档/测试对这些规则和字符类实际匹配的内容相对缺乏,因此必须查看其后端之一以验证是什么。
MoarVM(低级实现)
MoarVM 是唯一官方支持的后端。
search of MoarVM for CCLASS 显示多个匹配项。
重要的似乎是ops.c 其中includes a switch (cclass) statement 又包括MVM_CCLASS_ALPHABETIC 和MVM_CCLASS_WORD 的情况,它们对应于NQP 的类似命名的常量。
根据代码的cmets:
CCLASS_ALPHABETIC 当前与完整的 Raku 或 NQP <:L> 规则匹配完全相同的字符,即 Unicode 已归类为“字母”的字符。
我认为这意味着<alpha> 相当于CCLASS_ALPHABETIC 和_ 的并集(下划线)。
CCLASS_WORD 匹配相同的加号 <:Nd>,即十进制数字(在任何人类语言中,而不仅仅是英语)。
我认为这意味着 Raku / NQP <alnum> 规则等同于 CCLASS_WORD。
ident的规范和“规范”
Raku的官方规范体现在roast[2]中。
search of roast for ident 显示多个匹配项。
大多数人只是偶然使用<ident>,作为测试其他东西的一部分。规范要求它们按所示工作,但您不会通过查看偶然使用来理解 <ident> 应该做什么。
三个测试清楚地测试<ident> 本身。其中一个基本上是多余的,剩下两个。我发现这两个匹配项的6.c 和6.c.errata 版本之间没有变化:
来自S05-mass/rx.t:
ok ('2+3 ab2' ~~ /<ident>/) && matchcheck($/, q/mob<ident>: <ab2 @ 4>/), 'capturing builtin <ident>';
ok 测试它的第一个参数返回True。此调用测试 <ident> 跳过 2+3 并匹配 ab2。
来自S05-mass/charsets.t:
is $latin-chars.comb(/<ident>/).join(" "), "ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz ª µ º ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö øùúûüýþÿ", 'ident chars';
is 测试它的第一个参数是否匹配它的第二个。此调用从由前 256 个 Unicode 代码点(Latin-1 字符集)组成的字符串中测试 ident 规则匹配的内容。
下面是这个测试的一个变体,它更清楚地显示了发生的匹配:
say ~$_ for $latin-chars ~~ m:g/<ident>/;
打印:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
_
abcdefghijklmnopqrstuvwxyz
ª
µ
º
ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ
ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö
øùúûüýþÿ
但是<ident> 将匹配的不仅仅是来自 Latin-1 的一百个左右的字符。因此,虽然上述测试涵盖了 <ident> 是官方指定/测试要匹配的,但它们显然没有涵盖全部情况。
让我们看一下official speculation,它可能被认为与“规范”相关。
首先,我们注意到顶部的警告:
Note: these documents may be out of date.
For Perl 6 documentation see docs.perl6.org;
for specs, see the official test suite.
此警告中的术语“规格”是“规格”的缩写。如前所述,官方规范测试套件是roast,而不是任何人类语言。
(有些人仍然认为这些历史设计文档也是“规范”,并称它们为“规范”,但官方的观点是“规范”,应用于设计文档,应该被认为是“推测”的缩写,强调它们不是完全可以依赖的。)
search for ident in design.raku.org 显示多个匹配项。
最有用的匹配在the Predefined Subrules section of S05:
这些是任何语法或正则表达式的一些预定义子规则:
呃……
<ident>、“字符类”和“标识符”的(更正)文档
来自Predefined character classes in the official doc:
Class Description
<ident> Identifier. Also a default rule.
这在三个方面具有误导性:
ident 不是 a character class。字符类匹配该字符类中的单个字符;如果与量词一起使用,它们只会匹配一串这样的字符,每个字符都可以是该类中的任何字符。相比之下,<ident> 匹配特定的字符模式。它可能是一个角色,但你无法控制它;该规则是贪婪的,匹配符合模式的尽可能多的字符。如果应用量词,它控制整个规则的重复,而不是规则的单个匹配中包含多少个字符。
所有内置规则都是默认规则。我认为默认注释是为了强调如果您不喜欢内置模式,您可以编写自己的 ident 规则。这适用于所有规则,尽管覆盖诸如 <lower>(小写)等规范字符类之类的内置函数通常意义不大。
ident不匹配标识符!或者,更准确地说,对于大多数 Raku 标识符,它自己不会这样做。有关详细信息,请参阅下一节。
ident vs Raku 标识符
my @Identifiers = < $bar %hash Foo Foo::Bar your_ident anothers' my-ident >;
say (~$/ if m/^<ident>$/ for @Identifiers); # (Foo your_ident)
say (~$/ if m/ <ident> / for @Identifiers); # (bar hash Foo Foo your_ident anothers my)
在 NQP 的 Grammar.nqp 中定义的 nqp 语法中,有:
token identifier { <.ident> [ <[\-']> <.ident> ]* }
在 Raku 的语法(在 Rakudo 的 Grammar.nqp 中定义)中,有些代码看起来略有不同,但效果完全相同:
token apostrophe { <[ ' \- ]> }
token identifier { <.ident> [ <.apostrophe> <.ident> ]* }
所以<identifier> 匹配包含一个或多个<ident>s 和<apostrophe>s 之间的模式。
ident 方法在NQPMatchRole 中,这意味着它是用户语法规则命名空间的一部分。
但identifier 方法不由 Raku 或 nqp 导出。所以它们不是用户语法规则命名空间的一部分。
如果我们编写自己的 indentifier 令牌,我们可以看到它的实际效果:
my token identifier { <.ident> [ <[\-']> <.ident> ]* }
my token sigil { <[$@%&]> }
say (~$/ if m/^ <sigil>? <identifier> $/ for @Identifiers)
显示:
($bar %hash Foo your_ident my-ident)
总结以上和其他一些注意事项:
<ident> 仅匹配<identifier> 匹配的部分(尽管它们对于简单名称是相同的)。考虑is-prime。这是一个 Raku 标识符,但包含 两个 <ident> 匹配项(is 和 prime)。
<identifier> 仅匹配“Raku 标识符”的 部分(尽管它们对于简单名称是相同的)。考虑infix:<+>。这有时称为 Raku 标识符,但需要 <identifier> 匹配和 :<+> 匹配。
Raku 标识符本身只是名称的部分(尽管对于最简单的名称它们是相同的)。考虑包含 两个 <identifier> 匹配项的 Foo-Bar::Baz-Qux(每个匹配项又包含两个 <ident> 匹配项)。
脚注
[1]如果您不确定什么是捕获,请参阅Capturing、Named captures 和Subrules。
[2] Raku 的官方规范是一个名为 bake 的测试套件 -- Repository Of A将S具体化Tests。 roast 的特定分支的最新版本定义了 Raku 的特定版本。当我第一次写这个答案时,只有两个官方分支/版本的烤,因此也有 Raku。第一个是6.c 又名6.Christmas。这是cut on Christmas day 2015,从那天起就被故意冻结了。第二个是6.c.errata,它保守地添加了对6.c 的更正,被认为足够重要并且向后兼容,可以包含在(当时)当前官方推荐的Raku 版本中。一个“官方兼容”的 Raku 编译器通过了一些官方的烘焙分支。 Rakudo 编译器(当时)通过了6.c.errata。如果您阅读了所有涉及某个功能的测试,例如,6.c.errata 烘焙分支,那么您将阅读该功能的完整定义官方指定6.c.errata 的含义Raku 语言的版本。