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