[m-dev.] For review interactive queries for the external debugger

Erwan Jahier Erwan.Jahier at irisa.fr
Thu Apr 22 01:38:24 AEST 1999


I have appended the corresponding Opium-M code at the end of the diff.

------------------------
Estimated hours taken: 10

This change allows interactive queries to be typed from the external debugger.

browser/debugger_interface.m:
	Define new debugger requests: query/1, cc_query/1, io_query/1 and
	mmc_options/1.

	Define 2 new procedures that are used in trace/mercury_trace_external.c:
	get_list_modules_to_import/3 retrieves from a *query/1 request a list 
	of modules to be imported; and get_mmc_options/2 retrieves from a 
	mmc_options/1 request the option to pass to mmc to compile the query. 

browser/interactive_query.m:
	Define a new procedure query_external/7 that does the same job as 
	query/7 but for the external debugger.

	Unset the environment variable `MERCURY_OPTIONS' before compiling a
	query; `MERCURY_OPTIONS' is exported before executing a program under
	the control of Opium-M (and mdb) and is not supposed to be set before
	compiling a program.

trace/mercury_trace_browse.ch:
	Add a new function MR_trace_query_external() to interface the
	ML_query_external() function defined by browser/interfactive_query.m.

trace/mercury_trace_external.c:
	Add code to implement new commands `query', `cc_query', `io_query',
	and `mmc_options', using the MR_trace_query_external() function defined 
	by trace/mercury_trace_browse.h.

trace/mercury_trace_external.h:
	Export MR_debugger_socket_in and MR_debugger_socket_out since there
	are needed in interactive_query.m.


Index: browser/debugger_interface.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/debugger_interface.m,v
retrieving revision 1.8
diff -u -r1.8 debugger_interface.m
--- debugger_interface.m	1999/02/22 08:28:30	1.8
+++ debugger_interface.m	1999/04/21 14:48:50
@@ -32,6 +32,7 @@
 :- implementation.
 :- import_module io, require.
 :- import_module list, bool, std_util.
+:- import_module interactive_query.
 
 dummy_pred_to_avoid_warning_about_nothing_exported.
 
@@ -160,6 +161,14 @@
 			% something went wrong when trying to get the
 			% next request
 	;	error(string)
+			% to type interactive queries
+	;	query(imports)
+			% to type cc interactive queries
+	;	cc_query(imports)
+			% to type interactive queries that perform io
+	;	io_query(imports)
+			% options to compile queries with
+	;	mmc_options(options)
 	.
 
 :- type event_number == int.
@@ -513,6 +522,60 @@
 	***********/
 
 
+%-----------------------------------------------------------------------------%
+
+:- pred get_list_modules_to_import(debugger_request, int, imports).
+:- mode get_list_modules_to_import(in, out, out) is det.
+
+:- pragma export(get_list_modules_to_import(in, out, out),
+		"ML_DI_get_list_modules_to_import").
+
+get_list_modules_to_import(DebuggerRequest, CardList, ModulesList) :-
+	(
+		DebuggerRequest = query(List)
+	->
+		ModulesList = List,
+		length(ModulesList, CardList)
+	;
+		DebuggerRequest = cc_query(List)
+	->
+		ModulesList = List,
+		length(ModulesList, CardList)
+	;
+		DebuggerRequest = io_query(List)
+	->
+		ModulesList = List,
+		length(ModulesList, CardList)
+	;
+		error("get_list_modules_to_import: not a query request")
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred get_mmc_options(debugger_request, options).
+:- mode get_mmc_options(in, out) is det.
+
+:- pragma export(get_mmc_options(in, out), "ML_DI_get_mmc_options").
+
+get_mmc_options(DebuggerRequest, Options) :-
+	(
+		DebuggerRequest = mmc_options(Options1)
+	->
+		Options = Options1
+	;
+		error("get_mmc_options: not a mmc_options request")
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred init_mercury_string(string).
+:- mode init_mercury_string(out) is det.
+
+:- pragma export(init_mercury_string(out), "ML_DI_init_mercury_string").
+
+init_mercury_string("").
+
+%------------------------------------------------------------------------------%
 
 :- pred classify_request(debugger_request, int).
 :- mode classify_request(in, out) is det.
@@ -533,6 +596,10 @@
 classify_request(stack, 10).
 classify_request(nondet_stack, 11).
 classify_request(stack_regs, 12).
+classify_request(query(_),13).
+classify_request(cc_query(_),14).
+classify_request(io_query(_),15).
+classify_request(mmc_options(_),16).
 
 
 %-----------------------------------------------------------------------------%
Index: browser/interactive_query.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/interactive_query.m,v
retrieving revision 1.2
diff -u -r1.2 interactive_query.m
--- interactive_query.m	1999/03/25 22:24:51	1.2
+++ interactive_query.m	1999/04/21 14:48:51
@@ -22,6 +22,10 @@
 		io__input_stream::in, io__output_stream::in,
 		state::di, state::uo) is det.
 
+% query_external/7 is the same as query/7 but for the use of the external 
+% debugger.
+:- pred query_external(query_type::in, imports::in, options::in,
+		io__input_stream::in, io__output_stream::in,
+		state::di, state::uo) is det.
+
 :- type query_type ---> normal_query ; cc_query ; io_query.
 :- type imports == list(string).
 :- type options == string.
@@ -73,6 +77,62 @@
 		)
 	).
 
+
+% Type of the terms sent to the socket during an interactive query session 
+% under the control of the external debugger.
+:- type interactive_query_response 
+	--->	iq_ok
+	;	iq_imported(imports)
+	;	iq_quit
+	;	iq_eof
+	;	iq_error(string)
+	.
+
+:- pragma export(query_external(in, in, in, in, in, di, uo), 
+	"ML_query_external").
+
+query_external(QueryType, Imports, Options, SocketIn, SocketOut) -->
+	io__set_input_stream(SocketIn, OldStdin),
+	term_io__read_term(Result),
+	io__set_input_stream(OldStdin, _),
+	( { Result = eof },
+		send_term_to_socket(iq_eof, SocketOut)
+	; { Result = error(ErrorMsg, _Line) },
+		send_term_to_socket(iq_error(ErrorMsg), SocketOut),
+		query_external(QueryType, Imports, Options, SocketIn, SocketOut)
+	; { Result = term(VarSet, Term) },
+		(if { Term = term__functor(term__atom("quit"), [], _) } then
+			send_term_to_socket(iq_quit, SocketOut)
+		else if { Term = term__functor(term__atom("options"),
+				[term__functor(term__string(NewOptions),
+					[], _)], _) } then
+			send_term_to_socket(iq_ok, SocketOut),
+			query_external(QueryType, Imports, NewOptions,
+				SocketIn, SocketOut)
+		else if { term_to_list(Term, ModuleList) } then
+			{ list__append(Imports, ModuleList, NewImports) },
+			send_term_to_socket(iq_imported(NewImports), SocketOut),
+			query_external(QueryType, NewImports, Options,
+				SocketIn, SocketOut)
+		else
+			run_query(Options,
+				prog(QueryType, Imports, Term, VarSet)),
+			send_term_to_socket(iq_ok, SocketOut),
+			query_external(QueryType, Imports, Options,
+				SocketIn, SocketOut)
+		)
+	).
+
+:- pred send_term_to_socket(interactive_query_response, io__output_stream,
+	io__state, io__state).
+:- mode send_term_to_socket(in, in, di, uo) is det.
+send_term_to_socket(Term, SocketStream) -->
+	write(SocketStream, Term),
+	print(SocketStream, ".\n"),
+	flush_output(SocketStream).
+
 :- func query_prompt(query_type) = string.
 query_prompt(normal_query) = "?- ".
 query_prompt(cc_query) = "?- ".
@@ -90,12 +150,19 @@
 :- mode run_query(in, in, di, uo) is det.
 run_query(Options, Program) -->
 	{ SourceFile = "query.m" },
-	write_prog_to_file(Program, SourceFile),
-	compile_file(Options, Succeeded),
-	(if { Succeeded = yes } then
-		dynamically_load_and_run
+	io__get_environment_var("MERCURY_OPTIONS", MAYBE_MERCURY_OPTIONS),
+	(if { MAYBE_MERCURY_OPTIONS = yes(MERCURY_OPTIONS) } then	
+		io__set_environment_var("MERCURY_OPTIONS", ""),
+		write_prog_to_file(Program, SourceFile),
+		compile_file(Options, Succeeded),
+		(if { Succeeded = yes } then
+			dynamically_load_and_run
+		else
+			{ true }
+		),
+		io__set_environment_var("MERCURY_OPTIONS", MERCURY_OPTIONS)
 	else
-		{ true }
+		print("Unable to unset MERCURY_OPTIONS environment variable")
 	).
 
 %-----------------------------------------------------------------------------%
Index: trace/mercury_trace_browse.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_browse.c,v
retrieving revision 1.3
diff -u -r1.3 mercury_trace_browse.c
--- mercury_trace_browse.c	1999/03/05 12:52:33	1.3
+++ mercury_trace_browse.c	1999/04/21 14:48:55
@@ -29,6 +29,7 @@
 #include "browse.h"
 #include "interactive_query.h"
 #include "std_util.h"
+#include "mercury_trace_external.h"
 #include <stdio.h>
 
 static	Word		MR_trace_browser_state;
@@ -129,5 +130,16 @@
 	MR_TRACE_CALL_MERCURY(
 		ML_query(type, imports_list, (String) options_on_heap,
 			(Word) &mdb_in, (Word) &mdb_out);
+	);
+}
+
+void
+MR_trace_query_external(MR_Query_Type type, String options, int num_imports,
+	Word imports_list)
+{
+	MR_TRACE_CALL_MERCURY(
+		ML_query_external(type, imports_list,  options,
+			(Word) &MR_debugger_socket_in, 
+			(Word) &MR_debugger_socket_out);
 	);
 }
Index: trace/mercury_trace_browse.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_browse.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_trace_browse.h
--- mercury_trace_browse.h	1999/03/05 12:52:33	1.2
+++ mercury_trace_browse.h	1999/04/21 14:48:55
@@ -35,4 +35,7 @@
 extern	void	MR_trace_query(MR_Query_Type type, const char *options,
 			int num_imports, /* const */ char *imports[]);
 
+extern	void	MR_trace_query_external(MR_Query_Type type, String options,
+			int num_imports, Word imports_list);
+
 #endif	/* MERCURY_TRACE_BROWSE_H */
Index: trace/mercury_trace_external.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_external.c,v
retrieving revision 1.14
diff -u -r1.14 mercury_trace_external.c
--- mercury_trace_external.c	1999/03/25 03:02:18	1.14
+++ mercury_trace_external.c	1999/04/21 14:48:57
@@ -27,6 +27,7 @@
 #include "mercury_trace_external.h"
 #include "mercury_trace_util.h"
 #include "mercury_layout_util.h"
+#include "mercury_trace_browse.h"
 
 #include "debugger_interface.h"
 #include "std_util.h"
@@ -65,13 +66,21 @@
 					 port of the current event	      */
 	MR_REQUEST_STACK         = 10,/* print the ancestors list             */
 	MR_REQUEST_NONDET_STACK  = 11,/* print the nondet stack		      */
-	MR_REQUEST_STACK_REGS    = 12 /* prints the contents of the virtual
+	MR_REQUEST_STACK_REGS    = 12,/* prints the contents of the virtual
 							   machine registers. */
+	MR_REQUEST_INTERACTIVE_QUERY_NORMAL	 
+				 = 13,/* wait for a normal interactive query  */
+	MR_REQUEST_INTERACTIVE_QUERY_CC	 
+				 = 14,/* wait for a cc interactive query      */
+	MR_REQUEST_INTERACTIVE_QUERY_IO	 
+				 = 15,/* wait for a io interactive query      */
+	MR_REQUEST_MMC_OPTIONS	 = 16 /* import modules for interactive 
+					 queries			      */
 
 } MR_debugger_request_type;
 
-static MercuryFile MR_debugger_socket_in;
-static MercuryFile MR_debugger_socket_out;
+MercuryFile MR_debugger_socket_in;
+MercuryFile MR_debugger_socket_out;
 
 /*
 ** Use a GNU C extension to enforce static type checking
@@ -116,6 +125,10 @@
 static void	MR_dump_stack_record_print_to_socket(FILE *fp, 
 			const MR_Stack_Layout_Entry *entry_layout, int count, 
 			int start_level, Word *base_sp, Word *base_curfr);
+static void	MR_get_list_modules_to_import(Word debugger_request, 
+			Integer *modules_list_card_ptr, Word *modules_list_ptr);
+static void	MR_get_mmc_options(Word debugger_request, 
+			String *mmc_options_ptr);
 
 #if 0
 This pseudocode should go in the debugger process:
@@ -375,7 +388,16 @@
 	MR_Trace_Port	port = event_info->MR_trace_port;
 	const char 	*path = event_info->MR_event_path;
 	Word		*saved_regs = event_info->MR_saved_regs;
+	Integer		modules_list_card;
+	Word		modules_list;
 
+/* 
+** MR_mmc_options contains the options to pass to mmc when compiling queries.
+** We initialise it to the String "".
+*/
+	static String	MR_mmc_options;
+	MR_TRACE_CALL_MERCURY(ML_DI_init_mercury_string(&MR_mmc_options));
+
 	event_details.MR_call_seqno = MR_trace_call_seqno;
 	event_details.MR_call_depth = MR_trace_call_depth;
 	event_details.MR_event_number = MR_trace_event_number;
@@ -533,6 +555,56 @@
 					MR_saved_maxfr(saved_regs));
 				break;
 			
+			case MR_REQUEST_INTERACTIVE_QUERY_NORMAL:
+				if (MR_debug_socket) {
+					fprintf(stderr, "\nMercury runtime: "
+						"REQUEST_INTERACTIVE_QUERY"
+						"_NORMAL\n");
+				}
+				MR_get_list_modules_to_import(
+					debugger_request, &modules_list_card,
+					&modules_list);
+				MR_trace_query_external(MR_NORMAL_QUERY, 
+					MR_mmc_options, modules_list_card, 
+					modules_list);
+				break;
+
+			case MR_REQUEST_INTERACTIVE_QUERY_IO:
+				if (MR_debug_socket) {
+					fprintf(stderr, "\nMercury runtime: "
+						"REQUEST_INTERACTIVE_QUERY_IO\n");
+				}
+				MR_get_list_modules_to_import(
+					debugger_request, &modules_list_card,
+					&modules_list);
+				MR_trace_query_external(MR_IO_QUERY, 
+					MR_mmc_options, modules_list_card, 
+					modules_list);
+				break;
+
+			case MR_REQUEST_INTERACTIVE_QUERY_CC:
+				if (MR_debug_socket) {
+					fprintf(stderr, "\nMercury runtime: "
+						"REQUEST_INTERACTIVE_QUERY_CC\n");
+				}
+				MR_get_list_modules_to_import(
+					debugger_request, &modules_list_card,
+					&modules_list);
+				MR_trace_query_external(MR_CC_QUERY, 
+					MR_mmc_options, modules_list_card, 
+					modules_list);
+				break;
+
+			case MR_REQUEST_MMC_OPTIONS:
+				if (MR_debug_socket) {
+					fprintf(stderr, "\nMercury runtime: "
+						"REQUEST_MMC_OPTIONS\n");
+				}
+				MR_get_mmc_options(debugger_request, 
+					&MR_mmc_options);
+				MR_send_message_to_socket("mmc_options_ok");
+				break;
+
 			case MR_REQUEST_NO_TRACE:
 				cmd->MR_trace_cmd = MR_CMD_TO_END;
 				return jumpaddr;
@@ -1057,6 +1129,28 @@
 	MR_send_message_to_socket_format("det(\"%s\").\n", 
 		MR_detism_names[entry->MR_sle_detism]);
 
+}
+
+static void
+MR_get_list_modules_to_import(Word debugger_request, 
+	Integer *modules_list_card_ptr, Word *modules_list_ptr)
+{
+	MR_TRACE_CALL_MERCURY(
+		ML_DI_get_list_modules_to_import(
+			debugger_request, 
+			modules_list_card_ptr, 
+			modules_list_ptr);
+		);
+}
+
+static void
+MR_get_mmc_options(Word debugger_request, String *mmc_options_ptr)
+{
+	MR_TRACE_CALL_MERCURY(
+		ML_DI_get_mmc_options(
+			debugger_request, 
+			mmc_options_ptr);
+		);
 }
 
 #endif /* MR_USE_EXTERNAL_DEBUGGER */
Index: trace/mercury_trace_external.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_external.h,v
retrieving revision 1.5
diff -u -r1.5 mercury_trace_external.h
--- mercury_trace_external.h	1999/02/20 06:08:14	1.5
+++ mercury_trace_external.h	1999/04/21 14:48:57
@@ -14,6 +14,13 @@
 extern	Code   *MR_trace_event_external(MR_Trace_Cmd_Info *cmd,
 			MR_Event_Info *event_info);
 
+/*
+** External debugger socket streams.
+*/
+
+extern MercuryFile MR_debugger_socket_in;
+extern MercuryFile MR_debugger_socket_out;
+
 #endif	/* MR_USE_EXTERNAL_DEBUGGER */
 
 #endif	/* MERCURY_TRACE_EXTERNAL_H */









%------------------------------------------------------------------------------%
% Copyright (C) 1999 IRISA/INRIA.
% 
% Author : Erwan Jahier
% File   : interactive_queries.op
%

%------------------------------------------------------------------------------%

opium_scenario(
	name		: interactive_queries,
	files		: [interactive_queries],
	scenarios	: [],
	message		:
"Scenario that handles interactive queries."
	).


%------------------------------------------------------------------------------%
opium_command(
	name		: query,
	arg_list	: [ModuleList],
	arg_type_list	: [is_list],
	abbrev		: _,
	interface	: menu,
	command_type	: opium,
	implementation	: query_Op,
	parameters	: [],
	message : 
"The commands query/1, cc_query/1 and io_query/1 allow you to type in queries \
(goals) interactively in the debugger. When you use one of these commands, the \
debugger will respond with a query prompt (`?-' or `run <--'), at which you \
can type in a goal; the debugger will the compile and execute the goal and \
display the answer(s). You can return from the query prompt to the Opium-M \
prompt by typing the end-of-file indicator (typically control-D or \
control-Z), or by typing `quit.'. \n\
\n\
The list of module names passed downed in argument of the query specify which \
modules will be imported. Note that you can also add new modules to the list \
of imports directly at the query prompt, by using a command of the form \
`[\"module\"]', e.g. `[\"int\"]'. You need to import all the modules that \
define symbols used in your query. Queries can only use symbols that are \
exported from a module; entities which are declared in a module's \
implementation section only  cannot be used. \n\
\n\
The three variants differ in what kind of goals they allow. For goals which \
perform I/O, you need to use `io_query/1'; this lets you type in the goal \
using DCG syntax. For goals which don't do I/O, but which have determinism \
`cc_nondet' or `cc_multi', you need to use `cc_query/1'; this finds only one \
solution to the specified goal. For all other goals, you can use plain \
`query/1', which finds all the solutions to the goal. \
\n\
For `query/1' and `cc_query/1', the debugger will print out all the variables \
in the goal using `io__write'. The goal must bind all of its variables to \
ground terms, otherwise you will get a mode error. \n\
\n\
The current implementation works by compiling the queries on-the-fly and then \
dynamically linking them into the program being debugged.  Thus it may take a \
little while for your query to be executed. Each query will be written to a \
file named `query.m' in the current directory, so make sure you don't name \
your source file `query.m'. Note that dynamic linking may not be supported \
on some systems; if you are using a system for which dynamic linking is not \
supported, you will get an error message when you try to run these commands."
	).

