35
36:- module(prolog_trace,
37 [ trace/1, 38 trace/2, 39 tracing/2, 40 notraceall/0
41 ]). 42:- autoload(library(apply),[maplist/2]). 43:- autoload(library(error),[instantiation_error/1]). 44:- autoload(library(prolog_wrap),[wrap_predicate/4]). 45:- autoload(library(prolog_code), [pi_head/2]). 46
47
56
57:- meta_predicate
58 trace(:),
59 trace(:, +),
60 tracing(:, -). 61
62:- dynamic tracing_mask/2. 63:- volatile tracing_mask/2. 64
104
105trace(Pred) :-
106 trace(Pred, +all).
107
108trace(Pred, Spec) :-
109 '$find_predicate'(Pred, Preds),
110 Preds \== [],
111 maplist(set_trace(Spec), Preds).
112
113set_trace(Spec, Pred) :-
114 ( tracing_mask(Pred, Spec0)
115 -> true
116 ; Spec0 = 0
117 ),
118 modify(Spec, Spec0, Spec1),
119 retractall(tracing_mask(Pred, _)),
120 ( Spec1 == []
121 -> true
122 ; asserta(tracing_mask(Pred, Spec1))
123 ),
124 mask_ports(Spec1, Ports),
125 pi_head(Pred, Head0),
126 ( predicate_property(Head0, imported_from(M))
127 -> requalify(Head0, M, Head)
128 ; Head = Head0
129 ),
130 ( Spec1 == 0
131 -> unwrap_predicate(Head, trace),
132 print_message(informational, trace(Head, Ports))
133 ; wrapper(Spec1, Head, Wrapped, Wrapper),
134 wrap_predicate(Head, trace, Wrapped, Wrapper),
135 print_message(informational, trace(Head, Ports))
136 ).
137
138requalify(Term, M, M:Plain) :-
139 strip_module(Term, _, Plain).
140
141modify(Var, _, _) :-
142 var(Var),
143 !,
144 instantiation_error(Var).
145modify([], Spec, Spec) :-
146 !.
147modify([H|T], Spec0, Spec) :-
148 !,
149 modify(H, Spec0, Spec1),
150 modify(T, Spec1, Spec).
151modify(+Port, Spec0, Spec) :-
152 !,
153 port_mask(Port, Mask),
154 Spec is Spec0 \/ Mask.
155modify(-Port, Spec0, Spec) :-
156 !,
157 port_mask(Port, Mask),
158 Spec is Spec0 /\ \Mask.
159modify(Port, Spec0, Spec) :-
160 port_mask(Port, Mask),
161 Spec is Spec0 \/ Mask.
162
163port_mask(all, 0x0f).
164port_mask(call, 0x01).
165port_mask(exit, 0x02).
166port_mask(redo, 0x04).
167port_mask(fail, 0x08).
168
169mask_ports(0, []) :-
170 !.
171mask_ports(Pattern, [H|T]) :-
172 is_masked(Pattern, H, Pattern1),
173 mask_ports(Pattern1, T).
174
175wrapper(Ports, Head, Wrapped, Wrapper) :-
176 wrapper(Ports, Head, Id-Level, Wrapped, Wrapped1),
177 Wrapper = ( prolog_current_frame(Id),
178 prolog_frame_attribute(Id, level, Level),
179 Wrapped1
180 ).
181
182wrapper(0, _, _, Wrapped, Wrapped) :-
183 !.
184wrapper(Pattern, Head, Id, Wrapped, Call) :-
185 is_masked(Pattern, call, Pattern1),
186 !,
187 wrapper(Pattern1, Head, Id, Wrapped, Call0),
188 Call = ( print_message(debug, frame(Head, trace(call, Id))),
189 Call0
190 ).
191wrapper(Pattern, Head, Id, Wrapped, Call) :-
192 is_masked(Pattern, exit, Pattern1),
193 !,
194 wrapper(Pattern1, Head, Id, Wrapped, Call0),
195 Call = ( Call0,
196 print_message(debug, frame(Head, trace(exit, Id)))
197 ).
198wrapper(Pattern, Head, Id, Wrapped, Call) :-
199 is_masked(Pattern, redo, Pattern1),
200 !,
201 wrapper(Pattern1, Head, Id, Wrapped, Call0),
202 Call = ( call_cleanup(Call0, Det = true),
203 ( Det == true
204 -> true
205 ; true
206 ; print_message(debug, frame(Head, trace(redo, Id))),
207 fail
208 )
209 ).
210wrapper(Pattern, Head, Id, Wrapped, Call) :-
211 is_masked(Pattern, fail, Pattern1),
212 !,
213 wrapper(Pattern1, Head, Id, Wrapped, Call0),
214 Call = call(( call_cleanup(Call0, Det = true),
215 ( Det == true
216 -> !
217 ; true
218 )
219 ; print_message(debug, frame(Head, trace(fail, Id))),
220 fail
221 )).
222
223is_masked(Pattern0, Port, Pattern) :-
224 port_mask(Port, Mask),
225 Pattern0 /\ Mask =:= Mask,
226 !,
227 Pattern is Pattern0 /\ \Mask.
228
232
233tracing(Spec, Ports) :-
234 tracing_mask(Spec, Mask),
235 mask_ports(Mask, Ports).
236
240
241notraceall :-
242 forall(tracing(M:Spec, _Ports),
243 trace(M:Spec, -all))