package DX::State;
+use Return::MultiLevel qw(with_return);
+use DX::Op::FromCode;
use Moo;
has next_op => (is => 'ro', required => 1);
$var->bound_value; $var->clear_bound_value;
return $state->mark_choice($var) unless $var->bound_stream->is_exhausted;
}
+ if (our $No_Options_Handler) {
+ $No_Options_Handler->(undef);
+ }
die "Out of options";
}
sub run {
my ($state) = @_;
- while (my $op = $state->next_op) {
- $state = $op->run($state);
+ with_return {
+ my ($return) = @_;
+ local our $No_Options_Handler = $return;
+ while (my $op = $state->next_op) {
+ $state = $op->run($state);
+ }
+ return $state;
}
- return $state;
+}
+
+sub push_backtrack {
+ $_[0]->then(DX::Op::FromCode->new(code => sub { $_[1]->backtrack }));
}
1;
}
}
+sub test_values {
+ my ($vars, $test) = @_;
+ sub {
+ my ($self, $state) = @_;
+ my @values = map $state->scope_var($_)->bound_value, @$vars;
+ if ($test->(@values)) {
+ return $state->then($self->next);
+ }
+ return $state->backtrack;
+ }
+}
+
my $op = FromCode->new(
code => bind_array(S => \@servers),
next => FromCode->new(
- code => sub {
- my ($self, $state) = @_;
- my $server = $state->scope_var('S')->bound_value;
- if ($server =~ /\.example\.com$/) {
- return $state->then($self->next);
- }
- return $state->backtrack;
- },
+ code => test_values([ 'S' ], sub { $_[0] =~ /\.example\.com$/ })
)
);
-my %scope = map +($_ => $_), qw(S);
-my %by_id = map +($_ => DX::Var->new(id => $_)), qw(S);
+sub make_state {
+ my ($vars, $op) = @_;
-my $state = DX::State->new(
- next_op => $op,
- return_stack => [],
- by_id => \%by_id,
- scope => \%scope,
- last_choice => []
-);
+ my %scope = map +($_ => $_), @{$vars};
+ my %by_id = map +($_ => DX::Var->new(id => $_)), @{$vars};
+
+ DX::State->new(
+ next_op => $op,
+ return_stack => [],
+ by_id => \%by_id,
+ scope => \%scope,
+ last_choice => []
+ );
+}
-my $stream = DX::ResultStream->new(for_state => $state);
+my $stream = DX::ResultStream->new(for_state => make_state([ 'S' ], $op));
is($stream->next->{'S'}, $_)
for qw(jim.example.com joe.example.com bob.example.com);
-dies_ok { $stream->next } 'No more';
+is($stream->next, undef, 'No more');
+
+exit 0;
+
+my $complex_op = FromCode->new(
+ code => bind_array(S => \@servers),
+ next => FromCode->new(
+ code => test_values([ 'S' ], sub { $_[0] =~ /\.example\.com$/ }),
+ next => FromCode->new(
+ code => bind_array(P => \@shells),
+ next => FromCode->new(
+ code => test_values([ qw(S P) ], sub { $shells{$_[1]}{$_[0]} }),
+ )
+ )
+ )
+);
+
+my $cstream = DX::ResultStream->new(
+ for_state => make_state([ qw(S P) ], $complex_op)
+);
+
+::Dwarn($cstream->next);
+::Dwarn($cstream->next);
+::Dwarn($cstream->next);
+::Dwarn($cstream->next);
+::Dwarn($cstream->next);
done_testing;