33
34:- module(scasp_embed,
35 [ begin_scasp/1, 36 begin_scasp/2, 37 end_scasp/0,
38 scasp_listing/2, 39 scasp_model/1, 40 scasp_model/2, 41 scasp_stack/1, 42 scasp_justification/2, 43 (not)/1, 44 (-)/1, 45
46 op(700, xfx, .\=.),
47 op(700, xfx, '\u2209'),
48 op(900, fy, not)
49 ]). 50:- use_module(ops). 51:- use_module(input). 52:- use_module(compile). 53:- use_module(predicates). 54:- use_module(solve). 55:- use_module(model). 56:- use_module(stack). 57:- use_module(options). 58:- use_module(listing). 59
60:- use_module(library(apply)). 61:- use_module(library(error)). 62:- use_module(library(lists)). 63:- use_module(library(prolog_code)). 64
65:- meta_predicate
66 scasp_model(:),
67 scasp_justification(:, +),
68 not(0),
69 -(:). 70
72:- create_prolog_flag(scasp_show_model,
73 false,
74 [keep(true), type(atom)]). 75:- create_prolog_flag(scasp_show_justification,
76 false,
77 [keep(true), type(atom)]). 78
104
105:- thread_local
106 loading_scasp/3. 107
127
128begin_scasp(Unit) :-
129 begin_scasp(Unit, all).
130
131begin_scasp(Unit, Exports) :-
132 scasp_module(Unit, Module),
133 prolog_load_context(module, Context),
134 source_location(File, Line),
135 '$set_source_module'(OldModule, Module),
136 '$declare_module'(Module, scasp, Context, File, Line, false),
137 scasp_push_operators,
138 '$style_check'(OldStyle, OldStyle),
139 style_check(-singleton),
140 discontiguous(Module:(#)/1),
141 asserta(loading_scasp(Unit, File,
142 _{ module:Module,
143 old_module:OldModule,
144 old_style:OldStyle,
145 exports:Exports
146 })).
147
148scasp_module(Unit, Module) :-
149 atom_concat('_scasp_', Unit, Module).
150
154
155end_scasp :-
156 throw(error(context_error(nodirective, end_scasp), _)).
157
158end_scasp(Clauses) :-
159 ( retract(loading_scasp(Unit, _File, Dict))
160 -> _{ old_module:OldModule,
161 old_style:OldStyle,
162 exports:Exports
163 } :< Dict,
164 '$set_source_module'(_, OldModule),
165 scasp_pop_operators,
166 '$style_check'(_, OldStyle),
167 ( Exports == []
168 -> Options = [unknown(fail)]
169 ; Options = []
170 ),
171 scasp_compile_unit(Unit, Options),
172 link_clauses(OldModule, Unit, Clauses, Exports)
173 ; throw(error(context_error(scasp_close(-)), _))
174 ).
175
176loading_scasp(Unit) :-
177 source_location(File, _Line),
178 loading_scasp(Unit,File,_).
179
180user:term_expansion(end_of_file, _) :-
181 loading_scasp(Unit),
182 print_message(error, scasp(not_closed_program(Unit))),
183 end_scasp,
184 fail.
185user:term_expansion((:- Constraint), Clause) :-
186 loading_scasp(_),
187 Constraint \== end_scasp,
188 !,
189 Clause = ('_false_0' :- Constraint).
190user:term_expansion((?- Query), Clause) :-
191 loading_scasp(_),
192 !,
193 Clause = scasp_query(Query, 1).
194user:term_expansion(#(discontiguous(Preds)), (:- discontiguous(Preds))) :-
195 loading_scasp(_).
196user:term_expansion(#(pred(Preds)), #(pred(Preds))) :-
197 loading_scasp(_),
198 prolog_load_context(variable_names, Vars),
199 maplist(bind_var, Vars).
200user:term_expansion((:- end_scasp), Clauses) :-
201 \+ current_prolog_flag(xref, true),
202 end_scasp(Clauses).
203
204bind_var(Name = $(Name)).
205
206
210
211:- thread_local
212 done_unit/1. 213
214scasp_compile_unit(Unit, Options) :-
215 call_cleanup(scasp_compile_unit_(Unit, Options),
216 retractall(done_unit(_))).
217
218scasp_compile_unit_(Unit, Options) :-
219 scasp_module(Unit, Module),
220 ( current_module(Module)
221 -> true
222 ; existence_error(scasp_unit, Unit)
223 ),
224 findall(Clause, scasp_clause(Unit, Clause), Clauses),
225 scasp_compile(Module:Clauses, Options).
226
230
231scasp_clause(Unit, _Clause) :-
232 done_unit(Unit),
233 !,
234 fail.
235scasp_clause(Unit, Clause) :-
236 assertz(done_unit(Unit)),
237 scasp_module(Unit, Module),
238 QHead = Module:Head,
239 predicate_property(QHead, interpreted),
240 \+ scasp_compiled(Head),
241 \+ predicate_property(QHead, imported_from(_)),
242 @(clause(Head, Body), Module),
243 mkclause(Head, Body, Clause).
244
245mkclause(scasp_query(Query,_N), true, Clause) =>
246 Clause = (?- Query).
247mkclause(#(include(Unit)), true, Clause) =>
248 scasp_clause(Unit, Clause).
249mkclause(#(Directive), true, Clause) => 250 Clause = #(Directive).
251mkclause('_false_0', Body, Clause) =>
252 Clause = (:- Body).
253mkclause(Head, true, Clause) =>
254 Clause = Head.
255mkclause(Head, Body, Clause) =>
256 Clause = (Head :- Body).
257
262
263link_clauses(_ContextModule, Unit, Clauses, Exports) :-
264 scasp_module(Unit, Module),
265 findall(Head, link_predicate(Module:Head), Heads),
266 check_exports(Exports, Heads),
267 convlist(link_clause(Module, Exports), Heads, Clauses).
268
269link_predicate(Module:Head) :-
270 Module:pr_user_predicate(PI),
271 \+ not_really_a_user_predicate(PI),
272 pi_head(PI, Head).
273
275not_really_a_user_predicate((not)/1).
276not_really_a_user_predicate(o_nmr_check/0).
277not_really_a_user_predicate(global_constraints/0).
278
279check_exports(all, _) :- !.
280check_exports(Exports, Heads) :-
281 must_be(list, Exports),
282 maplist(check_export(Heads), Exports).
283
284check_export(Heads, -Name/Arity) :-
285 !,
286 atom_concat(-, Name, NName),
287 check_export(Heads, NName/Arity).
288check_export(Heads, Export) :-
289 pi_head(Export, EHead), 290 ( memberchk(EHead, Heads)
291 -> true
292 ; existence_error(predicate, Export)
293 ).
294
295link_clause(Module, Exports, Head,
296 (Head :- scasp_embed:scasp_call(Module:Head))) :-
297 ( Exports == all
298 -> true
299 ; functor(Head, NName, Arity),
300 atom_concat(-, Name, NName)
301 -> memberchk(-Name/Arity, Exports)
302 ; pi_head(PI, Head),
303 memberchk(PI, Exports)
304 ).
305
306
310
311:- public scasp_call/1. 312
313scasp_call(Query) :-
314 scasp_compile_query(Query, Compiled, []),
315 scasp_stack(StackIn),
316 solve(Compiled, StackIn, StackOut, Model),
317 save_model(Model),
318 Compiled = M:_, 319 save_stack(M:StackOut).
320
327
328not(M:Query) :-
329 clause(M:Query, scasp_embed:scasp_call(Module:Query)),
330 scasp_call(Module:not(Query)).
331
335
336-(M:Query) :-
337 Query =.. [Name|Args],
338 atom_concat(-, Name, NName),
339 NQuery =.. [NName|Args],
340 clause(M:NQuery, scasp_embed:scasp_call(Module:NQuery)),
341 scasp_call(Module:NQuery).
342
343
349
350save_model(Model) :-
351 ( nb_current(scasp_model, Model0)
352 -> append(Model, Model0, FullModel),
353 b_setval(scasp_model, FullModel)
354 ; b_setval(scasp_model, Model)
355 ).
356
362
363scasp_model(M:Model) :-
364 scasp_model(M:Model, []).
365
366scasp_model(M:Model, _Options) :-
367 nb_current(scasp_model, RawModel),
368 canonical_model(RawModel, Model1),
369 unqualify_model(Model1, M, Model).
370
371save_stack(Stack) :-
372 b_setval(scasp_stack, Stack),
373 justification_tree(Stack, Tree, []),
374 b_setval(scasp_tree, Tree).
375
380
381scasp_stack(Stack) :-
382 ( nb_current(scasp_stack, Stack0)
383 -> Stack = Stack0
384 ; Stack = []
385 ).
386
390
391scasp_justification(M:Tree, Options) :-
392 nb_current(scasp_tree, Tree0),
393 remove_origins(Tree0, Tree1, Options),
394 unqualify_justitication_tree(Tree1, M, Tree).
395
396remove_origins(Tree0, Tree, Options) :-
397 option(source(false), Options),
398 !,
399 remove_origins(Tree0, Tree).
400remove_origins(Tree, Tree, _).
401
402remove_origins(M:Tree0, Result) =>
403 Result = M:Tree,
404 remove_origins(Tree0, Tree).
405remove_origins(Term0-Children0, Result) =>
406 Result = Term-Children,
407 remove_origin(Term0, Term),
408 maplist(remove_origins, Children0, Children).
409remove_origins(Nodes0, Nodes), is_list(Nodes0) =>
410 maplist(remove_origins, Nodes0, Nodes).
411remove_origins(Node0, Node) =>
412 remove_origin(Node0, Node).
413
414remove_origin(goal_origin(Term, _), Result) =>
415 Result = Term.
416remove_origin(Term, Result) =>
417 Result = Term.
418
419
423
424scasp_listing(Unit, Options) :-
425 scasp_module(Unit, Module),
426 scasp_portray_program(Module:Options).
427
428:- residual_goals(scasp_residuals). 429
434
435scasp_residuals -->
436 { '$current_typein_module'(TypeIn),
437 scasp_residual_types(Types)
438 },
439 scasp_residuals(Types, TypeIn).
440
441scasp_residuals([], _) -->
442 [].
443scasp_residuals([model(Options)|T], M) -->
444 ( {scasp_model(M:Model, Options)}
445 -> [ scasp_show_model(Model, Options) ]
446 ; []
447 ),
448 scasp_residuals(T, M).
449scasp_residuals([justification(Options)|T], M) -->
450 ( {scasp_stack(Stack), Stack \== []}
451 -> [ scasp_show_stack(M:Stack, Options) ]
452 ; []
453 ),
454 scasp_residuals(T, M).
455
456scasp_residual_types(Types) :-
457 findall(Type, scasp_residual_type(Type), Types).
458
459scasp_residual_type(model(Options)) :-
460 current_prolog_flag(scasp_show_model, Spec),
461 Spec \== false,
462 res_options(Spec, Options).
463scasp_residual_type(justification(Options)) :-
464 current_prolog_flag(scasp_show_justification, Spec),
465 Spec \== false,
466 res_options(Spec, Options).
467
468res_options(List, Options), is_list(List) =>
469 Options = List.
470res_options(true, Options) =>
471 Options = [unicode(true)].
472res_options(unicode, Options) =>
473 Options = [unicode(true)].
474res_options(human, Options) =>
475 Options = [human(true)].
476
477user:portray(scasp_show_model(Model, Options)) :-
478 ansi_format(comment, '% s(CASP) model~n', []),
479 print_model(Model, Options).
480user:portray(scasp_show_stack(M:Stack, Options)) :-
481 ansi_format(comment, '% s(CASP) justification', []),
482 justification_tree(Stack, Tree0, Options),
483 unqualify_justitication_tree(Tree0, M, Tree),
484 print_justification_tree(Tree, [full_stop(false)|Options]).
485user:portray('\u2209'(V,S)) :- 486 format('~p \u2209 ~p', [V, S]).
487
488
489 492
493:- multifile
494 prolog:alternate_syntax/4,
495 prolog:xref_update_syntax/2. 496
497prolog:alternate_syntax(scasp, Module, Setup, Restore) :-
498 Setup = scasp_ops:scasp_push_operators(Module),
499 Restore = scasp_ops:scasp_pop_operators.
500
501prolog:xref_update_syntax(begin_scasp(_Unit), Module) :-
502 scasp_ops:scasp_push_operators(Module).
503prolog:xref_update_syntax(begin_scasp(_Unit, _Exports), Module) :-
504 scasp_ops:scasp_push_operators(Module).
505prolog:xref_update_syntax(end_scasp, _Module) :-
506 scasp_ops:scasp_pop_operators.
507
508:- multifile
509 prolog_colour:term_colours/2. 510
511prolog_colour:term_colours(#(Directive),
512 expanded - [DirColours]) :-
513 debug(scasp(highlight), 'Got ~p', [Directive]),
514 dir_colours(Directive, DirColours).
515
516dir_colours(pred(_Head::_Template),
517 expanded -
518 [ expanded -
519 [ body,
520 comment(_)
521 ]
522 ]).
523dir_colours(show(Preds),
524 expanded - [Colours]) :-
525 decl_show_colours(Preds, Colours).
526dir_colours(include(_Unit),
527 expanded -
528 [ classify
529 ]).
530dir_colours(discontiguous(_Preds),
531 expanded -
532 [ declarations(discontiguous)
533 ]).
534
535decl_show_colours((A,B), Colours) =>
536 Colours = classify-[CA,CB],
537 decl_show_colours(A, CA),
538 decl_show_colours(B, CB).
539decl_show_colours(not(_A), Colours) =>
540 Colours = built_in-[declarations(show)].
541decl_show_colours(_A, Colours) =>
542 Colours = declarations(show).
543
544
545 548
557
558:- multifile pce_xref_gui:gxref_called/2. 559:- autoload(library(prolog_xref), [xref_called/4]). 560
561pce_xref_gui:gxref_called(Source, Callable) :-
562 nonvar(Source),
563 callable(Callable),
564 !,
565 ( xref_called_cond(Source, Callable, _)
566 -> true
567 ; scasp_called(Callable)
568 -> true
569 ; xref_dynamic(Source, Callable),
570 scasp_negate(Callable, NegCallable),
571 xref_dynamic(Source, NegCallable),
572 xref_called_cond(Source, NegCallable, _)
573 ).
574
575xref_dynamic(Source, Callable) :-
576 xref_defined(Source, Callable, dynamic(_)), !.
577xref_dynamic(Source, Callable) :-
578 xref_defined(Source, Callable, thread_local(_)).
579
580xref_called_cond(Source, Callable, Cond) :-
581 xref_called(Source, Callable, By, Cond),
582 By \= Callable. 583
584scasp_negate(Callable, NegCallable) :-
585 atom(Callable),
586 !,
587 scasp_neg_atom(Callable, NegCallable).
588scasp_negate(Callable, NegCallable) :-
589 compound_name_arguments(Callable, Name, Args),
590 scasp_neg_atom(Name, NegName),
591 compound_name_arguments(NegCallable, NegName, Args).
592
593scasp_neg_atom(Neg, Pos) :-
594 atom_concat(-, Pos, Neg),
595 !.
596scasp_neg_atom(Pos, Neg) :-
597 atom_concat(-, Pos, Neg).
598
599scasp_called(pr_pred_predicate(_,_,_,_)).
600scasp_called(scasp_expand_program(_,_,_,_)).
601scasp_called(-)