YAP 7.1.0
debug.yap
Go to the documentation of this file.
1/**********************************************************************a***
2* *
3 * YAP Prolog *
4* *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6* *
7* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8* *
9**************************************************************************
10* *
11* File: debug.yap *
12* Last rev: *
13* mods: *
14* comments: YAP debugger *
15* *
16*************************************************************************/
17
18/**
19 @file pl/debug.yap
20**/
21
22:- module(system('$debug',[]),
23 []).
24
25/**
26 @defgroup Deb_Interaction Interacting with the debugger
27@{
28 @ingroup YAPProgramming
29
30Debugging with YAP is similar to debugging with C-Prolog. Both systems
31include a procedural debugger, based on Byrd's four port model. In this
32model, execution is seen at the procedure level: each activation of a
33procedure is seen as a box with control flowing into and out of that
34box.
35
36In the four port model control is caught at four key points: before
37entering the procedure, after exiting the procedure (meaning successful
38evaluation of all queries activated by the procedure), after backtracking but
39before trying new alternative to the procedure and after failing the
40procedure. Each one of these points is named a port:
41
42```
43 *--------------------------------------*
44 Call | | Exit
45---------> + descendant(X,Y) :- offspring(X,Y). + --------->
46 | |
47 | descendant(X,Z) :- |
48<--------- + offspring(X,Y), descendant(Y,Z). + <---------
49 Fail | | Redo
50 *--------------------------------------*
51```
52
53
54
55+ `Call`
56
57 The call port is activated before initial invocation of
58procedure. Afterwards, execution will try to match the goal with the
59head of existing clauses for the procedure.
60
61+ `Exit`
62
63 This port is activated if the procedure succeeds.
64Control will now leave the procedure and return to its ancestor.
65
66+ `Redo`
67
68 If the goal, or goals, activated after the call port
69fail then backtracking will eventually return control to this procedure
70through the redo port.
71
72+ `Fail`
73
74 If all clauses for this predicate fail, then the
75invocation fails, and control will try to redo the ancestor of this
76invocation.
77
78
79To start debugging, the user will either call `trace` or spy the
80relevant procedures, entering debug mode, and start execution of the
81program. When finding the first spy-point, YAP's debugger will take
82control and show a message of the form:
83v
84```
85* (1) call: quicksort([1,2,3],_38) ?
86```
87
88The debugger message will be shown while creeping, or at spy-points,
89and it includes four or five fields:
90
91+
92The first three characters are used to point out special states of the
93debugger. If the port is exit and the first character is '?', the
94current call is non-deterministic, that is, it still has alternatives to
95be tried. If the second character is a `\*`, execution is at a
96spy-point. If the third character is a `>`, execution has returned
97either from a skip, a fail or a redo command.
98+
99The second field is the activation number, and uniquely identifies the
100activation. The number will start from 1 and will be incremented for
101each activation found by the debugger.
102+
103In the third field, the debugger shows the active port.
104+
105The fourth field is the goal. The goal is written by
106`write_term/3` on the standard error stream, using the options
107given by debugger_print_options.
108
109
110If the active port is leashed, the debugger will prompt the user with a
111`?`, and wait for a command. A debugger command is just a
112character, followed by a return. By default, only the call and redo
113entries are leashed, but the leash/1 predicate can be used in
114order to make the debugger stop where needed.
115
116There are several commands available, but the user only needs to
117remember the help command, which is `h`. This command shows all the
118available options, which are:
119
120+ `c` - creep
121
122 this command makes YAP continue execution and stop at the next
123leashed port.
124
125+ `return` - creep
126
127 the same as c
128
129+ `l` - leap
130
131 YAP will execute until it meets a port for a spied predicate; this mode
132keeps all computation history for debugging purposes, so it is more
133expensive than standard execution. Use <tt>k</tt> or <tt>z</tt> for fast execution.
134
135+ `k` - quasi-leap
136
137 similar to leap but faster since the computation history is
138not kept; useful when leap becomes too slow.
139
140+ `z` - zip
141
142
143 same as <tt>k</tt>
144 `s` - skip
145
146 YAP will continue execution without showing any messages until
147returning to the current activation. Spy-points will be ignored in this
148mode. Note that this command keeps all debugging history, use <tt>t</tt> for fast execution. This command is meaningless, and therefore illegal, in the fail
149and exit ports.
150
151+ `t` - fast-skip
152
153 similar to skip but faster since computation history is not
154kept; useful if skip becomes slow.
155
156+ `f [ _GoalId_]` - fail
157
158 If given no argument, forces YAP to fail the goal, skipping the fail
159port and backtracking to the parent.
160If <tt>f</tt> receives a goal number as
161the argument, the command fails all the way to the goal. If goal _GoalId_ has completed execution, YAP fails until meeting the first active ancestor.
162
163+ `r` [ _GoalId_] - retry
164
165 This command forces YAP to jump back call to the port. Note that any
166side effects of the goal cannot be undone. This command is not available
167at the call port. If <tt>f</tt> receives a goal number as the argument, the
168command retries goal _GoalId_ instead. If goal _GoalId_ has
169vcompleted execution, YAP fails until meeting the first active ancestor.
170
171q+ `a` - abort
172
173 execution will be aborted, and the interpreter will return to the
174top-level. YAP disactivates debug mode, but spypoints are not removed.
175
176+ `n` - nodebug
177
178 stop debugging and continue execution. The command will not clear active
179§spy-points.
180
181+ `e` - exit
182
183 leave YAP.
184
185+ `h` - help
186
187 show the debugger commands.
188
189+ `!` Query
190
191 execute a query. YAP will not show the result of the query.
192
193+ `b` - break
194
195 break active execution and launch a break level. This is the same as `!break`.
196
197+ `+` - spy this goal
198
199 start spying the active goal. The same as `! spy G` where _G_
200is the active goal.
201
202+ `-` - nospy this goal
203
204 stop spying the active goal. The same as `! nospy G` where _G_ is
205the active goal.
206
207+ `p` - print
208
209 shows the active goal using print/1
210
211+ `d` - display
212
213 shows the active goal using display/1
214
215+ `<Depth` - debugger write depth
216
217 sets the maximum write depth, both for composite terms and lists, that
218will be used by the debugger. For more
219information about `write_depth/2` ( (see Input/Output Control)).
220
221+ `<` - full term
222
223 resets to the default of ten the debugger's maximum write depth. For
224more information about `write_depth/2` ( (see Input/Output Control)).
225
226+ `A` - alternatives
227
228 show the list of backtrack points in the current execution.
229
230+ `g [ _N_]`
231
232 show the list of ancestors in the current debugging environment. If it
233receives _N_, show the first _N_ ancestors.
234
235
236The debugging information, when fast-skip `quasi-leap` is used, will
237be lost.
238
239*/
240
241
242
243/*-----------------------------------------------------------------------------
244
245 spy
246
247-----------------------------------------------------------------------------*/
248
249
250/**
251 * @defgroup DebImplementation Implementation of the Debugger
252 * @{
253 * @brief Prolog code to do debugging.
254 *
255 * The debugger is an interpreter. with main predicates:
256 * - $trace: this is the API
257 * - trace_goal: reduce a query to a goal
258 * - trace_goal: execute:
259 * + using the source, Luke
260 * + hooking into the WAM procedure call mechanism
261 * + asking Prolog to do it (system_library-builtins)
262 *
263 * |flag | description | initial | possible values
264 * | ----------------------------------------------------------------
265 * | spy_gn | last goal number | 1 | 1...
266 * | spy_trace | trace | 0 | 0, 1
267 * | spy_status | step | creep | creep,leap,skip
268 * | ... | | stop at goal | -1 | Integer >= 1
269 * | ... | | stop at spy-points | stop | stop,
270 *
271 *
272 *
273 */
274
275
276%'$trace'(G) :- write(user_error,'$spy'(G)), nl, fail.
277%
278/**
279 * @pred $spy( +Goal )
280 *(Goal)`
281*/
282prolog:'$spy'(Mod:G) :-
283 '$trace'(Mod:G, outer).
284
285/**
286 * @pred $trace( +Goal, +Context )
287 *
288 * This launches a goal from the debugger with the call. It must:
289 * - disable user interaction;
290 * - verify whether debugging is still ok;
291 * - enter the debugger core.
292 * The top gated_call should set up creeping for the next call.
293 *
294 * @param _Mod_:_Goal_ is the goal to be examined.
295 * @return `call(Goal)`
296*/
297%%! The first case matches system_predicates or zip
298'$trace'(M:G, Ctx) :-
299 '$get_debugger_state'(trace,Trace),
300 '$set_debugger_state'( creep, 0, yes, Trace, false ),
302 '$id_goal'(GoalNumberN),
303 trace_goal(G, M, Ctx, GoalNumberN, CP),
304 '$creep'.
305
306/**
307 * @pred debugger_io.
308 *
309 * set up the stream used for debugging,
310 * - must be interactive.
311 * - default is `user_input`, but /dev/tty and CONIN$ can be used directly if
312 * user_input is bound to a file.
313 *
314*/
315'$debugger_io' :-
316 '$debugger_input',
317 '$debugger_output'.
318
319'$debugger_input' :-
320 stream_property(_,alias(debugger_input)),
321 stream_property.
322'$debugger_input' :-
323 S = stream_property,
324 stream_property(S,tty(true)),
325 % stream_property(S,input),
326 stream_property,
327 set_stream(S,alias(debugger_input)).
328'$debugger_input' :-
329 current_prolog_flag(unix, true ),
330 current_prolog_flag,
331 open('/dev/tty', read, _S, [alias(debugger_input),bom(false)]).
332'$debugger_input' :-
333 current_prolog_flag(windows, true ),
334 current_prolog_flag,
335 open('CONIN$', read, _S, [alias(debugger_input),bom(false)]).
336'$debugger_output' :-
337 stream_property(_,alias(debugger_output)),
338 stream_property.
339'$debugger_output' :-
340 S = stream_property,
341 stream_property(S,tty(true)),
342 % stream_property(S,output),
343 stream_property,
344 set_stream(S,alias(debugger_output)).
345'$debugger_output' :-
346 current_prolog_flag(unix, true ),
347 current_prolog_flag,
348 open('/dev/tty', write, _S, [alias(debugger_output)]).
349'$debugger_output' :-
350 current_prolog_flag(windows, true ),
351 current_prolog_flag,
352 open('CONOUT$', write, _S, [alias(debugger_output)]).
353
354
355'$trace_meta_call'( G, CP, _, M ) :-
356 trace_goal(G, M, outer, _GN, CP ).
357
358
359/** @pred 'enter_creep'([M|G])
360 *
361 *
362 *
363 */
364'$debug'(M:G) :-
365 '$yap_strip_module'(G,M,Q),
367 trace_goal(Q, M, outer, _GN, CP ),
368 '$creep'.
369
370
371'$creep'(G0, M0, CP, GoalNumber) :-
372 '$yap_strip_module'(M0:G0, M, G), % spy a literal
373 trace_goal(G, M, outer, GoalNumber, CP),
374 '$creep'.
375
376%% @pred trace_goal( +G, +M, +GoalNumber, +CP)
377%
378% debug a complex query
379%
380trace_goal(V, M, _, _, _) :-
381 '$set_debugger_state'(debug,false),
382 var(V),
383 var,
384 call(M:V).
385trace_goal(!,_, _, _,CP) :-
386 trace_goal,
387 cut_by(CP).
388trace_goal(current_choice_point(CP),_, _, _,CP) :-
389 trace_goal.
390trace_goal(query_to_answer(G,Vs,Port, Bindings,Goals),_, _, _, _) :-
391 trace_goal,
392 query_to_answer(G, Vs,Port, Bindings,Goals).
393trace_goal(cut_by(M), _, _, _, _) :-
394 trace_goal,
395 cut_by(M).
396trace_goal(M:G, _, GN0, GN, CP) :-
397 trace_goal,
398 '$yap_strip_module'(M:G, M0, G0),
399 trace_goal(G0, M0, GN0, GN, CP ).
400trace_goal((A,B), M, GN0, GN, CP) :- trace_goal,
401 trace_goal(A, M, inner, GN, CP),
402 trace_goal(B, M, GN0, _GN, CP).
403trace_goal((A->B;C), M, GN0, GN, CP) :- trace_goal,
404 (trace_goal(A, M, inner, GN, CP) ->
405 trace_goal(B, M, GN0, _GN1, CP);
406 trace_goal(C, M, GN0, _GN2, CP)).
407trace_goal((A*->B;C), M, GN0, GN, CP) :- trace_goal,
408 (trace_goal(A, M, inner, GN, CP) *->
409 trace_goal(B, M, GN0, _GN1, CP);
410 trace_goal(C, M, GN0, _GN2, CP)).
411trace_goal((A->B), M, GN0, GN, CP) :- trace_goal,
412 (trace_goal(A, M, inner, GN, CP) ->
413 trace_goal(B, M, GN0, _GN, CP)).
414trace_goal((A*->B), M, GN0, GN, CP) :- trace_goal,
415 (trace_goal(A, M, inner, GN, CP) *->
416 trace_goal(B, M, GN0, _GN, CP)).
417trace_goal((A;B), M, GN0, GN, CP) :- trace_goal,
418 (trace_goal(A, M, GN0, GN, CP);
419 trace_goal(B, M, GN0, _GN, CP)).
420trace_goal((A|B), M, GN0, GN, CP) :- trace_goal,
421 (trace_goal(A, M, GN0, GN, CP);
422 trace_goal(B, M, GN0, _GN, CP)).
423trace_goal(forall(A,B), M, GN0, GN, CP) :- trace_goal,
424 forall(
425 trace_goal(A, M, GN0, GN, CP),
426 trace_goal(B, M, GN0, _GN, CP)
427 ).
428trace_goal((\+ A), M, GN0, GN, CP) :- trace_goal,
429 \+ trace_goal(A, M, GN0, GN, CP).
430trace_goal(once(A), M, GN0, GN, CP) :- trace_goal,
431 once(trace_goal(A, M, GN0, GN, CP)).
432trace_goal(ignore( A), M, GN0, GN, CP) :- trace_goal,
433 ignore( trace_goal(A, M, GN0, GN, CP) ).
434trace_goal(true, _M, _GN0, _GN, _CP) :- trace_goal.
435trace_goal(G,M, Ctx, GoalNumber0, CP0) :-
436 '$imported_predicate'(G,M,NG,NM),
437 M\=NM,
438 '$imported_predicate',
439 trace_goal(NG,NM, Ctx, GoalNumber0, CP0).
440trace_goal(G,M, Ctx, GoalNumberN, CP0) :-
441 '$debuggable'(G,M,GoalNumberN),
442 '$debuggable',
443 '$id_goal'(GoalNumberN),
445 '$predicate_type'(G,M,T),
446 handle_port([call], GoalNumberN, G, M, Ctx, CPN, H),
447 catch(
448 trace_goal_(T,G,M, Ctx, GoalNumberN, CP0, H),
449 Error,
450 trace_error(Error, GoalNumberN, G, M, Ctx, GoalNumberN, CP0, CPN)
451 ).
452
453trace_goal(G,M, _Ctx, _GoalNumber,_CP0) :- % let us exit the debugger.
454 '$meta_hook'(M:G,M:NG),
455 '$execute_nonstop'(NG,M).
456
457
458%% @pred $trace_goal_( +Goal, +Module, +Border, +CallId, +CallInfop)
459
460%%
461%% Actually debugs a goal!
462%%
463trace_goal_(updatable_procedure,G,M, _Ctx,GoalNumber,CPN, H) :-
464 trace_goal_(source_procedure,G,M, _Ctx,GoalNumber, CPN, H).
465trace_goal_(exo_procedure,G,M, _Ctx,GoalNumber, CPN, H) :-
466 trace_goal_(source_procedure,G,M, _Ctx,GoalNumber, CPN, H).
467trace_goal_(mega_procedure,G,M, _Ctx,GoalNumber, CPN, H) :-
468 trace_goal_(source_procedure,G,M, _Ctx,GoalNumber, CPN, H).
469trace_goal_(undefined_procedure,G, M, _Ctx, _GoalNumber, _CPN, _H) :-
470 'undefp'(M:G).
471trace_goal_(source_procedure,G,M, _Ctx,GoalNumber, _CP, H) :-
472 '$id_goal'(GoalNumber),
474 %clause generator: it controls fail, redo
475 '$creep_enumerate_sources'(
476 true,
477 M:G, B,
478 Port0,
479 handle_port([Port0], GoalNumber, G, M, false, CP, H)
480 ),
481 '$creep_run_sources'(
482 handle_port([call,Port0], GoalNumber, G, M, false, CP, H),
483 M,B, CP,
484 Port,
485 handle_port([Port,Port0], GoalNumber, G, M, false, CP, H)
486
487 ).
488trace_goal_(sourceless_procedure, G,M, Ctx,GoalNumber,_CP, H) :-
489 '$id_goal'(GoalNumber),
491 '$number_of_clauses'(G,M,N),
492 N > 0,
493 '$number_of_clauses',
494 '$creep_enumerate_refs'(
495 true,
496 M:G,
497 N,
498 Ref,
499 Port0,
500 handle_port([Port0], GoalNumber, G, M, Ctx, CP, H)
501 ),
502 % source mode'$creep_run_refs'(
503 handle_port([call,Port0], GoalNumber, G, M, Ctx, CP, H),
504
505 M:G,Ref, CP,
506 Port,
507 handle_port([Port,Port0], GoalNumber, G, M, Ctx, CP, H)
508 ).
509trace_goal_(system_procedure,throw(G), _M, _Ctx, _GoalNumber, _CP, _H) :-
510 trace_goal_,
511 throw(G).
512trace_goal_(system_procedure,G, M, Ctx, GoalNumber, CP, H) :-
513 trace_goal_(private_procedure,G, M, Ctx, GoalNumber, CP, H).
514
515trace_goal_(private_procedure,G, M, Ctx, GoalNumber, CP, H) :-
516 '$id_goal'(GoalNumber),
517 /* (
518 '$is_private'(G, M)
519 ;
520 current_prolog_flag(debug,false)
521 ),
522 !,
523 */
524
525 % debugging allowed.gated_call(
526
527 '$meta_hook'(M:G,M:NG),
528 M:NG,
529 Port,
530 handle_port([Port,exit], GoalNumber, G, M, Ctx, CP, H)
531 ).
532
533'$creep_enumerate_sources'(Setup, M:Goal, B, Catcher, Cleanup) :-
534 '$setup_call_catcher_cleanup'(Setup),
535 Task0 = cleanup( true, Catcher, Cleanup, Tag, true, CP0),
536 TaskF = cleanup( true, Catcher, Cleanup, Tag, false, CP0),
537 '$tag_cleanup'(CP0, Task0),
538 clause(M:Goal,B),
539 '$cleanup_on_exit'(CP0, TaskF).
540
541
542'$creep_enumerate_refs'(Setup, M:Goal, _N, Ref, Catcher, Cleanup) :-
543 '$setup_call_catcher_cleanup'(Setup),
544 Task0 = cleanup( true, Catcher, Cleanup, Tag, true, CP0),
545 TaskF = cleanup( true, Catcher, Cleanup, Tag, false, CP0),
546 '$tag_cleanup'(CP0, Task0),
547 nth_clause(M:Goal,_J,Ref),
548 '$cleanup_on_exit'(CP0, TaskF).
549
550
551'$creep_run_sources'(Setup, M, B, CP, Catcher, Cleanup) :-
552 '$setup_call_catcher_cleanup'(Setup),
553 Task0 = cleanup( true, Catcher, Cleanup, Tag, true, CP0),
554 TaskF = cleanup( true, Catcher, Cleanup, Tag, false, CP0),
555 '$tag_cleanup'(CP0, Task0),
556 trace_goal(B,M,outer,_, CP),
557 '$cleanup_on_exit'(CP0, TaskF).
558
559'$creep_run_private'(Setup, M, G, _CP, Catcher, Cleanup) :-
560 '$setup_call_catcher_cleanup'(Setup),
561 Task0 = cleanup( true, Catcher, Cleanup, Tag, true, CP0),
562 TaskF = cleanup( true, Catcher, Cleanup, Tag, false, CP0),
563 '$tag_cleanup'(CP0, Task0),
564'$execute_nonstop'(G,M),
565 '$cleanup_on_exit'(CP0, TaskF).
566
567'$creep_run_refs'(Setup, M:Goal, Ref, CP, Catcher, Cleanup) :-
568 '$setup_call_catcher_cleanup'(Setup),
569 Task0 = cleanup( true, Catcher, Cleanup, Tag, true, CP0),
570 TaskF = cleanup( true, Catcher, Cleanup, Tag, false, CP0),
571 '$tag_cleanup'(CP0, Task0),
572 '$creep_clause'( Goal, M, Ref, CP ),
573 '$cleanup_on_exit'(CP0, TaskF).
574
575
576'$meta_hook'(MG,M:NG) :-
577 '$yap_strip_module'(MG,M,G),
578 '$debuggable'(G,M,+inf),
579 functor(G,N,A),
580 N\=functor,
581 functor(PredDef,N,A),
582 G =..[_|As],
583 recorded('$m', meta_predicate(M,PredDef),_),
584 PredDef=..[N|Ms],
585 '$debugger_prepare_meta_arguments'(As, Ms, NAs),
586 NAs \== As,
587 '$debugger_prepare_meta_arguments',
588 NG=..[N|NAs].
589'$meta_hook'(MG,MG).
590
591/**
592 * @Pred '$enter_trace'(+L, 0:G, +Module, +Info)
593 *
594 * call goal: prelims
595 *
596 * @parameter _Module_:_G_
597 * @parameter _L_ is the list of active goals
598 * @parameter _Info_ describes the goal
599 *
600 */
601'$enter_trace'(L, G, Module, CP, Info) :-
602 '$id_goal'(L), /* get goal no. */
603 /* get goal list */
604 '__NB_getval__'('$spy_glist',History,History=[]),
605 Info = info(L,Module,G,CP,_Retry,_Det,_HasFoundAnswers),
606 H = [Info|History],
607 b_setval('$spy_glist',H). /* and update it */
608
609'$id_goal'(L) :-
610 var(L),
611 var,
612 ( '__NB_getval__'('$spy_gn',L,fail) -> '__NB_getval__' ; L = 0 ),
613 /* bump it */
614 L1 is L+1,
615 /* and save it globaly */
616 '__NB_setval__'('$spy_gn',L1).
617'$id_goal'(L) :- integer(L).
618
619
620handle_port([exception(redo(_))|_], _GoalNumber, _G, _M, _G0, _CP, _H) :-
621 handle_port.
622handle_port([exception(fail(_))|_], _GoalNumber, _G, _M, _G0, _CP, _H) :-
623 handle_port.
624handle_port(Ports, GoalNumber, G, M, G0, CP, H) :-
625 '$stop_creeping'(_),
626 %writeln((Ports->G;GoalNumber)),
627 '$trace_port'(Ports, GoalNumber, G, M, G0, CP, H).
628
629/**
630 * @pred '$trace_go'(+L, 0:G, +Module, +Info)
631 *
632 * It needs to run in two separate steps:
633 * 1. Select a clause;
634 * 2. Debug it.
635 * We use a marker to track who we are in gated_call.
636 *
637 * @parameter _Module_:_G_
638 * @parameter _GoalNumber_ identifies the active goal
639 * @parameter _Info_ describes the goal
640 *
641 */
642'$trace_port'(_Ports, _GoalNumber, _Ctxt, _Module,_From, _CP,_Info) :-
643 prolog_flag( debug, false),
644 prolog_flag.
645'$trace_port'(Ports, GoalNumber, _Ctxt, _Module,_From, _CP,_Info) :-
646 %writeln(GoalNumber:Ports),
647 '$leap'(Ports,GoalNumber),
648 '$leap'.
649'$trace_port'(Ports, GoalNumber, Ctxt, Module,From, CP,Info) :-
650 ('$ports_to_port'(Ports, Port)->'$ports_to_port';Port='$ports_to_port'),
651 %writeln(Port),
652 ignore('$trace_port_'(Port, GoalNumber, Ctxt, Module, CP,Info)),
653 '$cross_run_deb'(Port,From,GoalNumber).
654
655
656'$ports_to_port'([answer,exit], answer).
657'$ports_to_port'([answer,answer], answer).
658'$ports_to_port'([call], call).
659'$ports_to_port'([call,redo], redo).
660'$ports_to_port'([call,exit], internal).
661'$ports_to_port'([exit,exit], exit).
662'$ports_to_port'([exit,answer], answer).
663'$ports_to_port'( [exit], internal).
664'$ports_to_port'([exit,redo], internal).
665'$ports_to_port'([fail,exit], fail).
666'$ports_to_port'([fail,answer], redo).
667'$ports_to_port'([exit,fail], internal).
668'$ports_to_port'( [fail], fail).
669'$ports_to_port'([redo,answer], redo).
670'$ports_to_port'([redo,exit], redo).
671'$ports_to_port'([redo], redo).
672'$ports_to_port'([!,answer], exit).
673'$ports_to_port'([!,exit], exit).
674'$ports_to_port'([!,redo], fail).
675'$ports_to_port'([!,fail], fail).
676'$ports_to_port'([answer,!], exit).
677'$ports_to_port'([exit,!], exit).
678'$ports_to_port'([redo,!], redo).
679'$ports_to_port'([fail,!], fail).
680'$ports_to_port'([!], internal).
681'$ports_to_port'([exception(E),_], exception(E)).
682'$ports_to_port'([exception(E)],exception(E)).
683'$ports_to_port'([external_exception(E),_], exception(E)).
684'$ports_to_port'([external_exception(E)],exception(E)).
685
686
687'$trace_port_'(call, GoalNumber, G, Module, CP,Info) :-
688 '$enter_trace'(GoalNumber, G, Module,CP, Info),
689 '$port'(call,G,Module,GoalNumber,deterministic,CP, Info).
690'$trace_port_'(exit, GoalNumber, G, Module, CP,Info) :-
691 '$port'(exit,G,Module,GoalNumber,deterministic, CP, Info).
692'$trace_port_'(answer, GoalNumber, G, Module, CP,Info) :-
693 '$port'(exit,G,Module,GoalNumber,nondeterministic, CP, Info).
694'$trace_port_'(redo, GoalNumber, G, Module, CP,Info) :-
695 '$port'(redo,G,Module,GoalNumber,nondeterministic, CP, Info). /* inform user_error */
696'$trace_port_'(fail, GoalNumber, G, Module, CP,Info) :-
697 '$port'(fail,G,Module,GoalNumber,deterministic, CP, Info). /* inform user_error */
698'$trace_port_'(! ,_GoalNumber,_G,_Module,_CP,_Info) :- /* inform user_error */
699 '$trace_port_'.
700'$trace_port_'(exception(redo(_)), _GoalNumber, _G, _Module, _CP, _Info) :-
701 '$trace_port_'.
702'$trace_port_'(exception(fail(_)), _GoalNumber, _G, _Module, _CP, _Info) :-
703 '$trace_port_'.
704'$trace_port_'(exception(E), GoalNumber, G, Module, CP,Info) :-
705 '$port'(exception(E),G,Module,GoalNumber,deterministic,CP,Info). /* inform user_error */
706'$trace_port_'(internal, _GoalNumber, _G, _Module, _CP,_Info).
707
708
709
710%%% - abort: forward throw while the call is newer than goal
711%% @pred '$re_trace_goal'( Exception, +Goal, +Mod, +GoalID )
712%
713% debugger code for exceptions. Recognised cases are:
714% - abort always forwarded
715% - redo resets the goal
716% - fail gives up on the goal.
717%% trace_error(_Event, _GoalNumber, _G, _Module, _, _, _, _CP) :-
718%% writeln(trace_error(_Event, _GoalNumber, _G, _Module,_CP,_H)),
719%% fail.
720%'$reenter_debugger'(exception(Event)),
721% fail.
722trace_error(abort, _GoalNumber, _G, _Module, _Ctx, _GoalNumber0, _CP0, _CP) :-
723 trace_error,
724 trace_error.
725trace_error(event(fail,G0), _GoalNumber, _G, _Module, _Ctx, GoalNumber0, _CP0, _CP) :-
726 trace_error,
727 (
728 GoalNumber0 > G0
729 ->
730 throw(event(fail,G0))
731 ;
732 throw
733 ).
734trace_error(redo(G0), _GoalNumber, G, M, Ctx, GoalNumber0, CP0, _CP) :-
735 trace_error,
736 (
737 GoalNumber0 > G0
738 ->
739 throw(redo(G0))
740 ;
741 '$get_debugger_state'(trace,Trace),
742 '$set_debugger_state'( creep, 0, yes, Trace, false ),
743 trace_goal(G,M, Ctx, GoalNumber0, CP0)
744 ).
745%trace_error( error(Id,Info), _, _, _, _) :-
746% !,
747% throw( error(Id, Info) ).
748%%% - forward through the debugger
749trace_error(Event, _, _, _, _,_,_, _) :-
750 throw(Event).
751
752% just fail here, don't really need to call debugger, the user knows what he
753% wants to do
754'$loop_fail'(_GoalNumber, _G, _Module, _Creep) :-
755 current_prolog_flag(debug, true),
756 current_prolog_flag.
757
758%
759% skip a goal or a port
760%
761
762'$gg'(CP,Goal) :-
764 CP = CP0,
765 Goal.
766
767
768'$port'(P,G,Module,L,Deterministic,_CP, Info) :-
769 '$id_goal'(L), /* get goal no. */
770 % at this point we are done with leap or skip
771 '$get_debugger_state'(trace,Trace),
772 '$set_debugger_state'( creep, L, yes, Trace, false ),
773 '$set_debugger_state',
774 '$set_debugger_state',
775 '$clear_input'(debugger_input),
776 '$trace_msg'(P,G,Module,L,Deterministic),
777 (
778 '$unleashed'(P) ->
779 '$action'('\n',P,L,G,Module,Info),
780 nl(debugger_output)
781
782 ;
783 prompt1(' ? '),
784 get_char(user_input,C),
785 '$action'(C,P,L,G,Module,_Info)
786 ),
787 !.
788
789'$trace_msg'(P,G,Module,L,Deterministic) :-
790 functor(P,P0,_),
791 (P = exit, Deterministic \= deterministic -> Det = '?' ; Det = ' '),
792 ('$pred_being_spied'(G,Module) -> CSPY = '*' ; CSPY = ' '),
793 % vsc: fix this
794 % ( SL = L -> SLL = '>' ; SLL = ' '),
795
796 SLL = ' ',
797 ( Module\=,
798 Module\=
799 ->
800 GW = Module:G
801 ;
802 GW = G
803 ),
804 format(debugger_output,'~N~a~a~a (~d) ~q:',[Det,CSPY,SLL,L,P0]),
805 '$debugger_write'(debugger_output,GW).
806
807'$unleashed'(call) :- get_value('$leash',L), L /\ 0get_value =:= 0. %'
808'$unleashed'(exit) :- get_value('$leash',L), L /\ 0get_value =:= 0. %'
809'$unleashed'(redo) :- get_value('$leash',L), L /\ 0get_value =:= 0. %'
810'$unleashed'(fail) :- get_value('$leash',L), L /\ 0get_value =:= 0. %'
811% the same as fail.
812'$unleashed'(exception(_)) :- get_value('$leash',L), L /\ 0get_value =:= 0. %
813
814'$debugger_write'(Stream, G) :-
815 prolog_flag( debugger_print_options, OUT ), prolog_flag,
816 write_term(Stream, G, OUT).
817'$debugger_write'(Stream, G) :-
818 writeq(Stream, G).
819
820'$action'('\r',P,CallNumber,G,Module,H) :- '$action', % newline creep
821 get_char( debugger_input,C),
822 '$action'(C,P,CallNumber,G,Module,H).
823'$action'('\n',_,_,_,_,_) :- '$action', % newline creep
824 '$get_debugger_state'(trace,Trace),
825 '$set_debugger_state'( creep, 0, stop, Trace, false ).
826'$action'(!,_,_,_,_,_) :- '$action', % ! 'g execute
827 read(debugger_input, G),
828 % don't allow yourself to be caught by creep.
829 ignore( G ),
830 skip( debugger_input, 10), % '
831 skip.
832'$action'(<,_,_,_,_,_) :- '$action', % <'Depth
833 '$new_deb_depth',
834 skip( debugger_input, 10),
835 skip.
836'$action'('C',_,_,_,_,_) :-
837 yap_flag(system_options, Opts),
838 yap_flag:memberchk( call_tracer, Opts),
839 memberchk, % <'Depth
840 skip( debugger_input, 10),
841 '__NB_getval__'('$trace',Trace,fail),
842 '$set_debugger_state'( creep, 0, stop,Trace,false).
843'$action'(^,_,_,G,_,_) :- '$action', % '
844 '$print_deb_sterm'(G),
845 skip( debugger_input, 10),
846 skip.
847'$action'(a,_,_,_,_,_) :- '$action', % 'a abort
848 skip( debugger_input, 10),
849 skip,
850 skip.
851'$action'(b,_,_,_,_,_) :- '$action', % 'b break
852 '$stop_creeping'(_),
853 skip( debugger_input, 10),
854 skip,
855 skip.
856'$action'('A',_,_,_,_,_) :- '$action', % 'b break
857 skip( debugger_input, 10),
858 '$stack_dump',
859 skip.
860'$action'(c,_,_,_,_,_) :- '$action', % 'c creep
861 skip( debugger_input, 10),
862 '$get_debugger_state'(trace,Trace),
863 '$set_debugger_state'( creep,0,stop,Trace, false ).
864'$action'(e,_,_,_,_,_) :- '$action', % 'e exit
865 '$action'.
866'$action'(f,_,CallNumber,_,_,_) :- '$action', % 'f fail
867 '$scan_number'( ScanNumber),
868 ( ScanNumber == 0 -> Goal = CallNumber ; Goal = ScanNumber ),
869 throw(event(fail,Goal)).
870'$action'(h,_,_,_,_,_) :- '$action', % 'h help
871 '$action_help',
872 skip( debugger_input, 10),
873 skip.
874'$action'(?,_,_,_,_,_) :- '$action', % '? help
875 '$action_help',
876 skip( debugger_input, 10),
877 skip.
878'$action'(p,_,_,G,Module,_) :- '$action', % 'p print
879 ((Module = prolog ; Module = user) ->
880 print(user_error,G), nl(user_error)
881 ;
882 print(user_error,Module:G), nl(user_error)
883 ),
884 skip( debugger_input, 10),
885 skip.
886'$action'(d,_,_,G,Module,_) :- '$action', % 'd display
887 ((Module = prolog ; Module = user) ->
888 display(user_error,G), nl(user_error)
889 ;
890 display(user_error,Module:G), nl(user_error)
891 ),
892 skip( debugger_input, 10),
893 skip.
894'$action'(l,_,CallNumber,_,_,_) :- '$action', % 'leap
895 '$scan_number'(ScanNumber),
896 ( ScanNumber == 0 -> Goal = CallNumber ; Goal = ScanNumber ),
897 '$get_debugger_state'(trace,Trace),
898 '$set_debugger_state'( leap, 0, stop,Trace, false ).
899'$action'(z,_,CallNumber,_,_,_CP) :- '$action',
900 '$scan_number'(ScanNumber), % 'z zip, fast leap
901 '$get_debugger_state'(trace,Trace),
902 ( '$scan_number'(ScanNumber)-> Goal = CallNumber ; Goal = ScanNumber ),
903 '$set_debugger_state'( zip , Goal, stop, Trace, false ).
904% skip first call (for current goal),
905% stop next time.
906'$action'(k,_,_CallNumber,_,_,_) :- '$action',
907 skip( debugger_input, 10), % k zip, fast leap
908 '$get_debugger_state'(trace,Trace),
909 '$set_debugger_state'( zip, 0, stop, Trace, false).
910% skip first call (for current goal),
911% stop next time.
912'$action'(n,_,_,_,_,_) :- '$action', % 'n nodebug
913 skip( debugger_input, 10), % '
914 % tell debugger never to stop.
915 skip.
916'$action'(r,P,CallNumber,_,_,_) :- '$action', % r retry
917 '$scan_number'(ScanNumber),
918 ( ScanNumber == 0 -> Goal = CallNumber ; Goal = ScanNumber ),
919 ( (P==call) ->
920 '$ilgl'(s) %
921 ;
922 '$ilgl'
923 ),
924 throw(redo(Goal)).
925'$action'(s,P,CallNumber,_,_,_) :- '$action', % 's skip
926 '$scan_number'(ScanNumber),
927 ( ScanNumber == 0 -> Goal = CallNumber ; Goal = ScanNumber ),
928 ( (P==call; P==redo) ->
929 '$get_debugger_state'(trace,Trace),
930 '$set_debugger_state'( leap, Goal, ignore,Trace,false)
931 ;
932 '$ilgl'(s) %
933 ).
934'$action'(t,P,CallNumber,_,_,_) :- '$action', % 't fast skip
935 '$scan_number'(ScanNumber),
936 ( ScanNumber == 0 -> Goal = CallNumber ; Goal = ScanNumber ),
937 ( (P=call; P=redo) ->
938 '$get_debugger_state'(trace,Trace),
939 '$set_debugger_state'( zip, Goal, ignore,Trace, false)
940 ;
941 '$ilgl'(t) %
942 ).
943'$action'(q,P,CallNumber,_,_,_) :- '$action', % qst skip
944 '$scan_number'(ScanNumber),
945 ( ScanNumber == 0 -> Goal = CallNumber ; Goal = ScanNumber ),
946 ( (P=call; P=redo) ->
947 '$get_debugger_state'(trace,Trace),
948 '$set_debugger_state'( leap, Goal, stop, Trace, false)
949 ;
950 '$ilgl'(t) %
951 ).
952'$action'(+,_,_,G,M,_) :- '$action', %% spy this
953 functor(G,F,N), spy(M:(F/N)),
954 skip( debugger_input, 10),
955 skip.
956'$action'(-,_,_,G,M,_) :- '$action', %% nospy this
957 functor(G,F,N), nospy(M:(F/N)),
958 skip( debugger_input, 10),
959 skip.
960'$action'(g,_,_,_,_,_) :- '$action', % g ancestors
961 '$scan_number'(HowMany),
962 '$show_ancestors'(HowMany),
963 '$show_ancestors'.
964'$action'('T',exception(G),_,_,_,_) :- '$action', % T throw
965 throw( G ).
966'$action'(C,_,_,_,_,_) :-
967 skip( debugger_input, 10),
968 '$ilgl'(C),
969 '$ilgl'.
970
971'$show_ancestors'(HowMany) :-
972 '__NB_getval__'('$spy_glist',[_|History], fail),
973 (
974 History == []
975 ->
976 print_message(help, ancestors([]))
977 ;
978 '$show_ancestors'(History,HowMany),
979 nl(user_error)
980 ).
981
982'$show_ancestors'([],_).
983'$show_ancestors'([_|_],0) :- '$show_ancestors'.
984'$show_ancestors'([info(L,M,G,_CP,Retry,Det,_Exited)|History],HowMany) :-
985 '$show_ancestor'(L,M,G,Retry,Det,HowMany,HowMany1),
986 '$show_ancestors'(History,HowMany1).
987
988% skip exit port, we're looking at true ancestors
989'$show_ancestor'(_,_,_,_,Det,HowMany,HowMany) :-
990 nonvar(Det), nonvar.
991% look at retry
992'$show_ancestor'(GoalNumber, M, G, Retry, _, HowMany, HowMany1) :-
993 nonvar(Retry), nonvar,
994 HowMany1 is HowMany-1,
995 '$trace_msg'(redo, G, M, GoalNumber, _), nl(user_error).
996'$show_ancestor'(GoalNumber, M, G, _, _, HowMany, HowMany1) :-
997 HowMany1 is HowMany-1,
998 '$trace_msg'(call, G, M, GoalNumber, _), nl(user_error).
999
1000
1001'$action_help' :-
1002 format(user_error,'newline creep a abort~n', []),
1003 format(user_error,'c creep e exit~n', []),
1004 format(user_error,'f Goal fail h help~n', []),
1005 format(user_error,'l leap r Goal retry~n', []),
1006 format(user_error,'s skip t fastskip~n', []),
1007 format(user_error,'q quasiskip k quasileap~n', []),
1008 format(user_error,'b break n no debug~n', []),
1009 format(user_error,'p print d display~n', []),
1010 format(user_error,'<D depth D < full term~n', []),
1011 format(user_error,'+ spy this - nospy this~n', []),
1012 format(user_error,'^ view subg ^^ view using~n', []),
1013 format(user_error,'A choices g [N] ancestors~n', []),
1014 format(user_error,'T throw ~n', []),
1015 format(user_error,'! g execute goal~n', []).
1016
1017'$ilgl'(C) :-
1018 print_message(warning, trace_command(C)),
1019 print_message(help, trace_help),
1020 print_message.
1021
1022'$scan_number'(Nb) :-
1023 findall(C, '$get_deb_code'(C), S),
1024 S = [_|_],
1025 ,
1026 number_codes(Nb,S).
1027'$scan_number'(0).
1028
1029'$get_deb_code'(C) :-
1030 '$get_deb_code',
1031 get_code( debugger_input, C),
1032 ( C == 10 -> !, fail ;
1033 C == -1 -> !, fail ;
1034 C < "0" -> fail ;
1035 C > "9" -> fail ;
1036 true
1037 ).
1038
1039'$print_deb_sterm'(G) :-
1040 '$get_sterm_list'(L), '$get_sterm_list',
1041 '$deb_get_sterm_in_g'(L,G,A),
1042 recorda('$debug_ub_skel',L,_),
1043 format(user_error,'~n~w~n~n',[A]).
1044'$print_deb_sterm'(_) :- skip( debugger_input, 10).
1045
1046'$get_sterm_list'(L) :-
1047 get_code( debugger_input_input,C),
1048 '$deb_inc_in_sterm_oldie'(C,L0,CN),
1049 '$get_sterm_list'(L0,CN,0,L).
1050
1051'$deb_inc_in_sterm_oldie'(94,L0,CN) :- '$deb_inc_in_sterm_oldie',
1052 get_code( debugger_input,CN),
1053 ( recorded('$debug_sub_skel',L0,_) -> recorded ;
1054 CN = [] ).
1055'$deb_inc_in_sterm_oldie'(C,[],C).
1056
1057'$get_sterm_list'(L0,C,N,L) :-
1058 ( C =:= "^", N =\= 0 ->
1059 get_code(debugger_input, CN),
1060 '$get_sterm_list'([N|L0],CN,0,L)
1061 ;
1062 C >= "0", C =< "9" ->
1063 NN is 10*N+C-"0", get_code(debugger_input, CN),
1064 '$get_sterm_list'(L0,CN,NN,L)
1065 ;
1066 C =:= 10 ->
1067 (N =:= 0 -> L = L0 ; L=[N|L0])
1068 ).
1069
1070'$deb_get_sterm_in_g'([],G,G).
1071'$deb_get_sterm_in_g'([H|T],G,A) :-
1072 '$deb_get_sterm_in_g'(T,G,A1),
1073 arg(H,A1,A).
1074
1075'$new_deb_depth' :-
1076 get_code( debugger_input,C),
1077 '$get_deb_depth'(C,D),
1078 '$set_deb_depth'(D).
1079
1080'$get_deb_depth'(10,10) :- '$get_deb_depth'. % default depth is 0
1081'$get_deb_depth'(C,XF) :-
1082 '$get_deb_depth_char_by_char'(C,0,XF).
1083
1084'$get_deb_depth_char_by_char'(10,X,X) :- '$get_deb_depth_char_by_char'.
1085'$get_deb_depth_char_by_char'(C,X0,XF) :-
1086 C >= "0", C =< "9", '$get_deb_depth_char_by_char',
1087 XI is X0*10+C-"0",
1088 get_code( debugger_input,NC),
1089 '$get_deb_depth_char_by_char'(NC,XI,XF).
1090% reset when given garbage.
1091'$get_deb_depth_char_by_char'(_C,X,X).
1092
1093'$set_deb_depth'(D) :-
1094 current_prolog_flag(debugger_print_options,L),
1095 '$delete_if_there'(L, max_depth(_), max_depth(D), LN),
1096 set_prolog_flag(debugger_print_options,LN).
1097
1098'$delete_if_there'([], _, TN, [TN]).
1099'$delete_if_there'([T|L], T, TN, [TN|L]) :- '$delete_if_there'.
1100'$delete_if_there'([Q|L], T, TN, [Q|LN]) :-
1101 '$delete_if_there'(L, T, TN, LN).
1102
1103'$debugger_deterministic_goal'(exit).
1104'$debugger_deterministic_goal'(fail).
1105'$debugger_deterministic_goal'(!).
1106'$debugger_deterministic_goal'(exception(_)).
1107'$debugger_deterministic_goal'(external_exception(_)).
1108
1109
1110'$cps'([CP|CPs]) :-
1111 '$cps':choicepoint(CP,_A_,_B,_C,_D,_E,_F),
1112 '$cps'(CPs).
1113'$cps'([]).
1114
1115
1116'$debugger_skip_trace_goal'([CP|CPs],CPs1) :-
1117 '$debugger_skip_trace_goal':choicepoint(CP,_,prolog,trace_goal,4,(_;_),_),
1118 choicepoint,
1119 '$debugger_skip_trace_goal'(CPs,CPs1).
1120'$debugger_skip_trace_goal'(CPs,CPs).
1121
1122'$debugger_skip_traces'([CP|CPs],CPs1) :-
1123 '$debugger_skip_traces':choicepoint(CP,_,prolog,'$port',4,(_;_),_),
1124 choicepoint,
1125 '$debugger_skip_traces'(CPs,CPs1).
1126'$debugger_skip_traces'(CPs,CPs).
1127
1128'$debugger_skip_loop_spy2'([CP|CPs],CPs1) :-
1129 '$debugger_skip_loop_spy2':choicepoint(CP,_,prolog,'$loop_spy2',5,(_;_),_),
1130 choicepoint,
1131 '$debugger_skip_loop_spy2'(CPs,CPs1).
1132'$debugger_skip_loop_spy2'(CPs,CPs).
1133
1134'$debugger_prepare_meta_arguments'([], [], []).
1135'$debugger_prepare_meta_arguments'([A|As], [M|Ms], ['$trace'(MA:GA,outer)|NAs]) :-
1136 number(M),
1137 number,
1138 '$yap_strip_module'(A,MA,GA),
1139 '$debugger_prepare_meta_arguments'(As, Ms, NAs).
1140'$debugger_prepare_meta_arguments'([A|As], [_|Ms], [A|NAs]):-
1141 '$debugger_prepare_meta_arguments'(As, Ms, NAs).
1142
1143%% @}
1144
catch( : Goal,+ Exception,+ Action)
clause(+ H, B)
nth_clause(+ H, I,- R)
Definition: preds.yap:176
open(+ F,+ M,- S,+ Opts)
prompt1(+ _A__)
read(+ Stream, -Term )
stream_property( Stream, Prop )
Definition: top.yap:2
throw(+ Ball)
yap_flag( ?Param, ?Value)
get_char(+ S,- C)
get_code(+ S,- C)
nl(+ S)
skip(+ S,- C)
nospy( + P )
Definition: spy.yap:150
spy( + P )
number_codes(? I,? L)
findall( T,+ G,- L)
Definition: setof.yap:70
display(+ S, T)
print(+ S, T)
write_term(+ S, + T, + Opts)
writeq(+ S, ? T)
call( 0:P )
forall(: Cond,: Action)
ignore(: Goal)
once( 0:G)
current_prolog_flag(? Flag,- Value)
set_prolog_flag(+ Flag,+ Value)
print_message(+ Severity, +Term)
get_value(+ A,- V)
arg(+ N,+ T, A)
current_choice_point( -CP )
functor( T, F, N)
integer( T)
nonvar( T)
number( T)
var( T)
memberchk(+ Element, + Set)