Grammars

29.1 A First Grammar

grammar KeyValue {
    token TOP     { <pair>* %% \n }                  # TOP is the default entry point
    token pair    { <key> \h* '=' \h* <value> }
    token key     { \w+ }
    token value   { \N+ }
}

my $config = q:to/END/;
name = Raku
version = 6.d
author = Larry
END

my $match = KeyValue.parse($config.trim);
say $match<pair>.map({ ~.<key> => ~.<value> }).Hash;   # {author => Larry, name => Raku, version => 6.d}

29.2 A JSON Grammar

grammar JSON::Tiny::Grammar {
    rule  TOP      { ^ <value> $ }
    rule  value    { <object> | <array> | <string> | <number> | <true> | <false> | <null> }
    rule  object   { '{' ~ '}' [ <pair>* % ',' ] }      # ~ : goal-matching (open ~ close inner)
    rule  pair     { <string> ':' <value> }
    rule  array    { '[' ~ ']' [ <value>* % ',' ] }
    token string   { '"' ~ '"' [ <str-char>* ] }
    token str-char { <-["\\]> | '\\' <["\\/bfnrt]> | '\\u' <xdigit>**4 }
    token number   { '-'? [ 0 | <[1..9]>\d* ] [ '.' \d+ ]? [ <[eE]> <[+-]>? \d+ ]? }
    token true     { 'true' }
    token false    { 'false' }
    token null     { 'null' }
}
say so JSON::Tiny::Grammar.parse('{"name": "Raku", "tags": ["fun", "grammars"], "year": 2015}');   # True

29.3 Grammar Features

.parse($str) (must match the whole string), .subparse($str) (prefix), .parsefile($path), :rule<other-entry>, :actions(...).

Inheritance: grammar Extended is Base { token value { <extra> | <base-value=.Base::value> } }. Grammars are classes, so you can override tokens.

Proto regexes for extensible alternatives:

<.ws> (non-capturing whitespace, used by rules), <?> (always matches), <!> (never matches), <.panic("msg")>-style error reporting via methods, :my $var declarations inside regexes, and dynamic variables for context-sensitive parsing.

Debugging grammars: use Grammar::Tracer; (prints a parse trace) and use Grammar::Debugger; (interactive). Both are installable with zef.

grammar Calc {
    token TOP { <expr> }
    proto token op {*}
    token op:sym<+> { <sym> }
    token op:sym<-> { <sym> }
    token op:sym<*> { <sym> }
    token expr { <num> [ \s* <op> \s* <num> ]* }
    token num { \d+ }
}
say Calc.parse('1 + 2 * 3')<expr><op>».Str;   # (+ *)