# See https://www.reddit.com/r/ProgrammingLanguages/comments/9j9r97/lexer_modes_parser_token_advancingpeeking/e6r2k7c
# use Grammar::Tracer;
my @args; # Store arguments to ease into showing P6 is building a complete parse tree
grammar string { ... } # stub declaration because grammars recursively call each other
grammar mainline-code {
rule TOP { <statement>* %% \n+ } # %% RHS is separator
token statement { <routine-call>? <eol-comment>? }
token routine-call { <method-call> | <sub-call> }
token method-call { <ident> '.' <ident> }
token sub-call { <ident> \s+ <argument>* % ',' } # % means ',' only in between
token argument {
[ | <number>
| <variable>
| <string::TOP> # Recursively call string grammar
]
# Hack to hint that parse tree is being built:
{ @args.append: .keys, .Str given $/ }
}
token variable { '$' <ident> }
token number { \d+ }
token eol-comment { '#' \N* }
}
grammar string {
rule TOP { \" ~ \" <content>* } # `~` looks between LHS/RHS operands for content
token content {
|| <mainline-code::variable> # Reuse mainline-code grammar parsing for variable
|| <before '$({'> <embedded-code> # `before` peeks ahead
|| . # Otherwise munch a single character
}
# Recursively call mainline grammar in attempt to parse code block embedded in string:
rule embedded-code { '$({' ~ '})' <mainline-code::TOP> }
}
(.say for @args) given mainline-code.parse: q:to<EOS>;
println "it is $({
# This is a comment!?
sleep 250
date.now
}) right now!"
EOS
say mainline-code.parse: 'println "hello $person!"';