my \example-code = "(a + b)*3";
use lib '.';
use ExampleGrammar;
use CleanAST :Parens;
my \cst = ExampleGrammar .parse:
example-code,
actions => CleanAST;
say .ast given cst
use CleanAST :Parens;
unit grammar ExampleGrammar does Parens;
rule TOP { <INFIX-EXPR> | <EXPR> }
rule INFIX-EXPR { <EXPR> <INFIX> <EXPR> }
rule EXPR { <.lparen> <TOP> <.rparen> | <VAL> }
token INFIX { <ADD> | <MUL> }
token ADD { '+' }
token MUL { '*' }
token VAL { <IDENT> | <NUM> }
token IDENT { <.ident> }
token NUM { <.digit>+ }
unit class CleanAST;
our $*Parens is export(:Parens);
role Parens is Grammar is export(:Parens) {
token lparen { '(' {$*Parens++} }
token rparen { ')' {$*Parens--} }
}
# Example of a helper method:
sub ast-from-first-child { CALLERS::('$/').caps[0].value.ast }
method TOP ($/) {
# These two lines could be replaced by a call to the above helper method:
with $<INFIX-EXPR> { make $<INFIX-EXPR>.ast }
with $<EXPR> { make $<EXPR>.ast }
}
method EXPR ($/) {
# Example of using the above helper method:
make ast-from-first-child;
# Instead of these two lines:
# with $<VAL> { make $<VAL>.ast }
# with $<TOP> { make $<TOP>.ast }
}
method INFIX ($/) {
# These two lines could be replaced by a call to a helper routine for ast
# nodes which are just strings corresponding to their grammar rule name:
with $<ADD> { make 'ADD' }
with $<MUL> { make 'MUL' }
}
method VAL ($/) {
# These two lines could be replaced by a call to a helper routine for ast
# nodes which are strings constructed based on their grammar rule name:
with $<IDENT> { make q:s [IDENT{ str:"$<IDENT>" }] }
with $<NUM> { make q:s [NUM{ num:"$<NUM>" }] }
}
method INFIX-EXPR ($/) {
# This code could be replaced by a call to a helper routine that handles the
# desired ast formatting for an infix expression. Obviously there could be
# helper routines for other typical grammatical slots (prefix, postfix, etc.)
my $infix-and-curly = q:s:to<END>.chop;
$<INFIX>.ast() {
left: $<EXPR>[0].ast(),
right: $<EXPR>[1].ast()
}
END
# If indent level above zero, expand indent as appropriate
if try $*Parens {
$infix-and-curly.=subst: :g, / ^^ ' ' /, ' ' x $*Parens+1;
$infix-and-curly.=subst: / ^^ <?before '}'> /, ' ' x $*Parens;
}
make $infix-and-curly;
}