39698676da43d92c3ca5fdbc0bdfb4b257066f21
[scpubgit/DX.git] / lib / DX / Step / ResolveProposition.pm
1 package DX::Step::ResolveProposition;
2
3 use DX::Step::EnterRecheck;
4 use DX::Step::Backtrack;
5
6 use Types::Standard qw(ArrayRef);
7 use DX::Utils qw(expand_deps);
8
9 use DX::Class;
10
11 with 'DX::Role::Step';
12
13 has resolves => (is => 'lazy', init_arg => undef, builder => sub {
14   my ($self) = @_;
15   $self->resolution_space->proposition;
16 });
17
18 has resolution_space => (is => 'ro', isa => ResolutionSpace);
19
20 has current_resolution => (is => 'lazy', init_arg => undef, builder => sub {
21   my ($self) = @_;
22   $self->resolution_space->next_resolution;
23 });
24
25 has actions => (is => 'lazy', init_arg => undef, builder => sub {
26   my ($self) = @_;
27   $self->current_resolution->actions;
28 });
29
30 has depends_on => (is => 'lazy', init_arg => undef, builder => sub {
31   my ($self) = @_;
32   expand_deps($self->current_resolution->veracity_depends_on);
33 });
34
35 has alternative_step => (is => 'lazy', init_arg => undef, builder => sub {
36   my ($self) = @_;
37   my $rspace = $self->resolution_space->remaining_resolution_space;
38   return undef unless @{$rspace->members};
39   return $rspace->next_step;
40 });
41
42 sub but_first {
43   my ($self, @actions) = @_;
44   $self->but(actions => [ @actions, @{$self->actions} ]);
45 }
46
47 sub but_with_dependencies_on {
48   my ($self, @deps) = @_;
49   $self->but(depends_on => [ @{$self->depends_on}, @deps ]);
50 }
51
52 sub apply_to {
53   my ($self, $old_ss) = @_;
54   trace resolve => [ statement => [
55     [ symbol => 'resolve' ],
56     [ block => [
57       [ statement => [
58         [ symbol => 'proposition' ],
59         @{$self->resolves->for_deparse->[1]},
60       ] ],
61       (@{$self->actions}
62         ? [ statement => [
63             [ symbol => 'actions' ],
64             [ block => $self->actions ],
65           ] ]
66         : ()),
67       [ statement => [
68         [ symbol => 'depends_on' ],
69         [ pairs => [
70           map [
71             (split '::', ${$_->[0]})[-1],
72             [ value_path => [ @{$_}[1..$#$_] ] ]
73           ], @{$self->depends_on}
74         ] ],
75       ] ],
76     ] ]
77   ] ];
78   my $ns = do {
79     if (my $prop = $old_ss->next_proposition) {
80       DX::Step::ConsiderProposition->new(
81         proposition => $prop
82       )
83     } else {
84       $old_ss->on_solution_step
85     }
86   };
87   my $ss = $old_ss->but(
88     next_step => $ns,
89     decisions_taken => [
90       [ $self->resolution_space, $old_ss ],
91       @{$old_ss->decisions_taken}
92     ],
93   );
94   my $new_ss = $self->_apply_to_ss($ss);
95   return $ss->but(next_step => DX::Step::Backtrack->new) unless $new_ss;
96   return $new_ss;
97 }
98
99 sub _apply_to_ss {
100   my ($self, $old_ss) = @_;
101   my $old_hyp = $old_ss->current_hypothesis;
102   (my $hyp, my @recheck) = $old_hyp->with_resolution(
103     $self->resolves, $self->depends_on, $self->actions
104   );
105   return undef unless $hyp;
106   return $self->_recheck_for(
107     $old_ss->but(current_hypothesis => $hyp),
108     @recheck
109   );
110 }
111
112 sub _recheck_for {
113   my ($self, $old_ss, @recheck) = @_;
114
115   return $old_ss unless @recheck;
116
117   my $ss = $old_ss->but(
118     next_step => DX::Step::EnterRecheck->new(
119       proposition_list => \@recheck,
120       on_completion_step => $old_ss->next_step,
121       on_failure_step => DX::Step::Backtrack->new,
122     ),
123   );
124
125   return $ss;
126 }
127
128 1;