# Create NQP ops without Call::Name roundabout class RakuAST::Nqp is RakuAST::Expression { has Str $.op; has RakuAST::ArgList $.args; method new(Str $op, *@args) { nqp::die('RakuAST::Nqp does not support nqp::const. Use RakuAST::Nqp::Const') if $op eq 'const'; my $obj := nqp::create(self); nqp::bindattr($obj, RakuAST::Nqp, '$!op', $op); my $args; if nqp::elems(@args) == 1 { my $it := @args[0]; if nqp::istype($it, RakuAST::ArgList) { nqp::bindattr($obj, RakuAST::Nqp, '$!args', $it); $args := nqp::getattr(@args[0], RakuAST::ArgList, '$!args'); } elsif nqp::istype($it, List) { $it.elems; # reify $obj.set-args($args := nqp::getattr($it, List, '$!reified')); } else { $obj.set-args($args := @args); } } else { $obj.set-args($args := @args); } # We want to make use of nqp ops as simple as possible, so # we automatically convert common types to their RakuAST # equivalents. my int $i := 0; my int $n := nqp::elems($args); while $i < $n { my $arg := $args[$i]; if nqp::istype($arg,Str) { $args[$i] := RakuAST::StrLiteral.new($arg); } elsif nqp::istype($arg,Int) { $args[$i] := RakuAST::IntLiteral.new($arg); } ++$i; } $obj } method set-args($args) { my $arglist := nqp::create(RakuAST::ArgList); nqp::bindattr($arglist, RakuAST::ArgList, '$!args', $args); nqp::bindattr(self, RakuAST::Nqp, '$!args', $arglist); } method visit-children(Code $visitor) { my @args := nqp::getattr(self.args, RakuAST::ArgList, '$!args'); for @args { $visitor($_); } } method IMPL-EXPR-QAST(RakuAST::IMPL::QASTContext $context) { my $call := QAST::Op.new(:op($!op)); $!args.IMPL-ADD-QAST-ARGS($context, $call); # We generally want to send unboxed string/int values in for dispatch # arguments (although leave normal ones alone); we can't really # know which are which, but if we're writing out an `nqp::op` # just assume that they should all be unboxed; most situations # will see the dispatch op generated anyway. my int $i := 0; my int $n := nqp::elems($call.list); while $i < $n { my $arg := $call[$i]; if nqp::istype($arg, QAST::Want) && ($arg[1] eq 'Ss' || $arg[1] eq 'Ii') { $call[$i] := $arg[2]; } $i++; } $call } } class RakuAST::Nqp::Const is RakuAST::Expression { has Str $.name; method new(Str $name) { my $obj := nqp::create(self); nqp::bindattr($obj, RakuAST::Nqp::Const, '$!name', $name); $obj } method IMPL-EXPR-QAST(RakuAST::IMPL::QASTContext $context) { QAST::Op.new(:op, :name($!name)); } }