diff --git a/src/niecza b/src/niecza index bad1244b..92790c63 100644 --- a/src/niecza +++ b/src/niecza @@ -73,14 +73,7 @@ method process_name($/, :$declaring, :$defer, :$clean) { } for $defer ?? () !! @ns.grep($Op) { - $_ = ~self.trivial_eval($/, $_); - # XXX should this always stringify? - if $_ ~~ Cool { - $_ = ~$_; - } else { - $_ = "XXX"; - $/.CURSOR.sorry("Name components must evaluate to strings"); - } + $_ = self.eval_ast_str($/, $_) // "XXX"; } if $declaring { @@ -136,6 +129,13 @@ dyn: return $pkg; } } +method eval_ast_str($/, $ast) { + my $val; + $/.CURSOR.trymop({ + $val = self.eval_ast($/, $ast).to_string; + }); + $val; +} method get_cp_ext($/) { if $/ eq any <:_ :U :D :T> { return ""; @@ -143,9 +143,7 @@ method get_cp_ext($/) { return ":" ~ ($ ?? '' !! '!') ~ $; } else { my $suf = ~$; - $/.CURSOR.trymop({ - $suf = self.eval_ast($/, $.ast).to_string if $.ast; - }); + $suf = self.eval_ast_str($/, $.ast) // $suf if $.ast; return ":" ~ $ ~ "<" ~ $suf ~ ">"; } } @@ -168,6 +166,150 @@ method colonpair($/) { make { term => $OpSimplePair.new(key => $, value => $tv) }; } +method process_block_traits($/, @tr) { + my $sub = $*CURLEX; + my $pack = $sub.body_of; + for @tr -> $T { + my $tr = $T.ast; + if $pack && $tr { + my $super = $tr; + + $T.CURSOR.sorry("superclass $super.name() declared outside of any class"), + next unless $sub.body_of; + $T.CURSOR.sorry("superclass $super.name() declared in an augment"), + next if defined $*AUGMENT_BUFFER; + $T.CURSOR.sorry("cannot declare a superclass in this kind of package"), + next if !$pack.CAN('add_super'); + + $T.CURSOR.trymop({ + $pack.add_super($super); + }); + } elsif $pack && $tr { + my $role = $tr; + + $T.CURSOR.sorry("role $role.name() used outside of any class"), next + unless $sub.body_of; + $T.CURSOR.sorry("role $role.name() used in an augment"), + next if defined $*AUGMENT_BUFFER; + $T.CURSOR.sorry("cannot use a role in this kind of package"), + next if !$pack.CAN('add_role'); + + $T.CURSOR.trymop({ + $pack.add_role($role); + }); + } elsif $pack && $tr { + my @exports = @( $tr ); + $sub.outer.add_exports($pack.name, $pack, @exports); + } elsif !$pack && $tr { + my @exports = @( $tr ); + $sub.outer.add_exports($sub.outervar, $sub, @exports); + $sub.set_extend('exported', @exports); + $sub.outer.create_static_pad; + $/.CURSOR.mark_used($sub.outervar) + if defined $sub.outervar; + } elsif !$pack && $tr { + $sub.set_signature(Any); + } elsif !$pack && $tr { + $sub.outer.create_static_pad; + $sub.set_extend('pure', True); + } elsif !$pack && grep { defined $tr{$_} }, { + my $rel = $tr.keys.[0]; + my $to = $tr.values.[0]; + $to = $to.inside if $to ~~ $OpParen; + $to = $to.children[0] if $to ~~ $OpStatementList && $to.children == 1; + + my $oprec; + if $to ~~ $OpLexical { + $oprec = $T.CURSOR.function_O($to.name); + } elsif $to ~~ $OpStringLiteral && $sub.name ~~ /^(\w+)\:\<.*\>$/ { + $oprec = $T.CURSOR.cat_O(~$0, $to.text); + } else { + $T.CURSOR.sorry("Cannot interpret operator reference"); + next; + } + unless $sub.get_extend('prec') { + $T.CURSOR.sorry("Target does not seem to be an operator"); + next; + } + unless $oprec { + $T.CURSOR.sorry("No precedence available for reference target"); + next; + } + if $rel eq 'equiv' { + $sub.set_extend('prec', $oprec.kv); + } else { + my %prec = $sub.get_extend('prec'); + %prec = $oprec.; + %prec ~~ s/\=/<=/ if $rel eq 'looser'; + %prec ~~ s/\=/>=/ if $rel eq 'tighter'; + $sub.set_extend('prec', %prec.kv); + } + } elsif !$pack && $tr { + my $arg = self.eval_ast_str($T, $tr) // ''; + my %prec = $sub.get_extend('prec'); + unless %prec { + $T.CURSOR.sorry("Target does not seem to be an operator"); + next; + } + unless $arg eq any < left right non list unary chain > { + $T.CURSOR.sorry("Invalid associativity $arg"); + next; + } + %prec = $arg; + $sub.set_extend('prec', %prec.kv); + } elsif !$pack && $tr { + my $arg = self.eval_ast_str($T, $tr) // ''; + my %prec = $sub.get_extend('prec'); + unless %prec { + $T.CURSOR.sorry("Target does not seem to be an operator"); + next; + } + %prec = $arg; + %prec = "like $sub.name()"; + $sub.set_extend('prec', %prec.kv); + } elsif !$pack && $tr { + # XXX this is a smidge ugly + my ($name, @rest) = (self.eval_ast_str($T, $tr) // "a").words; + $sub.set_extend('builtin', $name, map +*, @rest); + } elsif !$pack && $tr { + $sub.set_return_pass; + } elsif !$pack && $tr { + } elsif !$pack && $tr { + } elsif !$pack && $tr { + $sub.set_unsafe; + } else { + $T.CURSOR.sorry("Unhandled trait $tr.keys[0] for this context"); + } + } +} +method statement_prefix:BEGIN ($/) { + # MAJOR HACK - allows test code like BEGIN { @*INC.push: ... } to work + # Should go away later once the spec is less slushy + repeat while False { + my $c = ($ || $).ast; + + last unless $c ~~ $OpStatementList; + last unless $c.children == 1; + my $d = $c.children.[0]; + last unless $d ~~ $OpCallMethod; + last unless $d.receiver ~~ $OpContextVar; + last unless $d.receiver.name eq '@*INC'; + last if $d.private || $d.ismeta; + last unless $d.name eq any ; + last unless +$d.getargs == 1; + last unless defined my $str = self.eval_ast_str($/, $d.getargs.[0]); + @*INC."$d.name()"($str); + make $OpStatementList.new; + return; + } + + $*CURLEX.create_static_pad; + my $con = self.make_constant($/, 'anon', 'BEGIN'); + $.ast.run_BEGIN($con.name); + $con.init = True; + make $con; +} + } # remove run_dispatch