mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-20 03:43:51 +00:00
Estimated hours taken: 40 Branches: main This is the second part of a change to support term dependency analysis in the declarative debugger. A `mark' command is implemented for the term browser, which allows a particular subterm to be selected and returned from the browser. The declarative debugger interprets this as a suspicious subterm, and tries to find a child or sibling node from which this subterm comes. This is used to determine the next question to be asked of the oracle. browser/browse.m: Update the browser interface to allow for marked subterms being returned from the browser. Implement and document the mark command. Rewrite run_command as a switch instead of a chain of if-then-elses. This forces all unimplemented commands to be explicitly listed, and gives better error checking. browser/browser_info.m: Add a maybe_mark field to the browser_info. It is initially `no', but is updated when the mark command is given. browser/declarative_analyser.m: Select which child or sibling node to ask about next by searching for the origin of the suspicious subterm. If the subterm has mode `out' we act as if the oracle had answered no, and if the subterm has mode `in' we act as if the oracle had answered yes. In future we may not wish to presume this -- we do so now mainly to keep the analysis algorithm simpler. browser/declarative_debugger.m: Add a functor for suspicious subterms to the decl_answer type. browser/declarative_oracle.m: Accommodate the changed answer type. The oracle does not try to store information about suspicious subterms in the knowledge base, because in principle this could lead to infinite loops (although currently this wouldn't be a problem since we don't ever use the information to move upward in the tree, so no cycle could be formed). browser/declarative_user.m: Accommodate the changed answer type, and interpret marked terms from the browser as suspicious subterms. browser/parse.m: Add the new command. browser/program_representation.m: Add a procedure to convert the browser's list(dir) to a term_path. Change atomic_goal_rep_is_call/2 so it fails for special predicates, which was originally intended. trace/mercury_trace_browse.c: Ignore the extra argument -- marked terms are not currently used in the main debugger. tests/debugger/declarative/Mmakefile: tests/debugger/declarative/input_term_dep.*: tests/debugger/declarative/output_term_dep.*: tests/debugger/declarative/special_term_dep.*: New test cases.
221 lines
6.8 KiB
Mathematica
221 lines
6.8 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2001 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: program_representation.m
|
|
% Authors: zs, dougl
|
|
%
|
|
% This module defines the representation of procedure bodies
|
|
% used by the declarative debugger.
|
|
%
|
|
% One of the things we want the declarative debugger to be able to do
|
|
% is to let the user specify which part of which output argument of an
|
|
% incorrect or inadmissible atom is suspicious, and then find out where
|
|
% that particular subterm came from, i.e. where it was bound. Doing this
|
|
% requires knowing what the bodies of that procedure and its descendants are.
|
|
%
|
|
% If the Mercury compiler is invoked with options requesting declarative
|
|
% debugging, it will include in each procedure layout a pointer to a simplified
|
|
% representation of the goal that is the body of the corresponding procedure.
|
|
% We use a simplified representation partly because we want to insulate the
|
|
% code of the declarative debugger from irrelevant changes in HLDS types,
|
|
% and partly because we want to minimize the space taken in up in executables
|
|
% by these representations.
|
|
%
|
|
% The current representation is intended to contain all the information
|
|
% we are pretty sure can be usefully exploited by the declarative debugger.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module mdb__program_representation.
|
|
|
|
:- interface.
|
|
|
|
:- import_module list, std_util.
|
|
:- import_module mdb__browser_info.
|
|
|
|
% A representation of the goal we execute. These need to be
|
|
% generated statically and stored inside the executable.
|
|
%
|
|
% Each element of this structure will correspond one-to-one
|
|
% to the original stage 90 HLDS.
|
|
|
|
:- type goal_rep
|
|
---> conj_rep(
|
|
list(goal_rep) % The conjuncts in the original
|
|
% order.
|
|
)
|
|
; disj_rep(
|
|
list(goal_rep) % The disjuncts in the original
|
|
% order.
|
|
)
|
|
; switch_rep(
|
|
list(goal_rep) % The switch arms in the
|
|
% original order.
|
|
)
|
|
; ite_rep(
|
|
goal_rep, % Condition.
|
|
goal_rep, % Then branch.
|
|
goal_rep % Else branch.
|
|
)
|
|
; negation_rep(
|
|
goal_rep % The negated goal.
|
|
)
|
|
; some_rep(
|
|
goal_rep % The quantified goal.
|
|
)
|
|
; atomic_goal_rep(
|
|
detism_rep,
|
|
string, % Filename of context.
|
|
int, % Line number of context.
|
|
list(var_rep), % The sorted list of the
|
|
% variables bound by the
|
|
% atomic goal.
|
|
atomic_goal_rep
|
|
).
|
|
|
|
:- type atomic_goal_rep
|
|
---> unify_construct_rep(
|
|
var_rep,
|
|
cons_id_rep,
|
|
list(var_rep)
|
|
)
|
|
; unify_deconstruct_rep(
|
|
var_rep,
|
|
cons_id_rep,
|
|
list(var_rep)
|
|
)
|
|
; unify_assign_rep(
|
|
var_rep, % target
|
|
var_rep % source
|
|
)
|
|
; unify_simple_test_rep(
|
|
var_rep,
|
|
var_rep
|
|
)
|
|
; pragma_foreign_code_rep(
|
|
list(var_rep) % arguments
|
|
)
|
|
; higher_order_call_rep(
|
|
var_rep, % the closure to call
|
|
list(var_rep) % arguments
|
|
)
|
|
; method_call_rep(
|
|
var_rep, % typeclass info var
|
|
int, % method number
|
|
list(var_rep) % arguments
|
|
)
|
|
; plain_call_rep(
|
|
string, % name of called pred
|
|
list(var_rep) % arguments
|
|
).
|
|
|
|
:- type var_rep == int.
|
|
|
|
:- type cons_id_rep == string.
|
|
|
|
:- type detism_rep
|
|
---> det_rep
|
|
; semidet_rep
|
|
; nondet_rep
|
|
; multidet_rep
|
|
; cc_nondet_rep
|
|
; cc_multidet_rep
|
|
; erroneous_rep
|
|
; failure_rep.
|
|
|
|
% If the given atomic goal is a call to a predicate or function
|
|
% (not including the special predicates `unify' and `compare'),
|
|
% then return the list of variables that are passed as arguments.
|
|
%
|
|
:- pred atomic_goal_rep_is_call(atomic_goal_rep, list(var_rep)).
|
|
:- mode atomic_goal_rep_is_call(in, out) is semidet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The following three types are derived from compiler/hlds_goal.m.
|
|
|
|
:- type goal_path == list(goal_path_step).
|
|
|
|
:- type goal_path_step ---> conj(int)
|
|
; disj(int)
|
|
; switch(int)
|
|
; ite_cond
|
|
; ite_then
|
|
; ite_else
|
|
; neg
|
|
; exist(maybe_cut)
|
|
; first
|
|
; later.
|
|
|
|
:- type maybe_cut ---> cut ; no_cut.
|
|
|
|
:- pred path_step_from_string(string, goal_path_step).
|
|
:- mode path_step_from_string(in, out) is semidet.
|
|
|
|
% Head variables are represented by a number from 1..N,
|
|
% where N is the arity.
|
|
|
|
:- type arg_pos == var_rep.
|
|
|
|
% A particular subterm within a term is represented by a term_path.
|
|
% This is the list of argument positions that need to be followed
|
|
% in order to travel from the root to the subterm. In contrast to
|
|
% goal_paths, this list is in top-down order.
|
|
|
|
:- type term_path == list(arg_pos).
|
|
|
|
:- pred convert_dirs_to_term_path(list(dir), term_path).
|
|
:- mode convert_dirs_to_term_path(in, out) is det.
|
|
|
|
% Returns type_of(_ `with_type` goal_rep), for use in C code.
|
|
:- func goal_rep_type = type_desc.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module string, char, require.
|
|
|
|
atomic_goal_rep_is_call(pragma_foreign_code_rep(Args), Args).
|
|
atomic_goal_rep_is_call(higher_order_call_rep(_, Args), Args).
|
|
atomic_goal_rep_is_call(method_call_rep(_, _, Args), Args).
|
|
atomic_goal_rep_is_call(plain_call_rep(Name, Args), Args) :-
|
|
Name \= "unify",
|
|
Name \= "compare".
|
|
|
|
path_step_from_string(String, Step) :-
|
|
string__first_char(String, First, Rest),
|
|
path_step_from_string_2(First, Rest, Step).
|
|
|
|
:- pred path_step_from_string_2(char, string, goal_path_step).
|
|
:- mode path_step_from_string_2(in, in, out) is semidet.
|
|
|
|
path_step_from_string_2('c', NStr, conj(N)) :-
|
|
string__to_int(NStr, N).
|
|
path_step_from_string_2('d', NStr, disj(N)) :-
|
|
string__to_int(NStr, N).
|
|
path_step_from_string_2('s', NStr, switch(N)) :-
|
|
string__to_int(NStr, N).
|
|
path_step_from_string_2('?', "", ite_cond).
|
|
path_step_from_string_2('t', "", ite_then).
|
|
path_step_from_string_2('e', "", ite_else).
|
|
path_step_from_string_2('~', "", neg).
|
|
path_step_from_string_2('q', "!", exist(cut)).
|
|
path_step_from_string_2('q', "", exist(no_cut)).
|
|
path_step_from_string_2('f', "", first).
|
|
path_step_from_string_2('l', "", later).
|
|
|
|
convert_dirs_to_term_path([], []).
|
|
convert_dirs_to_term_path([child(N) | Dirs], [N | TermPath]) :-
|
|
convert_dirs_to_term_path(Dirs, TermPath).
|
|
convert_dirs_to_term_path([parent | _], _) :-
|
|
error("convert_dirs_to_term_path: not in canonical form").
|
|
|
|
:- pragma export(goal_rep_type = out, "ML_goal_rep_type").
|
|
goal_rep_type = type_of(_ `with_type` goal_rep).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|