Perl6 には Grammar という機能があるのですが、これがまた凄いんです。スキャナとトークナイザと処理系が引っ付いている様な物がデフォルトで提供されているんです。
通常はこれらが別の機能として提供されており、プログラミング言語を実装する過程でデータの受け渡しがシームレスではなく、実装を変えたりするのが非常に面倒だったりします。しかしこれが Perl6 という一つの処理系の中で提供されてしまっている為、本来であれば数百ステップくらい掛かってしまう俺言語のコードが50ステップ程度で書けてしまいます。
use v6;
grammar SyoboiScript::Grammar {
token num { <[0..9]>+ }
token ident { <[a..z]>+ }
token op { '+' || '-' || '*' || '/' }
token exp { <ident> || <num> }
token expr { <exp> | <exp> \s* <op> \s* <exp> }
token let { <ident> \s* '=' \s* <expr> }
token call { <ident> '(' \s* <expr> \s* ')' }
token stmt { <call> || <let> }
rule TOP { ^ ( <stmt> || '#' .* || "\n" )* $ }
}
class SyoboiScript::Action {
my Hash $func = {
print => sub ($arg) {
say $arg;
}
};
my Hash $vars;
method num($/) { make EVAL $/.Str }
method ident($/){
make $vars{$/.Str};
}
method call($/){
make $func{$<ident>.Str}(self.expr($<expr>));
}
method let($/){
my $v = self.expr($<expr>);
$vars{$<ident>.Str} = $v;
make $v;
}
method expr($/){
given $<op> {
when '+' { make [+]($<exp>>>.ast) }
when '-' { make [-]($<exp>>>.ast) }
when '*' { make [*]($<exp>>>.ast) }
when '/' { make [/]($<exp>>>.ast) }
default { make $<exp>>>.ast[0] }
}
}
method exp($/) {
make $/.values[0].ast;
}
method TOP($/) { make $<exp>.ast; }
}
sub MAIN(Bool :$dump = False, Str :$file = 'syoboi.ss') {
my $act = SyoboiScript::Action.new;
SyoboiScript::Grammar.parse(slurp($file), actions => $act);
}
たったこれだけですが、以下の syoboi.ss
というスクリプトファイルを読み込み、画面に3と表示するプログラミング言語が実装出来ました。
a = 1
a = a + 2
print(a)
Perl6 凄い!