query_Op(ModuleList) :-
	( not getval(state_of_opium, running) ->
		write("No program is running, you can't make a query.\n")
	;
		true
	),
	% strings need to quoted before being sent.
	maplist(quote_string, ModuleList, QuotedList),
	send_message_to_socket(query(QuotedList)),
	loop_for_queries(query).

loop_for_queries(QueryType) :-
	display_query_prompt(QueryType),
	read(Term),
	( Term = options(String) ->
		quote_string(String, QuotedString),
		Term2 = options(QuotedString)
	;
		Term2 = Term
	),
	send_message_to_socket(Term2),
	nl,
	read_message_from_socket(Response),
	( 
		( Response == iq_eof ; Response == iq_quit ),
		write("End of the interactive queries session.\n"),
		!
	;
		Response = iq_imported(ImportedMod),
		write("The currently imported modules are "), 
		print(ImportedMod),
		nl,
		loop_for_queries(QueryType),
		!
	;
		Response = iq_error(ErrorMsg),
		printf("%w\n", ErrorMsg),
		loop_for_queries(QueryType),
		!
	;
		Response == iq_ok,
		nl,
		loop_for_queries(QueryType),
		!
	;
		% Should never occur
		printf("Bad message from interactive_query:query_", []),
		printf("external/7: %w.\n", Response),
		fail
	).

