Grammar to parse module specification

hyt*_*thm 9 perl6 raku

Raku modules can be specified in different ways, for example:

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>>;

I wrote the below grammar to parse the module spec which works fine for most of specs but it fails if the auth field contains < or >. How can I fix the grammar to match in this case as well?

I can't figure out how to say match everything in between < and > including any < and > as well.

#!/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
Run Code Online (Sandbox Code Playgroud)

Jo *_*ing 7

If you know that the inner field will basically be in the same format as the value token, you can recursively match for value with $<val>=[.*? <value>?]. This even lets you capture the contents of the inner field seperately:

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

If you don't want the inner contents than you can use the recursive <~~> in place of <value>

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

  • 我建议不要使用`。*?`,而应在标记`value'内使用`&lt;-[&gt;]&gt; *`(除`&gt;`外的所有内容)。否则,您可能会错误地匹配`&lt;abc&gt; def&gt;`之类的字符串。 (2认同)