| # use Grammar::Tracer;
|
|
|
| grammar Vixen {
|
| token id { <[A..Za..z*]>+ <![:]> }
|
| token selector { <[A..Za..z*]>+ \: }
|
| token string { \" <[A..Za..z*]>* \" }
|
| token param { \: <id> }
|
| token ass { \:\= }
|
|
|
| proto rule obj {*}
|
| rule obj:sym<block> { <block> }
|
| rule obj:sym<paren> { '(' <call> ')' }
|
| rule obj:sym<string> { <string> }
|
| rule obj:sym<name> { <id> }
|
|
|
| proto rule unary {*}
|
| rule unary:sym<chain> { <obj> (<id>* % <ws>) }
|
|
|
| proto rule message {*}
|
| rule message:sym<key> { (<selector> <unary>)+ }
|
|
|
| proto rule call {*}
|
| rule call:sym<cascade> { <unary> (<message>* % ';') }
|
|
|
| proto rule assign {*}
|
| rule assign:sym<assign> { <id> <ass> <call> }
|
| rule assign:sym<call> { <call> }
|
|
|
| proto rule exprs {*}
|
| rule exprs:sym<rv> { (<assign> '.')* '^' <call> }
|
| rule exprs:sym<nil> { (<assign> '.')* <call> }
|
|
|
| rule block { '[' <param>* '|' <exprs> ']' }
|
|
|
| rule TOP { <block> }
|
| }
|
|
|
| class MakeBlocks {
|
| has Int $!syms;
|
|
|
| method gensym { $!syms += 1; "gs" ~ $!syms; }
|
| method callTo($name, @row) {
|
| say "callTo $name ", @row;
|
| my $args = @row.join;
|
| say "backtick -E $name \{ \$\{V\}/call: $args \}";
|
| $name;
|
| }
|
| method callAnon(@row) { self.callTo: self.gensym, @row; }
|
|
|
| method obj:sym<block>($/) { make $<block>.Str; }
|
| method obj:sym<paren>($/) { make $<call>.made; }
|
| method obj:sym<string>($/) { make $<string>.Str; }
|
| method obj:sym<name>($/) { make $<id>.Str; }
|
|
|
| method unary:sym<chain>($/) {
|
| my Str $rv = $<obj>.made;
|
| for $<id> {
|
| my @row = @_.map: *.made;
|
| @row.prepend: $rv;
|
| say "my unary row: ", @row;
|
| my ($name, $line) = self.callAnon(@row);
|
| $rv = $name;
|
| say $line;
|
| }
|
| make $rv;
|
| }
|
|
|
| method message:sym<key>($/) {
|
| my $verb = $/[0, 2 ... *].join;
|
| say "my verb: $verb";
|
| make $[1, 3 ... *].map(*.made).prepend: $verb;
|
| }
|
|
|
| method call:sym<cascade>($/) {
|
| my Str $target = $<unary>.made;
|
| my Str $rv = $target;
|
| for $<message> {
|
| my @row = @_.map: *.target;
|
| @row.prepend: $target;
|
| say "my cascade row: ", @row;
|
| my ($name, $line) = self.callAnon(@row);
|
| $rv = $name;
|
| say $line;
|
| }
|
| make $rv;
|
| }
|
|
|
| method assign:sym<assign>($/) { make self.callTo($<id>.made, $<call>.made); }
|
| method assign:sym<call>($/) { make self.callAnon($<call>.made); }
|
|
|
| method exprs:sym<rv>($/) { make $<call>.made; }
|
| method exprs:sym<nil>($/) {
|
| say "importas -iS Nil \$Nil";
|
| make $<call>.made;
|
| }
|
|
|
| method block($/) {
|
| say "#!/usr/bin/env -S execlineb -s", $<param>.elems + 1;
|
| say "importas -iS V";
|
| say "export self \$1";
|
| for $<param>.kv -> $i, $n {
|
| say "export ", substr($n, 1), " \$", $i + 2;
|
| }
|
| make $<exprs>.made;
|
| }
|
|
|
| method TOP($/) { say "top"; make $<block>.made; }
|
| }
|
|
|
| my $actions = MakeBlocks.new();
|
| my $parsed = Vixen.parse: slurp $*IN, :$actions;
|
| say "Parse tree: ", $parsed;
|
| say "Made: ", $parsed.made;
|