Did you know ... | Search Documentation: |
![]() | Implementing a yield based debugger |
Starting with version 9.3.21, the SWI-Prolog foreign interface allows
you to implement a debugger based on yielding, similar to
section 12.4.1.2.
This implies that instead of using the built-in debugger or the prolog_trace_interception/4
hook that is used for e.g., driving the GUI debugger, PL_next_solution()
returns when trace interaction is required. The embedding system can
interact with the user and resume PL_next_solution().
This is notably required by the WASM described in section
13 version, where we need to return to the browser event loop to
interact with the user. Yielding on behalf of the debugger is enabled
using the PL_Q_TRACE_WITH_YIELD
flag of PL_open_query().
The skeleton or using these facilities is below.
PL_get_trace_context()
retrieves a Prolog term that provides information similar to prolog_trace_interception/4.
qid_t qid = PL_open_query(module, PL_Q_EXT_STATUS| PL_Q_ALLOW_YIELD|PL_Q_TRACE_WITH_YIELD, predicate, argv); for(;;) { int rc = PL_next_solution(qid); switch(rc) { case PL_S_YIELD_DEBUG: PL_get_trace_context(msg); trace_reply(msg, action); PL_set_trace_action(action); break; case ... } }
The trace_reply() is a user defined function that typically calls Prolog to display the current goal and requests the user how to continue. PL_set_trace_action() processes the same term as output argument of prolog_trace_interception/4, telling Prolog how to continue. One option for trace_reply() is to call a Prolog predicate. Below is a partial implementation for such a predicate. Here, trace_reply/3 uses the character typed by the user to derive the trace continuation action.
read_trace_reply(Msg, Action) :- print_message(debug, Msg), format(user_error, '? ', []), get_single_char(Code), char_code(Char, Code), trace_reply(Char, Msg, Action).
frame(Frame, Choice, Port, PC)
. This provides the same
information as passed to prolog_trace_interception/4.
The additional PC argument provides the program counter in
the executing clause. The msg term may be passed to
print_message/2
to print the current port and goal, similarly to the commandline
debugger.