Skip to content

Instantly share code, notes, and snippets.

@moritz
Created December 19, 2020 14:13
Show Gist options
  • Save moritz/5c283004d360119d865a0eaa32ed3e87 to your computer and use it in GitHub Desktop.
Save moritz/5c283004d360119d865a0eaa32ed3e87 to your computer and use it in GitHub Desktop.
Advent of Code day 18 solultion in Raku #rakulang
grammar Expression {
token integer { \d+ }
proto token operator { <*> }
token operator:sym<+> { <sym> }
token operator:sym<*> { <sym> }
rule term { <integer> | <parens> }
rule parens { '(' ~ ')' <expression> }
rule expression { <term> + % <operator> }
token TOP { <.ws> <expression> }
}
class ExpressionAction {
method integer($/) { make $/.Int }
method operator:sym<+>($/) { make &[+] }
method operator:sym<*>($/) { make &[*] }
method term($/) { make $/.caps[0].value.made }
method parens($/) { make $<expression>.made }
method expression($/) { make [ $/.caps>>.value>>.made ] }
method TOP($/) { make $<expression>.made }
}
multi eval-ast(Int $x) { $x }
multi eval-ast(@ast) {
my $value = eval-ast(@ast.shift);
while @ast {
my &operator = @ast.shift;
my \rhs = eval-ast @ast.shift;
$value = operator($value, rhs);
}
return $value;
}
sub expr(Str $input) {
my $match = Expression.parse($input, :actions(ExpressionAction));
die "Invalid input <$input>\n" unless $match;
return eval-ast($match.made);
}
multi MAIN('test') {
use Test;
plan 3;
is expr('123'), 123, 'single-integer expression';
is expr('1 + 2 * 3 + 4 * 5 + 6'), 71, 'left to right, no parenthesis';
is expr('1 + (2 * 3) + (4 * (5 + 6))'), 51, 'Parenthesis expression'
}
multi MAIN() {
say [+] $*IN.lines.map: &expr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment