package DX::Op::CallRule;

use DX::Op::SetScope;
use DX::Op::FromCode;
use DX::Var;
use DX::ArrayStream;
use Moo;

with 'DX::Role::Op';

has rule_name => (is => 'ro', required => 1);
has rule_args => (is => 'ro', required => 1);
has full_name => (is => 'lazy', builder => sub {
  my ($self) = @_;
  join('/', $self->rule_name, scalar @{$self->rule_args});
});

sub run {
  my ($self, $state) = @_;
#warn "Call: ".$self->full_name;
  my @args;
  foreach my $arg (@{$self->rule_args}) {
    ($state, my $expanded) = $self->_expand_argspec($state, $arg);
    push @args, $expanded;
  }
  my @rules = @{$state->rule_set->rules->{$self->full_name}||[]};
  die "No rules for ${\$self->full_name}" unless @rules;
  my $var = DX::Var->new(id => "rule:".$self->full_name)
                   ->with_stream(DX::ArrayStream->from_array(@rules));
  my $invoke = DX::Op::FromCode->new(
    code => sub {
      my ($self, $state) = @_;
      my $call = $state->resolve_value($var)->but(args => \@args);
      $state->but(scope => {})->then($call);
    }
  );
  my $ret_op = DX::Op::SetScope->new(
    scope => $state->scope, next => $self->next
  );
  $state->push_return_then($ret_op, $invoke)->mark_choice($var);
}

1;
