mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
Estimated hours taken: 12 Branches: main Move the mdbcomp library to its own directory. To make this change less painful to test, improve the way we handle installs. browser/mdbcomp.m: browser/mer_mdbcomp.m: browser/prim_data.m: browser/program_representation.m: browser/trace_counts.m: Move these files to the mdbcomp directory. browser/Mmakefile: browser/Mercury.options: mdbcomp/Mmakefile: mdbcomp/Mercury.options: Split the contents of the old Mmakefile and Mercury.options file in the browser directory between these files as appropriate. Simplify away the stuff not needed now that there is only one library per directory. Make the browser directory see the relevant files from the mdbcomp directory. Mmake.common.in: Separate out the prefixes allowed in the browser and the mdbcomp directories. Mmake.workspace: Set up a make variable to refer to the mdbcomp directory. Adjust references to the mdbcomp library to point to its new location. Mmakefile: Make invocations visit the mdbcomp library as necessary. Improve the way we install grades. Making temporary backups of the directories modified by the install process is unsatisfactory for two reasons. First, if the install fails, the cleanup script, which is necessary for user friendliness, destroys any evidence of the cause. Second, the restore of the backup wasn't perfect, e.g. it left the .d files modified to depend on .mih files, which don't exist in LLDS grades, and also left altered timestamps. This diff changes the install process to make a single tmp_dir subdirectory of the workspace, with all the work of install_grade being done inside tmp_dir. The original directories aren't touched at all. */Mmakefile: Adjust references to the browser directory to refer to the mdbcomp directory instead or as well. scripts/Mmake.rules: */Mmakefile: Make it easier to debug Mmakefiles. Previously, creating a Mmake.makefile with mmake -s and invoking "make -d" ignored the most fundamental rules of mmake, because Mmake.rules was treating an unset MMAKE_USE_MMC_MAKE as if it were set to "yes", simply because it was different from "no". This diff changes it to treat an unset MMAKE_USE_MMC_MAKE as if it were set to "no", which is a more sensible default. scripts/prepare_tmp_dir_fixed_part.in: scripts/scripts/prepare_tmp_dir_grade_part: Two new scripts that each do half the work of preparing tmp_dir for the real work of the install_grade make target. The fixed_part script prepares the parts of tmp_dir that are grade-independent, while the grade_part scripts prepares the parts that are grade-dependent. configure.in: Test C files in the mdbcomp directory to see whether they need to be recompiled after reconfiguration. Create prepare_tmp_dir_fixed_part from prepare_tmp_dir_fixed_part.in. compiler/*.m: runtime/mercury_wrapper.c: Update the references to the moved files. compiler/notes/overall_design.html: Mention the new directory.
348 lines
11 KiB
Mathematica
348 lines
11 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2001-2005 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 mdbcomp.program_representation.
|
|
|
|
:- interface.
|
|
|
|
:- import_module char, list, std_util, bool.
|
|
|
|
% 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 proc_rep
|
|
---> proc_rep(
|
|
list(var_rep), % The head variables, in order,
|
|
% including the ones introduced
|
|
% by the compiler.
|
|
goal_rep % The procedure body.
|
|
).
|
|
|
|
:- 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.
|
|
maybe_cut
|
|
)
|
|
; 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
|
|
)
|
|
; unsafe_cast_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) % the call's plain arguments
|
|
)
|
|
; method_call_rep(
|
|
var_rep, % typeclass info var
|
|
int, % method number
|
|
list(var_rep) % the call's plain arguments
|
|
)
|
|
; plain_call_rep(
|
|
string, % name of called pred's module
|
|
string, % name of the called pred
|
|
list(var_rep) % the call's arguments
|
|
)
|
|
; builtin_call_rep(
|
|
string, % name of called pred's module
|
|
string, % name of the called pred
|
|
list(var_rep) % the call's 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 behaves like a call in the sense that it
|
|
% generates events, then return the list of variables that are passed
|
|
% as arguments.
|
|
%
|
|
:- func atomic_goal_generates_event(atomic_goal_rep) = maybe(list(var_rep)).
|
|
|
|
% If the given goal generates internal events directly then this
|
|
% function will return yes and no otherwise.
|
|
%
|
|
:- func goal_generates_internal_event(goal_rep) = bool.
|
|
|
|
% call_is_primitive(ModuleName, PredName): succeeds iff a call to the
|
|
% named predicate behaves like a primitive operation, in the sense that
|
|
% it does not generate events.
|
|
:- pred call_is_primitive(string::in, string::in) is semidet.
|
|
|
|
% The atomic goals module, name and arity
|
|
:- type atomic_goal_id
|
|
---> atomic_goal_id(string, string, int).
|
|
|
|
% Can we find out the atomic goals name, module and arity from
|
|
% its atomic_goal_rep? If so return them, otherwise return no.
|
|
:- func atomic_goal_identifiable(atomic_goal_rep) =
|
|
maybe(atomic_goal_id).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% 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.
|
|
|
|
% Does `some G' have a different determinism from plain `G'?
|
|
:- type maybe_cut ---> cut ; no_cut.
|
|
|
|
:- pred path_from_string_det(string, goal_path).
|
|
:- mode path_from_string_det(in, out) is det.
|
|
|
|
:- pred path_from_string(string, goal_path).
|
|
:- mode path_from_string(in, out) is semidet.
|
|
|
|
:- pred path_step_from_string(string, goal_path_step).
|
|
:- mode path_step_from_string(in, out) is semidet.
|
|
|
|
:- pred is_path_separator(char).
|
|
:- mode is_path_separator(in) is semidet.
|
|
|
|
% User-visible head variables are represented by a number from 1..N,
|
|
% where N is the user-visible arity.
|
|
%
|
|
% Both user-visible and compiler-generated head variables can be
|
|
% referred to via their position in the full list of head variables;
|
|
% the first head variable is at position 1.
|
|
|
|
:- type arg_pos
|
|
---> user_head_var(int) % Nth in the list of arguments after
|
|
% filtering out non-user-visible vars.
|
|
; any_head_var(int) % Nth in the list of all arguments.
|
|
|
|
% (M-N+1)th argument in the list of all arguments,
|
|
% where N is the value of the int in the constructor
|
|
% and M is the total number of arguments.
|
|
; any_head_var_from_back(int).
|
|
|
|
% 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(int).
|
|
|
|
% Returns type_of(_ `with_type` proc_rep), for use in C code.
|
|
:- func proc_rep_type = type_desc.
|
|
|
|
% 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_generates_event(unify_construct_rep(_, _, _)) = no.
|
|
atomic_goal_generates_event(unify_deconstruct_rep(_, _, _)) = no.
|
|
atomic_goal_generates_event(unify_assign_rep(_, _)) = no.
|
|
atomic_goal_generates_event(unify_simple_test_rep(_, _)) = no.
|
|
atomic_goal_generates_event(unsafe_cast_rep(_, _)) = no.
|
|
atomic_goal_generates_event(pragma_foreign_code_rep(_)) = no.
|
|
atomic_goal_generates_event(higher_order_call_rep(_, Args)) = yes(Args).
|
|
atomic_goal_generates_event(method_call_rep(_, _, Args)) = yes(Args).
|
|
atomic_goal_generates_event(builtin_call_rep(_, _, _)) = no.
|
|
atomic_goal_generates_event(plain_call_rep(ModuleName, PredName, Args)) =
|
|
( call_is_primitive(ModuleName, PredName) ->
|
|
% These calls behave as primitives and do not generate events.
|
|
no
|
|
;
|
|
yes(Args)
|
|
).
|
|
|
|
call_is_primitive(ModuleName, PredName) :-
|
|
(
|
|
ModuleName = "builtin",
|
|
( PredName = "unify"
|
|
; PredName = "compare"
|
|
)
|
|
;
|
|
ModuleName = "profiling_builtin"
|
|
;
|
|
ModuleName = "term_size_prof_builtin"
|
|
;
|
|
%
|
|
% The following are also treated as primitive since
|
|
% compiler generated predicate events are not
|
|
% included in the annotated trace at the moment.
|
|
%
|
|
PredName = "__Unify__"
|
|
;
|
|
PredName = "__Index__"
|
|
;
|
|
PredName = "__Compare__"
|
|
).
|
|
|
|
goal_generates_internal_event(conj_rep(_)) = no.
|
|
goal_generates_internal_event(disj_rep(_)) = yes.
|
|
goal_generates_internal_event(switch_rep(_)) = yes.
|
|
goal_generates_internal_event(ite_rep(_, _, _)) = yes.
|
|
goal_generates_internal_event(negation_rep(_)) = yes.
|
|
goal_generates_internal_event(some_rep(_, _)) = no.
|
|
% Atomic goals may generate interface events, not internal events.
|
|
goal_generates_internal_event(atomic_goal_rep(_, _, _, _, _)) = no.
|
|
|
|
atomic_goal_identifiable(unify_construct_rep(_, _, _)) = no.
|
|
atomic_goal_identifiable(unify_deconstruct_rep(_, _, _)) = no.
|
|
atomic_goal_identifiable(unify_assign_rep(_, _)) = no.
|
|
atomic_goal_identifiable(unify_simple_test_rep(_, _)) = no.
|
|
atomic_goal_identifiable(unsafe_cast_rep(_, _)) = no.
|
|
atomic_goal_identifiable(pragma_foreign_code_rep(_)) = no.
|
|
atomic_goal_identifiable(higher_order_call_rep(_, _)) = no.
|
|
atomic_goal_identifiable(method_call_rep(_, _, _)) = no.
|
|
atomic_goal_identifiable(builtin_call_rep(Module, Name, Args)) =
|
|
yes(atomic_goal_id(Module, Name, length(Args))).
|
|
atomic_goal_identifiable(plain_call_rep(Module, Name, Args)) =
|
|
yes(atomic_goal_id(Module, Name, length(Args))).
|
|
|
|
:- pragma export(proc_rep_type = out, "ML_proc_rep_type").
|
|
|
|
proc_rep_type = type_of(_ `with_type` proc_rep).
|
|
|
|
:- pragma export(goal_rep_type = out, "ML_goal_rep_type").
|
|
|
|
goal_rep_type = type_of(_ `with_type` goal_rep).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
path_from_string_det(GoalPathStr, GoalPath) :-
|
|
( path_from_string(GoalPathStr, GoalPathPrime) ->
|
|
GoalPath = GoalPathPrime
|
|
;
|
|
error("path_from_string_det: path_from_string failed")
|
|
).
|
|
|
|
path_from_string(GoalPathStr, GoalPath) :-
|
|
StepStrs = string__words(is_path_separator, GoalPathStr),
|
|
list__map(path_step_from_string, StepStrs, GoalPath).
|
|
|
|
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).
|
|
|
|
is_path_separator(';').
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|