Skip to content

Commit f72fb2b

Browse files
committed
handle custom_args case by allowing any number of args
1 parent 1168608 commit f72fb2b

File tree

1 file changed

+100
-91
lines changed

1 file changed

+100
-91
lines changed

src/vm/moar/QAST/QASTCompilerMAST.nqp

Lines changed: 100 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -668,124 +668,133 @@ class QAST::MASTCompiler {
668668
push_op(@pre, 'takeclosure', $reg, $reg);
669669
}
670670

671-
# Analyze parameters to get count of required/optional and make sure
672-
# all is in order.
673-
my $param_index := 0;
674-
my int $pos_required := 0;
675-
my int $pos_optional := 0;
676-
my int $pos_slurpy := 0;
677-
for $block.params {
678-
if $_.named {
679-
# Don't count.
680-
}
681-
elsif $_.slurpy {
682-
if $pos_slurpy {
683-
nqp::die("Only one slurpy positional allowed");
671+
if $node.custom_args {
672+
# The block does the arg processing by itself, so we accept any number
673+
# of args here.
674+
push_op(@pre, 'checkarity',
675+
MAST::IVal.new( :size(16), :value(0)),
676+
MAST::IVal.new( :size(16), :value(-1)));
677+
}
678+
else {
679+
# Analyze parameters to get count of required/optional and make sure
680+
# all is in order.
681+
my $param_index := 0;
682+
my int $pos_required := 0;
683+
my int $pos_optional := 0;
684+
my int $pos_slurpy := 0;
685+
for $block.params {
686+
if $_.named {
687+
# Don't count.
684688
}
685-
$pos_slurpy := 1;
686-
}
687-
elsif $_.default {
688-
if $pos_slurpy {
689-
nqp::die("Optional positionals must come before all slurpy positionals");
689+
elsif $_.slurpy {
690+
if $pos_slurpy {
691+
nqp::die("Only one slurpy positional allowed");
692+
}
693+
$pos_slurpy := 1;
690694
}
691-
$pos_optional++;
692-
}
693-
else {
694-
if $pos_optional {
695-
nqp::die("Required positionals must come before all optional positionals");
695+
elsif $_.default {
696+
if $pos_slurpy {
697+
nqp::die("Optional positionals must come before all slurpy positionals");
698+
}
699+
$pos_optional++;
696700
}
697-
if $pos_slurpy {
698-
nqp::die("Required positionals must come before all slurpy positionals");
701+
else {
702+
if $pos_optional {
703+
nqp::die("Required positionals must come before all optional positionals");
704+
}
705+
if $pos_slurpy {
706+
nqp::die("Required positionals must come before all slurpy positionals");
707+
}
708+
$pos_required++;
699709
}
700-
$pos_required++;
701710
}
702-
}
703711

704-
# check the arity
705-
push_op(@pre, 'checkarity',
706-
MAST::IVal.new( :size(16), :value($pos_required)),
707-
MAST::IVal.new( :size(16), :value($pos_slurpy ?? -1 !! $pos_required + $pos_optional)));
712+
# check the arity
713+
push_op(@pre, 'checkarity',
714+
MAST::IVal.new( :size(16), :value($pos_required)),
715+
MAST::IVal.new( :size(16), :value($pos_slurpy ?? -1 !! $pos_required + $pos_optional)));
708716

709-
# build up instructions to bind the params
710-
for $block.params -> $var {
717+
# build up instructions to bind the params
718+
for $block.params -> $var {
711719

712-
my $scope := $var.scope;
713-
nqp::die("Param scope must be 'local' or 'lexical'")
714-
if $scope ne 'lexical' && $scope ne 'local';
720+
my $scope := $var.scope;
721+
nqp::die("Param scope must be 'local' or 'lexical'")
722+
if $scope ne 'lexical' && $scope ne 'local';
715723

716-
my $param_kind := self.type_to_register_kind($var.returns);
717-
my $opslot := @kind_to_op_slot[$param_kind];
724+
my $param_kind := self.type_to_register_kind($var.returns);
725+
my $opslot := @kind_to_op_slot[$param_kind];
718726

719-
my $opname_index := ($var.named ?? 8 !! 0) + ($var.default ?? 4 !! 0) + $opslot;
720-
my $opname := @param_opnames[$opname_index];
727+
my $opname_index := ($var.named ?? 8 !! 0) + ($var.default ?? 4 !! 0) + $opslot;
728+
my $opname := @param_opnames[$opname_index];
721729

722-
# what will be put in the value register
723-
my $val;
730+
# what will be put in the value register
731+
my $val;
724732

725-
if $var.slurpy {
726-
if $var.named {
727-
$opname := "param_sn";
733+
if $var.slurpy {
734+
if $var.named {
735+
$opname := "param_sn";
736+
}
737+
else {
738+
$opname := "param_sp";
739+
}
728740
}
729-
else {
730-
$opname := "param_sp";
741+
elsif $var.named {
742+
$val := MAST::SVal.new( :value($var.named) );
743+
}
744+
else { # positional
745+
$val := MAST::IVal.new( :size(16), :value($param_index));
731746
}
732-
}
733-
elsif $var.named {
734-
$val := MAST::SVal.new( :value($var.named) );
735-
}
736-
else { # positional
737-
$val := MAST::IVal.new( :size(16), :value($param_index));
738-
}
739747

740-
# the variable register
741-
my $valreg := $scope eq 'lexical'
742-
?? $block.lexical_param($var.name)
743-
!! $block.local($var.name);
748+
# the variable register
749+
my $valreg := $scope eq 'lexical'
750+
?? $block.lexical_param($var.name)
751+
!! $block.local($var.name);
744752

745-
# NQP->QAST always provides a default value for optional NQP params
746-
# even if no default initializer expression is provided.
747-
if $var.default {
748-
# generate end label to skip initialization code
749-
my $endlbl := MAST::Label.new( :name(self.unique('param') ~ '_end') );
753+
# NQP->QAST always provides a default value for optional NQP params
754+
# even if no default initializer expression is provided.
755+
if $var.default {
756+
# generate end label to skip initialization code
757+
my $endlbl := MAST::Label.new( :name(self.unique('param') ~ '_end') );
750758

751-
# generate default initialization code. Could also be
752-
# wrapped in another QAST::Block.
753-
my $default_mast := self.as_mast($var.default, :want($param_kind));
759+
# generate default initialization code. Could also be
760+
# wrapped in another QAST::Block.
761+
my $default_mast := self.as_mast($var.default, :want($param_kind));
754762

755-
# nqp::die("default initialization result type doesn't match the param type")
756-
# unless $default_mast.result_kind == $param_kind;
763+
# nqp::die("default initialization result type doesn't match the param type")
764+
# unless $default_mast.result_kind == $param_kind;
757765

758-
# emit param grabbing op
759-
push_op(@pre, $opname, $valreg, $val, $endlbl);
766+
# emit param grabbing op
767+
push_op(@pre, $opname, $valreg, $val, $endlbl);
760768

761-
# emit default initialization code
762-
push_ilist(@pre, $default_mast);
769+
# emit default initialization code
770+
push_ilist(@pre, $default_mast);
763771

764-
# put the initialization result in the variable register
765-
push_op(@pre, 'set', $valreg, $default_mast.result_reg);
766-
$*REGALLOC.release_register($default_mast.result_reg, $default_mast.result_kind);
772+
# put the initialization result in the variable register
773+
push_op(@pre, 'set', $valreg, $default_mast.result_reg);
774+
$*REGALLOC.release_register($default_mast.result_reg, $default_mast.result_kind);
767775

768-
# end label to skip initialization code
769-
nqp::push(@pre, $endlbl);
770-
}
771-
elsif $var.slurpy {
772-
if $var.named {
773-
push_op(@pre, $opname, $valreg);
776+
# end label to skip initialization code
777+
nqp::push(@pre, $endlbl);
778+
}
779+
elsif $var.slurpy {
780+
if $var.named {
781+
push_op(@pre, $opname, $valreg);
782+
}
783+
else {
784+
push_op(@pre, $opname, $valreg, MAST::IVal.new( :value($pos_required + $pos_optional) ));
785+
}
774786
}
775787
else {
776-
push_op(@pre, $opname, $valreg, MAST::IVal.new( :value($pos_required + $pos_optional) ));
788+
# emit param grabbing op
789+
push_op(@pre, $opname, $valreg, $val);
777790
}
778-
}
779-
else {
780-
# emit param grabbing op
781-
push_op(@pre, $opname, $valreg, $val);
782-
}
783791

784-
if $scope eq 'lexical' {
785-
# emit the op to bind the lexical to the result register
786-
push_op(@pre, 'bindlex', $block.lexical($var.name), $valreg);
792+
if $scope eq 'lexical' {
793+
# emit the op to bind the lexical to the result register
794+
push_op(@pre, 'bindlex', $block.lexical($var.name), $valreg);
795+
}
796+
$param_index++;
787797
}
788-
$param_index++;
789798
}
790799

791800
nqp::splice($frame.instructions, @pre, 0, 0);

0 commit comments

Comments
 (0)