mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 23:05:21 +00:00
Estimated hours taken: 40 Implement the expanding of implicit subtrees in the declarative debugger. When the maximum depth is reached by the front end, it now returns to the back end a request for the missing subtree. If the back end receives such a request, it restarts declarative debugging with a different topmost call and a deeper depth bound. The EDT instance needs to know when to request expansion, so CALL nodes need a flag to indicate whether they were at the maximum depth. The front end needs to be able to point out the bug and/or subtree to the back end, so CALL, EXIT and FAIL nodes need to record the event number. browser/declarative_execution.m: - Store the event number in CALL, EXIT and FAIL nodes. - Store a bool in CALL nodes which indicates whether the event was at the maximum depth or not. browser/declarative_debugger.m: - Store the event number of the buggy event in the reported bug, and pass this event number to the back end so it can go back to that event. - Add a case for expanding an implicit tree to the diagnoser_response type, and handle this response properly. - Export procedures to C that allow acces to the diagnoser_response type. - Accommodate the changes to the trace_node type. browser/declarative_analyser.m: - Store the list of previous prime suspects in the analyser state. That way they don't have to be specially dealt with when restarting analysis with an expanded subtree. - When starting analysis, assume the top node is wrong; this is not an unreasonable assumption, and the strategy works better for the case when a subtree is expanded. browser/declarative_user.m: - Accommodate changes to the reported bug. trace/mercury_trace_declarative.c: - Change the depth step size to a reasonable number, now that it works. This also has the effect of testing the change, since some test cases go deeper than the new limit. - Filter events outside the topmost call. Rather than keep track of the minimum depth, we record the topmost call sequence number and use a global to keep track of whether we have entered or left this procedure. - Factor out code in the existing mechanism for starting declarative debugging, so that it can be used to re-start debugging as well. - Accommodate the changes to the trace_node type. - Output error messages if declarative debugging fails to start properly. - Handle the reponse from the diagnoser, by jumping to the buggy event (if a bug is found) or re-executing to expand a subtree (if one is requested). - Add a new checkpoint for events which are filtered out of the annotated trace. trace/mercury_trace_internal.c: - Don't report error messages when declarative debugging fails to start. Errors are now reported by the declarative debugger before returning. tests/debugger/declarative/*.inp: tests/debugger/declarative/*.exp: tests/debugger/declarative/*.exp2: - Update to reflect the removed questions. tests/debugger/declarative/Mmakefile: tests/debugger/declarative/filter.m: tests/debugger/declarative/filter.inp: tests/debugger/declarative/filter.exp: - New test case to cover the code which filters events which are outside the topmost call.
589 lines
18 KiB
Mathematica
589 lines
18 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2000 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.
|
|
%
|
|
|
|
:- module mdb__declarative_debugger.
|
|
:- interface.
|
|
:- import_module io, list, bool, std_util.
|
|
:- import_module mdb__declarative_execution.
|
|
|
|
% 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(
|
|
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(
|
|
decl_atom, % The called atom, in its initial
|
|
% state.
|
|
event_number % The fail event.
|
|
).
|
|
|
|
:- type decl_i_bug
|
|
---> inadmissible_call(
|
|
decl_atom, % The parent atom, in its initial
|
|
% state.
|
|
decl_position, % The location of the call in the
|
|
% parent's body.
|
|
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 this type represent goal behaviour. This representation
|
|
% is used by the front end (in this module), as well as the
|
|
% oracle and user interface.
|
|
%
|
|
:- type decl_question
|
|
% The node is a suspected wrong answer. The
|
|
% argument is the atom in its final state of
|
|
% instantiatedness (ie. at the EXIT event).
|
|
%
|
|
---> wrong_answer(decl_atom)
|
|
|
|
% The node is a suspected missing answer. The
|
|
% first argument is the atom in its initial state
|
|
% of instantiatedness (ie. at the CALL event),
|
|
% and the second argument is the list of solutions.
|
|
%
|
|
; missing_answer(decl_atom, list(decl_atom)).
|
|
|
|
:- type decl_answer == pair(decl_question, decl_truth).
|
|
|
|
:- type decl_atom == trace_atom.
|
|
|
|
% 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),
|
|
% or a fail port (partially uncovered atom).
|
|
%
|
|
---> bug_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__input_stream, io__output_stream,
|
|
diagnoser_state(R)).
|
|
:- mode diagnoser_state_init(in, in, out) is det.
|
|
|
|
:- pred diagnosis(S, R, diagnoser_response, diagnoser_state(R),
|
|
diagnoser_state(R), io__state, io__state)
|
|
<= annotated_trace(S, R).
|
|
:- mode diagnosis(in, in, out, in, out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module require, int, char.
|
|
:- import_module mdb__declarative_analyser, mdb__declarative_oracle.
|
|
|
|
:- type diagnoser_state(R)
|
|
---> diagnoser(
|
|
analyser_state(edt_node(R)),
|
|
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(InStr, OutStr, Diagnoser) :-
|
|
analyser_state_init(Analyser),
|
|
oracle_state_init(InStr, OutStr, Oracle),
|
|
Diagnoser = diagnoser(Analyser, Oracle).
|
|
|
|
diagnosis(Store, NodeId, Response, Diagnoser0, Diagnoser) -->
|
|
{ diagnoser_get_analyser(Diagnoser0, Analyser0) },
|
|
{ start_analysis(wrap(Store), dynamic(NodeId), AnalyserResponse,
|
|
Analyser0, Analyser) },
|
|
{ diagnoser_set_analyser(Diagnoser0, Analyser, Diagnoser1) },
|
|
handle_analyser_response(Store, AnalyserResponse, Response,
|
|
Diagnoser1, Diagnoser).
|
|
|
|
:- pred handle_analyser_response(S, analyser_response(edt_node(R)),
|
|
diagnoser_response, diagnoser_state(R), diagnoser_state(R),
|
|
io__state, io__state) <= annotated_trace(S, R).
|
|
:- mode handle_analyser_response(in, in, out, in, out, di, uo) is det.
|
|
|
|
handle_analyser_response(_, no_suspects, no_bug_found, D, D) -->
|
|
[].
|
|
|
|
handle_analyser_response(_, bug_found(Bug), Response, Diagnoser0,
|
|
Diagnoser) -->
|
|
|
|
confirm_bug(Bug, Response, Diagnoser0, Diagnoser).
|
|
|
|
handle_analyser_response(Store, oracle_queries(Queries), Response,
|
|
Diagnoser0, Diagnoser) -->
|
|
|
|
{ diagnoser_get_oracle(Diagnoser0, Oracle0) },
|
|
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, oracle_response, diagnoser_response,
|
|
diagnoser_state(R), diagnoser_state(R), io__state, io__state)
|
|
<= annotated_trace(S, R).
|
|
:- mode handle_oracle_response(in, in, out, in, out, di, uo) is det.
|
|
|
|
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) },
|
|
handle_analyser_response(Store, AnalyserResponse, Response,
|
|
Diagnoser1, Diagnoser).
|
|
|
|
handle_oracle_response(_, no_oracle_answers, no_bug_found, D, D) -->
|
|
[].
|
|
|
|
handle_oracle_response(_, abort_diagnosis, no_bug_found, D, D) -->
|
|
io__write_string("Diagnosis aborted.\n").
|
|
|
|
:- pred confirm_bug(decl_bug, diagnoser_response, diagnoser_state(R),
|
|
diagnoser_state(R), io__state, io__state).
|
|
:- mode confirm_bug(in, out, in, out, di, uo) is det.
|
|
|
|
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(InStr, OutStr, Diagnoser).
|
|
|
|
% Export a monomorphic version of diagnosis/9, to make it
|
|
% easier to call from C code.
|
|
%
|
|
:- pred diagnosis_store(trace_node_store, trace_node_id, diagnoser_response,
|
|
diagnoser_state(trace_node_id), diagnoser_state(trace_node_id),
|
|
io__state, io__state).
|
|
:- mode diagnosis_store(in, in, out, in, out, di, uo) is det.
|
|
|
|
:- pragma export(diagnosis_store(in, in, out, in, out, di, uo),
|
|
"MR_DD_decl_diagnosis").
|
|
|
|
diagnosis_store(Store, Node, Response, State0, State) -->
|
|
diagnosis(Store, Node, 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_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).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% This section defines an instance of the EDT in terms of
|
|
% any instance of execution tree.
|
|
%
|
|
|
|
:- type edt_node(R)
|
|
---> dynamic(R).
|
|
|
|
:- instance mercury_edt(wrap(S), edt_node(R)) <= annotated_trace(S, R)
|
|
where [
|
|
pred(edt_root_question/3) is trace_root_question,
|
|
pred(edt_root_e_bug/3) is trace_root_e_bug,
|
|
pred(edt_children/3) is trace_children
|
|
].
|
|
|
|
% The wrap/1 around the first argument of the instance is
|
|
% required by the language.
|
|
%
|
|
:- type wrap(S) ---> wrap(S).
|
|
|
|
:- pred trace_root_question(wrap(S), edt_node(R), decl_question)
|
|
<= annotated_trace(S, R).
|
|
:- mode trace_root_question(in, in, out) is det.
|
|
|
|
trace_root_question(wrap(Store), dynamic(Ref), Root) :-
|
|
det_edt_node_from_id(Store, Ref, Node),
|
|
(
|
|
Node = fail(_, CallId, RedoId, _),
|
|
call_node_from_id(Store, CallId, Call),
|
|
Call = call(_, _, CallAtom, _, _, _),
|
|
get_answers(Store, RedoId, [], Answers),
|
|
Root = missing_answer(CallAtom, Answers)
|
|
;
|
|
Node = exit(_, _, _, ExitAtom, _),
|
|
Root = wrong_answer(ExitAtom)
|
|
).
|
|
|
|
:- pred get_answers(S, R, list(decl_atom), list(decl_atom))
|
|
<= annotated_trace(S, R).
|
|
:- mode get_answers(in, in, in, out) is det.
|
|
|
|
get_answers(Store, RedoId, As0, As) :-
|
|
(
|
|
maybe_redo_node_from_id(Store, RedoId, redo(_, ExitId))
|
|
->
|
|
exit_node_from_id(Store, ExitId, exit(_, _, NextId, Atom, _)),
|
|
get_answers(Store, NextId, [Atom | As0], As)
|
|
;
|
|
As = As0
|
|
).
|
|
|
|
:- pred trace_root_e_bug(wrap(S), edt_node(R), decl_e_bug)
|
|
<= annotated_trace(S, R).
|
|
:- mode trace_root_e_bug(in, in, out) is det.
|
|
|
|
trace_root_e_bug(wrap(S), dynamic(Ref), Bug) :-
|
|
det_edt_node_from_id(S, Ref, Node),
|
|
(
|
|
Node = exit(_, _, _, Atom, Event),
|
|
Bug = incorrect_contour(Atom, unit, Event)
|
|
;
|
|
Node = fail(_, CallId, _, Event),
|
|
call_node_from_id(S, CallId, Call),
|
|
Call = call(_, _, CallAtom, _, _, _),
|
|
Bug = partially_uncovered_atom(CallAtom, Event)
|
|
).
|
|
|
|
:- pred trace_children(wrap(S), edt_node(R), list(edt_node(R)))
|
|
<= annotated_trace(S, R).
|
|
:- mode trace_children(in, in, out) is semidet.
|
|
|
|
trace_children(wrap(Store), dynamic(Ref), Children) :-
|
|
det_edt_node_from_id(Store, Ref, Node),
|
|
(
|
|
Node = fail(PrecId, CallId, _, _),
|
|
not_at_depth_limit(Store, CallId),
|
|
missing_answer_children(Store, PrecId, [], Children)
|
|
;
|
|
Node = exit(PrecId, CallId, _, _, _),
|
|
not_at_depth_limit(Store, CallId),
|
|
wrong_answer_children(Store, PrecId, [], Children)
|
|
).
|
|
|
|
:- pred not_at_depth_limit(S, R) <= annotated_trace(S, R).
|
|
:- mode not_at_depth_limit(in, in) is semidet.
|
|
|
|
not_at_depth_limit(Store, Ref) :-
|
|
call_node_from_id(Store, Ref, call(_, _, _, _, _, no)).
|
|
|
|
:- pred wrong_answer_children(S, R, list(edt_node(R)), list(edt_node(R)))
|
|
<= annotated_trace(S, R).
|
|
:- mode wrong_answer_children(in, in, in, out) is det.
|
|
|
|
wrong_answer_children(Store, NodeId, Ns0, Ns) :-
|
|
det_trace_node_from_id(Store, NodeId, Node),
|
|
(
|
|
Node = call(_, _, _, _, _, _),
|
|
Ns = Ns0
|
|
;
|
|
Node = neg(_, _, _),
|
|
Ns = Ns0
|
|
;
|
|
Node = exit(_, Call, _, _, _),
|
|
call_node_from_id(Store, Call, call(Prec, _, _, _, _, _)),
|
|
wrong_answer_children(Store, Prec, [dynamic(NodeId) | Ns0], Ns)
|
|
;
|
|
Node = redo(_, _),
|
|
error("wrong_answer_children: unexpected REDO node")
|
|
;
|
|
Node = fail(_, Call, _, _),
|
|
call_node_from_id(Store, Call, call(Prec, _, _, _, _, _)),
|
|
wrong_answer_children(Store, Prec, [dynamic(NodeId) | Ns0], Ns)
|
|
;
|
|
Node = cond(Prec, _, Flag),
|
|
(
|
|
Flag = succeeded
|
|
->
|
|
wrong_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Ns = Ns0
|
|
)
|
|
;
|
|
Node = switch(Back, _),
|
|
wrong_answer_children(Store, Back, Ns0, Ns)
|
|
;
|
|
Node = first_disj(Back, _),
|
|
wrong_answer_children(Store, Back, Ns0, Ns)
|
|
;
|
|
Node = later_disj(_, _, FirstDisj),
|
|
first_disj_node_from_id(Store, FirstDisj, first_disj(Back, _)),
|
|
wrong_answer_children(Store, Back, Ns0, Ns)
|
|
;
|
|
Node = then(Back, _),
|
|
wrong_answer_children(Store, Back, Ns0, Ns)
|
|
;
|
|
Node = else(Prec, Cond),
|
|
missing_answer_children(Store, Prec, Ns0, Ns1),
|
|
cond_node_from_id(Store, Cond, cond(Back, _, _)),
|
|
wrong_answer_children(Store, Back, Ns1, Ns)
|
|
;
|
|
Node = neg_succ(Prec, Neg),
|
|
missing_answer_children(Store, Prec, Ns0, Ns1),
|
|
neg_node_from_id(Store, Neg, neg(Back, _, _)),
|
|
wrong_answer_children(Store, Back, Ns1, Ns)
|
|
;
|
|
Node = neg_fail(Prec, Neg),
|
|
wrong_answer_children(Store, Prec, Ns0, Ns1),
|
|
neg_node_from_id(Store, Neg, neg(Back, _, _)),
|
|
wrong_answer_children(Store, Back, Ns1, Ns)
|
|
).
|
|
|
|
:- pred missing_answer_children(S, R, list(edt_node(R)), list(edt_node(R)))
|
|
<= annotated_trace(S, R).
|
|
:- mode missing_answer_children(in, in, in, out) is det.
|
|
|
|
missing_answer_children(Store, NodeId, Ns0, Ns) :-
|
|
det_trace_node_from_id(Store, NodeId, Node),
|
|
(
|
|
Node = call(_, _, _, _, _, _),
|
|
Ns = Ns0
|
|
;
|
|
Node = neg(_, _, _),
|
|
Ns = Ns0
|
|
;
|
|
Node = exit(_, Call, Redo, _, _),
|
|
(
|
|
maybe_redo_node_from_id(Store, Redo, redo(Prec0, _))
|
|
->
|
|
Prec = Prec0
|
|
;
|
|
call_node_from_id(Store, Call, CallNode),
|
|
CallNode = call(Prec, _, _, _, _, _)
|
|
),
|
|
missing_answer_children(Store, Prec, [dynamic(NodeId) | Ns0],
|
|
Ns)
|
|
;
|
|
Node = redo(_, Exit),
|
|
exit_node_from_id(Store, Exit, exit(Prec, _, _, _, _)),
|
|
missing_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Node = fail(_, CallId, MaybeRedo, _),
|
|
(
|
|
maybe_redo_node_from_id(Store, MaybeRedo, Redo)
|
|
->
|
|
Redo = redo(Prec, _),
|
|
Next = Prec
|
|
;
|
|
call_node_from_id(Store, CallId, Call),
|
|
Call = call(Back, _, _, _, _, _),
|
|
Next = Back
|
|
),
|
|
missing_answer_children(Store, Next, [dynamic(NodeId) | Ns0],
|
|
Ns)
|
|
;
|
|
Node = cond(Prec, _, Flag),
|
|
(
|
|
Flag = succeeded
|
|
->
|
|
missing_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Ns = Ns0
|
|
)
|
|
;
|
|
Node = switch(Prec, _),
|
|
missing_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Node = first_disj(Prec, _),
|
|
missing_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Node = later_disj(Prec, _, _),
|
|
missing_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Node = then(Prec, _),
|
|
missing_answer_children(Store, Prec, Ns0, Ns)
|
|
;
|
|
Node = else(Prec, Cond),
|
|
missing_answer_children(Store, Prec, Ns0, Ns1),
|
|
cond_node_from_id(Store, Cond, cond(Back, _, _)),
|
|
missing_answer_children(Store, Back, Ns1, Ns)
|
|
;
|
|
Node = neg_succ(Prec, Neg),
|
|
missing_answer_children(Store, Prec, Ns0, Ns1),
|
|
neg_node_from_id(Store, Neg, neg(Back, _, _)),
|
|
missing_answer_children(Store, Back, Ns1, Ns)
|
|
;
|
|
Node = neg_fail(Prec, Neg),
|
|
wrong_answer_children(Store, Prec, Ns0, Ns1),
|
|
neg_node_from_id(Store, Neg, neg(Back, _, _)),
|
|
missing_answer_children(Store, Back, Ns1, Ns)
|
|
).
|
|
|
|
:- pred edt_subtree_details(S, edt_node(R), event_number, sequence_number)
|
|
<= annotated_trace(S, R).
|
|
:- mode edt_subtree_details(in, in, out, out) is det.
|
|
|
|
edt_subtree_details(Store, dynamic(Ref), Event, SeqNo) :-
|
|
det_edt_node_from_id(Store, Ref, Node),
|
|
(
|
|
Node = exit(_, Call, _, _, Event)
|
|
;
|
|
Node = fail(_, Call, _, Event)
|
|
),
|
|
call_node_from_id(Store, Call, call(_, _, _, SeqNo, _, _)).
|
|
|
|
:- inst trace_node_edt_node =
|
|
bound( exit(ground, ground, ground, ground, ground)
|
|
; fail(ground, ground, ground, ground)).
|
|
|
|
:- pred det_edt_node_from_id(S, R, trace_node(R)) <= annotated_trace(S, R).
|
|
:- mode det_edt_node_from_id(in, in, out(trace_node_edt_node)) is det.
|
|
|
|
det_edt_node_from_id(Store, Ref, Node) :-
|
|
(
|
|
trace_node_from_id(Store, Ref, Node0),
|
|
(
|
|
Node0 = exit(_, _, _, _, _)
|
|
;
|
|
Node0 = fail(_, _, _, _)
|
|
)
|
|
->
|
|
Node = Node0
|
|
;
|
|
error("det_edt_node_from_id: not an EXIT or FAIL node")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- 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)
|
|
).
|
|
decl_bug_get_event_number(i_bug(IBug), Event) :-
|
|
IBug = inadmissible_call(_, _, _, Event).
|
|
|