【问题标题】:Grammar to parse module specification解析模块规范的语法
【发布时间】:2025-12-20 04:50:11
【问题描述】:

Raku 模块可以用不同的方式指定,例如:

MyModule

MyModule:ver<1.0.3>

MyModule:ver<1.0.3>:auth<Name (email@example.com)>;

MyModule:ver<1.0.3>:auth<Name <email@example.com>>;

我编写了下面的grammar 来解析模块规范,该规范适用于大多数规范,但如果auth 字段包含<>,它将失败。在这种情况下如何修复语法以匹配?

我不知道怎么说匹配<> 之间的所有内容,包括任何<>

#!/usr/bin/env perl6

grammar Spec {

  token TOP { <spec> }

  token spec { <name> <keyval>* }

  token name { [<-[./:<>()\h]>+]+ % '::' }

  token keyval { ':' <key> <value> }

  proto token key { * }
  token key:sym<ver>     { <sym> }
  token key:sym<version> { <sym> }
  token key:sym<auth>    { <sym> }
  token key:sym<api>     { <sym> }
  token key:sym<from>    { <sym> }

  # BUG: fix specs that contains '<>' inside value;
  token value { '<' ~ '>' $<val>=<-[<>]>* | '(' ~ ')' $<val>=<-[()]>* }

}

my \tests = (
  'MyModule:ver<1.0.3>:auth<Name (email@example.com)>',
  'MyModule:ver<1.0.3>:auth<Name <email@example.com>>',
);

for tests -> \spec {

  say so Spec.parse: spec;

}

# Output:
True
False

【问题讨论】:

  • 谢谢 Jo King,我想用您的评论将问题标记为已解决,是否愿意将评论发布为答案?
  • 注意这个语法有很多问题。首先,受限令牌比package ::("Foo.Bar") { }(理论上use foo.bar:from&lt;Java&gt;)所证明的需要更严格。其次,它尝试解析需要评估代码的非常量版本定义。第三,一旦添加任何新属性(甚至是现有属性,例如:file&lt;...&gt;),它就会中断。第四,它不考虑转义&lt;&gt;
  • 感谢 ugexe 指出这些问题,正在努力解决。

标签: raku


【解决方案1】:

如果您知道内部字段与值标记的格式基本相同,则可以使用$&lt;val&gt;=[.*? &lt;value&gt;?] 递归匹配值。这甚至可以让您单独捕获内部字段的内容:

token value { '<' ~ '>' $<val>=[.*? <value>?] | '(' ~ ')' $<val>=<-[()]>* }

如果您不想要内部内容,则可以使用递归 &lt;~~&gt; 代替 &lt;value&gt;

token value { '<' ~ '>' $<val>=[.*? <~~>?] | '(' ~ ')' $<val>=<-[()]>* }

【讨论】:

  • 我建议不要使用.*?,而是在令牌value 中使用&lt;-[&gt;]&gt;*(除&gt; 之外的所有内容)。否则你可能会错误地匹配像 &lt;abc&gt;def&gt; 这样的字符串。