display_query_prompt(query) :-
	write("\n?- ").

display_query_prompt(cc_query) :-
	write("\n?- ").

display_query_prompt(io_query) :-
	write("\nrun <-- ").


quote_string(String, StringQuoted):- 
	concat_string(["\"", String, "\""], String2),
	atom_string(StringQuoted, String2).

%------------------------------------------------------------------------------%
opium_command(
	name		: cc_query,
	arg_list	: [ModuleList],
	arg_type_list	: [is_list],
	abbrev		: _,
	interface	: menu,
	command_type	: opium,
	implementation	: cc_query_Op,
	parameters	: [],
	message : 

"cf query/1."
	).

cc_query_Op(ModuleList) :-
	( not getval(state_of_opium, running) ->
		write("No program is running, you can't make a query.\n")
	;
		true
	),
	% strings need to quoted before being sent.
	maplist(quote_string, ModuleList, QuotedList),
	send_message_to_socket(cc_query(QuotedList)),
	loop_for_queries(cc_query).

%------------------------------------------------------------------------------%
opium_command(
	name		: io_query,
	arg_list	: [ModuleList],
	arg_type_list	: [is_list],
	abbrev		: _,
	interface	: menu,
	command_type	: opium,
	implementation	: io_query_Op,
	parameters	: [],
	message : 

"cf query/1."
	).

