35
36:- module(prolog_codewalk,
37 [ prolog_walk_code/1, 38 prolog_program_clause/2 39 ]). 40:- use_module(library(record),[(record)/1, op(_,_,record)]). 41
42:- autoload(library(apply),[maplist/2]). 43:- autoload(library(debug),[debug/3,debugging/1,assertion/1]). 44:- autoload(library(error),[must_be/2]). 45:- autoload(library(listing),[portray_clause/1]). 46:- autoload(library(lists),[member/2,nth1/3,append/3]). 47:- autoload(library(option),[meta_options/3]). 48:- autoload(library(prolog_clause),
49 [clause_info/4,initialization_layout/4,clause_name/2]). 50:- autoload(library(prolog_metainference),
51 [inferred_meta_predicate/2,infer_meta_predicate/2]). 52
53
85
86:- meta_predicate
87 prolog_walk_code(:). 88
89:- multifile
90 prolog:called_by/4,
91 prolog:called_by/2. 92
93:- predicate_options(prolog_walk_code/1, 1,
94 [ undefined(oneof([ignore,error,trace])),
95 autoload(boolean),
96 clauses(list),
97 module(atom),
98 module_class(list(oneof([user,system,library,
99 test,development]))),
100 source(boolean),
101 trace_reference(any),
102 trace_condition(callable),
103 on_trace(callable),
104 on_edge(callable),
105 infer_meta_predicates(oneof([false,true,all])),
106 walk_meta_predicates(boolean),
107 evaluate(boolean),
108 verbose(boolean)
109 ]). 110
111:- record
112 walk_option(undefined:oneof([ignore,error,trace])=ignore,
113 autoload:boolean=true,
114 source:boolean=true,
115 module:atom, 116 module_class:list(oneof([user,system,library,
117 test,development]))=[user,library],
118 infer_meta_predicates:oneof([false,true,all])=true,
119 walk_meta_predicates:boolean=true,
120 clauses:list, 121 trace_reference:any=(-),
122 trace_condition:callable, 123 on_edge:callable, 124 on_trace:callable, 125 126 clause, 127 caller, 128 initialization, 129 undecided, 130 evaluate:boolean, 131 verbose:boolean=false). 132
133:- thread_local
134 multifile_predicate/3. 135
243
244prolog_walk_code(Options) :-
245 meta_options(is_meta, Options, QOptions),
246 prolog_walk_code(1, QOptions).
247
248prolog_walk_code(Iteration, Options) :-
249 statistics(cputime, CPU0),
250 make_walk_option(Options, OTerm, _),
251 ( walk_option_clauses(OTerm, Clauses),
252 nonvar(Clauses)
253 -> walk_clauses(Clauses, OTerm)
254 ; forall(( walk_option_module(OTerm, M0),
255 copy_term(M0, M),
256 current_module(M),
257 scan_module(M, OTerm)
258 ),
259 find_walk_from_module(M, OTerm)),
260 walk_from_multifile(OTerm),
261 walk_from_initialization(OTerm)
262 ),
263 infer_new_meta_predicates(New, OTerm),
264 statistics(cputime, CPU1),
265 ( New \== []
266 -> CPU is CPU1-CPU0,
267 ( walk_option_verbose(OTerm, true)
268 -> Level = informational
269 ; Level = silent
270 ),
271 print_message(Level,
272 codewalk(reiterate(New, Iteration, CPU))),
273 succ(Iteration, Iteration2),
274 prolog_walk_code(Iteration2, Options)
275 ; true
276 ).
277
278is_meta(on_edge).
279is_meta(on_trace).
280is_meta(trace_condition).
281
285
286walk_clauses(Clauses, OTerm) :-
287 must_be(list, Clauses),
288 forall(member(ClauseRef, Clauses),
289 ( user:clause(CHead, Body, ClauseRef),
290 ( CHead = Module:Head
291 -> true
292 ; Module = user,
293 Head = CHead
294 ),
295 walk_option_clause(OTerm, ClauseRef),
296 walk_option_caller(OTerm, Module:Head),
297 walk_called_by_body(Body, Module, OTerm)
298 )).
299
303
304scan_module(M, OTerm) :-
305 walk_option_module(OTerm, M1),
306 nonvar(M1),
307 !,
308 \+ M \= M1.
309scan_module(M, OTerm) :-
310 walk_option_module_class(OTerm, Classes),
311 module_property(M, class(Class)),
312 memberchk(Class, Classes),
313 !.
314
321
322walk_from_initialization(OTerm) :-
323 walk_option_caller(OTerm, '<initialization>'),
324 forall(init_goal_in_scope(Goal, SourceLocation, OTerm),
325 ( walk_option_initialization(OTerm, SourceLocation),
326 walk_from_initialization(Goal, OTerm))).
327
328init_goal_in_scope(Goal, SourceLocation, OTerm) :-
329 '$init_goal'(_When, Goal, SourceLocation),
330 SourceLocation = File:_Line,
331 ( walk_option_module(OTerm, M),
332 nonvar(M)
333 -> module_property(M, file(File))
334 ; walk_option_module_class(OTerm, Classes),
335 source_file_property(File, module(MF))
336 -> module_property(MF, class(Class)),
337 memberchk(Class, Classes),
338 walk_option_module(OTerm, MF)
339 ; true
340 ).
341
342walk_from_initialization(M:Goal, OTerm) :-
343 scan_module(M, OTerm),
344 !,
345 walk_called_by_body(Goal, M, OTerm).
346walk_from_initialization(_, _).
347
348
353
354find_walk_from_module(M, OTerm) :-
355 debug(autoload, 'Analysing module ~q', [M]),
356 walk_option_module(OTerm, M),
357 forall(predicate_in_module(M, PI),
358 walk_called_by_pred(M:PI, OTerm)).
359
360walk_called_by_pred(Module:Name/Arity, _) :-
361 multifile_predicate(Name, Arity, Module),
362 !.
363walk_called_by_pred(Module:Name/Arity, _) :-
364 functor(Head, Name, Arity),
365 predicate_property(Module:Head, multifile),
366 !,
367 assertz(multifile_predicate(Name, Arity, Module)).
368walk_called_by_pred(Module:Name/Arity, OTerm) :-
369 functor(Head, Name, Arity),
370 ( no_walk_property(Property),
371 predicate_property(Module:Head, Property)
372 -> true
373 ; walk_option_caller(OTerm, Module:Head),
374 walk_option_clause(OTerm, ClauseRef),
375 forall(catch(clause(Module:Head, Body, ClauseRef), _, fail),
376 walk_called_by_body(Body, Module, OTerm))
377 ).
378
379no_walk_property(number_of_rules(0)). 380no_walk_property(foreign). 381
385
386walk_from_multifile(OTerm) :-
387 forall(retract(multifile_predicate(Name, Arity, Module)),
388 walk_called_by_multifile(Module:Name/Arity, OTerm)).
389
390walk_called_by_multifile(Module:Name/Arity, OTerm) :-
391 functor(Head, Name, Arity),
392 forall(catch(clause_not_from_development(
393 Module:Head, Body, ClauseRef, OTerm),
394 _, fail),
395 ( walk_option_clause(OTerm, ClauseRef),
396 walk_option_caller(OTerm, Module:Head),
397 walk_called_by_body(Body, Module, OTerm)
398 )).
399
400
405
406clause_not_from_development(Module:Head, Body, Ref, OTerm) :-
407 clause(Module:Head, Body, Ref),
408 \+ ( clause_property(Ref, file(File)),
409 module_property(LoadModule, file(File)),
410 \+ scan_module(LoadModule, OTerm)
411 ).
412
420
421walk_called_by_body(True, _, _) :-
422 True == true,
423 !. 424walk_called_by_body(Body, Module, OTerm) :-
425 set_undecided_of_walk_option(error, OTerm, OTerm1),
426 set_evaluate_of_walk_option(false, OTerm1, OTerm2),
427 catch(walk_called(Body, Module, _TermPos, OTerm2),
428 missing(Missing),
429 walk_called_by_body(Missing, Body, Module, OTerm)),
430 !.
431walk_called_by_body(Body, Module, OTerm) :-
432 format(user_error, 'Failed to analyse:~n', []),
433 portray_clause(('<head>' :- Body)),
434 debug_walk(Body, Module, OTerm).
435
438:- if(debugging(codewalk(trace))). 439debug_walk(Body, Module, OTerm) :-
440 gtrace,
441 walk_called_by_body(Body, Module, OTerm).
442:- else. 443debug_walk(_,_,_).
444:- endif. 445
450
451walk_called_by_body(Missing, Body, _, OTerm) :-
452 debugging(codewalk),
453 format(user_error, 'Retrying due to ~w (~p)~n', [Missing, OTerm]),
454 portray_clause(('<head>' :- Body)), fail.
455walk_called_by_body(undecided_call, Body, Module, OTerm) :-
456 catch(forall(walk_called(Body, Module, _TermPos, OTerm),
457 true),
458 missing(Missing),
459 walk_called_by_body(Missing, Body, Module, OTerm)).
460walk_called_by_body(subterm_positions, Body, Module, OTerm) :-
461 ( ( walk_option_clause(OTerm, ClauseRef), nonvar(ClauseRef),
462 clause_info(ClauseRef, _, TermPos, _NameOffset),
463 TermPos = term_position(_,_,_,_,[_,BodyPos])
464 -> WBody = Body
465 ; walk_option_initialization(OTerm, SrcLoc),
466 ground(SrcLoc), SrcLoc = _File:_Line,
467 initialization_layout(SrcLoc, Module:Body, WBody, BodyPos)
468 )
469 -> catch(forall(walk_called(WBody, Module, BodyPos, OTerm),
470 true),
471 missing(subterm_positions),
472 walk_called_by_body(no_positions, Body, Module, OTerm))
473 ; set_source_of_walk_option(false, OTerm, OTerm2),
474 forall(walk_called(Body, Module, _BodyPos, OTerm2),
475 true)
476 ).
477walk_called_by_body(no_positions, Body, Module, OTerm) :-
478 set_source_of_walk_option(false, OTerm, OTerm2),
479 forall(walk_called(Body, Module, _NoPos, OTerm2),
480 true).
481
482
509
510walk_called(Term, Module, parentheses_term_position(_,_,Pos), OTerm) :-
511 nonvar(Pos),
512 !,
513 walk_called(Term, Module, Pos, OTerm).
514walk_called(Var, _, TermPos, OTerm) :-
515 var(Var), 516 !,
517 undecided(Var, TermPos, OTerm).
518walk_called(M:G, _, term_position(_,_,_,_,[MPos,Pos]), OTerm) :-
519 !,
520 ( nonvar(M)
521 -> walk_called(G, M, Pos, OTerm)
522 ; undecided(M, MPos, OTerm)
523 ).
524walk_called((A,B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
525 !,
526 walk_called(A, M, PA, OTerm),
527 walk_called(B, M, PB, OTerm).
528walk_called((A->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
529 !,
530 walk_called(A, M, PA, OTerm),
531 walk_called(B, M, PB, OTerm).
532walk_called((A*->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
533 !,
534 walk_called(A, M, PA, OTerm),
535 walk_called(B, M, PB, OTerm).
536walk_called(\+(A), M, term_position(_,_,_,_,[PA]), OTerm) :-
537 !,
538 \+ \+ walk_called(A, M, PA, OTerm).
539walk_called((A;B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
540 !,
541 ( walk_option_evaluate(OTerm, Eval), Eval == true
542 -> Goal = (A;B),
543 setof(Goal,
544 ( walk_called(A, M, PA, OTerm)
545 ; walk_called(B, M, PB, OTerm)
546 ),
547 Alts0),
548 variants(Alts0, Alts),
549 member(Goal, Alts)
550 ; \+ \+ walk_called(A, M, PA, OTerm), 551 \+ \+ walk_called(B, M, PB, OTerm)
552 ).
553walk_called(Goal, Module, TermPos, OTerm) :-
554 walk_option_trace_reference(OTerm, To), To \== (-),
555 ( subsumes_term(To, Module:Goal)
556 -> M2 = Module
557 ; predicate_property(Module:Goal, imported_from(M2)),
558 subsumes_term(To, M2:Goal)
559 ),
560 trace_condition(M2:Goal, TermPos, OTerm),
561 print_reference(M2:Goal, TermPos, trace, OTerm),
562 fail. 563walk_called(Goal, Module, _, OTerm) :-
564 evaluate(Goal, Module, OTerm),
565 !.
566walk_called(Goal, M, TermPos, OTerm) :-
567 ( ( predicate_property(M:Goal, imported_from(IM))
568 -> true
569 ; IM = M
570 ),
571 prolog:called_by(Goal, IM, M, Called)
572 ; prolog:called_by(Goal, Called)
573 ),
574 Called \== [],
575 !,
576 walk_called_by(Called, M, Goal, TermPos, OTerm).
577walk_called(Meta, M, term_position(_,E,_,_,ArgPosList), OTerm) :-
578 walk_option_walk_meta_predicates(OTerm, true),
579 ( walk_option_autoload(OTerm, false)
580 -> nonvar(M),
581 '$get_predicate_attribute'(M:Meta, defined, 1)
582 ; true
583 ),
584 ( predicate_property(M:Meta, meta_predicate(Head))
585 ; inferred_meta_predicate(M:Meta, Head)
586 ),
587 !,
588 walk_option_clause(OTerm, ClauseRef),
589 register_possible_meta_clause(ClauseRef),
590 walk_meta_call(1, Head, Meta, M, ArgPosList, E-E, OTerm).
591walk_called(Closure, _, _, _) :-
592 blob(Closure, closure),
593 !,
594 '$closure_predicate'(Closure, Module:Name/Arity),
595 functor(Head, Name, Arity),
596 '$get_predicate_attribute'(Module:Head, defined, 1).
597walk_called(ClosureCall, _, _, _) :-
598 compound(ClosureCall),
599 compound_name_arity(ClosureCall, Closure, _),
600 blob(Closure, closure),
601 !,
602 '$closure_predicate'(Closure, Module:Name/Arity),
603 functor(Head, Name, Arity),
604 '$get_predicate_attribute'(Module:Head, defined, 1).
605walk_called(Goal, Module, _, _) :-
606 nonvar(Module),
607 '$get_predicate_attribute'(Module:Goal, defined, 1),
608 !.
609walk_called(Goal, Module, TermPos, OTerm) :-
610 callable(Goal),
611 !,
612 undefined(Module:Goal, TermPos, OTerm).
613walk_called(Goal, _Module, TermPos, OTerm) :-
614 not_callable(Goal, TermPos, OTerm).
615
619
620trace_condition(Callee, TermPos, OTerm) :-
621 walk_option_trace_condition(OTerm, Cond), nonvar(Cond),
622 !,
623 cond_location_context(OTerm, TermPos, Context0),
624 walk_option_caller(OTerm, Caller),
625 walk_option_module(OTerm, Module),
626 put_dict(#{caller:Caller, module:Module}, Context0, Context),
627 call(Cond, Callee, Context).
628trace_condition(_, _, _).
629
630cond_location_context(OTerm, _TermPos, Context) :-
631 walk_option_clause(OTerm, Clause), nonvar(Clause),
632 !,
633 Context = #{clause:Clause}.
634cond_location_context(OTerm, _TermPos, Context) :-
635 walk_option_initialization(OTerm, Init), nonvar(Init),
636 !,
637 Context = #{initialization:Init}.
638
640
641undecided(Var, TermPos, OTerm) :-
642 walk_option_undecided(OTerm, Undecided),
643 ( var(Undecided)
644 -> Action = ignore
645 ; Action = Undecided
646 ),
647 undecided(Action, Var, TermPos, OTerm).
648
649undecided(ignore, _, _, _) :- !.
650undecided(error, _, _, _) :-
651 throw(missing(undecided_call)).
652
654
655evaluate(Goal, Module, OTerm) :-
656 walk_option_evaluate(OTerm, Evaluate),
657 Evaluate \== false,
658 evaluate(Goal, Module).
659
660evaluate(A=B, _) :-
661 unify_with_occurs_check(A, B).
662
666
667undefined(_, _, OTerm) :-
668 walk_option_undefined(OTerm, ignore),
669 !.
670undefined(Goal, _, _) :-
671 predicate_property(Goal, autoload(_)),
672 !.
673undefined(Goal, TermPos, OTerm) :-
674 ( walk_option_undefined(OTerm, trace)
675 -> Why = trace
676 ; Why = undefined
677 ),
678 print_reference(Goal, TermPos, Why, OTerm).
679
683
684not_callable(Goal, TermPos, OTerm) :-
685 print_reference(Goal, TermPos, not_callable, OTerm).
686
687
693
694print_reference(Goal, TermPos, Why, OTerm) :-
695 walk_option_clause(OTerm, Clause), nonvar(Clause),
696 !,
697 ( compound(TermPos),
698 arg(1, TermPos, CharCount),
699 integer(CharCount) 700 -> From = clause_term_position(Clause, TermPos)
701 ; walk_option_source(OTerm, false)
702 -> From = clause(Clause)
703 ; From = _,
704 throw(missing(subterm_positions))
705 ),
706 print_reference2(Goal, From, Why, OTerm).
707print_reference(Goal, TermPos, Why, OTerm) :-
708 walk_option_initialization(OTerm, Init), nonvar(Init),
709 Init = File:Line,
710 !,
711 ( compound(TermPos),
712 arg(1, TermPos, CharCount),
713 integer(CharCount) 714 -> From = file_term_position(File, TermPos)
715 ; walk_option_source(OTerm, false)
716 -> From = file(File, Line, -1, _)
717 ; From = _,
718 throw(missing(subterm_positions))
719 ),
720 print_reference2(Goal, From, Why, OTerm).
721print_reference(Goal, _, Why, OTerm) :-
722 print_reference2(Goal, _, Why, OTerm).
723
724print_reference2(Goal, From, trace, OTerm) :-
725 walk_option_on_trace(OTerm, Closure),
726 nonvar(Closure),
727 walk_option_caller(OTerm, Caller),
728 call(Closure, Goal, Caller, From),
729 !.
730print_reference2(Goal, From, trace, OTerm) :-
731 walk_option_on_edge(OTerm, Closure),
732 nonvar(Closure),
733 walk_option_caller(OTerm, Caller),
734 translate_location(From, Dict),
735 call(Closure, Goal, Caller, Dict),
736 !.
737print_reference2(Goal, From, Why, _OTerm) :-
738 make_message(Why, Goal, From, Message, Level),
739 print_message(Level, Message).
740
741
742make_message(undefined, Goal, Context,
743 error(existence_error(procedure, PI), Context), error) :-
744 goal_pi(Goal, PI).
745make_message(not_callable, Goal, Context,
746 error(type_error(callable, Goal), Context), error).
747make_message(trace, Goal, Context,
748 trace_call_to(PI, Context), informational) :-
749 goal_pi(Goal, PI).
750
751
752goal_pi(Goal, M:Name/Arity) :-
753 strip_module(Goal, M, Head),
754 callable(Head),
755 !,
756 functor(Head, Name, Arity).
757goal_pi(Goal, Goal).
758
759:- dynamic
760 possible_meta_predicate/2. 761
768
769register_possible_meta_clause(ClausesRef) :-
770 nonvar(ClausesRef),
771 clause_property(ClausesRef, predicate(PI)),
772 pi_head(PI, Head, Module),
773 module_property(Module, class(user)),
774 \+ predicate_property(Module:Head, meta_predicate(_)),
775 \+ inferred_meta_predicate(Module:Head, _),
776 \+ possible_meta_predicate(Head, Module),
777 !,
778 assertz(possible_meta_predicate(Head, Module)).
779register_possible_meta_clause(_).
780
781pi_head(Module:Name/Arity, Head, Module) :-
782 !,
783 functor(Head, Name, Arity).
784pi_head(_, _, _) :-
785 assertion(fail).
786
788
789infer_new_meta_predicates([], OTerm) :-
790 walk_option_infer_meta_predicates(OTerm, false),
791 !.
792infer_new_meta_predicates(MetaSpecs, OTerm) :-
793 findall(Module:MetaSpec,
794 ( retract(possible_meta_predicate(Head, Module)),
795 infer_meta_predicate(Module:Head, MetaSpec),
796 ( walk_option_infer_meta_predicates(OTerm, all)
797 -> true
798 ; calling_metaspec(MetaSpec)
799 )
800 ),
801 MetaSpecs).
802
807
808calling_metaspec(Head) :-
809 arg(_, Head, Arg),
810 calling_metaarg(Arg),
811 !.
812
813calling_metaarg(I) :- integer(I), !.
814calling_metaarg(^).
815calling_metaarg(//).
816
817
827
828walk_meta_call(I, Head, Meta, M, ArgPosList, EPos, OTerm) :-
829 arg(I, Head, AS),
830 !,
831 ( ArgPosList = [ArgPos|ArgPosTail]
832 -> true
833 ; ArgPos = EPos,
834 ArgPosTail = []
835 ),
836 ( integer(AS)
837 -> arg(I, Meta, MA),
838 extend(MA, AS, Goal, ArgPos, ArgPosEx, OTerm),
839 walk_called(Goal, M, ArgPosEx, OTerm)
840 ; AS == (^)
841 -> arg(I, Meta, MA),
842 remove_quantifier(MA, Goal, ArgPos, ArgPosEx, M, MG, OTerm),
843 walk_called(Goal, MG, ArgPosEx, OTerm)
844 ; AS == (//)
845 -> arg(I, Meta, DCG),
846 walk_dcg_body(DCG, M, ArgPos, OTerm)
847 ; true
848 ),
849 succ(I, I2),
850 walk_meta_call(I2, Head, Meta, M, ArgPosTail, EPos, OTerm).
851walk_meta_call(_, _, _, _, _, _, _).
852
853remove_quantifier(Goal, _, TermPos, TermPos, M, M, OTerm) :-
854 var(Goal),
855 !,
856 undecided(Goal, TermPos, OTerm).
857remove_quantifier(_^Goal0, Goal,
858 term_position(_,_,_,_,[_,GPos]),
859 TermPos, M0, M, OTerm) :-
860 !,
861 remove_quantifier(Goal0, Goal, GPos, TermPos, M0, M, OTerm).
862remove_quantifier(M1:Goal0, Goal,
863 term_position(_,_,_,_,[_,GPos]),
864 TermPos, _, M, OTerm) :-
865 !,
866 remove_quantifier(Goal0, Goal, GPos, TermPos, M1, M, OTerm).
867remove_quantifier(Goal, Goal, TermPos, TermPos, M, M, _).
868
869
874
875walk_called_by([], _, _, _, _).
876walk_called_by([H|T], M, Goal, TermPos, OTerm) :-
877 ( H = G0+N
878 -> subterm_pos(G0, M, Goal, TermPos, G, GPos),
879 ( extend(G, N, G2, GPos, GPosEx, OTerm)
880 -> walk_called(G2, M, GPosEx, OTerm)
881 ; true
882 )
883 ; subterm_pos(H, M, Goal, TermPos, G, GPos),
884 walk_called(G, M, GPos, OTerm)
885 ),
886 walk_called_by(T, M, Goal, TermPos, OTerm).
887
888subterm_pos(Sub, _, Term, TermPos, Sub, SubTermPos) :-
889 subterm_pos(Sub, Term, TermPos, SubTermPos),
890 !.
891subterm_pos(Sub, M, Term, TermPos, G, SubTermPos) :-
892 nonvar(Sub),
893 Sub = M:H,
894 !,
895 subterm_pos(H, M, Term, TermPos, G, SubTermPos).
896subterm_pos(Sub, _, _, _, Sub, _).
897
898subterm_pos(Sub, Term, TermPos, SubTermPos) :-
899 subterm_pos(Sub, Term, same_term, TermPos, SubTermPos),
900 !.
901subterm_pos(Sub, Term, TermPos, SubTermPos) :-
902 subterm_pos(Sub, Term, ==, TermPos, SubTermPos),
903 !.
904subterm_pos(Sub, Term, TermPos, SubTermPos) :-
905 subterm_pos(Sub, Term, =@=, TermPos, SubTermPos),
906 !.
907subterm_pos(Sub, Term, TermPos, SubTermPos) :-
908 subterm_pos(Sub, Term, subsumes_term, TermPos, SubTermPos),
909 !.
910
914
915walk_dcg_body(Var, _Module, TermPos, OTerm) :-
916 var(Var),
917 !,
918 undecided(Var, TermPos, OTerm).
919walk_dcg_body([], _Module, _, _) :- !.
920walk_dcg_body([_|_], _Module, _, _) :- !.
921walk_dcg_body(String, _Module, _, _) :-
922 string(String),
923 !.
924walk_dcg_body(!, _Module, _, _) :- !.
925walk_dcg_body(M:G, _, term_position(_,_,_,_,[MPos,Pos]), OTerm) :-
926 !,
927 ( nonvar(M)
928 -> walk_dcg_body(G, M, Pos, OTerm)
929 ; undecided(M, MPos, OTerm)
930 ).
931walk_dcg_body((A,B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
932 !,
933 walk_dcg_body(A, M, PA, OTerm),
934 walk_dcg_body(B, M, PB, OTerm).
935walk_dcg_body((A->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
936 !,
937 walk_dcg_body(A, M, PA, OTerm),
938 walk_dcg_body(B, M, PB, OTerm).
939walk_dcg_body((A*->B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
940 !,
941 walk_dcg_body(A, M, PA, OTerm),
942 walk_dcg_body(B, M, PB, OTerm).
943walk_dcg_body((A;B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
944 !,
945 ( walk_dcg_body(A, M, PA, OTerm)
946 ; walk_dcg_body(B, M, PB, OTerm)
947 ).
948walk_dcg_body((A|B), M, term_position(_,_,_,_,[PA,PB]), OTerm) :-
949 !,
950 ( walk_dcg_body(A, M, PA, OTerm)
951 ; walk_dcg_body(B, M, PB, OTerm)
952 ).
953walk_dcg_body({G}, M, brace_term_position(_,_,PG), OTerm) :-
954 !,
955 walk_called(G, M, PG, OTerm).
956walk_dcg_body(G, M, TermPos, OTerm) :-
957 extend(G, 2, G2, TermPos, TermPosEx, OTerm),
958 walk_called(G2, M, TermPosEx, OTerm).
959
960
968
969:- meta_predicate
970 subterm_pos(+, +, 2, +, -),
971 sublist_pos(+, +, +, +, 2, -). 972:- public
973 subterm_pos/5. 974
975subterm_pos(_, _, _, Pos, _) :-
976 var(Pos), !, fail.
977subterm_pos(Sub, Term, Cmp, Pos, Pos) :-
978 call(Cmp, Sub, Term),
979 !.
980subterm_pos(Sub, Term, Cmp, term_position(_,_,_,_,ArgPosList), Pos) :-
981 is_list(ArgPosList),
982 compound(Term),
983 nth1(I, ArgPosList, ArgPos),
984 arg(I, Term, Arg),
985 subterm_pos(Sub, Arg, Cmp, ArgPos, Pos).
986subterm_pos(Sub, Term, Cmp, list_position(_,_,ElemPosList,TailPos), Pos) :-
987 sublist_pos(ElemPosList, TailPos, Sub, Term, Cmp, Pos).
988subterm_pos(Sub, {Arg}, Cmp, brace_term_position(_,_,ArgPos), Pos) :-
989 subterm_pos(Sub, Arg, Cmp, ArgPos, Pos).
990
991sublist_pos([EP|TP], TailPos, Sub, [H|T], Cmp, Pos) :-
992 ( subterm_pos(Sub, H, Cmp, EP, Pos)
993 ; sublist_pos(TP, TailPos, Sub, T, Cmp, Pos)
994 ).
995sublist_pos([], TailPos, Sub, Tail, Cmp, Pos) :-
996 TailPos \== none,
997 subterm_pos(Sub, Tail, Cmp, TailPos, Pos).
998
1002
1003extend(Goal, 0, Goal, TermPos, TermPos, _) :- !.
1004extend(Goal, _, _, TermPos, TermPos, OTerm) :-
1005 var(Goal),
1006 !,
1007 undecided(Goal, TermPos, OTerm).
1008extend(M:Goal, N, M:GoalEx,
1009 term_position(F,T,FT,TT,[MPos,GPosIn]),
1010 term_position(F,T,FT,TT,[MPos,GPosOut]), OTerm) :-
1011 !,
1012 ( var(M)
1013 -> undecided(N, MPos, OTerm)
1014 ; true
1015 ),
1016 extend(Goal, N, GoalEx, GPosIn, GPosOut, OTerm).
1017extend(Goal, N, GoalEx, TermPosIn, TermPosOut, _) :-
1018 callable(Goal),
1019 !,
1020 Goal =.. List,
1021 length(Extra, N),
1022 extend_term_pos(TermPosIn, N, TermPosOut),
1023 append(List, Extra, ListEx),
1024 GoalEx =.. ListEx.
1025extend(Closure, N, M:GoalEx, TermPosIn, TermPosOut, OTerm) :-
1026 blob(Closure, closure), 1027 !,
1028 '$closure_predicate'(Closure, M:Name/Arity),
1029 length(Extra, N),
1030 extend_term_pos(TermPosIn, N, TermPosOut),
1031 GoalEx =.. [Name|Extra],
1032 ( N =:= Arity
1033 -> true
1034 ; print_reference(Closure, TermPosIn, closure_arity_mismatch, OTerm)
1035 ).
1036extend(Goal, _, _, TermPos, _, OTerm) :-
1037 print_reference(Goal, TermPos, not_callable, OTerm).
1038
1039extend_term_pos(Var, _, _) :-
1040 var(Var),
1041 !.
1042extend_term_pos(term_position(F,T,FT,TT,ArgPosIn),
1043 N,
1044 term_position(F,T,FT,TT,ArgPosOut)) :-
1045 !,
1046 length(Extra, N),
1047 maplist(=(0-0), Extra),
1048 append(ArgPosIn, Extra, ArgPosOut).
1049extend_term_pos(F-T, N, term_position(F,T,F,T,Extra)) :-
1050 length(Extra, N),
1051 maplist(=(0-0), Extra).
1052
1053
1055
1056variants([], []).
1057variants([H|T], List) :-
1058 variants(T, H, List).
1059
1060variants([], H, [H]).
1061variants([H|T], V, List) :-
1062 ( H =@= V
1063 -> variants(T, V, List)
1064 ; List = [V|List2],
1065 variants(T, H, List2)
1066 ).
1067
1071
1072predicate_in_module(Module, PI) :-
1073 current_predicate(Module:PI),
1074 PI = Name/Arity,
1075 \+ hidden_predicate(Name, Arity),
1076 functor(Head, Name, Arity),
1077 \+ predicate_property(Module:Head, imported_from(_)).
1078
1079
1080hidden_predicate(Name, _) :-
1081 atom(Name), 1082 sub_atom(Name, 0, _, _, '$wrap$').
1083
1084
1085 1088
1098
1099prolog_program_clause(ClauseRef, Options) :-
1100 make_walk_option(Options, OTerm, _),
1101 setup_call_cleanup(
1102 true,
1103 ( current_module(Module),
1104 scan_module(Module, OTerm),
1105 module_clause(Module, ClauseRef, OTerm)
1106 ; retract(multifile_predicate(Name, Arity, MM)),
1107 multifile_clause(ClauseRef, MM:Name/Arity, OTerm)
1108 ; initialization_clause(ClauseRef, OTerm)
1109 ),
1110 retractall(multifile_predicate(_,_,_))).
1111
1112
1113module_clause(Module, ClauseRef, _OTerm) :-
1114 predicate_in_module(Module, Name/Arity),
1115 \+ multifile_predicate(Name, Arity, Module),
1116 functor(Head, Name, Arity),
1117 ( predicate_property(Module:Head, multifile)
1118 -> assertz(multifile_predicate(Name, Arity, Module)),
1119 fail
1120 ; predicate_property(Module:Head, Property),
1121 no_enum_property(Property)
1122 -> fail
1123 ; catch(nth_clause(Module:Head, _, ClauseRef), _, fail)
1124 ).
1125
1126no_enum_property(foreign).
1127
1128multifile_clause(ClauseRef, M:Name/Arity, OTerm) :-
1129 functor(Head, Name, Arity),
1130 catch(clauseref_not_from_development(M:Head, ClauseRef, OTerm),
1131 _, fail).
1132
1133clauseref_not_from_development(Module:Head, Ref, OTerm) :-
1134 nth_clause(Module:Head, _N, Ref),
1135 \+ ( clause_property(Ref, file(File)),
1136 module_property(LoadModule, file(File)),
1137 \+ scan_module(LoadModule, OTerm)
1138 ).
1139
1140initialization_clause(ClauseRef, OTerm) :-
1141 catch(clause(system:'$init_goal'(_File, M:_Goal, SourceLocation),
1142 true, ClauseRef),
1143 _, fail),
1144 walk_option_initialization(OTerm, SourceLocation),
1145 scan_module(M, OTerm).
1146
1147
1149
1150translate_location(clause_term_position(ClauseRef, TermPos), Dict),
1151 clause_property(ClauseRef, file(File)) =>
1152 arg(1, TermPos, CharCount),
1153 filepos_line(File, CharCount, Line, LinePos),
1154 Dict = _{ clause: ClauseRef,
1155 file: File,
1156 character_count: CharCount,
1157 line_count: Line,
1158 line_position: LinePos
1159 }.
1160translate_location(clause(ClauseRef), Dict),
1161 clause_property(ClauseRef, file(File)),
1162 clause_property(ClauseRef, line_count(Line)) =>
1163 Dict = _{ clause: ClauseRef,
1164 file: File,
1165 line_count: Line
1166 }.
1167translate_location(clause(ClauseRef), Dict) =>
1168 Dict = _{ clause: ClauseRef
1169 }.
1170translate_location(file_term_position(Path, TermPos), Dict) =>
1171 arg(1, TermPos, CharCount),
1172 filepos_line(Path, CharCount, Line, LinePos),
1173 Dict = _{ file: Path,
1174 character_count: CharCount,
1175 line_count: Line,
1176 line_position: LinePos
1177 }.
1178translate_location(Var, Dict), var(Var) =>
1179 Dict = _{}.
1180
1181 1184
1185:- multifile
1186 prolog:message//1,
1187 prolog:message_location//1. 1188
1189prolog:message(trace_call_to(PI, Context)) -->
1190 [ 'Call to ~q at '-[PI] ],
1191 '$messages':swi_location(Context).
1192
1193prolog:message_location(clause_term_position(ClauseRef, TermPos)) -->
1194 { clause_property(ClauseRef, file(File)) },
1195 message_location_file_term_position(File, TermPos).
1196prolog:message_location(clause(ClauseRef)) -->
1197 { clause_property(ClauseRef, file(File)),
1198 clause_property(ClauseRef, line_count(Line))
1199 },
1200 !,
1201 [ url(File:Line), ': ' ].
1202prolog:message_location(clause(ClauseRef)) -->
1203 { clause_name(ClauseRef, Name) },
1204 [ '~w: '-[Name] ].
1205prolog:message_location(file_term_position(Path, TermPos)) -->
1206 message_location_file_term_position(Path, TermPos).
1207prolog:message(codewalk(reiterate(New, Iteration, CPU))) -->
1208 [ 'Found new meta-predicates in iteration ~w (~3f sec)'-
1209 [Iteration, CPU], nl ],
1210 meta_decls(New),
1211 [ 'Restarting analysis ...'-[], nl ].
1212
1213meta_decls([]) --> [].
1214meta_decls([H|T]) -->
1215 [ ':- meta_predicate ~q.'-[H], nl ],
1216 meta_decls(T).
1217
1218message_location_file_term_position(File, TermPos) -->
1219 { arg(1, TermPos, CharCount),
1220 filepos_line(File, CharCount, Line, LinePos)
1221 },
1222 [ url(File:Line:LinePos), ': ' ].
1223
1228
1229filepos_line(File, CharPos, Line, LinePos) :-
1230 setup_call_cleanup(
1231 ( open(File, read, In),
1232 open_null_stream(Out)
1233 ),
1234 ( copy_stream_data(In, Out, CharPos),
1235 stream_property(In, position(Pos)),
1236 stream_position_data(line_count, Pos, Line),
1237 stream_position_data(line_position, Pos, LinePos)
1238 ),
1239 ( close(Out),
1240 close(In)
1241 ))