Commit | Line | Data |
9d759b64 |
1 | package DX::Predicate::MemberAt; |
2 | |
7f385fb2 |
3 | use DX::Utils qw(:builders :dep_types); |
dcf2adc7 |
4 | use DX::ActionBuilder::ProxySetToAdd; |
c35c4f36 |
5 | use DX::ActionBuilder::Null; |
9d759b64 |
6 | use DX::Class; |
7 | |
8 | with 'DX::Role::Predicate'; |
9 | |
7f385fb2 |
10 | # member_at Dict Key Value |
11 | # |
12 | # Dict must be set to a dict (later maybe also an array and Key -> Index) |
13 | # |
14 | # Key bound -> |
15 | # |
16 | # Key exists -> |
17 | # |
18 | # Value bound -> |
19 | # |
20 | # Dict.Key = Value -> |
21 | # |
22 | # Trivial resolution |
23 | # |
24 | # Dict.Key != Value -> |
25 | # |
26 | # Failure |
27 | # |
28 | # Value unbound -> |
29 | # |
30 | # Set value to Dict.Key |
31 | # |
32 | # Key does not exist -> |
33 | # |
34 | # Dict allows add -> |
35 | # |
36 | # Value bound -> |
37 | # |
38 | # Failure on (exists Dict.Key, Value) |
39 | # |
40 | # Value unbound -> |
41 | # |
42 | # Set value to ProxySetToAdd value |
43 | # |
44 | # Dict disallows add -> |
45 | # |
46 | # Failure on (exists Dict.Key) |
47 | # |
48 | # Key unbound -> |
49 | # |
50 | # Value must also be unbound, because seriously? |
51 | # |
52 | # Set [Key, Value] to each pair in turn |
53 | |
54 | sub _resolution_space_for { |
55 | my ($self, $dict, $key, $value) = @_; |
56 | |
57 | die "Fucked" unless $dict->does('DX::Role::StructuredValue'); |
58 | |
59 | if ($key->is_set) { |
60 | |
61 | if (my $cur_val = $dict->get_member_at($key)) { |
62 | |
63 | my $deps = [ |
64 | [ CONTENTS_OF ,=> $dict, $key->string_value ], |
65 | [ CONTENTS_OF ,=> $value ], |
66 | ]; |
67 | |
68 | if ($value->is_set) { |
69 | |
70 | my @members = ( |
71 | $cur_val->equals($value) |
72 | # Trivial resolution, D.K = V |
73 | ? res( |
74 | actions => [], |
75 | veracity_depends_on => $deps, |
76 | ) |
77 | # Failure |
78 | : () |
79 | ); |
80 | |
81 | return rspace( |
82 | geometry_depends_on => $deps, |
83 | members => \@members |
84 | ); |
85 | |
86 | } |
87 | |
88 | return rspace( |
89 | geometry_depends_on => [ |
90 | [ CONTENTS_OF ,=> $dict, $key->string_value ], |
91 | [ TYPE_OF ,=> $value ], |
92 | ], |
93 | members => [ |
94 | res( |
95 | actions => [ $value->action_for_set_value($cur_val) ], |
96 | veracity_depends_on => $deps, |
97 | ), |
98 | ] |
99 | ); |
100 | |
101 | } |
102 | |
103 | if ($dict->can_add_member) { |
104 | |
105 | my $deps = [ |
106 | [ EXISTENCE_OF ,=> $dict, $key->string_value ], |
107 | [ TYPE_OF ,=> $value ], |
108 | ]; |
109 | |
110 | if ($value->is_set) { |
111 | |
112 | # If we get here, it means (currently) that we entered recheck |
113 | # due to the deletion of the key from the dict and should fail |
114 | # (or there's a bug in the compiler but let's hope not) |
115 | return rspace( |
116 | geometry_depends_on => $deps, |
117 | members => [], |
118 | ); |
119 | } |
120 | |
121 | my @path = (@{$dict->value_path}, $key->string_value); |
122 | my $ab = DX::ActionBuilder::ProxySetToAdd->new( |
123 | target_path => \@path, |
124 | proxy_to => $dict->action_builder, |
125 | ); |
126 | |
127 | return rspace( |
128 | geometry_depends_on => $deps, |
129 | members => [ |
130 | res( |
131 | actions => [ |
132 | $value->action_for_set_value( |
133 | $value->but(action_builder => $ab), |
134 | ), |
135 | ], |
136 | # Veracity only depends on EXISTENCE_OF at this stage - if the |
137 | # $value is later set, recheck will lead us down a different path |
138 | # that will update those dependencies to include CONTENTS_OF |
139 | veracity_depends_on => $deps, |
140 | ), |
141 | ], |
142 | ); |
143 | |
144 | } |
145 | |
146 | # Dict doesn't allow adding keys and key doesn't exist, so |
147 | # the contents of the value is completely irrelevant to the failure |
148 | return rspace( |
149 | geometry_depends_on => [ |
150 | [ EXISTENCE_OF ,=> $dict, $key->string_value ], |
151 | ], |
152 | members => [], |
153 | ); |
154 | |
155 | } |
156 | |
157 | die "Fucked" if $value->is_set; # +D -K +V ? seriously ? |
158 | |
159 | # Laaater we may need to look at autovivifying an additional key/index |
160 | # ala ProxySetToAdd but I'm not 100% sure how that will make sense and |
161 | # premature generalisation is the root of all eval. |
162 | |
163 | my @cand = map [ |
164 | [ $_ ], |
165 | [ $dict->get_member_at($_) ], |
166 | ], map string($_), $dict->index_list; |
167 | |
168 | return rspace( |
169 | geometry_depends_on => [ |
170 | [ INDICES_OF ,=> $dict ], |
171 | [ TYPE_OF ,=> $key ], |
172 | [ TYPE_OF ,=> $value ], |
173 | ], |
174 | members => [ |
175 | rstrat( |
176 | action_prototypes => [ |
177 | [ $key => 'set_value' ], |
178 | [ $value => 'set_value' ], |
179 | ], |
180 | veracity_depends_on_builder => sub { |
1f3fa757 |
181 | my ($this_key, $this_val) = map @$_, @_; |
7f385fb2 |
182 | return [ |
183 | [ CONTENTS_OF ,=> $dict, $this_key->string_value ], |
184 | [ CONTENTS_OF ,=> $key ], |
185 | [ CONTENTS_OF ,=> $value ], |
186 | ]; |
187 | }, |
188 | implementation_candidates => \@cand, |
189 | ), |
190 | ], |
191 | ); |
192 | } |
193 | |
9d759b64 |
194 | 1; |