34
35:- module(when,
36 [ when/2 37 ]).
38:- set_prolog_flag(generate_debug_info, false).
39
40:- meta_predicate
41 when(+, 0),
42 suspend_list(+, 0),
43 trigger(+, 0),
44 trigger_disj(+, 0),
45 trigger_conj(+, +, 0).
46
61
83
84when(Condition, Goal) :-
85 '$eval_when_condition'(Condition, Optimised),
86 trigger_first(Optimised, Goal).
87
96
97
98trigger_first(true, Goal) :-
99 !,
100 call(Goal).
101trigger_first(nonvar(X), Goal) :-
102 !,
103 '$suspend'(X, when, trigger_nonvar(X, Goal)).
104trigger_first(Cond, Goal) :-
105 trigger(Cond, Goal).
106
107trigger(nonvar(X),Goal) :-
108 trigger_nonvar(X,Goal).
109trigger(ground(X),Goal) :-
110 trigger_ground(X,Goal).
111trigger(?=(X,Y),Goal) :-
112 trigger_determined(X,Y,Goal).
113trigger((G1,G2),Goal) :-
114 trigger_conj(G1,G2,Goal).
115trigger(or(GL),Goal) :-
116 trigger_disj(GL, check_disj(_DisjID,GL,Goal)).
117
118trigger_nonvar(X, Goal) :-
119 ( nonvar(X)
120 -> call(Goal)
121 ; '$suspend'(X, when, trigger_nonvar(X, Goal))
122 ).
123
124trigger_ground(X, Goal) :-
125 term_variables(X, Vs),
126 ( Vs = [H]
127 -> '$suspend'(H, when, trigger_ground(H, Goal))
128 ; Vs = [H|_]
129 -> T =.. [f|Vs],
130 '$suspend'(H, when, trigger_ground(T, Goal))
131 ; call(Goal)
132 ).
133
134trigger_determined(X, Y, Goal) :-
135 unifiable(X, Y, Unifier),
136 !,
137 ( Unifier == []
138 -> call(Goal)
139 ; put_attr(Det, when, det(trigger_determined(X,Y,Goal))),
140 suspend_list(Unifier, wake_det(Det))
141 ).
142trigger_determined(_, _, Goal) :-
143 call(Goal).
144
145
146wake_det(Det) :-
147 ( var(Det) ->
148 get_attr(Det,when,Attr),
149 del_attr(Det,when),
150 Det = (-),
151 Attr = det(Goal),
152 call(Goal)
153 ;
154 true
155 ).
156
157trigger_conj(G1,G2,Goal) :-
158 trigger(G1, trigger(G2,Goal)).
159
160trigger_disj([],_).
161trigger_disj([H|T], G) :-
162 trigger(H, G),
163 trigger_disj(T, G).
164
165
174
175check_disj(Disj,_,Goal) :-
176 ( Disj == (-)
177 -> true
178 ; Disj = (-),
179 call(Goal)
180 ).
181
182suspend_list([],_Goal).
183suspend_list([V=W|Unifier],Goal) :-
184 '$suspend'(V, when, Goal),
185 ( var(W)
186 -> '$suspend'(W, when, Goal)
187 ; true
188 ),
189 suspend_list(Unifier,Goal).
190
191attr_unify_hook(call(Goal), Other) :-
192 ( get_attr(Other, when, call(GOTher))
193 -> del_attr(Other, when),
194 Goal, GOTher
195 ; Goal
196 ).
197
198
200attribute_goals(V) -->
201 { get_attr(V, when, Attr) },
202 when_goals(Attr).
203
204when_goals(det(trigger_determined(X, Y, G))) -->
205 !,
206 ( { disj_goal(G, Disj, DG) }
207 -> disj_or(Disj, DG)
208 ; { G = when:trigger(C, Goal) }
209 -> [ when((?=(X,Y),C), Goal) ]
210 ; [ when(?=(X,Y), G) ]
211 ).
212when_goals(call(Conj)) -->
213 when_conj_goals(Conj).
214
215when_conj_goals((A,B)) -->
216 !,
217 when_conj_goals(A),
218 when_conj_goals(B).
219when_conj_goals(when:G) -->
220 when_goal(G).
221
222when_goal(trigger_nonvar(X, G)) -->
223 ( { disj_goal(G, Disj, DG) }
224 -> disj_or(Disj, DG)
225 ; { G = when:trigger(C, Goal) }
226 -> [ when((nonvar(X),C), Goal) ]
227 ; [ when(nonvar(X),G) ]
228 ).
229when_goal(trigger_ground(X, G)) -->
230 ( { disj_goal(G, Disj, DG) }
231 -> disj_or(Disj, DG)
232 ; { G = when:trigger(C, Goal) }
233 -> [ when((ground(X),C), Goal) ]
234 ; [ when(ground(X),G) ]
235 ).
236when_goal(wake_det(_)) -->
237 [].
238
239disj_goal(when:check_disj(X, _, _), [], -) :- X == (-).
240disj_goal(when:check_disj(-, Or, DG), Or, DG).
241
242disj_or([], _) --> [].
243disj_or(List, DG) -->
244 { or_list(List, Or) },
245 [when(Or, DG)].
246
247or_list([H], H) :- !.
248or_list([H|T], (H;OT)) :-
249 or_list(T, OT).
250
251:- multifile sandbox:safe_meta_predicate/1.
252
253sandbox:safe_meta_predicate(when:when/2).