35
36:- module('$expand',
37 [ expand_term/2, 38 expand_goal/2, 39 expand_term/4, 40 expand_goal/4, 41 var_property/2, 42
43 '$expand_closure'/3 44 ]).
45
68
69:- dynamic
70 system:term_expansion/2,
71 system:goal_expansion/2,
72 user:term_expansion/2,
73 user:goal_expansion/2,
74 system:term_expansion/4,
75 system:goal_expansion/4,
76 user:term_expansion/4,
77 user:goal_expansion/4.
78:- multifile
79 system:term_expansion/2,
80 system:goal_expansion/2,
81 user:term_expansion/2,
82 user:goal_expansion/2,
83 system:term_expansion/4,
84 system:goal_expansion/4,
85 user:term_expansion/4,
86 user:goal_expansion/4.
87
88:- meta_predicate
89 expand_terms(4, +, ?, -, -).
90
96
97expand_term(Term0, Term) :-
98 expand_term(Term0, _, Term, _).
99
100expand_term(Var, Pos, Expanded, Pos) :-
101 var(Var),
102 !,
103 Expanded = Var.
104expand_term(Term, Pos0, [], Pos) :-
105 cond_compilation(Term, X),
106 X == [],
107 !,
108 atomic_pos(Pos0, Pos).
109expand_term(Term, Pos0, Expanded, Pos) :-
110 b_setval('$term', Term),
111 '$def_modules'([term_expansion/4,term_expansion/2], MList),
112 call_term_expansion(MList, Term, Pos0, Term1, Pos1),
113 expand_term_2(Term1, Pos1, Term2, Pos),
114 rename(Term2, Expanded),
115 b_setval('$term', []).
116
117call_term_expansion([], Term, Pos, Term, Pos).
118call_term_expansion([M-Preds|T], Term0, Pos0, Term, Pos) :-
119 current_prolog_flag(sandboxed_load, false),
120 !,
121 ( '$member'(Pred, Preds),
122 ( Pred == term_expansion/2
123 -> M:term_expansion(Term0, Term1),
124 Pos1 = Pos0
125 ; M:term_expansion(Term0, Pos0, Term1, Pos1)
126 )
127 -> expand_terms(call_term_expansion(T), Term1, Pos1, Term, Pos)
128 ; call_term_expansion(T, Term0, Pos0, Term, Pos)
129 ).
130call_term_expansion([M-Preds|T], Term0, Pos0, Term, Pos) :-
131 ( '$member'(Pred, Preds),
132 ( Pred == term_expansion/2
133 -> allowed_expansion(M:term_expansion(Term0, Term1)),
134 call(M:term_expansion(Term0, Term1)),
135 Pos1 = Pos
136 ; allowed_expansion(M:term_expansion(Term0, Pos0, Term1, Pos1)),
137 call(M:term_expansion(Term0, Pos0, Term1, Pos1))
138 )
139 -> expand_terms(call_term_expansion(T), Term1, Pos1, Term, Pos)
140 ; call_term_expansion(T, Term0, Pos0, Term, Pos)
141 ).
142
143expand_term_2((Head --> Body), Pos0, Expanded, Pos) :-
144 dcg_translate_rule((Head --> Body), Pos0, Expanded0, Pos1),
145 !,
146 expand_bodies(Expanded0, Pos1, Expanded, Pos).
147expand_term_2(Term0, Pos0, Term, Pos) :-
148 nonvar(Term0),
149 !,
150 expand_bodies(Term0, Pos0, Term, Pos).
151expand_term_2(Term, Pos, Term, Pos).
152
159
160expand_bodies(Terms, Pos0, Out, Pos) :-
161 '$def_modules'([goal_expansion/4,goal_expansion/2], MList),
162 expand_terms(expand_body(MList), Terms, Pos0, Out, Pos),
163 remove_attributes(Out, '$var_info').
164
165expand_body(MList, (Head0 :- Body), Pos0, (Head :- ExpandedBody), Pos) :-
166 !,
167 term_variables(Head0, HVars),
168 mark_vars_non_fresh(HVars),
169 f2_pos(Pos0, HPos, BPos0, Pos, HPos, BPos),
170 expand_goal(Body, BPos0, ExpandedBody0, BPos, MList, (Head0 :- Body)),
171 ( compound(Head0),
172 '$current_source_module'(M),
173 replace_functions(Head0, Eval, Head, M),
174 Eval \== true
175 -> ExpandedBody = (Eval,ExpandedBody0)
176 ; Head = Head0,
177 ExpandedBody = ExpandedBody0
178 ).
179expand_body(MList, (:- Body), Pos0, (:- ExpandedBody), Pos) :-
180 !,
181 f1_pos(Pos0, BPos0, Pos, BPos),
182 expand_goal(Body, BPos0, ExpandedBody, BPos, MList, (:- Body)).
183
184expand_body(_MList, Head0, Pos, Clause, Pos) :- 185 compound(Head0),
186 '$current_source_module'(M),
187 replace_functions(Head0, Eval, Head, M),
188 Eval \== true,
189 !,
190 Clause = (Head :- Eval).
191expand_body(_, Head, Pos, Head, Pos).
192
193
200
201expand_terms(_, X, P, X, P) :-
202 var(X),
203 !.
204expand_terms(C, List0, Pos0, List, Pos) :-
205 nonvar(List0),
206 List0 = [_|_],
207 !,
208 ( is_list(List0)
209 -> list_pos(Pos0, Elems0, Pos, Elems),
210 expand_term_list(C, List0, Elems0, List, Elems)
211 ; '$type_error'(list, List0)
212 ).
213expand_terms(C, '$source_location'(File, Line):Clause0, Pos0, Clause, Pos) :-
214 !,
215 expand_terms(C, Clause0, Pos0, Clause1, Pos),
216 add_source_location(Clause1, '$source_location'(File, Line), Clause).
217expand_terms(C, Term0, Pos0, Term, Pos) :-
218 call(C, Term0, Pos0, Term, Pos).
219
224
225add_source_location(Clauses0, SrcLoc, Clauses) :-
226 ( is_list(Clauses0)
227 -> add_source_location_list(Clauses0, SrcLoc, Clauses)
228 ; Clauses = SrcLoc:Clauses0
229 ).
230
231add_source_location_list([], _, []).
232add_source_location_list([Clause|Clauses0], SrcLoc, [SrcLoc:Clause|Clauses]) :-
233 add_source_location_list(Clauses0, SrcLoc, Clauses).
234
236
237expand_term_list(_, [], _, [], []) :- !.
238expand_term_list(C, [H0|T0], [PH0], Terms, PosL) :-
239 !,
240 expand_terms(C, H0, PH0, H, PH),
241 add_term(H, PH, Terms, TT, PosL, PT),
242 expand_term_list(C, T0, [PH0], TT, PT).
243expand_term_list(C, [H0|T0], [PH0|PT0], Terms, PosL) :-
244 !,
245 expand_terms(C, H0, PH0, H, PH),
246 add_term(H, PH, Terms, TT, PosL, PT),
247 expand_term_list(C, T0, PT0, TT, PT).
248expand_term_list(C, [H0|T0], PH0, Terms, PosL) :-
249 expected_layout(list, PH0),
250 expand_terms(C, H0, PH0, H, PH),
251 add_term(H, PH, Terms, TT, PosL, PT),
252 expand_term_list(C, T0, [PH0], TT, PT).
253
255
256add_term(List, Pos, Terms, TermT, PosL, PosT) :-
257 nonvar(List), List = [_|_],
258 !,
259 ( is_list(List)
260 -> append_tp(List, Terms, TermT, Pos, PosL, PosT)
261 ; '$type_error'(list, List)
262 ).
263add_term(Term, Pos, [Term|Terms], Terms, [Pos|PosT], PosT).
264
265append_tp([], Terms, Terms, _, PosL, PosL).
266append_tp([H|T0], [H|T1], Terms, [HP], [HP|TP1], PosL) :-
267 !,
268 append_tp(T0, T1, Terms, [HP], TP1, PosL).
269append_tp([H|T0], [H|T1], Terms, [HP0|TP0], [HP0|TP1], PosL) :-
270 !,
271 append_tp(T0, T1, Terms, TP0, TP1, PosL).
272append_tp([H|T0], [H|T1], Terms, Pos, [Pos|TP1], PosL) :-
273 expected_layout(list, Pos),
274 append_tp(T0, T1, Terms, [Pos], TP1, PosL).
275
276
277list_pos(Var, _, _, _) :-
278 var(Var),
279 !.
280list_pos(list_position(F,T,Elems0,none), Elems0,
281 list_position(F,T,Elems,none), Elems).
282list_pos(Pos, [Pos], Elems, Elems).
283
284
285 288
292
293var_intersection(List1, List2, Intersection) :-
294 sort(List1, Set1),
295 sort(List2, Set2),
296 ord_intersection(Set1, Set2, Intersection).
297
301
302ord_intersection([], _Int, []).
303ord_intersection([H1|T1], L2, Int) :-
304 isect2(L2, H1, T1, Int).
305
306isect2([], _H1, _T1, []).
307isect2([H2|T2], H1, T1, Int) :-
308 compare(Order, H1, H2),
309 isect3(Order, H1, T1, H2, T2, Int).
310
311isect3(<, _H1, T1, H2, T2, Int) :-
312 isect2(T1, H2, T2, Int).
313isect3(=, H1, T1, _H2, T2, [H1|Int]) :-
314 ord_intersection(T1, T2, Int).
315isect3(>, H1, T1, _H2, T2, Int) :-
316 isect2(T2, H1, T1, Int).
317
318
326
327merge_variable_info([]).
328merge_variable_info([Var=State|States]) :-
329 ( get_attr(Var, '$var_info', CurrentState)
330 -> true
331 ; CurrentState = (-)
332 ),
333 merge_states(Var, State, CurrentState),
334 merge_variable_info(States).
335
336merge_states(_Var, State, State) :- !.
337merge_states(_Var, -, _) :- !.
338merge_states(Var, State, -) :-
339 !,
340 put_attr(Var, '$var_info', State).
341merge_states(Var, Left, Right) :-
342 ( get_dict(fresh, Left, false)
343 -> put_dict(fresh, Right, false)
344 ; get_dict(fresh, Right, false)
345 -> put_dict(fresh, Left, false)
346 ),
347 !,
348 ( Left >:< Right
349 -> put_dict(Left, Right, State),
350 put_attr(Var, '$var_info', State)
351 ; print_message(warning,
352 inconsistent_variable_properties(Left, Right)),
353 put_dict(Left, Right, State),
354 put_attr(Var, '$var_info', State)
355 ).
356
357
358save_variable_info([], []).
359save_variable_info([Var|Vars], [Var=State|States]):-
360 ( get_attr(Var, '$var_info', State)
361 -> true
362 ; State = (-)
363 ),
364 save_variable_info(Vars, States).
365
366restore_variable_info([]).
367restore_variable_info([Var=State|States]) :-
368 ( State == (-)
369 -> del_attr(Var, '$var_info')
370 ; put_attr(Var, '$var_info', State)
371 ),
372 restore_variable_info(States).
373
384
385var_property(Var, Property) :-
386 prop_var(Property, Var).
387
388prop_var(fresh(Fresh), Var) :-
389 ( get_attr(Var, '$var_info', Info),
390 get_dict(fresh, Info, Fresh0)
391 -> Fresh = Fresh0
392 ; Fresh = true
393 ).
394prop_var(name(Name), Var) :-
395 ( nb_current('$variable_names', Bindings),
396 '$member'(Name0=Var0, Bindings),
397 Var0 == Var
398 -> Name = Name0
399 ).
400
401
402mark_vars_non_fresh([]) :- !.
403mark_vars_non_fresh([Var|Vars]) :-
404 ( get_attr(Var, '$var_info', Info)
405 -> ( get_dict(fresh, Info, false)
406 -> true
407 ; put_dict(fresh, Info, false, Info1),
408 put_attr(Var, '$var_info', Info1)
409 )
410 ; put_attr(Var, '$var_info', '$var_info'{fresh:false})
411 ),
412 mark_vars_non_fresh(Vars).
413
414
422
423remove_attributes(Term, Attr) :-
424 term_variables(Term, Vars),
425 remove_var_attr(Vars, Attr).
426
427remove_var_attr([], _):- !.
428remove_var_attr([Var|Vars], Attr):-
429 del_attr(Var, Attr),
430 remove_var_attr(Vars, Attr).
431
435
436'$var_info':attr_unify_hook(_, _).
437
438
439 442
448
449expand_goal(A, B) :-
450 expand_goal(A, _, B, _).
451
452expand_goal(A, P0, B, P) :-
453 '$def_modules'([goal_expansion/4, goal_expansion/2], MList),
454 ( expand_goal(A, P0, B, P, MList, _)
455 -> remove_attributes(B, '$var_info'), A \== B
456 ),
457 !.
458expand_goal(A, P, A, P).
459
466
467'$expand_closure'(G0, N, G) :-
468 '$expand_closure'(G0, _, N, G, _).
469
470'$expand_closure'(G0, P0, N, G, P) :-
471 length(Ex, N),
472 extend_arg_pos(G0, P0, Ex, G1, P1),
473 expand_goal(G1, P1, G2, P2),
474 term_variables(G0, VL),
475 remove_arg_pos(G2, P2, [], VL, Ex, G, P).
476
477
478expand_goal(G0, P0, G, P, MList, Term) :-
479 '$current_source_module'(M),
480 expand_goal(G0, P0, G, P, M, MList, Term).
481
488
500
501expand_goal(G, P, G, P, _, _, _) :-
502 var(G),
503 !.
504expand_goal(M:G, P, M:G, P, _M, _MList, _Term) :-
505 var(M), var(G),
506 !.
507expand_goal(M:G, P0, M:EG, P, _M, _MList, Term) :-
508 atom(M),
509 !,
510 f2_pos(P0, PA, PB0, P, PA, PB),
511 '$def_modules'(M:[goal_expansion/4,goal_expansion/2], MList),
512 setup_call_cleanup(
513 '$set_source_module'(Old, M),
514 '$expand':expand_goal(G, PB0, EG, PB, M, MList, Term),
515 '$set_source_module'(Old)).
516expand_goal(G0, P0, G, P, M, MList, Term) :-
517 call_goal_expansion(MList, G0, P0, G1, P1),
518 !,
519 expand_goal(G1, P1, G, P, M, MList, Term/G1). 520expand_goal((A,B), P0, Conj, P, M, MList, Term) :-
521 !,
522 f2_pos(P0, PA0, PB0, P1, PA, PB),
523 expand_goal(A, PA0, EA, PA, M, MList, Term),
524 expand_goal(B, PB0, EB, PB, M, MList, Term),
525 simplify((EA,EB), P1, Conj, P).
526expand_goal((A;B), P0, Or, P, M, MList, Term) :-
527 !,
528 f2_pos(P0, PA0, PB0, P1, PA1, PB),
529 term_variables(A, AVars),
530 term_variables(B, BVars),
531 var_intersection(AVars, BVars, SharedVars),
532 save_variable_info(SharedVars, SavedState),
533 expand_goal(A, PA0, EA, PA, M, MList, Term),
534 save_variable_info(SharedVars, SavedState2),
535 restore_variable_info(SavedState),
536 expand_goal(B, PB0, EB, PB, M, MList, Term),
537 merge_variable_info(SavedState2),
538 fixup_or_lhs(A, EA, PA, EA1, PA1),
539 simplify((EA1;EB), P1, Or, P).
540expand_goal((A->B), P0, Goal, P, M, MList, Term) :-
541 !,
542 f2_pos(P0, PA0, PB0, P1, PA, PB),
543 expand_goal(A, PA0, EA, PA, M, MList, Term),
544 expand_goal(B, PB0, EB, PB, M, MList, Term),
545 simplify((EA->EB), P1, Goal, P).
546expand_goal((A*->B), P0, Goal, P, M, MList, Term) :-
547 !,
548 f2_pos(P0, PA0, PB0, P1, PA, PB),
549 expand_goal(A, PA0, EA, PA, M, MList, Term),
550 expand_goal(B, PB0, EB, PB, M, MList, Term),
551 simplify((EA*->EB), P1, Goal, P).
552expand_goal((\+A), P0, Goal, P, M, MList, Term) :-
553 !,
554 f1_pos(P0, PA0, P1, PA),
555 term_variables(A, AVars),
556 save_variable_info(AVars, SavedState),
557 expand_goal(A, PA0, EA, PA, M, MList, Term),
558 restore_variable_info(SavedState),
559 simplify(\+(EA), P1, Goal, P).
560expand_goal(call(A), P0, call(EA), P, M, MList, Term) :-
561 !,
562 f1_pos(P0, PA0, P, PA),
563 expand_goal(A, PA0, EA, PA, M, MList, Term).
564expand_goal(G0, P0, G, P, M, MList, Term) :-
565 is_meta_call(G0, M, Head),
566 !,
567 expand_meta(Head, G0, P0, G, P, M, MList, Term).
568expand_goal(G0, P0, G, P, M, MList, Term) :-
569 term_variables(G0, Vars),
570 mark_vars_non_fresh(Vars),
571 expand_functions(G0, P0, G, P, M, MList, Term).
572
579
580fixup_or_lhs(Old, New, PNew, Fix, PFixed) :-
581 nonvar(Old),
582 nonvar(New),
583 ( Old = (_ -> _)
584 -> New \= (_ -> _),
585 Fix = (New -> true)
586 ; New = (_ -> _),
587 Fix = (New, true)
588 ),
589 !,
590 lhs_pos(PNew, PFixed).
591fixup_or_lhs(_Old, New, P, New, P).
592
593lhs_pos(P0, _) :-
594 var(P0),
595 !.
596lhs_pos(P0, term_position(F,T,T,T,[P0,T-T])) :-
597 arg(1, P0, F),
598 arg(2, P0, T).
599
600
604
605is_meta_call(G0, M, Head) :-
606 compound(G0),
607 default_module(M, M2),
608 '$c_current_predicate'(_, M2:G0),
609 !,
610 '$get_predicate_attribute'(M2:G0, meta_predicate, Head),
611 has_meta_arg(Head).
612
613
615
616expand_meta(Spec, G0, P0, G, P, M, MList, Term) :-
617 functor(Spec, _, Arity),
618 functor(G0, Name, Arity),
619 functor(G1, Name, Arity),
620 f_pos(P0, ArgPos0, P, ArgPos),
621 expand_meta(1, Arity, Spec,
622 G0, ArgPos0, Eval,
623 G1, ArgPos,
624 M, MList, Term),
625 conj(Eval, G1, G).
626
627expand_meta(I, Arity, Spec, G0, ArgPos0, Eval, G, [P|PT], M, MList, Term) :-
628 I =< Arity,
629 !,
630 arg_pos(ArgPos0, P0, PT0),
631 arg(I, Spec, Meta),
632 arg(I, G0, A0),
633 arg(I, G, A),
634 expand_meta_arg(Meta, A0, P0, EvalA, A, P, M, MList, Term),
635 I2 is I + 1,
636 expand_meta(I2, Arity, Spec, G0, PT0, EvalB, G, PT, M, MList, Term),
637 conj(EvalA, EvalB, Eval).
638expand_meta(_, _, _, _, _, true, _, [], _, _, _).
639
640arg_pos(List, _, _) :- var(List), !. 641arg_pos([H|T], H, T) :- !. 642arg_pos([], _, []). 643
644mapex([], _).
645mapex([E|L], E) :- mapex(L, E).
646
651
652extended_pos(Var, _, Var) :-
653 var(Var),
654 !.
655extended_pos(term_position(F,T,FF,FT,Args),
656 _,
657 term_position(F,T,FF,FT,Args)) :-
658 var(Args),
659 !.
660extended_pos(term_position(F,T,FF,FT,Args0),
661 N,
662 term_position(F,T,FF,FT,Args)) :-
663 length(Ex, N),
664 mapex(Ex, T-T),
665 '$append'(Args0, Ex, Args),
666 !.
667extended_pos(F-T,
668 N,
669 term_position(F,T,F,T,Ex)) :-
670 !,
671 length(Ex, N),
672 mapex(Ex, T-T).
673extended_pos(Pos, N, Pos) :-
674 '$print_message'(warning, extended_pos(Pos, N)).
675
684
685expand_meta_arg(0, A0, PA0, true, A, PA, M, MList, Term) :-
686 !,
687 expand_goal(A0, PA0, A1, PA, M, MList, Term),
688 compile_meta_call(A1, A, M, Term).
689expand_meta_arg(N, A0, P0, true, A, P, M, MList, Term) :-
690 integer(N), callable(A0),
691 replace_functions(A0, true, _, M),
692 !,
693 length(Ex, N),
694 extend_arg_pos(A0, P0, Ex, A1, PA1),
695 expand_goal(A1, PA1, A2, PA2, M, MList, Term),
696 compile_meta_call(A2, A3, M, Term),
697 term_variables(A0, VL),
698 remove_arg_pos(A3, PA2, M, VL, Ex, A, P).
699expand_meta_arg(^, A0, PA0, true, A, PA, M, MList, Term) :-
700 replace_functions(A0, true, _, M),
701 !,
702 expand_setof_goal(A0, PA0, A, PA, M, MList, Term).
703expand_meta_arg(S, A0, _PA0, Eval, A, _PA, M, _MList, _Term) :-
704 replace_functions(A0, Eval, A, M), 705 ( Eval == true
706 -> true
707 ; same_functor(A0, A)
708 -> true
709 ; meta_arg(S)
710 -> throw(error(context_error(function, meta_arg(S)), _))
711 ; true
712 ).
713
714same_functor(T1, T2) :-
715 compound(T1),
716 !,
717 compound(T2),
718 compound_name_arity(T1, N, A),
719 compound_name_arity(T2, N, A).
720same_functor(T1, T2) :-
721 atom(T1),
722 T1 == T2.
723
724variant_sha1_nat(Term, Hash) :-
725 copy_term_nat(Term, TNat),
726 variant_sha1(TNat, Hash).
727
728wrap_meta_arguments(A0, M, VL, Ex, A) :-
729 '$append'(VL, Ex, AV),
730 variant_sha1_nat(A0+AV, Hash),
731 atom_concat('__aux_wrapper_', Hash, AuxName),
732 H =.. [AuxName|AV],
733 compile_auxiliary_clause(M, (H :- A0)),
734 A =.. [AuxName|VL].
735
740
741extend_arg_pos(A, P, _, A, P) :-
742 var(A),
743 !.
744extend_arg_pos(M:A0, P0, Ex, M:A, P) :-
745 !,
746 f2_pos(P0, PM, PA0, P, PM, PA),
747 extend_arg_pos(A0, PA0, Ex, A, PA).
748extend_arg_pos(A0, P0, Ex, A, P) :-
749 callable(A0),
750 !,
751 extend_term(A0, Ex, A),
752 length(Ex, N),
753 extended_pos(P0, N, P).
754extend_arg_pos(A, P, _, A, P).
755
756extend_term(Atom, Extra, Term) :-
757 atom(Atom),
758 !,
759 Term =.. [Atom|Extra].
760extend_term(Term0, Extra, Term) :-
761 compound_name_arguments(Term0, Name, Args0),
762 '$append'(Args0, Extra, Args),
763 compound_name_arguments(Term, Name, Args).
764
773
774remove_arg_pos(A, P, _, _, _, A, P) :-
775 var(A),
776 !.
777remove_arg_pos(M:A0, P0, _, VL, Ex, M:A, P) :-
778 !,
779 f2_pos(P, PM, PA0, P0, PM, PA),
780 remove_arg_pos(A0, PA, M, VL, Ex, A, PA0).
781remove_arg_pos(A0, P0, M, VL, Ex0, A, P) :-
782 callable(A0),
783 !,
784 length(Ex0, N),
785 ( A0 =.. [F|Args],
786 length(Ex, N),
787 '$append'(Args0, Ex, Args),
788 Ex==Ex0
789 -> extended_pos(P, N, P0),
790 A =.. [F|Args0]
791 ; M \== [],
792 wrap_meta_arguments(A0, M, VL, Ex0, A),
793 wrap_meta_pos(P0, P)
794 ).
795remove_arg_pos(A, P, _, _, _, A, P).
796
797wrap_meta_pos(P0, P) :-
798 ( nonvar(P0)
799 -> P = term_position(F,T,_,_,_),
800 atomic_pos(P0, F-T)
801 ; true
802 ).
803
804has_meta_arg(Head) :-
805 arg(_, Head, Arg),
806 direct_call_meta_arg(Arg),
807 !.
808
809direct_call_meta_arg(I) :- integer(I).
810direct_call_meta_arg(^).
811
812meta_arg(:).
813meta_arg(//).
814meta_arg(I) :- integer(I).
815
816expand_setof_goal(Var, Pos, Var, Pos, _, _, _) :-
817 var(Var),
818 !.
819expand_setof_goal(V^G, P0, V^EG, P, M, MList, Term) :-
820 !,
821 f2_pos(P0, PA0, PB, P, PA, PB),
822 expand_setof_goal(G, PA0, EG, PA, M, MList, Term).
823expand_setof_goal(M0:G, P0, M0:EG, P, M, MList, Term) :-
824 !,
825 f2_pos(P0, PA0, PB, P, PA, PB),
826 expand_setof_goal(G, PA0, EG, PA, M, MList, Term).
827expand_setof_goal(G, P0, EG, P, M, MList, Term) :-
828 !,
829 expand_goal(G, P0, EG0, P, M, MList, Term),
830 compile_meta_call(EG0, EG, M, Term). 831
832
840
841call_goal_expansion(MList, G0, P0, G, P) :-
842 current_prolog_flag(sandboxed_load, false),
843 !,
844 ( '$member'(M-Preds, MList),
845 '$member'(Pred, Preds),
846 ( Pred == goal_expansion/4
847 -> M:goal_expansion(G0, P0, G, P)
848 ; M:goal_expansion(G0, G),
849 P = P0
850 ),
851 G0 \== G
852 -> true
853 ).
854call_goal_expansion(MList, G0, P0, G, P) :-
855 ( '$member'(M-Preds, MList),
856 '$member'(Pred, Preds),
857 ( Pred == goal_expansion/4
858 -> Expand = M:goal_expansion(G0, P0, G, P)
859 ; Expand = M:goal_expansion(G0, G)
860 ),
861 allowed_expansion(Expand),
862 call(Expand),
863 G0 \== G
864 -> true
865 ).
866
874
875:- multifile
876 prolog:sandbox_allowed_expansion/1.
877
878allowed_expansion(QGoal) :-
879 strip_module(QGoal, M, Goal),
880 catch(prolog:sandbox_allowed_expansion(M:Goal), E, true),
881 ( var(E)
882 -> fail
883 ; !,
884 print_message(error, E),
885 fail
886 ).
887allowed_expansion(_).
888
889
890 893
900
901expand_functions(G0, P0, G, P, M, MList, Term) :-
902 expand_functional_notation(G0, P0, G1, P1, M, MList, Term),
903 ( expand_arithmetic(G1, P1, G, P, Term)
904 -> true
905 ; G = G1,
906 P = P1
907 ).
908
913
914expand_functional_notation(G0, P0, G, P, M, _MList, _Term) :-
915 contains_functions(G0),
916 replace_functions(G0, P0, Eval, EvalPos, G1, G1Pos, M),
917 Eval \== true,
918 !,
919 wrap_var(G1, G1Pos, G2, G2Pos),
920 conj(Eval, EvalPos, G2, G2Pos, G, P).
921expand_functional_notation(G, P, G, P, _, _, _).
922
923wrap_var(G, P, G, P) :-
924 nonvar(G),
925 !.
926wrap_var(G, P0, call(G), P) :-
927 ( nonvar(P0)
928 -> P = term_position(F,T,F,T,[P0]),
929 atomic_pos(P0, F-T)
930 ; true
931 ).
932
936
937contains_functions(Term) :-
938 \+ \+ ( '$factorize_term'(Term, Skeleton, Assignments),
939 ( contains_functions2(Skeleton)
940 ; contains_functions2(Assignments)
941 )).
942
943contains_functions2(Term) :-
944 compound(Term),
945 ( function(Term, _)
946 -> true
947 ; arg(_, Term, Arg),
948 contains_functions2(Arg)
949 -> true
950 ).
951
958
959:- public
960 replace_functions/4. 961
962replace_functions(GoalIn, Eval, GoalOut, Context) :-
963 replace_functions(GoalIn, _, Eval, _, GoalOut, _, Context).
964
965replace_functions(Var, Pos, true, _, Var, Pos, _Ctx) :-
966 var(Var),
967 !.
968replace_functions(F, FPos, Eval, EvalPos, Var, VarPos, Ctx) :-
969 function(F, Ctx),
970 !,
971 compound_name_arity(F, Name, Arity),
972 PredArity is Arity+1,
973 compound_name_arity(G, Name, PredArity),
974 arg(PredArity, G, Var),
975 extend_1_pos(FPos, FArgPos, GPos, GArgPos, VarPos),
976 map_functions(0, Arity, F, FArgPos, G, GArgPos, Eval0, EP0, Ctx),
977 conj(Eval0, EP0, G, GPos, Eval, EvalPos).
978replace_functions(Term0, Term0Pos, Eval, EvalPos, Term, TermPos, Ctx) :-
979 compound(Term0),
980 !,
981 compound_name_arity(Term0, Name, Arity),
982 compound_name_arity(Term, Name, Arity),
983 f_pos(Term0Pos, Args0Pos, TermPos, ArgsPos),
984 map_functions(0, Arity,
985 Term0, Args0Pos, Term, ArgsPos, Eval, EvalPos, Ctx).
986replace_functions(Term, Pos, true, _, Term, Pos, _).
987
988
992
993map_functions(Arity, Arity, _, LPos0, _, LPos, true, _, _) :-
994 !,
995 pos_nil(LPos0, LPos).
996map_functions(I0, Arity, Term0, LPos0, Term, LPos, Eval, EP, Ctx) :-
997 pos_list(LPos0, AP0, APT0, LPos, AP, APT),
998 I is I0+1,
999 arg(I, Term0, Arg0),
1000 arg(I, Term, Arg),
1001 replace_functions(Arg0, AP0, Eval0, EP0, Arg, AP, Ctx),
1002 map_functions(I, Arity, Term0, APT0, Term, APT, Eval1, EP1, Ctx),
1003 conj(Eval0, EP0, Eval1, EP1, Eval, EP).
1004
1005conj(true, X, X) :- !.
1006conj(X, true, X) :- !.
1007conj(X, Y, (X,Y)).
1008
1009conj(true, _, X, P, X, P) :- !.
1010conj(X, P, true, _, X, P) :- !.
1011conj(X, PX, Y, PY, (X,Y), _) :-
1012 var(PX), var(PY),
1013 !.
1014conj(X, PX, Y, PY, (X,Y), P) :-
1015 P = term_position(F,T,FF,FT,[PX,PY]),
1016 atomic_pos(PX, F-FF),
1017 atomic_pos(PY, FT-T).
1018
1023
1024function(.(_,_), _) :- \+ functor([_|_], ., _).
1025
1026
1027 1030
1038
1039expand_arithmetic(_G0, _P0, _G, _P, _Term) :- fail.
1040
1041
1042 1045
1053
1054f2_pos(Var, _, _, _, _, _) :-
1055 var(Var),
1056 !.
1057f2_pos(term_position(F,T,FF,FT,[A10,A20]), A10, A20,
1058 term_position(F,T,FF,FT,[A1, A2 ]), A1, A2) :- !.
1059f2_pos(parentheses_term_position(O,C,Pos0), A10, A20,
1060 parentheses_term_position(O,C,Pos), A1, A2) :-
1061 !,
1062 f2_pos(Pos0, A10, A20, Pos, A1, A2).
1063f2_pos(Pos, _, _, _, _, _) :-
1064 expected_layout(f2, Pos).
1065
1066f1_pos(Var, _, _, _) :-
1067 var(Var),
1068 !.
1069f1_pos(term_position(F,T,FF,FT,[A10]), A10,
1070 term_position(F,T,FF,FT,[A1 ]), A1) :- !.
1071f1_pos(parentheses_term_position(O,C,Pos0), A10,
1072 parentheses_term_position(O,C,Pos), A1) :-
1073 !,
1074 f1_pos(Pos0, A10, Pos, A1).
1075f1_pos(Pos, _, _, _) :-
1076 expected_layout(f1, Pos).
1077
1078f_pos(Var, _, _, _) :-
1079 var(Var),
1080 !.
1081f_pos(term_position(F,T,FF,FT,ArgPos0), ArgPos0,
1082 term_position(F,T,FF,FT,ArgPos), ArgPos) :- !.
1083f_pos(parentheses_term_position(O,C,Pos0), A10,
1084 parentheses_term_position(O,C,Pos), A1) :-
1085 !,
1086 f_pos(Pos0, A10, Pos, A1).
1087f_pos(Pos, _, _, _) :-
1088 expected_layout(compound, Pos).
1089
1090atomic_pos(Pos, _) :-
1091 var(Pos),
1092 !.
1093atomic_pos(Pos, F-T) :-
1094 arg(1, Pos, F),
1095 arg(2, Pos, T).
1096
1101
1102pos_nil(Var, _) :- var(Var), !.
1103pos_nil([], []) :- !.
1104pos_nil(Pos, _) :-
1105 expected_layout(nil, Pos).
1106
1107pos_list(Var, _, _, _, _, _) :- var(Var), !.
1108pos_list([H0|T0], H0, T0, [H|T], H, T) :- !.
1109pos_list(Pos, _, _, _, _, _) :-
1110 expected_layout(list, Pos).
1111
1115
1116extend_1_pos(Pos, _, _, _, _) :-
1117 var(Pos),
1118 !.
1119extend_1_pos(term_position(F,T,FF,FT,FArgPos), FArgPos,
1120 term_position(F,T,FF,FT,GArgPos), GArgPos0,
1121 FT-FT1) :-
1122 integer(FT),
1123 !,
1124 FT1 is FT+1,
1125 '$same_length'(FArgPos, GArgPos0),
1126 '$append'(GArgPos0, [FT-FT1], GArgPos).
1127extend_1_pos(F-T, [],
1128 term_position(F,T,F,T,[T-T1]), [],
1129 T-T1) :-
1130 integer(T),
1131 !,
1132 T1 is T+1.
1133extend_1_pos(Pos, _, _, _, _) :-
1134 expected_layout(callable, Pos).
1135
1136'$same_length'(List, List) :-
1137 var(List),
1138 !.
1139'$same_length'([], []).
1140'$same_length'([_|T0], [_|T]) :-
1141 '$same_length'(T0, T).
1142
1143
1150
1151:- create_prolog_flag(debug_term_position, false, []).
1152
1153expected_layout(Expected, Pos) :-
1154 current_prolog_flag(debug_term_position, true),
1155 !,
1156 '$print_message'(warning, expected_layout(Expected, Pos)).
1157expected_layout(_, _).
1158
1159
1160 1163
1170
1171simplify(Control, P, Control, P) :-
1172 current_prolog_flag(optimise, false),
1173 !.
1174simplify(Control, P0, Simple, P) :-
1175 simple(Control, P0, Simple, P),
1176 !.
1177simplify(Control, P, Control, P).
1178
1185
1186simple((X,Y), P0, Conj, P) :-
1187 ( true(X)
1188 -> Conj = Y,
1189 f2_pos(P0, _, P, _, _, _)
1190 ; false(X)
1191 -> Conj = fail,
1192 f2_pos(P0, P1, _, _, _, _),
1193 atomic_pos(P1, P)
1194 ; true(Y)
1195 -> Conj = X,
1196 f2_pos(P0, P, _, _, _, _)
1197 ).
1198simple((I->T;E), P0, ITE, P) :- 1199 ( true(I) 1200 -> ITE = T, 1201 f2_pos(P0, P1, _, _, _, _),
1202 f2_pos(P1, _, P, _, _, _)
1203 ; false(I)
1204 -> ITE = E,
1205 f2_pos(P0, _, P, _, _, _)
1206 ).
1207simple((X;Y), P0, Or, P) :-
1208 false(X),
1209 Or = Y,
1210 f2_pos(P0, _, P, _, _, _).
1211
1212true(X) :-
1213 nonvar(X),
1214 eval_true(X).
1215
1216false(X) :-
1217 nonvar(X),
1218 eval_false(X).
1219
1220
1223
1224eval_true(true).
1225eval_true(otherwise).
1226
1227eval_false(fail).
1228eval_false(false).
1229
1230
1231 1234
1235:- create_prolog_flag(compile_meta_arguments, false, [type(atom)]).
1236
1240
1241compile_meta_call(CallIn, CallIn, _, Term) :-
1242 var(Term),
1243 !. 1244compile_meta_call(CallIn, CallIn, _, _) :-
1245 var(CallIn),
1246 !.
1247compile_meta_call(CallIn, CallIn, _, _) :-
1248 ( current_prolog_flag(compile_meta_arguments, false)
1249 ; current_prolog_flag(xref, true)
1250 ),
1251 !.
1252compile_meta_call(CallIn, CallIn, _, _) :-
1253 strip_module(CallIn, _, Call),
1254 ( is_aux_meta(Call)
1255 ; \+ control(Call),
1256 ( '$c_current_predicate'(_, system:Call),
1257 \+ current_prolog_flag(compile_meta_arguments, always)
1258 ; current_prolog_flag(compile_meta_arguments, control)
1259 )
1260 ),
1261 !.
1262compile_meta_call(M:CallIn, CallOut, _, Term) :-
1263 !,
1264 ( atom(M), callable(CallIn)
1265 -> compile_meta_call(CallIn, CallOut, M, Term)
1266 ; CallOut = M:CallIn
1267 ).
1268compile_meta_call(CallIn, CallOut, Module, Term) :-
1269 compile_meta(CallIn, CallOut, Module, Term, Clause),
1270 compile_auxiliary_clause(Module, Clause).
1271
1272compile_auxiliary_clause(Module, Clause) :-
1273 Clause = (Head:-Body),
1274 '$current_source_module'(SM),
1275 ( predicate_property(SM:Head, defined)
1276 -> true
1277 ; SM == Module
1278 -> compile_aux_clauses([Clause])
1279 ; compile_aux_clauses([Head:-Module:Body])
1280 ).
1281
1282control((_,_)).
1283control((_;_)).
1284control((_->_)).
1285control((_*->_)).
1286control(\+(_)).
1287
1288is_aux_meta(Term) :-
1289 callable(Term),
1290 functor(Term, Name, _),
1291 sub_atom(Name, 0, _, _, '__aux_meta_call_').
1292
1293compile_meta(CallIn, CallOut, M, Term, (CallOut :- Body)) :-
1294 term_variables(Term, AllVars),
1295 term_variables(CallIn, InVars),
1296 intersection_eq(InVars, AllVars, HeadVars),
1297 variant_sha1(CallIn+HeadVars, Hash),
1298 atom_concat('__aux_meta_call_', Hash, AuxName),
1299 expand_goal(CallIn, _Pos0, Body, _Pos, M, [], (CallOut:-CallIn)),
1300 length(HeadVars, Arity),
1301 ( Arity > 256 1302 -> HeadArgs = [v(HeadVars)]
1303 ; HeadArgs = HeadVars
1304 ),
1305 CallOut =.. [AuxName|HeadArgs].
1306
1311
1312intersection_eq([], _, []).
1313intersection_eq([H|T0], L, List) :-
1314 ( member_eq(H, L)
1315 -> List = [H|T],
1316 intersection_eq(T0, L, T)
1317 ; intersection_eq(T0, L, List)
1318 ).
1319
1320member_eq(E, [H|T]) :-
1321 ( E == H
1322 -> true
1323 ; member_eq(E, T)
1324 ).
1325
1326 1329
1330:- multifile
1331 prolog:rename_predicate/2.
1332
1333rename(Var, Var) :-
1334 var(Var),
1335 !.
1336rename(end_of_file, end_of_file) :- !.
1337rename(Terms0, Terms) :-
1338 is_list(Terms0),
1339 !,
1340 '$current_source_module'(M),
1341 rename_preds(Terms0, Terms, M).
1342rename(Term0, Term) :-
1343 '$current_source_module'(M),
1344 rename(Term0, Term, M),
1345 !.
1346rename(Term, Term).
1347
1348rename_preds([], [], _).
1349rename_preds([H0|T0], [H|T], M) :-
1350 ( rename(H0, H, M)
1351 -> true
1352 ; H = H0
1353 ),
1354 rename_preds(T0, T, M).
1355
1356rename(Var, Var, _) :-
1357 var(Var),
1358 !.
1359rename(M:Term0, M:Term, M0) :-
1360 !,
1361 ( M = '$source_location'(_File, _Line)
1362 -> rename(Term0, Term, M0)
1363 ; rename(Term0, Term, M)
1364 ).
1365rename((Head0 :- Body), (Head :- Body), M) :-
1366 !,
1367 rename_head(Head0, Head, M).
1368rename((:-_), _, _) :-
1369 !,
1370 fail.
1371rename(Head0, Head, M) :-
1372 rename_head(Head0, Head, M).
1373
1374rename_head(Var, Var, _) :-
1375 var(Var),
1376 !.
1377rename_head(M:Term0, M:Term, _) :-
1378 !,
1379 rename_head(Term0, Term, M).
1380rename_head(Head0, Head, M) :-
1381 prolog:rename_predicate(M:Head0, M:Head).
1382
1383
1384 1387
1388:- thread_local
1389 '$include_code'/3.
1390
1391'$including' :-
1392 '$include_code'(X, _, _),
1393 !,
1394 X == true.
1395'$including'.
1396
1397cond_compilation((:- if(G)), []) :-
1398 source_location(File, Line),
1399 ( '$including'
1400 -> ( catch('$eval_if'(G), E, (print_message(error, E), fail))
1401 -> asserta('$include_code'(true, File, Line))
1402 ; asserta('$include_code'(false, File, Line))
1403 )
1404 ; asserta('$include_code'(else_false, File, Line))
1405 ).
1406cond_compilation((:- elif(G)), []) :-
1407 source_location(File, Line),
1408 ( clause('$include_code'(Old, OF, _), _, Ref)
1409 -> same_source(File, OF, elif),
1410 erase(Ref),
1411 ( Old == true
1412 -> asserta('$include_code'(else_false, File, Line))
1413 ; Old == false,
1414 catch('$eval_if'(G), E, (print_message(error, E), fail))
1415 -> asserta('$include_code'(true, File, Line))
1416 ; asserta('$include_code'(Old, File, Line))
1417 )
1418 ; throw(error(conditional_compilation_error(no_if, elif), _))
1419 ).
1420cond_compilation((:- else), []) :-
1421 source_location(File, Line),
1422 ( clause('$include_code'(X, OF, _), _, Ref)
1423 -> same_source(File, OF, else),
1424 erase(Ref),
1425 ( X == true
1426 -> X2 = false
1427 ; X == false
1428 -> X2 = true
1429 ; X2 = X
1430 ),
1431 asserta('$include_code'(X2, File, Line))
1432 ; throw(error(conditional_compilation_error(no_if, else), _))
1433 ).
1434cond_compilation(end_of_file, end_of_file) :- 1435 !,
1436 source_location(File, _),
1437 ( clause('$include_code'(_, OF, OL), _)
1438 -> ( File == OF
1439 -> throw(error(conditional_compilation_error(
1440 unterminated,OF:OL), _))
1441 ; true
1442 )
1443 ; true
1444 ).
1445cond_compilation((:- endif), []) :-
1446 !,
1447 source_location(File, _),
1448 ( ( clause('$include_code'(_, OF, _), _, Ref)
1449 -> same_source(File, OF, endif),
1450 erase(Ref)
1451 )
1452 -> true
1453 ; throw(error(conditional_compilation_error(no_if, endif), _))
1454 ).
1455cond_compilation(_, []) :-
1456 \+ '$including'.
1457
1458same_source(File, File, _) :- !.
1459same_source(_, _, Op) :-
1460 throw(error(conditional_compilation_error(no_if, Op), _)).
1461
1462
1463'$eval_if'(G) :-
1464 expand_goal(G, G2),
1465 '$current_source_module'(Module),
1466 Module:G2.