34
35:- module(codewalk_source, []). 36
37:- use_module(library(apply)). 38:- use_module(library(lists)). 39:- use_module(library(prolog_source)). 40:- use_module(library(prolog_xref), []). 41:- use_module(library(context_values)). 42:- use_module(library(option_utils)). 43:- use_module(library(extend_args)). 44
45:- multifile
46 codewalk:walk_code/2. 47
48codewalk:walk_code(source, Options) :-
49 do_source_walk_code(Options).
50
51head_caller(MHead, M:Head) :-
52 '$current_source_module'(CM),
53 strip_module(CM:MHead, M, Head).
54
55determine_caller((Head :- _), Caller) :- !, head_caller(Head, Caller).
56determine_caller((Head --> _), Caller) :-
57 !,
58 extend_args(Head, [_, _], EHead),
59 head_caller(EHead, Caller).
60determine_caller((:- Decl), Caller) :- !, decl_caller(Decl, Caller).
61determine_caller(Head, Caller) :- head_caller(Head, Caller).
62
63decl_caller(initialization(_), '<initialization>').
64decl_caller(_, '<declaration>').
65
66:- public
67 check_trace_reference/3,
68 do_goal_expansion/3,
69 determine_caller/1. 70
71prepare(To, Undefined, p(GRef)) :-
72 ( To \== (-)
73 ->( var(To)
74 ->assertz((system:goal_expansion(G, P, _, _) :-
75 '$current_source_module'(M),
76 once(do_goal_expansion(M, G, P)),
77 fail), GRef)
78 ; To = _:H
79 ->functor(H, F, A),
80 functor(G, F, A), 81 assertz((system:goal_expansion(G, P, _, _) :-
82 '$current_source_module'(M),
83 check_trace_reference(To, M, G),
84 once(do_goal_expansion(M, G, P)),
85 fail), GRef)
86 ; true
87 )
88 ; Undefined = ignore
89 ->true
90 ; Undefined = trace
91 ->assertz((system:goal_expansion(G, P, _, _) :-
92 '$current_source_module'(M),
93 \+ '$get_predicate_attribute'(M:G, defined, 1),
94 \+ predicate_property(M:G, autoload(_)),
95 once(do_goal_expansion(M, G, P)),
96 fail), GRef)
97 ; true
98 ).
99
100cleanup(p(GRef)) :-
101 ( nonvar(GRef)
102 ->erase(GRef)
103 ; true
104 ).
105
106skip((_,_)).
107skip((_;_)).
108skip((_->_)).
109skip((_*->_)).
110skip(\+(_)).
111skip(module(_, _)).
112skip(module(_, _, _)).
113skip(_:_).
114
115check_file(File) :-
116 current_context_value(file, File),
117 118 119 '$current_source_module'(M),
120 module_property(M, file(File)).
121
122determine_caller(Caller) :-
123 nb_current('$term', Term),
124 determine_caller(Term, Caller).
125
126check_trace_reference(To, M, Goal) :-
127 ( subsumes_term(To, M:Goal)
128 -> true
129 ; predicate_property(M:Goal, imported_from(M2)),
130 subsumes_term(To, M2:Goal)
131 ).
132
133do_goal_expansion(M, Goal, TermPos) :-
134 check_file(File),
135 \+ skip(Goal),
136 callable(Goal), 137 ( TermPos \= none
138 ->From = file_term_position(File, TermPos)
139 ; prolog_load_context(term_position, Pos),
140 stream_position_data(line_count, Pos, Line),
141 From = file(File, Line, -1, _)
142 ),
143 current_context_value(on_trace, OnTrace),
144 determine_caller(Caller),
145 call(OnTrace, M:Goal, Caller, From).
146
147do_source_walk_code(Options1) :-
148 foldl(select_option_default,
149 [on_trace(OnTrace)-(codewalk:true_3),
150 trace_reference(To)-To,
151 undefined(Undefined)-ignore,
152 variable_names(VNL)-VNL],
153 Options1, Options),
154 freeze(VNL, b_setval('$variable_names', VNL)),
155 with_context_values(
156 setup_call_cleanup(
157 ( '$current_source_module'(OldM),
158 freeze(M, '$set_source_module'(M)),
159 prepare(To, Undefined, Ref)
160 ),
161 walk_source(M, [variable_names(VNL)|Options]),
162 ( '$set_source_module'(OldM),
163 cleanup(Ref)
164 )), [on_trace], [OnTrace]).
165
166walk_source(M, Options) :-
167 option_module_files(Options, MFileD),
168 forall(( get_dict(M, MFileD, FileD),
169 get_dict(File, FileD, _)
170 ),
171 setup_call_cleanup(
172 prolog_open_source(File, In),
173 with_context_value(fetch_term(In, Options), file, File),
174 prolog_close_source(In))).
175
176fetch_term(In, Options1) :-
177 foldl(select_option_default,
178 [subterm_positons(TermPos)-TermPos,
179 term_position(Pos)-Pos,
180 syntax_errors(SE)-dec10,
181 process_comment(PC)-false,
182 comments(C)-C
183 ], Options1, Options2),
184 Options = [subterm_positions(TermPos),
185 syntax_errors(SE),
186 term_position(Pos),
187 process_comment(PC),
188 comments(C)
189 |Options2
190 ],
191 repeat,
192 read_clause(In, Term, Options),
193 prolog_xref:update_condition(Term),
194 '$current_source_module'(M),
195 prolog_xref:current_condition(Cond),
196 ( M:Cond
197 ->prolog_source:expand(Term, TermPos, In, Expanded),
198 prolog_source:update_state(Term, Expanded, M)
199 ; true
200 ),
201 Term == end_of_file,
202 !