34
35:- module(prolog_codewalk,
36 [ prolog_walk_code/1, 37 prolog_program_clause/2 38 ]). 39:- use_module(library(option)). 40:- use_module(library(record)). 41:- use_module(library(debug)). 42:- use_module(library(apply)). 43:- use_module(library(lists)). 44:- use_module(library(prolog_metainference)). 45
77
78:- meta_predicate
79 prolog_walk_code(:). 80
81:- multifile
82 prolog:called_by/4,
83 prolog:called_by/2. 84
85:- predicate_options(prolog_walk_code/1, 1,
86 [ undefined(oneof([ignore,error,trace])),
87 autoload(boolean),
88 clauses(list),
89 module(atom),
90 module_class(list(oneof([user,system,library,
91 test,development]))),
92 source(boolean),
93 trace_reference(any),
94 on_trace(callable),
95 infer_meta_predicates(oneof([false,true,all])),
96 evaluate(boolean),
97 verbose(boolean)
98 ]). 99
100:- record
101 walk_option(undefined:oneof([ignore,error,trace])=ignore,
102 autoload:boolean=true,
103 source:boolean=true,
104 module:atom, 105 module_class:list(oneof([user,system,library,
106 test,development]))=[user,library],
107 infer_meta_predicates:oneof([false,true,all])=true,
108 clauses:list, 109 trace_reference:any=(-),
110 on_trace:callable, 111 112 clause, 113 caller, 114 initialization, 115 undecided, 116 evaluate:boolean, 117 verbose:boolean=false). 118
119:- thread_local
120 multifile_predicate/3. 121
195
196prolog_walk_code(Options) :-
197 meta_options(is_meta, Options, QOptions),
198 prolog_walk_code(1, QOptions).
199
200prolog_walk_code(Iteration, Options) :-
201 statistics(cputime, CPU0),
202 make_walk_option(Options, OTerm, _),
203 ( walk_option_clauses(OTerm, Clauses),
204 nonvar(Clauses)
205 -> walk_clauses(Clauses, OTerm)
206 ; forall(( walk_option_module(OTerm, M),
207 current_module(M),
208 scan_module(M, OTerm)
209 ),
210 find_walk_from_module(M, OTerm)),
211 walk_from_multifile(OTerm),
212 walk_from_initialization(OTerm)
213 ),
214 infer_new_meta_predicates(New, OTerm),
215 statistics(cputime, CPU1),
216 ( New \== []
217 -> CPU is CPU1-CPU0,
218 ( walk_option_verbose(OTerm, true)
219 -> Level = informational
220 ; Level = silent
221 ),
222 print_message(Level,
223 codewalk(reiterate(New, Iteration, CPU))),
224 succ(Iteration, Iteration2),
225 prolog_walk_code(Iteration2, Options)
226 ; true
227 ).
228
229is_meta(on_trace).
230
231
235
236walk_clauses(Clauses, OTerm) :-
237 must_be(list, Clauses),
238 forall(member(ClauseRef, Clauses),
239 ( user:clause(CHead, Body, ClauseRef),
240 ( CHead = Module:Head
241 -> true
242 ; Module = user,
243 Head = CHead
244 ),
245 walk_option_clause(OTerm, ClauseRef),
246 walk_option_caller(OTerm, Module:Head),
247 walk_called_by_body(Body, Module, OTerm)
248 )).
249
253
254scan_module(M, OTerm) :-
255 walk_option_module_class(OTerm, Classes),
256 module_property(M, class(Class)),
257 memberchk(Class, Classes).
258
265
266walk_from_initialization(OTerm) :-
267 walk_option_caller(OTerm, '<initialization>'),
268 forall('$init_goal'(_File, Goal, SourceLocation),
269 ( walk_option_initialization(OTerm, SourceLocation),
270 walk_from_initialization(Goal, OTerm))).
271
272walk_from_initialization(M:Goal, OTerm) :-
273 scan_module(M, OTerm),
274 !,
275 walk_called_by_body(Goal, M, OTerm).
276walk_from_initialization(_, _).
277
278
283
284find_walk_from_module(M, OTerm) :-
285 debug(autoload, 'Analysing module ~q', [M]),
286 forall(predicate_in_module(M, PI),
287 walk_called_by_pred(M:PI, OTerm)).
288
289walk_called_by_pred(Module:Name/Arity, _) :-
290 multifile_predicate(Name, Arity, Module),
291 !.
292walk_called_by_pred(Module:Name/Arity, _) :-
293 functor(Head, Name, Arity),
294 predicate_property(Module:Head, multifile),
295 !,
296 assertz(multifile_predicate(Name, Arity, Module)).
297walk_called_by_pred(Module:Name/Arity, OTerm) :-
298 functor(Head, Name, Arity),
299 ( no_walk_property(Property),
300 predicate_property(Module:Head, Property)
301 -> true
302 ; walk_option_caller(OTerm, Module:Head),
303 walk_option_clause(OTerm, ClauseRef),
304 forall(catch(clause(Module:Head, Body, ClauseRef), _, fail),
305 walk_called_by_body(Body, Module, OTerm))
306 ).
307
308no_walk_property(number_of_rules(0)). 309no_walk_property(foreign). 310
314
315walk_from_multifile(OTerm) :-
316 forall(retract(multifile_predicate(Name, Arity, Module)),
317 walk_called_by_multifile(Module:Name/Arity, OTerm)).
318
319walk_called_by_multifile(Module:Name/Arity, OTerm) :-
320 functor(Head, Name, Arity),
321 forall(catch(clause_not_from_development(
322 Module:Head, Body, ClauseRef, OTerm),
323 _, fail),
324 ( walk_option_clause(OTerm, ClauseRef),
325 walk_option_caller(OTerm, Module:Head),
326 walk_called_by_body(Body, Module, OTerm)
327 )).
328
329
334
335clause_not_from_development(Module:Head, Body, Ref, OTerm) :-
336 clause(Module:Head, Body, Ref),
337 \+ ( clause_property(Ref, file(File)),
338 module_property(LoadModule, file(File)),
339 \+ scan_module(LoadModule, OTerm)
340 ).
341
349
350walk_called_by_body(True, _, _) :-
351 True == true,
352 !. 353walk_called_by_body(Body, Module, OTerm) :-
354 set_undecided_of_walk_option(error, OTerm, OTerm1),
355 set_evaluate_of_walk_option(false, OTerm1, OTerm2),
356 catch(walk_called(Body, Module, _TermPos, OTerm2),
357 missing(Missing),
358 walk_called_by_body(Missing, Body, Module, OTerm)),
359 !.
360walk_called_by_body(Body, Module, OTerm) :-
361 format(user_error, 'Failed to analyse:~n', []),
362 portray_clause(('<head>' :- Body)),
363 debug_walk(Body, Module, OTerm).
364
367:- if(debugging(codewalk(trace))). 368debug_walk(Body, Module, OTerm) :-
369 gtrace,
370 walk_called_by_body(Body, Module, OTerm).
371:- else. 372debug_walk(_,_,_).
373:- endif. 374
379
380walk_called_by_body(Missing, Body, _, OTerm) :-
381 debugging(codewalk),
382 format(user_error, 'Retrying due to ~w (~p)~n', [Missing, OTerm]),
383 portray_clause(('<head>' :- Body)), fail.
384walk_called_by_body(undecided_call, Body, Module, OTerm) :-
385 catch(forall(walk_called(Body, Module, _TermPos, OTerm),
386 true),
387 missing(Missing),
388 walk_called_by_body(Missing, Body, Module, OTerm)).
389walk_called_by_body(subterm_positions, Body, Module, OTerm) :-
390 ( ( walk_option_clause(OTerm, ClauseRef), nonvar(ClauseRef),
391 clause_info(ClauseRef, _, TermPos, _NameOffset),
392 TermPos = term_position(_,_,_,_,[_,BodyPos])
393 -> WBody = Body
394 ; walk_option_initialization(OTerm, SrcLoc),
395 ground(SrcLoc), SrcLoc = _File:_Line,
396 initialization_layout(SrcLoc, Module:Body, WBody, BodyPos)
397 )
398 -> catch(forall(walk_called(WBody, Module, BodyPos, OTerm),
399 true),
400 missing(subterm_positions),
401 walk_called_by_body(no_positions, Body, Module, OTerm))
402 ; set_source_of_walk_option(false, OTerm, OTerm2),
403 forall(walk_called(Body, Module, _BodyPos, OTerm2),
404 true)
405 ).
406walk_called_by_body(no_positions, Body, Module, OTerm) :-
407 set_source_of_walk_option(false, OTerm, OTerm2),
408 forall(walk_called(Body, Module, _NoPos, OTerm2),
409 true).
410
411
438
439walk_called(Term, Module, parentheses_term_position(_,_,Pos), OTerm) :-
440 nonvar(Pos),
441 !,
442 walk_called(Term, Module, Pos, OTerm).
443walk_called(Var, _, TermPos, OTerm) :-
444 var(Var), 445 !,
446 undecided(Var, TermPos, OTerm).
447walk_called(M:G, _, term_position(_,_,_,_,[MPos,Pos]), OTerm) :-
448 !,
449 ( nonvar(M)
450 -> walk_called(G, M, Pos, OTerm)
451 ; undecided(M, MPos, OTerm)
452 ).
453walk_called((A,B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
454 !,
455 walk_called(A, M, PA, OTerm),
456 walk_called(B, M, PB, OTerm).
457walk_called((A->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
458 !,
459 walk_called(A, M, PA, OTerm),
460 walk_called(B, M, PB, OTerm).
461walk_called((A*->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
462 !,
463 walk_called(A, M, PA, OTerm),
464 walk_called(B, M, PB, OTerm).
465walk_called(\+(A), M, term_position(_,_,_,_,[PA]), OTerm) :-
466 !,
467 \+ \+ walk_called(A, M, PA, OTerm).
468walk_called((A;B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
469 !,
470 ( walk_option_evaluate(OTerm, Eval), Eval == true
471 -> Goal = (A;B),
472 setof(Goal,
473 ( walk_called(A, M, PA, OTerm)
474 ; walk_called(B, M, PB, OTerm)
475 ),
476 Alts0),
477 variants(Alts0, Alts),
478 member(Goal, Alts)
479 ; \+ \+ walk_called(A, M, PA, OTerm), 480 \+ \+ walk_called(B, M, PB, OTerm)
481 ).
482walk_called(Goal, Module, TermPos, OTerm) :-
483 walk_option_trace_reference(OTerm, To), To \== (-),
484 ( subsumes_term(To, Module:Goal)
485 -> M2 = Module
486 ; predicate_property(Module:Goal, imported_from(M2)),
487 subsumes_term(To, M2:Goal)
488 ),
489 print_reference(M2:Goal, TermPos, trace, OTerm),
490 fail. 491walk_called(Goal, Module, _, OTerm) :-
492 evaluate(Goal, Module, OTerm),
493 !.
494walk_called(Goal, M, TermPos, OTerm) :-
495 ( ( predicate_property(M:Goal, imported_from(IM))
496 -> true
497 ; IM = M
498 ),
499 prolog:called_by(Goal, IM, M, Called)
500 ; prolog:called_by(Goal, Called)
501 ),
502 Called \== [],
503 !,
504 walk_called_by(Called, M, Goal, TermPos, OTerm).
505walk_called(Meta, M, term_position(_,E,_,_,ArgPosList), OTerm) :-
506 ( walk_option_autoload(OTerm, false)
507 -> nonvar(M),
508 '$get_predicate_attribute'(M:Meta, defined, 1)
509 ; true
510 ),
511 ( predicate_property(M:Meta, meta_predicate(Head))
512 ; inferred_meta_predicate(M:Meta, Head)
513 ),
514 !,
515 walk_option_clause(OTerm, ClauseRef),
516 register_possible_meta_clause(ClauseRef),
517 walk_meta_call(1, Head, Meta, M, ArgPosList, E-E, OTerm).
518walk_called(Goal, Module, _, _) :-
519 nonvar(Module),
520 '$get_predicate_attribute'(Module:Goal, defined, 1),
521 !.
522walk_called(Goal, Module, TermPos, OTerm) :-
523 callable(Goal),
524 !,
525 undefined(Module:Goal, TermPos, OTerm).
526walk_called(Goal, _Module, TermPos, OTerm) :-
527 not_callable(Goal, TermPos, OTerm).
528
530
531undecided(Var, TermPos, OTerm) :-
532 walk_option_undecided(OTerm, Undecided),
533 ( var(Undecided)
534 -> Action = ignore
535 ; Action = Undecided
536 ),
537 undecided(Action, Var, TermPos, OTerm).
538
539undecided(ignore, _, _, _) :- !.
540undecided(error, _, _, _) :-
541 throw(missing(undecided_call)).
542
544
545evaluate(Goal, Module, OTerm) :-
546 walk_option_evaluate(OTerm, Evaluate),
547 Evaluate \== false,
548 evaluate(Goal, Module).
549
550evaluate(A=B, _) :-
551 unify_with_occurs_check(A, B).
552
556
557undefined(_, _, OTerm) :-
558 walk_option_undefined(OTerm, ignore),
559 !.
560undefined(Goal, _, _) :-
561 predicate_property(Goal, autoload(_)),
562 !.
563undefined(Goal, TermPos, OTerm) :-
564 ( walk_option_undefined(OTerm, trace)
565 -> Why = trace
566 ; Why = undefined
567 ),
568 print_reference(Goal, TermPos, Why, OTerm).
569
573
574not_callable(Goal, TermPos, OTerm) :-
575 print_reference(Goal, TermPos, not_callable, OTerm).
576
577
583
584print_reference(Goal, TermPos, Why, OTerm) :-
585 walk_option_clause(OTerm, Clause), nonvar(Clause),
586 !,
587 ( compound(TermPos),
588 arg(1, TermPos, CharCount),
589 integer(CharCount) 590 -> From = clause_term_position(Clause, TermPos)
591 ; walk_option_source(OTerm, false)
592 -> From = clause(Clause)
593 ; From = _,
594 throw(missing(subterm_positions))
595 ),
596 print_reference2(Goal, From, Why, OTerm).
597print_reference(Goal, TermPos, Why, OTerm) :-
598 walk_option_initialization(OTerm, Init), nonvar(Init),
599 Init = File:Line,
600 !,
601 ( compound(TermPos),
602 arg(1, TermPos, CharCount),
603 integer(CharCount) 604 -> From = file_term_position(File, TermPos)
605 ; walk_option_source(OTerm, false)
606 -> From = file(File, Line, -1, _)
607 ; From = _,
608 throw(missing(subterm_positions))
609 ),
610 print_reference2(Goal, From, Why, OTerm).
611print_reference(Goal, _, Why, OTerm) :-
612 print_reference2(Goal, _, Why, OTerm).
613
614print_reference2(Goal, From, trace, OTerm) :-
615 walk_option_on_trace(OTerm, Closure),
616 walk_option_caller(OTerm, Caller),
617 nonvar(Closure),
618 call(Closure, Goal, Caller, From),
619 !.
620print_reference2(Goal, From, Why, _OTerm) :-
621 make_message(Why, Goal, From, Message, Level),
622 print_message(Level, Message).
623
624
625make_message(undefined, Goal, Context,
626 error(existence_error(procedure, PI), Context), error) :-
627 goal_pi(Goal, PI).
628make_message(not_callable, Goal, Context,
629 error(type_error(callable, Goal), Context), error).
630make_message(trace, Goal, Context,
631 trace_call_to(PI, Context), informational) :-
632 goal_pi(Goal, PI).
633
634
635goal_pi(Goal, M:Name/Arity) :-
636 strip_module(Goal, M, Head),
637 callable(Head),
638 !,
639 functor(Head, Name, Arity).
640goal_pi(Goal, Goal).
641
642:- dynamic
643 possible_meta_predicate/2. 644
651
652register_possible_meta_clause(ClausesRef) :-
653 nonvar(ClausesRef),
654 clause_property(ClausesRef, predicate(PI)),
655 pi_head(PI, Head, Module),
656 module_property(Module, class(user)),
657 \+ predicate_property(Module:Head, meta_predicate(_)),
658 \+ inferred_meta_predicate(Module:Head, _),
659 \+ possible_meta_predicate(Head, Module),
660 !,
661 assertz(possible_meta_predicate(Head, Module)).
662register_possible_meta_clause(_).
663
664pi_head(Module:Name/Arity, Head, Module) :-
665 !,
666 functor(Head, Name, Arity).
667pi_head(_, _, _) :-
668 assertion(fail).
669
671
672infer_new_meta_predicates([], OTerm) :-
673 walk_option_infer_meta_predicates(OTerm, false),
674 !.
675infer_new_meta_predicates(MetaSpecs, OTerm) :-
676 findall(Module:MetaSpec,
677 ( retract(possible_meta_predicate(Head, Module)),
678 infer_meta_predicate(Module:Head, MetaSpec),
679 ( walk_option_infer_meta_predicates(OTerm, all)
680 -> true
681 ; calling_metaspec(MetaSpec)
682 )
683 ),
684 MetaSpecs).
685
690
691calling_metaspec(Head) :-
692 arg(_, Head, Arg),
693 calling_metaarg(Arg),
694 !.
695
696calling_metaarg(I) :- integer(I), !.
697calling_metaarg(^).
698calling_metaarg(//).
699
700
710
711walk_meta_call(I, Head, Meta, M, ArgPosList, EPos, OTerm) :-
712 arg(I, Head, AS),
713 !,
714 ( ArgPosList = [ArgPos|ArgPosTail]
715 -> true
716 ; ArgPos = EPos,
717 ArgPosTail = []
718 ),
719 ( integer(AS)
720 -> arg(I, Meta, MA),
721 extend(MA, AS, Goal, ArgPos, ArgPosEx, OTerm),
722 walk_called(Goal, M, ArgPosEx, OTerm)
723 ; AS == (^)
724 -> arg(I, Meta, MA),
725 remove_quantifier(MA, Goal, ArgPos, ArgPosEx, M, MG, OTerm),
726 walk_called(Goal, MG, ArgPosEx, OTerm)
727 ; AS == (//)
728 -> arg(I, Meta, DCG),
729 walk_dcg_body(DCG, M, ArgPos, OTerm)
730 ; true
731 ),
732 succ(I, I2),
733 walk_meta_call(I2, Head, Meta, M, ArgPosTail, EPos, OTerm).
734walk_meta_call(_, _, _, _, _, _, _).
735
736remove_quantifier(Goal, _, TermPos, TermPos, M, M, OTerm) :-
737 var(Goal),
738 !,
739 undecided(Goal, TermPos, OTerm).
740remove_quantifier(_^Goal0, Goal,
741 term_position(_,_,_,_,[_,GPos]),
742 TermPos, M0, M, OTerm) :-
743 !,
744 remove_quantifier(Goal0, Goal, GPos, TermPos, M0, M, OTerm).
745remove_quantifier(M1:Goal0, Goal,
746 term_position(_,_,_,_,[_,GPos]),
747 TermPos, _, M, OTerm) :-
748 !,
749 remove_quantifier(Goal0, Goal, GPos, TermPos, M1, M, OTerm).
750remove_quantifier(Goal, Goal, TermPos, TermPos, M, M, _).
751
752
757
758walk_called_by([], _, _, _, _).
759walk_called_by([H|T], M, Goal, TermPos, OTerm) :-
760 ( H = G0+N
761 -> subterm_pos(G0, M, Goal, TermPos, G, GPos),
762 ( extend(G, N, G2, GPos, GPosEx, OTerm)
763 -> walk_called(G2, M, GPosEx, OTerm)
764 ; true
765 )
766 ; subterm_pos(H, M, Goal, TermPos, G, GPos),
767 walk_called(G, M, GPos, OTerm)
768 ),
769 walk_called_by(T, M, Goal, TermPos, OTerm).
770
771subterm_pos(Sub, _, Term, TermPos, Sub, SubTermPos) :-
772 subterm_pos(Sub, Term, TermPos, SubTermPos),
773 !.
774subterm_pos(Sub, M, Term, TermPos, G, SubTermPos) :-
775 nonvar(Sub),
776 Sub = M:H,
777 !,
778 subterm_pos(H, M, Term, TermPos, G, SubTermPos).
779subterm_pos(Sub, _, _, _, Sub, _).
780
781subterm_pos(Sub, Term, TermPos, SubTermPos) :-
782 subterm_pos(Sub, Term, same_term, TermPos, SubTermPos),
783 !.
784subterm_pos(Sub, Term, TermPos, SubTermPos) :-
785 subterm_pos(Sub, Term, ==, TermPos, SubTermPos),
786 !.
787subterm_pos(Sub, Term, TermPos, SubTermPos) :-
788 subterm_pos(Sub, Term, =@=, TermPos, SubTermPos),
789 !.
790subterm_pos(Sub, Term, TermPos, SubTermPos) :-
791 subterm_pos(Sub, Term, subsumes_term, TermPos, SubTermPos),
792 !.
793
797
798walk_dcg_body(Var, _Module, TermPos, OTerm) :-
799 var(Var),
800 !,
801 undecided(Var, TermPos, OTerm).
802walk_dcg_body([], _Module, _, _) :- !.
803walk_dcg_body([_|_], _Module, _, _) :- !.
804walk_dcg_body(String, _Module, _, _) :-
805 string(String),
806 !.
807walk_dcg_body(!, _Module, _, _) :- !.
808walk_dcg_body(M:G, _, term_position(_,_,_,_,[MPos,Pos]), OTerm) :-
809 !,
810 ( nonvar(M)
811 -> walk_dcg_body(G, M, Pos, OTerm)
812 ; undecided(M, MPos, OTerm)
813 ).
814walk_dcg_body((A,B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
815 !,
816 walk_dcg_body(A, M, PA, OTerm),
817 walk_dcg_body(B, M, PB, OTerm).
818walk_dcg_body((A->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
819 !,
820 walk_dcg_body(A, M, PA, OTerm),
821 walk_dcg_body(B, M, PB, OTerm).
822walk_dcg_body((A*->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
823 !,
824 walk_dcg_body(A, M, PA, OTerm),
825 walk_dcg_body(B, M, PB, OTerm).
826walk_dcg_body((A;B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
827 !,
828 ( walk_dcg_body(A, M, PA, OTerm)
829 ; walk_dcg_body(B, M, PB, OTerm)
830 ).
831walk_dcg_body((A|B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
832 !,
833 ( walk_dcg_body(A, M, PA, OTerm)
834 ; walk_dcg_body(B, M, PB, OTerm)
835 ).
836walk_dcg_body({G}, M, brace_term_position(_,_,PG), OTerm) :-
837 !,
838 walk_called(G, M, PG, OTerm).
839walk_dcg_body(G, M, TermPos, OTerm) :-
840 extend(G, 2, G2, TermPos, TermPosEx, OTerm),
841 walk_called(G2, M, TermPosEx, OTerm).
842
843
851
852:- meta_predicate
853 subterm_pos(+, +, 2, +, -),
854 sublist_pos(+, +, +, +, 2, -). 855
856subterm_pos(_, _, _, Pos, _) :-
857 var(Pos), !, fail.
858subterm_pos(Sub, Term, Cmp, Pos, Pos) :-
859 call(Cmp, Sub, Term),
860 !.
861subterm_pos(Sub, Term, Cmp, term_position(_,_,_,_,ArgPosList), Pos) :-
862 is_list(ArgPosList),
863 compound(Term),
864 nth1(I, ArgPosList, ArgPos),
865 arg(I, Term, Arg),
866 subterm_pos(Sub, Arg, Cmp, ArgPos, Pos).
867subterm_pos(Sub, Term, Cmp, list_position(_,_,ElemPosList,TailPos), Pos) :-
868 sublist_pos(ElemPosList, TailPos, Sub, Term, Cmp, Pos).
869subterm_pos(Sub, {Arg}, Cmp, brace_term_position(_,_,ArgPos), Pos) :-
870 subterm_pos(Sub, Arg, Cmp, ArgPos, Pos).
871
872sublist_pos([EP|TP], TailPos, Sub, [H|T], Cmp, Pos) :-
873 ( subterm_pos(Sub, H, Cmp, EP, Pos)
874 ; sublist_pos(TP, TailPos, Sub, T, Cmp, Pos)
875 ).
876sublist_pos([], TailPos, Sub, Tail, Cmp, Pos) :-
877 TailPos \== none,
878 subterm_pos(Sub, Tail, Cmp, TailPos, Pos).
879
883
884extend(Goal, 0, Goal, TermPos, TermPos, _) :- !.
885extend(Goal, _, _, TermPos, TermPos, OTerm) :-
886 var(Goal),
887 !,
888 undecided(Goal, TermPos, OTerm).
889extend(M:Goal, N, M:GoalEx,
890 term_position(F,T,FT,TT,[MPos,GPosIn]),
891 term_position(F,T,FT,TT,[MPos,GPosOut]), OTerm) :-
892 !,
893 ( var(M)
894 -> undecided(N, MPos, OTerm)
895 ; true
896 ),
897 extend(Goal, N, GoalEx, GPosIn, GPosOut, OTerm).
898extend(Goal, N, GoalEx, TermPosIn, TermPosOut, _) :-
899 callable(Goal),
900 !,
901 Goal =.. List,
902 length(Extra, N),
903 extend_term_pos(TermPosIn, N, TermPosOut),
904 append(List, Extra, ListEx),
905 GoalEx =.. ListEx.
906extend(Goal, _, _, TermPos, _, OTerm) :-
907 print_reference(Goal, TermPos, not_callable, OTerm).
908
909extend_term_pos(Var, _, _) :-
910 var(Var),
911 !.
912extend_term_pos(term_position(F,T,FT,TT,ArgPosIn),
913 N,
914 term_position(F,T,FT,TT,ArgPosOut)) :-
915 !,
916 length(Extra, N),
917 maplist(=(0-0), Extra),
918 append(ArgPosIn, Extra, ArgPosOut).
919extend_term_pos(F-T, N, term_position(F,T,F,T,Extra)) :-
920 length(Extra, N),
921 maplist(=(0-0), Extra).
922
923
925
926variants([], []).
927variants([H|T], List) :-
928 variants(T, H, List).
929
930variants([], H, [H]).
931variants([H|T], V, List) :-
932 ( H =@= V
933 -> variants(T, V, List)
934 ; List = [V|List2],
935 variants(T, H, List2)
936 ).
937
941
942predicate_in_module(Module, PI) :-
943 current_predicate(Module:PI),
944 PI = Name/Arity,
945 functor(Head, Name, Arity),
946 \+ predicate_property(Module:Head, imported_from(_)).
947
948
949 952
962
963prolog_program_clause(ClauseRef, Options) :-
964 make_walk_option(Options, OTerm, _),
965 setup_call_cleanup(
966 true,
967 ( current_module(Module),
968 scan_module(Module, OTerm),
969 module_clause(Module, ClauseRef, OTerm)
970 ; retract(multifile_predicate(Name, Arity, MM)),
971 multifile_clause(ClauseRef, MM:Name/Arity, OTerm)
972 ; initialization_clause(ClauseRef, OTerm)
973 ),
974 retractall(multifile_predicate(_,_,_))).
975
976
977module_clause(Module, ClauseRef, _OTerm) :-
978 predicate_in_module(Module, Name/Arity),
979 \+ multifile_predicate(Name, Arity, Module),
980 functor(Head, Name, Arity),
981 ( predicate_property(Module:Head, multifile)
982 -> assertz(multifile_predicate(Name, Arity, Module)),
983 fail
984 ; predicate_property(Module:Head, Property),
985 no_enum_property(Property)
986 -> fail
987 ; catch(nth_clause(Module:Head, _, ClauseRef), _, fail)
988 ).
989
990no_enum_property(foreign).
991
992multifile_clause(ClauseRef, M:Name/Arity, OTerm) :-
993 functor(Head, Name, Arity),
994 catch(clauseref_not_from_development(M:Head, ClauseRef, OTerm),
995 _, fail).
996
997clauseref_not_from_development(Module:Head, Ref, OTerm) :-
998 nth_clause(Module:Head, _N, Ref),
999 \+ ( clause_property(Ref, file(File)),
1000 module_property(LoadModule, file(File)),
1001 \+ scan_module(LoadModule, OTerm)
1002 ).
1003
1004initialization_clause(ClauseRef, OTerm) :-
1005 catch(clause(system:'$init_goal'(_File, M:_Goal, SourceLocation),
1006 true, ClauseRef),
1007 _, fail),
1008 walk_option_initialization(OTerm, SourceLocation),
1009 scan_module(M, OTerm).
1010
1011
1012 1015
1016:- multifile
1017 prolog:message//1,
1018 prolog:message_location//1. 1019
1020prolog:message(trace_call_to(PI, Context)) -->
1021 [ 'Call to ~q at '-[PI] ],
1022 prolog:message_location(Context).
1023
1024prolog:message_location(clause_term_position(ClauseRef, TermPos)) -->
1025 { clause_property(ClauseRef, file(File)) },
1026 message_location_file_term_position(File, TermPos).
1027prolog:message_location(clause(ClauseRef)) -->
1028 { clause_property(ClauseRef, file(File)),
1029 clause_property(ClauseRef, line_count(Line))
1030 },
1031 !,
1032 [ '~w:~d: '-[File, Line] ].
1033prolog:message_location(clause(ClauseRef)) -->
1034 { clause_name(ClauseRef, Name) },
1035 [ '~w: '-[Name] ].
1036prolog:message_location(file_term_position(Path, TermPos)) -->
1037 message_location_file_term_position(Path, TermPos).
1038prolog:message(codewalk(reiterate(New, Iteration, CPU))) -->
1039 [ 'Found new meta-predicates in iteration ~w (~3f sec)'-
1040 [Iteration, CPU], nl ],
1041 meta_decls(New),
1042 [ 'Restarting analysis ...'-[], nl ].
1043
1044meta_decls([]) --> [].
1045meta_decls([H|T]) -->
1046 [ ':- meta_predicate ~q.'-[H], nl ],
1047 meta_decls(T).
1048
1049message_location_file_term_position(File, TermPos) -->
1050 { arg(1, TermPos, CharCount),
1051 filepos_line(File, CharCount, Line, LinePos)
1052 },
1053 [ '~w:~d:~d: '-[File, Line, LinePos] ].
1054
1059
1060filepos_line(File, CharPos, Line, LinePos) :-
1061 setup_call_cleanup(
1062 ( open(File, read, In),
1063 open_null_stream(Out)
1064 ),
1065 ( copy_stream_data(In, Out, CharPos),
1066 stream_property(In, position(Pos)),
1067 stream_position_data(line_count, Pos, Line),
1068 stream_position_data(line_position, Pos, LinePos)
1069 ),
1070 ( close(Out),
1071 close(In)
1072 ))