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