io_query_Op(ModuleList) :-
	( not getval(state_of_opium, running) ->
		write("No program is running, you can't make a query.\n")
	;
		true
	),
	% strings need to quoted before being sent.
	maplist(quote_string, ModuleList, QuotedList),
	send_message_to_socket(io_query(QuotedList)),
	loop_for_queries(io_query).


%------------------------------------------------------------------------------%
opium_command(
	name		: mmc_options,
	arg_list	: [String],
	arg_type_list	: [string],
	abbrev		: _,
	interface	: menu,
	command_type	: opium,
	implementation	: mmc_options_Op,
	parameters	: [],
	message : 
"This command sets the options that will be passed to `mmc' to compile your \
query when you use one of the query commands: `query/1', `cc_query/2', or \
`io_query/3'. For example, if a query results in a compile error, it may \
sometimes be helpful to use mmc_options(\"mmc_options --verbose-errors\").\
"
	).


mmc_options_Op(Options) :- 
	( not getval(state_of_opium, running) ->
		write("No program is running, you can't set mmc options.\n")
	;
		true
	),
	quote_string(Options, QuotedOptions),
	send_message_to_socket(mmc_options(QuotedOptions)),
	read_message_from_socket(Response),
	printf("response to query = %w\n", [Response]),	
	(
		Response == mmc_options_ok,
		nl
	;
		% Should never occur
		write("Bad message from the Mercury proccess.\n"),
		write("mmc_options_ok expected.\n"),
		fail
	).

-- 
R1.


--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list