mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 13:55:07 +00:00
Estimated hours taken: 1 Branches: main Add the command 'pd' to the declarative debugger. This command returns to the procedural debugger at the event corresponding to the current question; it is notionally the inverse of the 'dd' command in the procedural debugger. browser/declarative_user.m: Handle the new command, and add a new alternative to the user_response type. browser/declarative_oracle.m: Handle the new user response, and add a new alternative to the oracle_response type. browser/declarative_debugger.m: Handle the new oracle response, and add a new alternative to the diagnoser_response type. Export some procedures to C so that the back end can interpret the new diagnoser response. Update an old comment. trace/mercury_trace_declarative.c: Handle the new diagnoser response. Rename the function MR_decl_handle_bug_found, since it now also handles the case where a symptom has been found. Interpret the diagnoser response using something like a switch, rather than something like an if-then-else. This gives better error messages if the diagnoser response type is changed. doc/user_guide.texi: Document the new command. tests/debugger/declarative/Mmakefile: tests/debugger/declarative/pd.exp: tests/debugger/declarative/pd.inp: tests/debugger/declarative/pd.m: Test the new feature.
570 lines
18 KiB
Mathematica
570 lines
18 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2002 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: declarative_debugger.m
|
|
% Author: Mark Brown
|
|
%
|
|
% This module has two main purposes:
|
|
% - to define the interface between the front and back ends of
|
|
% a Mercury declarative debugger, and
|
|
% - to implement a front end.
|
|
%
|
|
% The interface is defined by a procedure that can be called from
|
|
% the back end to perform diagnosis, and a typeclass which represents
|
|
% a declarative view of execution used by the front end.
|
|
%
|
|
% The front end implemented in this module analyses the EDT it is
|
|
% passed to diagnose a bug. It does this by a simple top-down search.
|
|
%
|
|
% Because Mercury modules are able to be compiled with different levels
|
|
% of tracing, the trace sequences generated by the back end, and passed
|
|
% to the front end as "annotated traces", can include or exclude certain
|
|
% types of events. This front end is able to cope with some variation in
|
|
% the trace events produced, but there are some basic requirements on
|
|
% trace sequences which the back end must meet:
|
|
%
|
|
% 1) if there are any events from a certain class (e.g. interface
|
|
% events, negation events, disj events) then we require all events
|
|
% of that class;
|
|
%
|
|
% 2) if there are any disj events, we require all negation events
|
|
% and if-then-else events.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module mdb__declarative_debugger.
|
|
:- interface.
|
|
:- import_module mdb__declarative_execution, mdb__program_representation.
|
|
:- import_module mdb__io_action.
|
|
:- import_module io, bool, list, std_util, string.
|
|
|
|
% This type represents the possible truth values for nodes
|
|
% in the EDT.
|
|
%
|
|
:- type decl_truth == bool.
|
|
|
|
% This type represents the possible responses to being
|
|
% asked to confirm that a node is a bug.
|
|
%
|
|
:- type decl_confirmation
|
|
---> confirm_bug
|
|
; overrule_bug
|
|
; abort_diagnosis.
|
|
|
|
% This type represents the bugs which can be diagnosed.
|
|
% The parameter of the constructor is the type of EDT nodes.
|
|
%
|
|
:- type decl_bug
|
|
% An EDT whose root node is incorrect,
|
|
% but whose children are all correct.
|
|
%
|
|
---> e_bug(decl_e_bug)
|
|
|
|
% An EDT whose root node is incorrect, and
|
|
% which has no incorrect children but at
|
|
% least one inadmissible one.
|
|
%
|
|
; i_bug(decl_i_bug).
|
|
|
|
:- type decl_e_bug
|
|
---> incorrect_contour(
|
|
final_decl_atom,% The head of the clause, in its
|
|
% final state of instantiation.
|
|
decl_contour, % The path taken through the body.
|
|
event_number % The exit event.
|
|
)
|
|
; partially_uncovered_atom(
|
|
init_decl_atom, % The called atom, in its initial
|
|
% state.
|
|
event_number % The fail event.
|
|
)
|
|
; unhandled_exception(
|
|
init_decl_atom, % The called atom, in its initial
|
|
% state.
|
|
decl_exception, % The exception thrown.
|
|
event_number % The excp event.
|
|
).
|
|
|
|
:- type decl_i_bug
|
|
---> inadmissible_call(
|
|
init_decl_atom, % The parent atom, in its initial
|
|
% state.
|
|
decl_position, % The location of the call in the
|
|
% parent's body.
|
|
init_decl_atom, % The inadmissible child, in its
|
|
% initial state.
|
|
event_number % The call event.
|
|
).
|
|
|
|
% XXX not yet implemented.
|
|
%
|
|
:- type decl_contour == unit.
|
|
:- type decl_position == unit.
|
|
|
|
% Values of the following two types represent questions from the
|
|
% analyser to the oracle about some aspect of program behaviour,
|
|
% and responses from the oracle, respectively. In both cases the
|
|
% type parameter is for the type of EDT nodes -- each question and
|
|
% answer keeps a reference to the node which generated it, so that
|
|
% the analyser is able to figure out what to do when the answer
|
|
% arrives back from the oracle.
|
|
%
|
|
:- type decl_question(T)
|
|
% The node is a suspected wrong answer. The first
|
|
% argument is the EDT node the question came from.
|
|
% The second argument is the atom in its final
|
|
% state of instantiatedness (ie. at the EXIT event).
|
|
%
|
|
---> wrong_answer(T, final_decl_atom)
|
|
|
|
% The node is a suspected missing answer. The
|
|
% first argument is the EDT node the question came
|
|
% from. The second argument is the atom in its
|
|
% initial state of instantiatedness (ie. at the
|
|
% CALL event), and the third argument is the list
|
|
% of solutions.
|
|
%
|
|
; missing_answer(T, init_decl_atom, list(final_decl_atom))
|
|
|
|
% The node is a possibly unexpected exception.
|
|
% The first argument is the EDT node the question
|
|
% came from. The second argument is the atom in
|
|
% its initial state of instantiation, and the third
|
|
% argument is the exception thrown.
|
|
%
|
|
; unexpected_exception(T, init_decl_atom, decl_exception).
|
|
|
|
:- type decl_answer(T)
|
|
% The oracle knows the truth value of this node.
|
|
%
|
|
---> truth_value(T, decl_truth)
|
|
|
|
% The oracle does not say anything about the truth
|
|
% value, but is suspicious of the subterm at the
|
|
% given term_path and arg_pos.
|
|
%
|
|
; suspicious_subterm(T, arg_pos, term_path).
|
|
|
|
% Extract the EDT node from a question.
|
|
%
|
|
:- func get_decl_question_node(decl_question(T)) = T.
|
|
|
|
:- type some_decl_atom
|
|
---> init(init_decl_atom)
|
|
; final(final_decl_atom).
|
|
|
|
:- type init_decl_atom
|
|
---> init_decl_atom(
|
|
init_atom :: trace_atom
|
|
).
|
|
|
|
:- type final_decl_atom
|
|
---> final_decl_atom(
|
|
final_atom :: trace_atom,
|
|
final_io_actions :: list(io_action)
|
|
).
|
|
|
|
:- type decl_exception == univ.
|
|
|
|
% The diagnoser eventually responds with a value of this type
|
|
% after it is called.
|
|
%
|
|
:- type diagnoser_response
|
|
|
|
% There was a bug found and confirmed. The
|
|
% event number is for a call port (inadmissible
|
|
% call), an exit port (incorrect contour),
|
|
% a fail port (partially uncovered atom),
|
|
% or an exception port (unhandled exception).
|
|
%
|
|
---> bug_found(event_number)
|
|
|
|
% There was another symptom of incorrect behaviour
|
|
% found; this symptom will be closer, in a sense,
|
|
% to the location of a bug.
|
|
%
|
|
; symptom_found(event_number)
|
|
|
|
% There was no symptom found, or the diagnoser
|
|
% aborted before finding a bug.
|
|
%
|
|
; no_bug_found
|
|
|
|
% The analyser requires the back end to reproduce
|
|
% part of the annotated trace, with a greater
|
|
% depth bound. The event number and sequence
|
|
% number are for the final event required (the
|
|
% first event required is the call event with
|
|
% the same sequence number).
|
|
%
|
|
; require_subtree(event_number, sequence_number).
|
|
|
|
:- type diagnoser_state(R).
|
|
|
|
:- pred diagnoser_state_init(io_action_map::in, io__input_stream::in,
|
|
io__output_stream::in, diagnoser_state(R)::out) is det.
|
|
|
|
:- pred diagnosis(S::in, R::in, int::in, int::in, int::in,
|
|
diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
:- pred unravel_decl_atom(some_decl_atom::in, trace_atom::out,
|
|
list(io_action)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The diagnoser generates exceptions of the following type.
|
|
%
|
|
:- type diagnoser_exception
|
|
---> internal_error(
|
|
string, % predicate/function name
|
|
string % error message
|
|
)
|
|
; io_error(
|
|
string, % predicate/function name
|
|
string % error message
|
|
)
|
|
; unimplemented_feature(
|
|
string % feature that is NYI
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module mdb__declarative_analyser, mdb__declarative_oracle.
|
|
:- import_module mdb__declarative_tree.
|
|
:- import_module exception, int, map.
|
|
|
|
unravel_decl_atom(DeclAtom, TraceAtom, IoActions) :-
|
|
(
|
|
DeclAtom = init(init_decl_atom(TraceAtom)),
|
|
IoActions = []
|
|
;
|
|
DeclAtom = final(final_decl_atom(TraceAtom, IoActions))
|
|
).
|
|
|
|
get_decl_question_node(wrong_answer(Node, _)) = Node.
|
|
get_decl_question_node(missing_answer(Node, _, _)) = Node.
|
|
get_decl_question_node(unexpected_exception(Node, _, _)) = Node.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type diagnoser_state(R)
|
|
---> diagnoser(
|
|
analyser_state :: analyser_state(edt_node(R)),
|
|
oracle_state :: oracle_state
|
|
).
|
|
|
|
:- pred diagnoser_get_analyser(diagnoser_state(R),
|
|
analyser_state(edt_node(R))).
|
|
:- mode diagnoser_get_analyser(in, out) is det.
|
|
|
|
diagnoser_get_analyser(diagnoser(Analyser, _), Analyser).
|
|
|
|
:- pred diagnoser_set_analyser(diagnoser_state(R), analyser_state(edt_node(R)),
|
|
diagnoser_state(R)).
|
|
:- mode diagnoser_set_analyser(in, in, out) is det.
|
|
|
|
diagnoser_set_analyser(diagnoser(_, B), A, diagnoser(A, B)).
|
|
|
|
:- pred diagnoser_get_oracle(diagnoser_state(R), oracle_state).
|
|
:- mode diagnoser_get_oracle(in, out) is det.
|
|
|
|
diagnoser_get_oracle(diagnoser(_, Oracle), Oracle).
|
|
|
|
:- pred diagnoser_set_oracle(diagnoser_state(R), oracle_state,
|
|
diagnoser_state(R)).
|
|
:- mode diagnoser_set_oracle(in, in, out) is det.
|
|
|
|
diagnoser_set_oracle(diagnoser(A, _), B, diagnoser(A, B)).
|
|
|
|
diagnoser_state_init(IoActionMap, InStr, OutStr, Diagnoser) :-
|
|
analyser_state_init(IoActionMap, Analyser),
|
|
oracle_state_init(InStr, OutStr, Oracle),
|
|
Diagnoser = diagnoser(Analyser, Oracle).
|
|
|
|
diagnosis(Store, NodeId, UseOldIoActionMap, IoActionStart, IoActionEnd,
|
|
Response, Diagnoser0, Diagnoser) -->
|
|
( { UseOldIoActionMap > 0 } ->
|
|
{ Diagnoser1 = Diagnoser0 }
|
|
;
|
|
make_io_action_map(IoActionStart, IoActionEnd, IoActionMap),
|
|
{ Analyser0 = Diagnoser0 ^ analyser_state },
|
|
{ analyser_state_replace_io_map(IoActionMap,
|
|
Analyser0, Analyser1) },
|
|
{ Diagnoser1 = Diagnoser0 ^ analyser_state := Analyser1 }
|
|
),
|
|
try_io(diagnosis_2(Store, NodeId, Diagnoser1), Result),
|
|
(
|
|
{ Result = succeeded({Response, Diagnoser}) }
|
|
;
|
|
{ Result = exception(UnivException) },
|
|
(
|
|
{ univ_to_type(UnivException, DiagnoserException) }
|
|
->
|
|
handle_diagnoser_exception(DiagnoserException,
|
|
Response, Diagnoser1, Diagnoser)
|
|
;
|
|
{ rethrow(Result) }
|
|
)
|
|
).
|
|
|
|
:- pred diagnosis_2(S::in, R::in, diagnoser_state(R)::in,
|
|
{diagnoser_response, diagnoser_state(R)}::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
diagnosis_2(Store, NodeId, Diagnoser0, {Response, Diagnoser}) -->
|
|
{ Analyser0 = Diagnoser0 ^ analyser_state },
|
|
{ start_analysis(wrap(Store), dynamic(NodeId), AnalyserResponse,
|
|
Analyser0, Analyser) },
|
|
{ diagnoser_set_analyser(Diagnoser0, Analyser, Diagnoser1) },
|
|
{ debug_analyser_state(Analyser, MaybeOrigin) },
|
|
handle_analyser_response(Store, AnalyserResponse, MaybeOrigin,
|
|
Response, Diagnoser1, Diagnoser).
|
|
|
|
:- pred handle_analyser_response(S::in, analyser_response(edt_node(R))::in,
|
|
maybe(subterm_origin(edt_node(R)))::in, diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
handle_analyser_response(_, no_suspects, _, no_bug_found, D, D) -->
|
|
io__write_string("No bug found.\n").
|
|
|
|
handle_analyser_response(_, bug_found(Bug), _, Response, Diagnoser0,
|
|
Diagnoser) -->
|
|
|
|
confirm_bug(Bug, Response, Diagnoser0, Diagnoser).
|
|
|
|
handle_analyser_response(Store, oracle_queries(Queries), MaybeOrigin, Response,
|
|
Diagnoser0, Diagnoser) -->
|
|
{ diagnoser_get_oracle(Diagnoser0, Oracle0) },
|
|
debug_origin(Flag),
|
|
(
|
|
{ MaybeOrigin = yes(Origin) },
|
|
{ Flag > 0 }
|
|
->
|
|
io__write_string("Origin: "),
|
|
write_origin(wrap(Store), Origin),
|
|
io__nl
|
|
;
|
|
[]
|
|
),
|
|
query_oracle(Queries, OracleResponse, Oracle0, Oracle),
|
|
{ diagnoser_set_oracle(Diagnoser0, Oracle, Diagnoser1) },
|
|
handle_oracle_response(Store, OracleResponse, Response, Diagnoser1,
|
|
Diagnoser).
|
|
|
|
handle_analyser_response(Store, require_explicit(Tree), _, Response,
|
|
Diagnoser, Diagnoser) -->
|
|
{
|
|
edt_subtree_details(Store, Tree, Event, Seqno),
|
|
Response = require_subtree(Event, Seqno)
|
|
}.
|
|
|
|
:- pred handle_oracle_response(S::in, oracle_response(edt_node(R))::in,
|
|
diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
handle_oracle_response(Store, oracle_answers(Answers), Response, Diagnoser0,
|
|
Diagnoser) -->
|
|
{ diagnoser_get_analyser(Diagnoser0, Analyser0) },
|
|
{ continue_analysis(wrap(Store), Answers, AnalyserResponse,
|
|
Analyser0, Analyser) },
|
|
{ diagnoser_set_analyser(Diagnoser0, Analyser, Diagnoser1) },
|
|
{ debug_analyser_state(Analyser, MaybeOrigin) },
|
|
handle_analyser_response(Store, AnalyserResponse, MaybeOrigin,
|
|
Response, Diagnoser1, Diagnoser).
|
|
|
|
handle_oracle_response(_, no_oracle_answers, no_bug_found, D, D) -->
|
|
[].
|
|
|
|
handle_oracle_response(Store, exit_diagnosis(Node), Response, D, D) -->
|
|
{ edt_subtree_details(Store, Node, Event, _) },
|
|
{ Response = symptom_found(Event) }.
|
|
|
|
handle_oracle_response(_, abort_diagnosis, no_bug_found, D, D) -->
|
|
io__write_string("Diagnosis aborted.\n").
|
|
|
|
:- pred confirm_bug(decl_bug::in, diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi.
|
|
|
|
confirm_bug(Bug, Response, Diagnoser0, Diagnoser) -->
|
|
{ diagnoser_get_oracle(Diagnoser0, Oracle0) },
|
|
oracle_confirm_bug(Bug, Confirmation, Oracle0, Oracle),
|
|
{ diagnoser_set_oracle(Diagnoser0, Oracle, Diagnoser) },
|
|
{
|
|
Confirmation = confirm_bug,
|
|
decl_bug_get_event_number(Bug, Event),
|
|
Response = bug_found(Event)
|
|
;
|
|
Confirmation = overrule_bug,
|
|
Response = no_bug_found
|
|
;
|
|
Confirmation = abort_diagnosis,
|
|
Response = no_bug_found
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Export a monomorphic version of diagnosis_state_init/4, to
|
|
% make it easier to call from C code.
|
|
%
|
|
:- pred diagnoser_state_init_store(io__input_stream, io__output_stream,
|
|
diagnoser_state(trace_node_id)).
|
|
:- mode diagnoser_state_init_store(in, in, out) is det.
|
|
|
|
:- pragma export(diagnoser_state_init_store(in, in, out),
|
|
"MR_DD_decl_diagnosis_state_init").
|
|
|
|
diagnoser_state_init_store(InStr, OutStr, Diagnoser) :-
|
|
diagnoser_state_init(map__init, InStr, OutStr, Diagnoser).
|
|
|
|
% Export a monomorphic version of diagnosis/10, to make it
|
|
% easier to call from C code.
|
|
%
|
|
:- pred diagnosis_store(trace_node_store::in, trace_node_id::in,
|
|
int::in, int::in, int::in, diagnoser_response::out,
|
|
diagnoser_state(trace_node_id)::in,
|
|
diagnoser_state(trace_node_id)::out, io__state::di, io__state::uo)
|
|
is cc_multi.
|
|
|
|
:- pragma export(diagnosis_store(in, in, in, in, in, out, in, out, di, uo),
|
|
"MR_DD_decl_diagnosis").
|
|
|
|
diagnosis_store(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
|
|
Response, State0, State) -->
|
|
diagnosis(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
|
|
Response, State0, State).
|
|
|
|
% Export some predicates so that C code can interpret the
|
|
% diagnoser response.
|
|
%
|
|
:- pred diagnoser_bug_found(diagnoser_response, event_number).
|
|
:- mode diagnoser_bug_found(in, out) is semidet.
|
|
|
|
:- pragma export(diagnoser_bug_found(in, out), "MR_DD_diagnoser_bug_found").
|
|
|
|
diagnoser_bug_found(bug_found(Event), Event).
|
|
|
|
:- pred diagnoser_symptom_found(diagnoser_response, event_number).
|
|
:- mode diagnoser_symptom_found(in, out) is semidet.
|
|
|
|
:- pragma export(diagnoser_symptom_found(in, out),
|
|
"MR_DD_diagnoser_symptom_found").
|
|
|
|
diagnoser_symptom_found(symptom_found(Event), Event).
|
|
|
|
:- pred diagnoser_no_bug_found(diagnoser_response).
|
|
:- mode diagnoser_no_bug_found(in) is semidet.
|
|
|
|
:- pragma export(diagnoser_no_bug_found(in), "MR_DD_diagnoser_no_bug_found").
|
|
|
|
diagnoser_no_bug_found(no_bug_found).
|
|
|
|
:- pred diagnoser_require_subtree(diagnoser_response, event_number,
|
|
sequence_number).
|
|
:- mode diagnoser_require_subtree(in, out, out) is semidet.
|
|
|
|
:- pragma export(diagnoser_require_subtree(in, out, out),
|
|
"MR_DD_diagnoser_require_subtree").
|
|
|
|
diagnoser_require_subtree(require_subtree(Event, SeqNo), Event, SeqNo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred handle_diagnoser_exception(diagnoser_exception::in,
|
|
diagnoser_response::out, diagnoser_state(R)::in,
|
|
diagnoser_state(R)::out, io__state::di, io__state::uo) is det.
|
|
|
|
handle_diagnoser_exception(internal_error(Loc, Msg), Response, D, D) -->
|
|
io__stderr_stream(StdErr),
|
|
io__write_strings(StdErr, [
|
|
"An internal error has occurred; diagnosis will be aborted. Debugging\n",
|
|
"message follows:\n",
|
|
Loc, ": ", Msg, "\n",
|
|
"Please report bugs to mercury-bugs@cs.mu.oz.au.\n"]),
|
|
{ Response = no_bug_found }.
|
|
|
|
handle_diagnoser_exception(io_error(Loc, Msg), Response, D, D) -->
|
|
io__stderr_stream(StdErr),
|
|
io__write_strings(StdErr, [
|
|
"I/O error: ", Loc, ": ", Msg, ".\n",
|
|
"Diagnosis will be aborted.\n"]),
|
|
{ Response = no_bug_found }.
|
|
|
|
handle_diagnoser_exception(unimplemented_feature(Feature), Response, D, D) -->
|
|
io__write_strings([
|
|
"Sorry, the diagnosis cannot continue because it requires support for\n",
|
|
"the following: ", Feature, ".\n",
|
|
"The debugger is a work in progress, and this is not supported in the\n",
|
|
"current version.\n"]),
|
|
{ Response = no_bug_found }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred decl_bug_get_event_number(decl_bug, event_number).
|
|
:- mode decl_bug_get_event_number(in, out) is det.
|
|
|
|
decl_bug_get_event_number(e_bug(EBug), Event) :-
|
|
(
|
|
EBug = incorrect_contour(_, _, Event)
|
|
;
|
|
EBug = partially_uncovered_atom(_, Event)
|
|
;
|
|
EBug = unhandled_exception(_, _, Event)
|
|
).
|
|
decl_bug_get_event_number(i_bug(IBug), Event) :-
|
|
IBug = inadmissible_call(_, _, _, Event).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred write_origin(wrap(S)::in, subterm_origin(edt_node(R))::in,
|
|
io__state::di, io__state::uo) is det <= annotated_trace(S, R).
|
|
|
|
write_origin(wrap(Store), Origin) -->
|
|
( { Origin = output(dynamic(NodeId), ArgPos, TermPath) } ->
|
|
{ exit_node_from_id(Store, NodeId, ExitNode) },
|
|
{ ProcName = ExitNode ^ exit_atom ^ proc_name },
|
|
io__write_string("output("),
|
|
io__write_string(ProcName),
|
|
io__write_string(", "),
|
|
io__write(ArgPos),
|
|
io__write_string(", "),
|
|
io__write(TermPath),
|
|
io__write_string(")")
|
|
;
|
|
io__write(Origin)
|
|
).
|
|
|
|
:- pragma foreign_code("C",
|
|
"
|
|
|
|
/*
|
|
** The declarative debugger will print diagnostic information about the origins
|
|
** computed by dependency tracking if this flag has a positive value.
|
|
*/
|
|
|
|
int MR_DD_debug_origin = 0;
|
|
|
|
").
|
|
|
|
:- pragma foreign_decl("C",
|
|
"
|
|
extern int MR_DD_debug_origin;
|
|
").
|
|
|
|
:- pred debug_origin(int::out, io__state::di, io__state::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
debug_origin(Flag::out, IO0::di, IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io],
|
|
"
|
|
Flag = MR_DD_debug_origin;
|
|
IO = IO0;
|
|
").
|