【问题标题】:A Perl 6 Regex to match a Perl 6 delimited comment匹配 Perl 6 分隔注释的 Perl 6 正则表达式
【发布时间】:2019-03-01 04:12:40
【问题描述】:

谁有一个 Perl 6 正则表达式可以匹配 Perl 6 分隔的 cmets?我更喜欢简短的东西而不是完整的语法,但我不排除任何东西。

作为我正在寻找的一个例子,我想要一些可以在这里解析 cmets 的东西:

#`{ foo {} bar }
#`« woo woo »
say #`(
This is a (
long )
multiliner()) "You rock!"
#`{{ { And don't forget the tricky repeating delimiters }}

我的总体目标是能够获取源文件并剥离 pod 和 cmets,然后用剩下的代码做一些有趣的事情。剥离线 cmets 和 pod 非常容易,但分隔 cmets 需要额外的技巧。我还希望这个解决方案很小并且只使用 Perl 6 核心,这样我就可以将它粘贴到我的 dotfiles 存储库中,而无需外部依赖。

【问题讨论】:

  • Pod 由 Perl 6 解析器与文件的其余部分一起处理。我认为,您可以访问已处理的 QAST 并剥离任何您想要的东西。
  • @jjmerelo:没那么容易——我一直在寻找一种将 QAST 改回 Python 的方法,但到目前为止,除了自己动手之外,如果可能的话,我仍然一无所知。
  • 我猜解析定界 cmets 的困难在于您还必须解析字符串常量?例如my $str = '#`( This is not a comment )'; #`( but this is a comment)
  • @jjmerelo:我想要一些类似于 Regex 的东西,而不是我可以从 Perl 6 解析器中提取出来的东西,因为这样做是高度实验性的,并且可能会发生变化。
  • @håkon-hægland:这也是一个问题,但我可以忍受过度识别这些并担心添加一个类似引号的解析器来防止它作为下一步。

标签: regex raku


【解决方案1】:

匹配你的例子

my %openers-closers = < { } « » ( ) >;        # (many more in reality)
my @openers         = %openers-closers.keys;  # { « ( ...
my ($open, $close);                           # possibly multiple chars

my token comment { '#`' <&open> <&middle> <&close> }

my token open {
  # Store first delimiter char:   Slurp as many as are repeated:
  ( ( @openers )                  $0* )

  # Store the full (possibly multiple character) delimiters:
  { $open = ~$0; $close = %openers-closers{$0[0]} x $0.chars }
}

my token middle {
  :my $nest-level; # for tracking nesting
  [
    # Continue if nested:  or if not at unnested end delimiter:
    [ <?{$nest-level}>     ||    <!&close> ]

    # Match either a nested delimiter:  or a single character: 
    ( $open || $close                   || . )

    # Keep track of nesting:
    { $_ = ~$0.tail; # set topic to latest match in list 
      $nest-level++ when $open; $nest-level-- when $close } 
  ]*
}

my token close { $close }

.say for $your-examples ~~ m:g / <.&comment> /

显示:

「{ foo {} bar }」
「« woo woo »」
「(
This is a (
long )
multiliner())」
「{{ { And don't forget the tricky repeating delimiters }}」

如果您知道 P6 正则表达式,希望代码是不言自明的。如果您想澄清任何问题,请使用 cmets。

查看相关的 Rakudo 源代码

我在上面写的时候没有参考 Rakudo 的源代码。 (我想看看我不这样做的结果。)

但是我现在已经查看了源代码,对于任何试图做你想做的事情并认真了解它在一般情况下的工作情况的人来说,这或多或少是强制性的事情案例。

作为我的起点,我特别想看看我是否能弄清楚为什么将此代码提供给 rakudo (2018.12):

#`{{ {{ And don't forget the tricky repeating delimiters  } }}

产生相当 LTA(Less Than Awesome)编译器错误:

Starter {{ is immediately followed by a combining codepoint...

这看起来与您的问题没有直接关系,但我在尝试理解嵌套分隔符规则时遇到了它。

因此,当我得到答案的这一部分时,我首先在 Rakudo 存储库中搜索“立即跟进”。这导致了 P6 语法中的fail-terminator method。 (也许你不感兴趣,但我很感兴趣。)

以下是我在标准语法中发现的其他内容,即 imo 与您正在尝试做的事情直接相关,或者至少准确理解代码所说的规则是关于匹配 cmets 的内容:

  • 解析这些 cmets 的 comment:sym&lt;#`(...)&gt; token。这导致:

  • list of openers。此列表应替换我的代码中仅与您的示例匹配的微不足道的 3 对开/关。

  • quibble token。这似乎是一个通用的“解析'引用'(分隔)的东西”。它导致:

  • babble token。这使用以下代码建立了“开始”和“停止”:

    $<B>=[<?before .>]
    {
        # Work out the delimiters.
        my $c := $/;
        my @delims := $c.peek_delimiters($c.target, $c.pos);
        my $start := @delims[0];
        my $stop  := @delims[1];
    

规则peek_delimiters不在P6语法文件中。

在 Rakudo 存储库中的搜索显示它不在 Rakudo 或 P6 中的任何位置。

在 NQP 中的搜索在 nqp 的语法中产生 a routine(Perl 6 语法继承自它,这就是 peek_delimiters 调用有效的原因以及我在 Rakudo/P6 中没有找到 NQP 时查看 NQP 的原因) .

我将在这一点上停下来得出一个结论。

结论

你有一个正则表达式。它可能会如你所愿。我不知道。

如果您最终调查了上述 Rakudo/NQP 代码并充分理解了它,可以写出关于 quibble、babble、nibble 等的演练,或者发现一个很好的现有文章(我没有搜索过一个),请在链接到它的答案中添加评论。我也会这样做。蒂亚!

【讨论】:

  • 感谢@raiph 的全面回答。我试图自己解决这个问题,但我无法弄清楚如何正确实现递归,所以现在我很高兴看到你解决了它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
相关资源
最近更新 更多