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}'); # True29.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; # (+ *)