【问题标题】:<.ident> function/capture in perl6 grammarsperl6 语法中的 <.ident> 函数/捕获
【发布时间】:2018-06-04 08:08:53
【问题描述】:

在阅读 perl6 (https://github.com/supernovus/exemel/blob/master/lib/XML/Grammar.pm6) 的 Xml 语法时,我在理解以下标记时遇到了一些困难。

token pident {
  <!before \d> [ \d+ <.ident>* || <.ident>+ ]+ % '-'
}

更具体地说,<.ident>,没有其他关于 ident 的定义,所以我假设它是一个保留术语。虽然我在 perl6.org 上找不到合适的定义。有谁知道这是什么意思?

【问题讨论】:

    标签: regex grammar raku


    【解决方案1】:

    TL;DR我将从一个精确且相对简洁的答案开始。此答案的其余部分适用于那些想要了解更多关于一般内置规则和/或特别是深入了解ident 的人。

    &lt;.ident&gt; 函数/捕获

    由于.&lt;.ident&gt; 仅匹配,它不会捕获[1]。对于这个答案的其余部分,我通常会省略 .,因为除了捕获方面之外,它对规则的含义没有任何影响。

    正如您可以在编程语言的声明中调用(也称为“调用”)一个函数一样,您也可以调用规则/令牌/正则表达式/方法(此后我通常只使用术语“规则") 在另一个规则的声明中。 &lt;foo&gt; 是用于调用名为 foo 的规则的语法;所以&lt;ident&gt; 调用了一个名为ident 的(方法)。

    在我写这篇文章的时候,XML::Grammar 语法本身并没有定义/声明一个名为 ident 的规则。这意味着调用最终被分派到具有该名称的内置声明。

    内置的ident 规则与声明为:

    token ident {
        [ <alpha> ]
        [ <alnum> ]*
    }
    

    official Predefined character classes doc 应提供&lt;alpha&gt;&lt;alnum&gt; 的精确定义。或者,相关详细信息也包含在此答案的后面。

    底线是ident 匹配一个或多个“字母数字”字符的字符串,但第一个字符不能是“数字”。

    因此abcdef123 都匹配,而123abc 不匹配。

    这个答案的其余部分

    对于那些对细节感兴趣的人,我写了以下部分:

    • Raku(标准语言和课程详情)

    • Rakudo(高级实现)

    • NQP(中级实施)

    • MoarVM(低级实现)

    • ident的规范和“规范”

    • (更正)&lt;ident&gt;、“字符类”和“标识符”的文档

    • ident vs Raku 标识符

    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
    

    规则调用,如语法中的&lt;ident&gt;,通常作为调用.parse 或类似语法的结果而被调用。 .parse 调用根据语法中的规则匹配输入字符串。

    当在匹配期间评估 XML::Grammar 中出现的 &lt;ident&gt; 时,结果是对 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_WORDCCLASS_ALPHABETIC 的超集,但并没有明确说明这些类实际匹配的内容。

    NQP 以多个“后端”或具体虚拟机为目标。鉴于 Rakudo/NQP 文档/测试对这些规则和字符类实际匹配的内容相对缺乏,因此必须查看其后端之一以验证是什么。

    MoarVM(低级实现)

    MoarVM 是唯一官方支持的后端。

    search of MoarVM for CCLASS 显示多个匹配项。

    重要的似乎是ops.c 其中includes a switch (cclass) statement 又包括MVM_CCLASS_ALPHABETICMVM_CCLASS_WORD 的情况,它们对应于NQP 的类似命名的常量。

    根据代码的cmets:

    CCLASS_ALPHABETIC 当前与完整的 Raku 或 NQP &lt;:L&gt; 规则匹配完全相同的字符,即 Unicode 已归类为“字母”的字符。

    我认为这意味着&lt;alpha&gt; 相当于CCLASS_ALPHABETIC_ 的并集(下划线)。

    CCLASS_WORD 匹配相同的加号 &lt;:Nd&gt;,即十进制数字(在任何人类语言中,而不仅仅是英语)。

    我认为这意味着 Raku / NQP &lt;alnum&gt; 规则等同于 CCLASS_WORD

    ident的规范和“规范”

    Raku的官方规范体现在roast[2]中。

    search of roast for ident 显示多个匹配项。

    大多数人只是偶然使用&lt;ident&gt;,作为测试其他东西的一部分。规范要求它们按所示工作,但您不会通过查看偶然使用来理解 &lt;ident&gt; 应该做什么。

    三个测试清楚地测试&lt;ident&gt; 本身。其中一个基本上是多余的,剩下两个。我发现这两个匹配项的6.c6.c.errata 版本之间没有变化:

    来自S05-mass/rx.t

    ok ('2+3 ab2' ~~ /<ident>/) && matchcheck($/, q/mob<ident>: <ab2 @ 4>/), 'capturing builtin <ident>';
    

    ok 测试它的第一个参数返回True。此调用测试 &lt;ident&gt; 跳过 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
    ª
    µ
    º
    ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ
    ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö
    øùúûüýþÿ
    

    但是&lt;ident&gt; 将匹配的不仅仅是来自 Latin-1 的一百个左右的字符。因此,虽然上述测试涵盖了 &lt;ident&gt;官方指定/测试要匹配的,但它们显然没有涵盖全部情况。

    让我们看一下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 ... 匹配一个标识符。

    呃……

    &lt;ident&gt;、“字符类”和“标识符”的(更正)文档

    来自Predefined character classes in the official doc

        Class                             Description
        <ident>                           Identifier. Also a default rule.
    

    这在三个方面具有误导性:

    • ident 不是 a character class。字符类匹配该字符类中的单个字符;如果与量词一起使用,它们只会匹配一串这样的字符,每个字符都可以是该类中的任何字符。相比之下,&lt;ident&gt; 匹配特定的字符模式。它可能是一个角色,但你无法控制它;该规则是贪婪的,匹配符合模式的尽可能多的字符。如果应用量词,它控制整个规则的重复,而不是规则的单个匹配中包含多少个字符。

    • 所有内置规则都是默认规则。我认为默认注释是为了强调如果您不喜欢内置模式,您可以编写自己的 ident 规则。这适用于所有规则,尽管覆盖诸如 &lt;lower&gt;(小写)等规范字符类之类的内置函数通常意义不大。

    • 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> ]* }
    

    所以&lt;identifier&gt; 匹配包含一个或多个&lt;ident&gt;s 和&lt;apostrophe&gt;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)
    

    总结以上和其他一些注意事项:

    • &lt;ident&gt; 仅匹配&lt;identifier&gt; 匹配的部分(尽管它们对于简单名称是相同的)。考虑is-prime。这是一个 Raku 标识符,但包含 两个 &lt;ident&gt; 匹配项(isprime)。

    • &lt;identifier&gt; 仅匹配“Raku 标识符”的 部分(尽管它们对于简单名称是相同的)。考虑infix:&lt;+&gt;。这有时称为 Raku 标识符,但需要 &lt;identifier&gt; 匹配和 :&lt;+&gt; 匹配。

    • Raku 标识符本身只是名称的部分(尽管对于最简单的名称它们是相同的)。考虑包含 两个 &lt;identifier&gt; 匹配项的 Foo-Bar::Baz-Qux(每个匹配项又包含两个 &lt;ident&gt; 匹配项)。

    脚注

    [1]如果您不确定什么是捕获,请参阅CapturingNamed capturesSubrules

    [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 语言的版本。

    【讨论】:

    • 回到第一级 - 这是一个匹配 perl6 标识符的正则表达式 - 例如$ 变量的名称(在 $ 之后)。 docs.perl6.org/language/syntax#Identifiers
    • @p6steve 我很抱歉。我已经完全重写了答案。这不仅仅是领先的印记。如您所见,&lt;ident&gt; 也不匹配连字符或撇号,因此.Str.say for 'is-prime' ~~ m:g/ &lt;ident&gt; /; # is␤prime。我将更新答案中的最后一部分以澄清这一点以及标识符和带有冒号对的标识符和名称之间的区别(后者允许::)。然后是一些文档补丁。
    【解决方案2】:

    一般来说,查找文档的位置是Perl6 documentation。这是正则表达式的一部分,and you can find it in the definition of character classes。它匹配 Perl6 标识符。 ident前面的.的作用是to suppress capture

    【讨论】:

    • 非常感谢。我对 perl 标识符的实际含义知之甚少。定义:(docs.perl6.org/language/syntax#Identifiers)。
    • 文档提示:截至 2018 年 6 月,如果您使用 docs.perl6.org 搜索框搜索某些内容,但在下拉列表中没有找到有用的匹配项,您可以在末尾添加空格 (有时需要 4 或 5),直到您看到 Not in Index (try web search)。单击该按钮将在 google 文档中搜索该单词。在这种情况下,您应该看到1 result,即Regexes - Perl 6 Documentation,并在摘录的开头显示一个粗体&lt;ident&gt;。现在您可以进入页面并在页面中搜索单词。
    • @raiph 有an issue to make that easier。但是我们仍然需要解决这个问题......
    • “它匹配 Perl6 标识符”。我将其归类为 pedagogical facilitation 值得 expansion
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 2020-02-09
    • 2018-02-27
    相关资源
    最近更新 更多