34
35:- module(metaprops,
36 [(declaration)/1,
37 (declaration)/2,
38 (global)/1,
39 (global)/2,
40 (type)/1,
41 (type)/2,
42 checkprop_goal/1,
43 compat/1,
44 compat/2,
45 with_cv_module/2,
46 cv_module/1,
47 instan/1,
48 instan/2,
49 last_prop_failure/1
50 ]). 51
52:- use_module(library(assertions)). 53:- use_module(library(resolve_calln)). 54:- use_module(library(context_values)). 55:- use_module(library(extend_args)). 56:- use_module(library(qualify_meta_goal)). 57
58:- true prop (type)/1 + (declaration(check), global(prop)) # "Defines a type.".
59
60type(Goal) :- call(Goal).
61
62:- true prop (global)/1 + (global(prop), declaration)
63# "A property that is global, i.e., can appear after the + in the assertion.
64and as meta predicates, meta_predicate F(0)".
65
66global(Goal) :- call(Goal).
67
68:- type assrt_type/1, assrt_status/1.
69
70:- global global(Prop, Goal) : (assrt_type(Prop), callable(Goal))
71# "Like global/1, but allows to specify the default assertion type".
72
73global(_, Goal) :- call(Goal).
74
75:- true prop (declaration)/1 + (global(prop), declaration)
76# "A property that is a declaration, i.e., an operator is added as op(1125, fx, F). Implies global/1".
77
78declaration(Goal) :- call(Goal).
79
80:- true prop declaration(Status, Goal) : (assrt_status(Status), callable(Goal)) + global(prop)
81# "Like declaration/1, but allows to specify the default assertion status".
82
83declaration(_, Goal) :- call(Goal).
84
85:- true prop cv_module/1.
86
87cv_module(CM) :-
88 current_context_value(current_module, CM),
89 !.
90cv_module(user).
91
92:- true prop type(T, A)
93# "~w is internally of type ~w, a predicate of arity 1 defined as a type/1."-[A, T].
94
95:- meta_predicate
96 type(1, ?),
97 type(1, ?, -). 98
99type(M:T, A) :-
100 type(M:T, A, H),
101 M:H.
102
103type(M:T, A, H) :-
104 extend_args(T, [Arg], H),
105 ( cv_module(C),
106 predicate_property(M:H, meta_predicate(Spec)),
107 functor(H, _, N),
108 arg(N, Spec, Meta),
109 '$expand':meta_arg(Meta)
110 ->Arg = C:A
111 ; Arg = A
112 ).
113
114:- multifile
115 unfold_calls:unfold_call_hook/4. 116
117unfold_calls:unfold_call_hook(type(T, A), metaprops, M, M:call(T, A)).
118
119:- true prop compat(Prop)
120# "Uses ~w as a compatibility property."-[Prop].
121
122:- meta_predicate compat(0 ). 123
124compat(M:Goal) :-
125 term_variables(Goal, VS),
126 compat(M:Goal, VS).
127
128:- use_module(library(gcb)). 129:- use_module(library(list_sequence)). 130:- use_module(library(substitute)). 131:- use_module(library(clambda)). 132:- use_module(library(terms_share)). 133
134:- thread_local
135 '$last_prop_failure'/2. 136
137generalize_term(STerm, Term, _) :-
138 \+ terms_share(STerm, Term).
139
140neg(nonvar(A), var(A)).
141neg(A==B, A \== B).
142neg(A =B, A \= B).
143neg(A=:=B, A =\= B).
144neg(A, \+A).
145
146current_prop_failure((SG :- Body)) :-
147 '$last_prop_failure'(Term, SubU),
148 sort(SubU, Sub),
149 greatest_common_binding(Term, Sub, ST, SSub, [[]], Unifier, []),
150 substitute(generalize_term(SSub), ST, SG),
151 maplist(\ A^NA^once(neg(A, NA)), SSub, NSub),
152 foldl(simplify_unifier(SG-SSub), Unifier, LitL, NSub),
153 LitL \= [],
154 list_sequence(LitL, Body).
155
156simplify_unifier(Term, A=B) -->
157 ( {occurrences_of_var(A, Term, 0 )}
158 ->{A=B}
159 ; [A=B]
160 ).
161
162last_prop_failure(L) :-
163 findall(E, once(current_prop_failure(E)), L),
164 retractall('$last_prop_failure'(_, _)).
165
166asserta_prop_failure(T, S) :-
167 once(( retract('$last_prop_failure'(T, L))
168 ; L = []
169 )),
170 asserta('$last_prop_failure'(T, [S|L])).
171
172cleanup_prop_failure(T, S) :-
173 retractall('$last_prop_failure'(_, _)),
174 asserta('$last_prop_failure'(T, S)).
175
176:- meta_predicate with_cv_module(0, +). 177with_cv_module(Goal, CM) :-
178 with_context_value(Goal, current_module, CM).
179
180:- meta_predicate checkprop_goal(0 ). 181checkprop_goal(Goal) :-
182 ( current_context_value(checkprop, CheckProp)
183 ->CheckProp = compat
184 ; Goal
185 ).
186
187:- meta_predicate compat(0, +). 188
189compat(M:Goal, VarL) :-
190 copy_term_nat(Goal-VarL, Term-VarTL), 191 sort(VarTL, VS),
192 cleanup_prop_failure(Term, []),
193 prolog_current_choice(CP),
194 with_context_value(
195 compat(Term, data(VS, Term, CP), M), checkprop, compat).
196
199compat(Var, _, _) :- var(Var), !.
200compat(M:Goal, D, _) :-
201 !,
202 compat(Goal, D, M).
203compat(A, D, M) :-
204 do_resolve_calln(A, B),
205 !,
206 compat(B, D, M).
207compat((A, B), D, M) :-
208 !,
209 compat(A, D, M),
210 compat(B, D, M).
211compat(type(T, A), D, M) :-
212 !,
213 strip_module(M:T, C, H),
214 type(C:H, A, G),
215 compat(G, D, C).
216compat(compat(A), D, M) :-
217 !,
218 compat(A, D, M).
219compat((A->B; C), D, M) :-
220 !,
221 ( call(M:A)
222 ->compat(B, D, M)
223 ; compat(C, D, M)
224 ),
225 !.
226compat(\+ G, _, M) :-
227 !,
228 \+ M:G.
229compat((A->B), D, M) :-
230 !,
231 ( call(M:A)
232 ->compat(B, D, M)
233 ).
234compat(!, data(_, _, CP), _) :-
235 !,
236 cut_from(CP).
237compat(checkprop_goal(_), _, _) :- !.
238compat(with_cv_module(A, C), D, M) :-
239 !,
240 with_cv_module(compat(A, D, M), C).
241compat(var(V), _, _) :-
242 nonvar(V),
243 !,
244 fail.
245compat(A, data(VarL, _, _), M) :-
246 247 compound(A),
248 A \= (_;_),
249 compatc(A, VarL, M),
250 !.
251compat(Term, D, M) :-
252 D = data(_, T, _),
253 asserta_prop_failure(T, Term),
254 compat_1(Term, D, M),
255 cleanup_prop_failure(T, []).
256
260
261compat_1((A; B), D, M) :-
262 ( compat(A, D, M)
263 ; compat(B, D, M)
264 ),
265 !.
266compat_1(@(A, C), D, M) :-
267 !,
268 compat_1(A, @(M:A, C), D, C, M).
269compat_1(A, D, M) :-
270 compat_1(A, M:A, D, M, M).
271
272compat_1(A, G, D, C, M) :-
273 ( is_type(A, M)
274 ->catch(compat_body(A, C, M, D),
275 _,
276 do_compat(G, D))
277 ; \+ ( \+ compat_safe(A, M),
278 \+ ground(A),
279 \+ aux_pred(A),
280 \+ is_prop(A, M),
281 print_message(warning, format("While checking compat, direct execution of predicate could cause infinite loops: ~q", [G-D])),
282 fail
283 ),
284 do_compat(G, D)
285 ),
286 !.
287
288aux_pred(P) :-
289 functor(P, F, _),
290 atom_concat('__aux_', _, F).
291
292compat_safe(_ =.. _, _).
293compat_safe(_ is _, _).
294compat_safe(call_cm(_, _, _), _).
295compat_safe(context_module(_), _).
296compat_safe(curr_arithmetic_function(_), _).
297compat_safe(current_predicate(_), _).
298compat_safe(functor(_, _, _), _).
299compat_safe(goal_2(_, _), _).
300compat_safe(prop_asr(_, _, _, _), _).
301compat_safe(static_strip_module(_, _, _, _), _).
302
303do_compat(Goal, data(VarL, _, _)) :-
304 term_variables(VarL, VS),
305 prolog_current_choice(CP),
306 maplist(freeze_cut(CP), VS),
307 Goal,
308 maplist(del_freeze, VS).
309
310del_freeze(Var) :-
311 ( attvar(Var)
312 ->del_attr(Var, freeze)
313 ; true
314 ).
315
316is_prop(Head, M) :-
317 prop_asr(Head, M, Stat, prop, _, _, _),
318 memberchk(Stat, [check, true]).
319
320is_type(Head, M) :-
321 once(( prop_asr(Head, M, Stat, prop, _, _, Asr),
322 memberchk(Stat, [check, true]),
323 once(prop_asr(glob, type(_), _, Asr))
324 )).
325
326:- meta_predicate compat_body(0,+,+,+,+). 327
328compat_body(MG, C, V, T, CP) :-
329 clause(MG, Body, Ref),
330 clause_property(Ref, module(S)), 331 ( predicate_property(MG, transparent),
332 \+ ( predicate_property(MG, meta_predicate(Meta)),
333 arg(_, Meta, Spec),
334 '$expand':meta_arg(Spec)
335 )
336 ->CM = C
337 ; CM = S
338 ),
339 compat(Body, data(V, T, CP), CM).
340
341compat_body(G1, C, M, data(V, T, _)) :-
342 qualify_meta_goal(G1, M, C, G),
343 prolog_current_choice(CP),
344 compat_body(M:G, C, V, T, CP).
345
346:- use_module(library(safe_prolog_cut_to)). 347
348cut_from(CP) :- catch(safe_prolog_cut_to(CP), _, true).
349
350freeze_cut(CP, V) :-
351 freeze(V, catch(prolog_cut_to(CP), _, true)).
352
353compatc(H, VarL, M) :-
354 functor(H, _, N),
355 arg(N, H, A),
356 ( var(A),
357 ord_intersect(VarL, [A], [A])
358 ; predicate_property(M:H, meta_predicate(Spec)),
359 arg(N, Spec, Meta),
360 '$expand':meta_arg(Meta),
361 A = X:Y,
362 ( ( var(X)
363 ; current_module(X)
364 )
365 ->var(Y),
366 ord_intersect(VarL, [Y], [Y])
367 )
368 ),
369 !.
370compatc(H, VarL, _) :-
371 compatc_arg(H, A),
372 ( var(A)
373 ->ord_intersect(VarL, [A], [A])
374 ; true
375 ).
382compatc_arg(var( A), A).
383compatc_arg(nonvar( A), A).
384compatc_arg(term( A), A).
385compatc_arg(gnd( A), A).
386compatc_arg(ground( A), A).
387compatc_arg(nonground(A), A).
388
389freeze_fail(CP, Term, V, N) :-
390 freeze(V, ( prolog_cut_to(CP),
391 cleanup_prop_failure(Term, [nonvar(N), N==V]),
392 fail
393 )).
394
395:- global instan(Prop)
396# "Uses Prop as an instantiation property. Verifies that execution of
397 ~w does not produce bindings for the argument variables."-[Prop].
398
399:- meta_predicate instan(0). 400
401instan(Goal) :-
402 term_variables(Goal, VS),
403 instan(Goal, VS).
404
405:- meta_predicate instan(0, +). 406
407instan(Goal, VS) :-
408 prolog_current_choice(CP),
409 \+ \+ ( copy_term_nat(Goal-VS, Term-VN),
410 maplist(freeze_fail(CP, Term), VS, VN),
411 with_context_value(Goal, checkprop, instan)
412 )