Files
mercury/browser/io_action.m
Zoltan Somogyi 048f8357cf Until now, programmers could add `tabled_for_io' annotations to foreign_procs
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.
2002-07-22 07:13:14 +00:00

107 lines
2.9 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 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: io_action.m
% Author: zs.
%
% This module defines the representation of I/O actions used by the
% declarative debugger.
%-----------------------------------------------------------------------------%
:- module mdb__io_action.
:- interface.
:- import_module mdb__util.
:- import_module bool, list, map, std_util, io.
:- type io_action
---> io_action(
io_action_proc_name :: string,
io_action_pf :: pred_or_func,
io_action_args :: list(univ)
).
:- type io_seq_num == int.
:- type io_action_map == map(io_seq_num, io_action).
:- pred make_io_action_map(int::in, int::in, io_action_map::out,
io__state::di, io__state::uo) is det.
:- pred io_action_to_synthetic_term(io_action::in, string::out,
list(univ)::out, bool::out) is det.
:- implementation.
:- import_module require, int.
io_action_to_synthetic_term(IoAction, ProcName, Args, IsFunc) :-
IoAction = io_action(ProcName, PredFunc, Args),
(
PredFunc = predicate,
IsFunc = no
;
PredFunc = function,
IsFunc = yes
).
make_io_action_map(Start, End, IoActionMap) -->
make_io_action_map_2(Start, End, map__init, IoActionMap).
:- pred make_io_action_map_2(int::in, int::in,
io_action_map::in, io_action_map::out, io__state::di, io__state::uo)
is det.
make_io_action_map_2(Cur, End, IoActionMap0, IoActionMap) -->
( { Cur = End } ->
{ IoActionMap = IoActionMap0 }
;
pickup_io_action(Cur, ProcName, IsFunc, Args),
{ update_io_action_map(Cur, ProcName, IsFunc, Args,
IoActionMap0, IoActionMap1) },
make_io_action_map_2(Cur + 1, End, IoActionMap1, IoActionMap)
).
:- pred update_io_action_map(int::in, string::in, bool::in, list(univ)::in,
io_action_map::in, io_action_map::out) is det.
update_io_action_map(IoActionNum, ProcName, IsFunc, Args,
IoActionMap0, IoActionMap) :-
(
IsFunc = no,
PredFunc = predicate
;
IsFunc = yes,
PredFunc = function
),
IoAction = io_action(ProcName, PredFunc, Args),
map__det_insert(IoActionMap0, IoActionNum, IoAction, IoActionMap).
:- pred pickup_io_action(int::in, string::out, bool::out, list(univ)::out,
io__state::di, io__state::uo) is det.
:- pragma foreign_proc("C",
pickup_io_action(SeqNum::in, ProcName::out, IsFunc::out, Args::out,
S0::di, S::uo),
[thread_safe, promise_pure, tabled_for_io],
"{
const char *problem;
const char *proc_name;
MR_save_transient_hp();
problem = MR_trace_get_action(SeqNum, &proc_name, &IsFunc, &Args);
MR_restore_transient_hp();
if (problem != NULL) {
MR_fatal_error(""pickup_io_action: MR_trace_get_action"");
}
/* cast away const */
ProcName = (MR_String) (MR_Integer) proc_name;
S = S0;
}").