There are two hooks related to breakpoints.
it possible for the user to extend the set of allowed conditions. This
hook is called, at breakpoint addition time, with each
simple test or action within the breakpoint spec, as the
Macro argument. If the hook succeeds, the
term returned in the Body argument is substituted for
the original test or action. Note that Body cannot span both the
test and the action part, i.e. it cannot contain the
operator. The whole Body will be interpreted either as a
test or as an action, depending on the context of the original
We now give a few examples for breakpoint macros. The last example defines a condition making a predicate invisible, a reformulation of the last example of the previous subsection.
:- multifile user:breakpoint_expansion/2. user:breakpoint_expansion( skip, [inv(I),skip(I)]). user:breakpoint_expansion( gpriv(Value), [goal_private(GP),true(memberchk(Value,GP))]). user:breakpoint_expansion( invisible, [silent,proceed, ( call -> get(mode(M)), gpriv(mymode(M)), skip ; exit -> gpriv(mymode(MM)), mode(MM) ; true )]). | ?- spy(foo/2, -invisible).
We first define the
skip macro, instructing the debugger to skip
the current invocation. This macro is only meaningful in the action
The second clause defines the
gpriv/2 macro, a
generalization of the earlier
mode_memory/1 predicate. For
gpriv(mymode(M)) expands to
goal_private(GP),true(memberchk(mymode(M),GP)). This embodies the
convention of using open-ended lists for the goal private field.
Finally, the last clause implements the action macro
invisible/0, which makes the predicate in question
disappear from the trace. The last line shows how this macro can be used
Below is an alternative implementation of the same macro. Here we use a Prolog predicate that returns the list of action variable settings to be applied at the given port. Notice that a variable can be used as a breakpoint condition, as long as this variable gets instantiated to a (simple or composite) breakpoint condition by the time it is reached in the process of breakpoint evaluation.
user:breakpoint_expansion(invisible, [true(invisible(Settings)),Settings]). invisible([proceed,silent,NewMode]) :- execution_state([mode(M),port(P),inv(Inv),goal_private(GP)]), memberchk(mymode(MM), GP), ( P == call -> MM = M, NewMode = skip(Inv) ; P = exit(_) -> NewMode = MM ; NewMode = M ).
The second hook related to breakpoints is
hook serves for customizing the behavior of the interactive
debugger, i.e. for introducing new interactive debugger commands. The
hook is called for each debugger command read in by the
debugger. DCommand contains the abstract format of the debugger
command read in, as returned by the query facility (see Query Processing). If the hook succeeds, it should return in
Actions an action part to be evaluated as the result of the
If you want to redefine an existing debugger command, you should study
library('SU_messages') to learn the abstract format of this
command, as returned by the query facility. If you want to add a new
command, it suffices to know that unrecognized debugger commands are
Line is the
code-list typed in, with any leading whitespace removed, and
Warning is a warning message.
The following example defines the ‘S’ interactive debugger command to behave as skip at Call and Redo ports, and as creep otherwise:
:- multifile user:debugger_command_hook/2. user:debugger_command_hook(unknown([0'S|_],_), Actions) :- execution_state([port(P),inv(I)]), Actions = [Mode,proceed,silent], ( P = call -> Mode = skip(I) ; P = redo -> Mode = skip(I) ; Mode = trace ).
Note that the
silent action is needed above; otherwise, the
trace message will be printed a second time, before continuing the
library(debugger_examples) contains some of the above
hooks, as well as several others.