mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-20 16:31:04 +00:00
Estimated hours taken: 12 Branches: main Until now, programmers could add `tabled_for_io' annotations to foreign_procs that do I/O, which asks the compiler to make those foreign_procs idempotent, i.e. ensures that they are performed at most once even in the presence of a retry operation in the debugger. This change adds a compiler option, --trace-table-io-require, which generates an error if a foreign_proc that does I/O does not have this annotation. Specifying this option thus ensures that all I/O done by the program is idempotent. In the future, we may want to have this option turned on in all debugging grades. Until we decide about, the new option is not yet documented. compiler/options.m: Add the new option --trace-table-io-require. compiler/handle_options.m: Make --trace-table-io-require imply --trace-table-io. compiler/table_gen.m: If --trace-table-io-require is enabled, require all I/O primitives to have the tabled_for_io annotation. compiler/mercury_compile.m: Pass I/O states to table_gen.m, since it can now generate error messages. trace/mercury_trace_util.h: trace/mercury_trace_vars.c: When calling Mercury code from the trace directory, disable I/O tabling, since any I/O actions executed by Mercury code in the browser directory (or by library code called from there) should not be tabled, not being part of the user program. Due to the depth of nesting, make mercury_trace_vars.c use four-space indentation. browser/collect_lib.m: browser/declarative_debugger.m: browser/declarative_execution.m: browser/dl.m: browser/io_action.m: browser/mdb.m: browser/name_mangle.m: browser/util.m: compiler/gcc.m: compiler/mercury_compile.m: compiler/passes_aux.m: compiler/process_util.m: compiler/stack_layout.m: library/io.m: library/time.m: tests/debugger/declarative/tabled_read_decl.m: Add a whole lot of tabled_for_io annotations, to enable the compiler to bootstrap with --trace-table-io-require enabled. In many cases, this required turning old-style pragma c_code into pragma foreign_proc. While doing that, I standardized the layouts of pragma foreign_procs. browser/util.m: Turn an impure semidet predicate into a pure det predicate with I/O states, to allow it to be tabled. Make it return a Mercury bool to indicate success or failure. library/bool.m: Add functions that allow C code to get their hands on the constants `yes' and `no', for communication with Mercury code. library/table_builtin.m: Add debugging code to the main primitive of I/O tabling. This is controlled both by the macro for retry debugging and a boolean global. library/mercury_trace_base.[ch]: Add the boolean global variable to switch the new debugging code in table_builtin.m on and off. library/mercury_trace_internal.c: When starting I/O tabling with retry debug enabled, turn on the switch. tests/debugger/queens.exp3: New expected output file that applies when the library is compiled with --trace-table-io-require.
190 lines
5.3 KiB
Mathematica
190 lines
5.3 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-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.
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module mdb__util.
|
|
|
|
:- interface.
|
|
|
|
:- import_module list, string, io.
|
|
|
|
% The stuff defined below is similar to types goal_path and trace_port
|
|
% defined in modules compiler/hlds_goal.m and compiler/trace.m.
|
|
% This enumeration must be EXACTLY the same as the MR_trace_port enum in
|
|
% runtime/mercury_trace_base.h, and in the same order, since the code
|
|
% assumes the representation is the same.
|
|
|
|
:- type trace_port_type
|
|
---> call
|
|
; exit
|
|
; redo
|
|
; fail
|
|
; exception
|
|
; ite_cond
|
|
; ite_then
|
|
; ite_else
|
|
; neg_enter
|
|
; neg_success
|
|
; neg_failure
|
|
; disj
|
|
; switch
|
|
; nondet_pragma_first
|
|
; nondet_pragma_later
|
|
.
|
|
|
|
% This enumeration must be EXACTLY the same as the MR_PredFunc enum in
|
|
% runtime/mercury_stack_layout.h, and in the same order, since the code
|
|
% assumes the representation is the same.
|
|
|
|
:- type pred_or_func
|
|
---> predicate
|
|
; function.
|
|
|
|
:- type goal_path_string == string.
|
|
|
|
:- type line_number == int.
|
|
|
|
% Get user input via the same method used by the internal
|
|
% debugger.
|
|
:- pred util__trace_getline(string, io__result(string), io__state,
|
|
io__state).
|
|
:- mode util__trace_getline(in, out, di, uo) is det.
|
|
|
|
:- pred util__trace_getline(string, io__result(string), io__input_stream,
|
|
io__output_stream, io__state, io__state).
|
|
:- mode util__trace_getline(in, out, in, in, di, uo) is det.
|
|
|
|
% trace_get_command is similar to trace_getline except that it
|
|
% breaks lines into semicolon separated commands, and replaces
|
|
% EOF with the command 'quit'.
|
|
:- pred util__trace_get_command(string, string, io__state, io__state).
|
|
:- mode util__trace_get_command(in, out, di, uo) is det.
|
|
|
|
:- pred util__trace_get_command(string, string, io__input_stream,
|
|
io__output_stream, io__state, io__state).
|
|
:- mode util__trace_get_command(in, out, in, in, di, uo) is det.
|
|
|
|
:- pred util__zip_with(pred(T1, T2, T3), list(T1), list(T2), list(T3)).
|
|
:- mode util__zip_with(pred(in, in, out) is det, in, in, out) is det.
|
|
|
|
% Apply predicate to argument repeatedly until the result
|
|
% remains the same.
|
|
:- pred util__limit(pred(list(T), list(T)), list(T), list(T)).
|
|
:- mode util__limit(pred(in,out) is det, in, out) is det.
|
|
|
|
% For use in representing unbound head variables in the "print goal"
|
|
% commands in the debugger.
|
|
:- type unbound ---> '_'.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module bool, int, require.
|
|
|
|
util__trace_getline(Prompt, Result) -->
|
|
io__input_stream(MdbIn),
|
|
io__output_stream(MdbOut),
|
|
util__trace_getline(Prompt, Result, MdbIn, MdbOut).
|
|
|
|
util__trace_getline(Prompt, Result, MdbIn, MdbOut) -->
|
|
call_trace_getline(MdbIn, MdbOut, Prompt, Line, Success),
|
|
{
|
|
Success = yes,
|
|
Result = ok(Line)
|
|
;
|
|
Success = no,
|
|
Result = eof
|
|
}.
|
|
|
|
:- pred call_trace_getline(input_stream::in, output_stream::in, string::in,
|
|
string::out, bool::out, io__state::di, io__state::uo) is det.
|
|
|
|
:- pragma c_header_code("
|
|
#include ""mercury_wrapper.h""
|
|
#include ""mercury_string.h""
|
|
#include ""mercury_trace_base.h""
|
|
#include ""mercury_trace_internal.h""
|
|
#include ""mercury_library_types.h""
|
|
#include ""bool.h""
|
|
").
|
|
|
|
:- pragma foreign_proc("C",
|
|
call_trace_getline(MdbIn::in, MdbOut::in, Prompt::in, Line::out,
|
|
Success::out, IO0::di, IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io],
|
|
"
|
|
char *line;
|
|
MercuryFile *mdb_in = (MercuryFile *) MdbIn;
|
|
MercuryFile *mdb_out = (MercuryFile *) MdbOut;
|
|
|
|
if (MR_address_of_trace_getline != NULL) {
|
|
line = (*MR_address_of_trace_getline)((char *) Prompt,
|
|
MR_file(*mdb_in), MR_file(*mdb_out));
|
|
} else {
|
|
MR_tracing_not_enabled();
|
|
/* not reached */
|
|
}
|
|
|
|
if (line == NULL) {
|
|
/* we copy the null string to avoid warnings about const */
|
|
MR_make_aligned_string_copy(Line, """");
|
|
Success = ML_bool_return_no();
|
|
} else {
|
|
MR_make_aligned_string_copy(Line, line);
|
|
MR_free(line);
|
|
Success = ML_bool_return_yes();
|
|
}
|
|
").
|
|
|
|
util__trace_get_command(Prompt, Result) -->
|
|
io__input_stream(MdbIn),
|
|
io__output_stream(MdbOut),
|
|
util__trace_get_command(Prompt, Result, MdbIn, MdbOut).
|
|
|
|
:- pragma foreign_proc("C",
|
|
util__trace_get_command(Prompt::in, Line::out, MdbIn::in,
|
|
MdbOut::in, State0::di, State::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io],
|
|
"
|
|
char *line;
|
|
MercuryFile *mdb_in = (MercuryFile *) MdbIn;
|
|
MercuryFile *mdb_out = (MercuryFile *) MdbOut;
|
|
|
|
if (MR_address_of_trace_getline != NULL) {
|
|
line = (*MR_address_of_trace_get_command)(
|
|
(char *) Prompt,
|
|
MR_file(*mdb_in), MR_file(*mdb_out));
|
|
} else {
|
|
MR_tracing_not_enabled();
|
|
/* not reached */
|
|
}
|
|
|
|
MR_make_aligned_string_copy(Line, line);
|
|
MR_free(line);
|
|
|
|
State = State0;
|
|
").
|
|
|
|
util__zip_with(Pred, XXs, YYs, Zipped) :-
|
|
( (XXs = [], YYs = []) ->
|
|
Zipped = []
|
|
; (XXs = [X|Xs], YYs = [Y|Ys]) ->
|
|
Pred(X,Y,PXY),
|
|
Zipped = [PXY|Rest],
|
|
util__zip_with(Pred, Xs, Ys, Rest)
|
|
;
|
|
error("zip_with: list arguments are of unequal length")
|
|
).
|
|
|
|
util__limit(Pred, Xs, Ys) :-
|
|
Pred(Xs, Zs),
|
|
( Xs = Zs ->
|
|
Ys = Zs
|
|
;
|
|
util__limit(Pred, Zs, Ys)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|