1:- module(scasp_dyncall,
2 [ scasp/2, 3 scasp_query_clauses/2, 4 scasp_model/1, 5 scasp_justification/2, 6
7 scasp_show/2, 8
9 (scasp_dynamic)/1, 10 scasp_assert/1, 11 scasp_assert/2, 12 scasp_retract/1, 13 scasp_retractall/1, 14 scasp_abolish/1, 15 (#)/1, 16 (#)/2, 17 (pred)/1,
18 (show)/1,
19 (abducible)/1,
20 (abducible)/2,
21
22 (#=)/2,
23 (#<>)/2,
24 (#<)/2,
25 (#>)/2,
26 (#=<)/2,
27 (#>=)/2,
28
29 op(900, fy, not),
30 op(950, xfx, ::), 31 op(1200, fx, #),
32 op(1150, fx, pred),
33 op(1150, fx, show),
34 op(1150, fx, abducible),
35 op(1150, fx, scasp_dynamic),
36 op(700, xfx, #=),
37 op(700, xfx, #<>),
38 op(700, xfx, #<),
39 op(700, xfx, #>),
40 op(700, xfx, #=<),
41 op(700, xfx, #>=)
42 ]). 43:- use_module(compile). 44:- use_module(embed). 45:- use_module(common). 46:- use_module(modules). 47:- use_module(source_ref). 48:- use_module(listing). 49:- use_module(clp/clpq, [apply_clpq_constraints/1]). 50:- use_module(pr_rules, [process_pr_pred/5]). 51:- use_module(predicates, [prolog_builtin/1, clp_builtin/1]). 52
53:- use_module(library(apply), [maplist/3, exclude/3, maplist/2]). 54:- use_module(library(assoc), [empty_assoc/1, get_assoc/3, put_assoc/4]). 55:- use_module(library(error),
56 [ instantiation_error/1,
57 permission_error/3,
58 type_error/2,
59 must_be/2
60 ]). 61:- use_module(library(lists), [member/2, append/3]). 62:- use_module(library(modules),
63 [in_temporary_module/3, current_temporary_module/1]). 64:- use_module(library(option), [option/2]). 65:- use_module(library(ordsets), [ord_intersect/2, ord_union/3]). 66:- use_module(library(prolog_code), [pi_head/2]). 67
68:- meta_predicate
69 scasp(0, +),
70 scasp_show(:, +),
71 scasp_query_clauses(:, -),
72 scasp_dynamic(:),
73 scasp_assert(:),
74 scasp_retract(:),
75 scasp_retractall(:),
76 scasp_abolish(:),
77 pred(:),
78 show(:),
79 abducible(:). 80
94
121
122scasp(Query, Options) :-
123 scasp_query_clauses(Query, Clauses),
124 qualify(Query, SrcModule:QQuery),
125 expand_program(SrcModule, Clauses, Clauses1, QQuery, QQuery1),
126 in_temporary_module(
127 Module,
128 prepare(Clauses1, Module, Options),
129 scasp_call_and_results(Module:QQuery1, SrcModule, Options)).
130
131prepare(Clauses, Module, Options) :-
132 scasp_compile(Module:Clauses, Options),
133 ( option(write_program(_), Options)
134 -> scasp_portray_program(Module:Options)
135 ; true
136 ).
137
138qualify(M:Q0, M:Q) :-
139 qualify(Q0, M, Q1),
140 intern_negation(Q1, Q).
141
142expand_program(SrcModule, Clauses, Clauses1, QQuery, QQuery1) :-
143 current_predicate(SrcModule:scasp_expand_program/4),
144 SrcModule:scasp_expand_program(Clauses, Clauses1, QQuery, QQuery1),
145 !.
146expand_program(_, Clauses, Clauses, QQuery, QQuery).
147
148
149scasp_call_and_results(Query, SrcModule, Options) :-
150 scasp_embed:scasp_call(Query),
151 ( option(model(Model), Options)
152 -> scasp_model(SrcModule:Model)
153 ; true
154 ),
155 ( option(tree(Tree), Options)
156 -> scasp_justification(SrcModule:Tree, Options)
157 ; true
158 ).
159
171
172scasp_show(Query, What) :-
173 What =.. [Type|Options],
174 scasp_show(Query, Type, Options).
175
176scasp_show(Query, code, Options) =>
177 Query = M:_,
178 scasp_query_clauses(Query, Clauses),
179 in_temporary_module(
180 Module,
181 prepare(Clauses, Module, []),
182 scasp_portray_program(Module:[source_module(M)|Options])).
183
187
188:- det(scasp_query_clauses/2). 189
190scasp_query_clauses(Query, Clauses) :-
191 query_callees(Query, Callees0),
192 include_global_constraint(Callees0, Constraints, Callees),
193 findall(Clause, scasp_clause(Callees, Clause), Clauses, QConstraints),
194 maplist(mkconstraint, Constraints, QConstraints).
195
196scasp_clause(Callees, source(ClauseRef, Clause)) :-
197 member(PI, Callees),
198 pi_head(PI, M:Head),
199 @(clause(Head, Body, ClauseRef), M),
200 mkclause(Head, Body, M, Clause).
201
202mkclause(Head, true, M, Clause) =>
203 qualify(Head, M, Clause).
204mkclause(Head, Body, M, Clause) =>
205 qualify((Head:-Body), M, Clause).
206
207mkconstraint(source(Ref, M:Body), source(Ref, (:- Constraint))) :-
208 qualify(Body, M, Constraint).
209
210qualify(-(Head), M, Q) =>
211 Q = -QHead,
212 qualify(Head, M, QHead).
213qualify(not(Head), M, Q) =>
214 Q = not(QHead),
215 qualify(Head, M, QHead).
216qualify(findall(Templ, Head, List), M, Q) =>
217 Q = findall(Templ, QHead, List),
218 qualify(Head, M, QHead).
219qualify((A,B), M, Q) =>
220 Q = (QA,QB),
221 qualify(A, M, QA),
222 qualify(B, M, QB).
223qualify((A:-B), M, Q) =>
224 Q = (QA:-QB),
225 qualify(A, M, QA),
226 qualify(B, M, QB).
227qualify(G, M, Q), callable(G) =>
228 ( built_in(G)
229 -> Q = G
230 ; implementation(M:G, Callee),
231 encoded_module_term(Callee, Q)
232 ).
233
240
241query_callees(M:Query, Callees) :-
242 findall(Call, body_calls_pi(Query,M,Call), Calls0),
243 sort(Calls0, Calls),
244 callee_graph(Calls, Callees).
245
246body_calls_pi(Query, M, PI) :-
247 body_calls(Query, M, Call),
248 pi_head(PI, Call).
249
250callee_graph(Preds, Nodes) :-
251 empty_assoc(Expanded),
252 callee_closure(Preds, Expanded, Preds, Nodes0),
253 sort(Nodes0, Nodes).
254
255callee_closure([], _, Preds, Preds).
256callee_closure([H|T], Expanded, Preds0, Preds) :-
257 ( get_assoc(H, Expanded, _)
258 -> callee_closure(T, Expanded, Preds0, Preds)
259 ; put_assoc(H, Expanded, true, Expanded1),
260 pi_head(H, Head),
261 predicate_callees(Head, Called),
262 exclude(expanded(Expanded1), Called, New),
263 append(New, T, Agenda),
264 append(New, Preds0, Preds1),
265 callee_closure(Agenda, Expanded1, Preds1, Preds)
266 ).
267
268expanded(Assoc, PI) :-
269 get_assoc(PI, Assoc, _).
270
272
273include_global_constraint(Callees0, Constraints, Callees) :-
274 include_global_constraint(Callees0, Callees, [], Constraints).
275
276include_global_constraint(Callees0, Callees, Constraints0, Constraints) :-
277 global_constraint(Constraint),
278 Constraint = source(_, Body),
279 \+ ( member(source(_, Body0), Constraints0),
280 Body =@= Body0
281 ),
282 query_callees(Body, Called),
283 ord_intersect(Callees0, Called),
284 !,
285 ord_union(Callees0, Called, Callees1),
286 include_global_constraint(Callees1, Callees,
287 [Constraint|Constraints0], Constraints).
288include_global_constraint(Callees, Callees, Constraints, Constraints).
289
290
291global_constraint(source(Ref, M:Body)) :-
292 ( current_temporary_module(M)
293 ; current_module(M)
294 ),
295 current_predicate(M:(-)/0),
296 \+ predicate_property(M:(-), imported_from(_)),
297 @(clause(-, Body, Ref), M).
298
303
304:- dynamic predicate_callees_c/4. 305
306predicate_callees(M:Head, Callees) :-
307 predicate_callees_c(Head, M, Gen, Callees0),
308 predicate_generation(M:Head, Gen),
309 !,
310 Callees = Callees0.
311predicate_callees(M:Head, Callees) :-
312 module_property(M, class(temporary)),
313 !,
314 predicate_callees_nc(M:Head, Callees).
315predicate_callees(M:Head, Callees) :-
316 retractall(predicate_callees_c(Head, M, _, _)),
317 predicate_callees_nc(M:Head, Callees0),
318 predicate_generation(M:Head, Gen),
319 assertz(predicate_callees_c(Head, M, Gen, Callees0)),
320 Callees = Callees0.
321
322predicate_callees_nc(Head, Callees) :-
323 findall(Callee, predicate_calls(Head, Callee), Callees0),
324 sort(Callees0, Callees).
325
326predicate_calls(Head0, PI) :-
327 generalise(Head0, M:Head),
328 @(clause(Head, Body), M),
329 body_calls(Body, M, Callee),
330 pi_head(PI, Callee).
331
332body_calls(Goal, _M, _), var(Goal) =>
333 instantiation_error(Goal).
334body_calls(true, _M, _) => fail.
335body_calls((A,B), M, Callee) =>
336 ( body_calls(A, M, Callee)
337 ; body_calls(B, M, Callee)
338 ).
339body_calls(not(A), M, Callee) =>
340 body_calls(A, M, Callee).
341body_calls(findall(_,G,_), M, Callee) =>
342 body_calls(G, M, Callee).
343body_calls(N, M, Callee), rm_classic_negation(N,A) =>
344 body_calls(A, M, Callee).
345body_calls(M:A, _, Callee), atom(M) =>
346 body_calls(A, M, Callee).
347body_calls(G, _M, _CalleePM), callable(G), built_in(G) =>
348 fail.
349body_calls(G, M, CalleePM), callable(G) =>
350 implementation(M:G, Callee0),
351 generalise(Callee0, Callee),
352 ( predicate_property(Callee, interpreted),
353 \+ predicate_property(Callee, meta_predicate(_))
354 -> pm(Callee, CalleePM)
355 ; \+ predicate_property(Callee, _)
356 -> pm(Callee, CalleePM) 357 ; pi_head(CalleePI, Callee),
358 permission_error(scasp, procedure, CalleePI)
359 ).
360body_calls(G, _, _) =>
361 type_error(callable, G).
362
363built_in(Head) :-
364 prolog_builtin(Head).
365built_in(Head) :-
366 clp_builtin(Head).
367built_in(_ is _).
368built_in(findall(_,_,_)).
369
370rm_classic_negation(-Goal, Goal) :-
371 !.
372rm_classic_negation(Goal, PGoal) :-
373 functor(Goal, Name, _),
374 atom_concat(-, Plain, Name),
375 Goal =.. [Name|Args],
376 PGoal =.. [Plain|Args].
377
378pm(P, P).
379pm(M:P, M:MP) :-
380 intern_negation(-P, MP).
381
382implementation(M0:Head, M:Head) :-
383 predicate_property(M0:Head, imported_from(M1)),
384 !,
385 M = M1.
386implementation(Head, Head).
387
388generalise(M:Head0, Gen), atom(M) =>
389 Gen = M:Head,
390 generalise(Head0, Head).
391generalise(-Head0, Gen) =>
392 Gen = -Head,
393 generalise(Head0, Head).
394generalise(Head0, Head) =>
395 functor(Head0, Name, Arity),
396 functor(Head, Name, Arity).
397
398predicate_generation(Head, Gen) :-
399 predicate_property(Head, last_modified_generation(Gen0)),
400 !,
401 Gen = Gen0.
402predicate_generation(_, 0).
403
404
405 408
415
416scasp_dynamic(M:Spec) :-
417 scasp_dynamic(Spec, M, private).
418scasp_dynamic(M:(Spec as Scoped)) :-
419 scasp_dynamic(Spec, M, Scoped).
420
421scasp_dynamic((A,B), M, Scoped) =>
422 scasp_dynamic(A, M, Scoped),
423 scasp_dynamic(B, M, Scoped).
424scasp_dynamic(Name/Arity, M, Scoped) =>
425 atom_concat(-, Name, NName),
426 ( Scoped == shared
427 -> dynamic((M:Name/Arity,
428 M:NName/Arity))
429 ; thread_local((M:Name/Arity,
430 M:NName/Arity))
431 ).
432
433:- multifile system:term_expansion/2. 434
435system:term_expansion((:- scasp_dynamic(Spec)), Directives) :-
436 phrase(scasp_dynamic_direcives(Spec), Directives).
437
438scasp_dynamic_direcives(Spec as Scope) -->
439 !,
440 scasp_dynamic_direcives(Spec, Scope).
441scasp_dynamic_direcives(Spec) -->
442 !,
443 scasp_dynamic_direcives(Spec, private).
444
445scasp_dynamic_direcives(Var, _) -->
446 { var(Var), !, fail }.
447scasp_dynamic_direcives((A,B), Scope) -->
448 scasp_dynamic_direcives(A, Scope),
449 scasp_dynamic_direcives(B, Scope).
450scasp_dynamic_direcives(Name/Arity, Scope) -->
451 { atom_concat(-, Name, NName) },
452 ( {Scope == shared}
453 -> [(:- dynamic((Name/Arity, NName/Arity)))]
454 ; [(:- thread_local((Name/Arity, NName/Arity)))]
455 ).
456
457
469
470scasp_assert(Clause) :-
471 scasp_assert(Clause, false).
472
473scasp_assert(M:(-Head :- Body0), Pos) =>
474 intern_negation(-Head, MHead),
475 expand_goal(Body0, Body),
476 scasp_assert_(M:(MHead :- Body), Pos).
477scasp_assert(M:(-Head), Pos) =>
478 intern_negation(-Head, MHead),
479 scasp_assert_(M:(MHead), Pos).
480scasp_assert(M:(:- Body0), Pos) =>
481 expand_goal(Body0, Body),
482 scasp_assert_(M:((-) :- Body), Pos).
483scasp_assert(M:(false :- Body0), Pos) =>
484 expand_goal(Body0, Body),
485 scasp_assert_(M:((-) :- Body), Pos).
486scasp_assert(M:(Head :- Body0), Pos) =>
487 expand_goal(Body0, Body),
488 scasp_assert_(M:(Head :- Body), Pos).
489scasp_assert(Head, Pos) =>
490 scasp_assert_(Head, Pos).
491
492scasp_assert_(Clause, false) =>
493 assertz(Clause).
494scasp_assert_(Clause, Pos) =>
495 assertz(Clause, Ref),
496 assertz(scasp_dynamic_clause_position(Ref, Pos)).
497
498scasp_assert_into(M, Pos, Rule) :-
499 scasp_assert(M:Rule, Pos).
500
501scasp_retract(M:(-Head :- Body0)) =>
502 intern_negation(-Head, MHead),
503 expand_goal(Body0, Body),
504 retract(M:(MHead :- Body)).
505scasp_retract(M:(-Head)) =>
506 intern_negation(-Head, MHead),
507 retract(M:(MHead)).
508scasp_retract(M:(:- Body0)) =>
509 expand_goal(Body0, Body),
510 retract(M:((-) :- Body)).
511scasp_retract(M:(false :- Body0)) =>
512 expand_goal(Body0, Body),
513 retract(M:((-) :- Body)).
514scasp_retract(M:(Head :- Body0)) =>
515 expand_goal(Body0, Body),
516 retract(M:(Head :- Body)).
517scasp_retract(Head) =>
518 retract(Head).
519
520scasp_retractall(M:(-Head)) =>
521 intern_negation(-Head, MHead),
522 retractall(M:MHead).
523scasp_retractall(Head) =>
524 retractall(Head).
525
530
531scasp_abolish(M:(Name/Arity)) =>
532 pi_head(Name/Arity, Head),
533 scasp_retractall(M:Head),
534 scasp_retractall(M:(-Head)).
535
536
537 540
545
546#(Directive) :- #(Directive, false).
547
548#(M:pred(Spec), _) => pred(M:Spec).
549#(M:show(Spec), _) => show(M:Spec).
550#(M:abducible(Spec), Pos) => abducible(M:Spec, Pos).
551
552pred(M:(Spec :: Template)) =>
553 process_pr_pred(Spec :: Template, Atom, Children, Cond, Human),
554 assertz(M:pr_pred_predicate(Atom, Children, Cond, Human)).
555
556show(M:PIs) =>
557 phrase(show(PIs), Clauses),
558 maplist(assert_show(M), Clauses).
559
560assert_show(M, Clause) :-
561 assertz(M:Clause).
562
563show(Var) -->
564 { var(Var),
565 instantiation_error(Var)
566 }.
567show((A,B)) -->
568 !,
569 show(A),
570 show(B).
571show(not(PI)) -->
572 { pi_head(PI, Head) },
573 [ pr_show_predicate(not(Head)) ].
574show(PI) -->
575 { pi_head(PI, Head) },
576 [ pr_show_predicate(Head) ].
577
582
583abducible(Spec) :- abducible(Spec, false).
584
585abducible(M:(A,B), Pos) =>
586 abducible(M:A, Pos),
587 abducible(M:B, Pos).
588abducible(M:Head, Pos), callable(Head) =>
589 abducible_rules(Head, Rules),
590 discontiguous(M:('abducible$'/1, 'abducible$$'/1)),
591 maplist(scasp_assert_into(M, Pos), Rules).
592
593abducible_rules(Head,
594 [ (Head :- not(NegHead), 'abducible$'(Head)),
595 (NegHead :- not Head),
596 ('abducible$'(Head) :- not 'abducible$$'(Head)),
597 ('abducible$$'(Head) :- not 'abducible$'(Head))
598 ]) :-
599 intern_negation(-Head, NegHead).
600
601abducible(Var) -->
602 { var(Var),
603 instantiation_error(Var)
604 }.
605abducible((A,B)) -->
606 !,
607 abducible(A),
608 abducible(B).
609abducible(Head) -->
610 { must_be(callable, Head),
611 abducible_rules(Head, Clauses)
612 },
613 list(Clauses).
614
615list([]) --> [].
616list([H|T]) --> [H], list(T).
617
618
619
620 623
624user:term_expansion(-Fact, MFact) :-
625 callable(Fact),
626 Fact \= _:_,
627 intern_negation(-Fact, MFact).
628user:term_expansion((-Head :- Body), (MHead :- Body)) :-
629 callable(Head),
630 Head \= _:_,
631 intern_negation(-Head, MHead).
632user:term_expansion((false :- Body), ((-) :- Body)).
633user:term_expansion((:- pred(SpecIn)),
634 pr_pred_predicate(Atom, Children, Cond, Human)) :-
635 process_pr_pred(SpecIn, Atom, Children, Cond, Human).
636user:term_expansion((:- show(SpecIn)), Clauses) :-
637 phrase(show(SpecIn), Clauses).
638user:term_expansion((:- abducible(SpecIn)), Clauses) :-
639 phrase(abducible(SpecIn), Clauses).
640user:term_expansion((# pred(SpecIn)),
641 pr_pred_predicate(Atom, Children, Cond, Human)) :-
642 process_pr_pred(SpecIn, Atom, Children, Cond, Human).
643user:term_expansion((# show(SpecIn)), Clauses) :-
644 phrase(show(SpecIn), Clauses).
645user:term_expansion((# abducible(SpecIn)), Clauses) :-
646 phrase(abducible(SpecIn), Clauses).
647
648user:goal_expansion(-Goal, MGoal) :-
649 callable(Goal),
650 intern_negation(-Goal, MGoal).
651
652
653 656
666
667A #= B :- apply_clpq_constraints(A #= B).
668A #<> B :- apply_clpq_constraints(A #<> B).
669A #< B :- apply_clpq_constraints(A #< B).
670A #> B :- apply_clpq_constraints(A #> B).
671A #=< B :- apply_clpq_constraints(A #=< B).
672A #>= B :- apply_clpq_constraints(A #>= B).
673
674
675 678
679:- multifile
680 sandbox:safe_meta_predicate/1. 681
686
687sandbox:safe_meta(scasp_dyncall:scasp(_, _), [])