mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 01:43:35 +00:00
browser/browser_info.m:
Avoid using "output" (and "input", for the sake of symmetry)
as function symbols.
browser/debugger_interface.m:
Avoid using "pred" and "func" as function symbols by putting a prefix
before each function symbol in the affected type.
browser/dl.m:
Avoid using "local" (and "global", again for symbols) as function symbols.
profiler/output_prof_info.m:
Avoid using "output" as a type name and as a function symbol.
browser/browse.m:
browser/collect_lib.m:
browser/declarative_user.m:
browser/interactive_query.m:
profiler/generate_output.m:
profiler/output.m:
Conform to the changes above.
extras/morphine/source/browse.op:
extras/morphine/source/collect.op:
extras/morphine/source/current_arg.op:
extras/morphine/source/current_slots.op:
extras/morphine/source/exec_control.op:
extras/morphine/source/forward_move.op:
extras/morphine/source/interactive_queries.op:
Conform to the renames of the function symbols in debugger_interface.m.
Since this code is in Prolog, I cannot be sure that I changed all the
places that should be changed, but that does not matter much.
Since Morphine was designed to work with the Prolog dialects of 1999,
had its last update in 2002, and we never test it, it is very likely
that it hasn't worked in a long time. We keep it around because
(a) it may interest someone, and (b) it doesn't require significant
maintenance. The fact that it does not run may be regrettable, but
it is not actually regretted by many would-be users, or (even) any at all.
(I actually noticed and fixed a bug while doing the above change:
it was a typo in a function symbol name.)
618 lines
16 KiB
Plaintext
618 lines
16 KiB
Plaintext
%--------------------------------------------------------------------------%
|
|
%
|
|
% Copyright (C) 1999-2001 INRIA/INSA de Rennes/IFSIC.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file License in the Morphine distribution.
|
|
%
|
|
% Author : Erwan Jahier <jahier@irisa.fr>
|
|
%
|
|
% Morphine built-ins, primitives and commands related to the control
|
|
% of the execution (part of scenario morphine_kernel.op). All predicates
|
|
% of this file are written to be run on an unix-like architecture.
|
|
|
|
|
|
%--------------------------------------------------------------------------%
|
|
opium_primitive(
|
|
name : init_morphine_session,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : _,
|
|
implementation : init_morphine_session_Op,
|
|
message :
|
|
"Initializes Morphine."
|
|
).
|
|
|
|
|
|
% :- pred init_morphine_session_Op is det.
|
|
init_morphine_session_Op :-
|
|
load_morphine_rc,
|
|
setval(state_of_morphine, not_running),
|
|
setval(a_program_has_been_run, no).
|
|
|
|
|
|
load_morphine_rc :-
|
|
(
|
|
getenv('PWD', Cwd),
|
|
append_strings(Cwd, "/.morphine-rc", CurrentMorphineRc),
|
|
exists(CurrentMorphineRc)
|
|
->
|
|
% If a `.morphine-rc' exists in the current directory, load it.
|
|
( get_file_info(CurrentMorphineRc, size, 0) ->
|
|
true
|
|
;
|
|
% Only print thet message if .morphine-rc is not empty
|
|
compile(CurrentMorphineRc)
|
|
)
|
|
;
|
|
% If no `.morphine-rc' exists in the current directory, look
|
|
% in the home directory if such a file is available to load it.
|
|
|
|
getenv('HOME', Dir),
|
|
append_strings(Dir, "/.morphine-rc", HomeMorphineRc),
|
|
(
|
|
exists(HomeMorphineRc)
|
|
->
|
|
( get_file_info(HomeMorphineRc, size, 0) ->
|
|
true
|
|
;
|
|
% Only print thet message if .morphine-rc is not empty
|
|
compile(HomeMorphineRc)
|
|
)
|
|
;
|
|
true
|
|
)
|
|
).
|
|
|
|
%--------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : re_init_morphine,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : _,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : re_init_morphine_Op,
|
|
parameters : [],
|
|
message :
|
|
'Re-initializes Morphine. This command might be useful if Morphine is broken.\
|
|
'
|
|
).
|
|
|
|
re_init_morphine_Op :-
|
|
init_morphine_session_Op.
|
|
|
|
|
|
%--------------------------------------------------------------------------%
|
|
morphine_abort :-
|
|
end_connection,
|
|
abort.
|
|
|
|
%--------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : run,
|
|
arg_list : [ProgramCall],
|
|
arg_type_list : [is_mercury_program_call],
|
|
abbrev : _,
|
|
interface : button,
|
|
command_type : opium,
|
|
implementation : run_Op,
|
|
parameters : [],
|
|
message :
|
|
"Executes a Mercury program from Morphine. \n\
|
|
\n\
|
|
Example: `run(hello)' executes the Mercury program `hello' under the control \
|
|
of Morphine. `run(\"./cat filename\")' executes the Mercury program `cat' \
|
|
that takes `filename' as argument.\
|
|
"
|
|
).
|
|
|
|
% :- pred run_Op(atom).
|
|
% :- mode run_Op(in) is det.
|
|
% run_Op(PathCallArgs) run the program ProgramName within Morphine.
|
|
run_Op(PathCallArgs0) :-
|
|
( string(PathCallArgs0) ->
|
|
PathCallArgs = PathCallArgs0
|
|
;
|
|
% Convert the input of run/1 to a string if necessary
|
|
term_string(PathCallArgs0, PathCallArgs)
|
|
),
|
|
decompose_path_call_and_args(PathCallArgs, Path, Call, Args),
|
|
run(Path, Call, Args).
|
|
|
|
% :- pred run(string, atom).
|
|
% :- mode run(in, in) is det.
|
|
run(ProgramPathStr, ProgramCallStr, ListArgsStr) :-
|
|
% We first check that the program exists before trying to run it.
|
|
append_strings(ProgramPathStr, ProgramCallStr, PathCallStr),
|
|
(
|
|
exists(PathCallStr),
|
|
!
|
|
;
|
|
printf("The program %w does not exists.\n", [PathCallStr]),
|
|
fail
|
|
),
|
|
(
|
|
% we store the argument of run/3 in order to restart easily
|
|
% the execution of the program with rerun/0 command.
|
|
setval(re_run_program,
|
|
run(ProgramPathStr, ProgramCallStr, ListArgsStr)),
|
|
|
|
term_string(ProgramCall, ProgramCallStr),
|
|
start_connection(ProgramCall, SocketAddress),
|
|
|
|
term_string(SocketAddress, SocketAddressStr),
|
|
get_parameter(socket_domain, [SocketDomain]),
|
|
|
|
run_program(ProgramPathStr, ProgramCallStr, ListArgsStr,
|
|
SocketAddressStr, SocketDomain, " local "),
|
|
|
|
accept(sock, _, newsock),
|
|
|
|
% state_of_morphine = running | not_running | eot (| bot)
|
|
setval(state_of_morphine, running),
|
|
|
|
read_message_from_socket(response_hello),
|
|
send_message_to_socket(hello_reply),
|
|
read_message_from_socket(response_start),
|
|
setval(a_program_has_been_run, yes),
|
|
print_event
|
|
->
|
|
true
|
|
;
|
|
write(stderr, "error in run/1"),
|
|
end_connection
|
|
).
|
|
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_primitive(
|
|
name : decompose_path_call_and_args,
|
|
arg_list : [PathCallArgs, Path, Call, Args],
|
|
arg_type_list : [is_atom_or_string, string, string, string],
|
|
abbrev : _,
|
|
implementation : decompose_path_call_and_args_Op,
|
|
message :
|
|
"Splits a Mercury program call into its path, call, and arguments list."
|
|
).
|
|
|
|
|
|
decompose_path_call_and_args_Op(PathCallArgs, Path, Call, Args) :-
|
|
(
|
|
% For calls of the form : `run("path/call arg1 arg2 ...")'
|
|
decompose_path_call_and_args1(PathCallArgs, Path, Call, Args),
|
|
!
|
|
;
|
|
% For calls of the form : `run("path/call(arg1, arg2, ...)")'.
|
|
% Note that with this syntax, it won't work if path contains
|
|
% `..' because of the precedence of the `..'.
|
|
% I keep the possibility of calling Mercury programs that
|
|
% way for backward compability reasons.
|
|
decompose_path_call_and_args2(PathCallArgs, Path, Call, Args)
|
|
).
|
|
|
|
decompose_path_call_and_args1(PathCallArgs, PathStr, CallStr, ArgsStr) :-
|
|
% PathCallArgs is of the form : "path/call arg1 arg2 ..."
|
|
% or 'path/call arg1 arg2 ...'.
|
|
split_string(PathCallArgs, ListString),
|
|
ListString = [PathCall | ListArgs],
|
|
pathname(PathCall, PathStr0, CallStr),
|
|
( PathStr0 = "" ->
|
|
PathStr = "./"
|
|
;
|
|
PathStr = PathStr0
|
|
),
|
|
% make sure the call is not of the form `cat(arg)'.
|
|
term_string(Call, CallStr),
|
|
Call =.. List,
|
|
length(List, 1),
|
|
string_list_to_string(ListArgs, ArgsStr).
|
|
|
|
decompose_path_call_and_args2(PathCallArgs, PathStr, CallStr, ArgsStr) :-
|
|
% PathCallArgs is of the form : "path/foo(arg1, arg2, ...)"
|
|
% or 'path/foo(arg1, arg2, ...)'.
|
|
pathname(PathCallArgs, PathStr0, CallArgsStr),
|
|
( PathStr0 = "" ->
|
|
PathStr = "./"
|
|
;
|
|
PathStr = PathStr0
|
|
),
|
|
term_string(CallArgs, CallArgsStr),
|
|
CallArgs =.. [Call | ArgList],
|
|
term_string(Call, CallStr),
|
|
maplist(atom_string, ArgList, ArgListStr),
|
|
string_list_to_string(ArgListStr, ArgsStr).
|
|
|
|
string_list_to_string([], " ").
|
|
string_list_to_string([String1|StringList], String) :-
|
|
string_list_to_string(StringList, String2),
|
|
concat_string([ " ", String1, String2], String).
|
|
|
|
|
|
% :- pred run_program(string, string, string, string, string).
|
|
% :- mode run_program(in, in, in, in, in) is det.
|
|
% run the mercury program in an other process
|
|
run_program(ProgramPathStr, PathCallStr, ListArgsStr,
|
|
SocketAddressStr, SocketDomain, RemoteMachine) :-
|
|
(
|
|
getenv('MERCURY_MORPHINE_DIR', Dir),
|
|
window_command(WindowsStr),
|
|
concat_string([
|
|
Dir, "/scripts/exec_mercury_program ",
|
|
SocketAddressStr, " ", SocketDomain, " ",
|
|
RemoteMachine, " ",
|
|
WindowsStr, " ",
|
|
" ", ProgramPathStr,
|
|
PathCallStr, "", ListArgsStr," &"],Command),
|
|
morphine_write_debug("Command ="),
|
|
morphine_write_debug(Command ),
|
|
sh(Command),
|
|
!
|
|
;
|
|
write(stderr, "eclipse.pl: error in morphine_run_program/2")
|
|
).
|
|
|
|
% :- pred list_args_to_string(list(atom), list(string)).
|
|
% :- mode list_args_to_string(in, out) is det.
|
|
list_args_to_string(ListArgs, ArgsStr) :-
|
|
maplist(arg_to_str, ListArgs, ListArgsStr),
|
|
list_string_to_string(ListArgsStr, ArgsStr).
|
|
|
|
% :- pred arg_to_str(atom, string).
|
|
% :- mode arg_to_str(in, out) is det.
|
|
arg_to_str(Argument, String) :-
|
|
term_string(Argument, String1),
|
|
append_strings(" ", String1, String).
|
|
|
|
% :- pred list_string_to_string(list(string), string).
|
|
% :- mode list_string_to_string(in, out) is det.
|
|
list_string_to_string([Str | ListStr], String) :-
|
|
list_string_to_string(ListStr, Str2),
|
|
append_strings(Str, Str2, String).
|
|
|
|
list_string_to_string([], "").
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_type(
|
|
name : is_mercury_program_call,
|
|
implementation : is_mercury_program_call_Op,
|
|
message :
|
|
"Succeeds for terms or strings of the form: \
|
|
`path/programcall arg1 arg2 ...' or `path/programcall(arg1, arg2, ...)'. \
|
|
It is intended to check the argument of `run/1'.\n\
|
|
\n\
|
|
Examples: `run(foo)', `run(\"foo\")', `run(\"./cat file\")', \
|
|
`run(./cat(file))', `run(\"../dir/cat file1 file2\")', \
|
|
`run(\"../dir/cat(file1,file2)\")'.\
|
|
"
|
|
).
|
|
|
|
is_mercury_program_call_Op(ProgramCall0) :-
|
|
( string(ProgramCall0) ->
|
|
ProgramCall = ProgramCall0,
|
|
!
|
|
;
|
|
term_string(ProgramCall0, ProgramCall)
|
|
),
|
|
% Checks program calls of the form "path/call arg1 arg2 ..."
|
|
split_string(ProgramCall, ListString),
|
|
ListString = [PathCall | _],
|
|
pathname(PathCall, _, CallStr),
|
|
term_string(Call, CallStr),
|
|
Call =.. List,
|
|
length(List, 1).
|
|
|
|
is_mercury_program_call_Op(ProgramCall0) :-
|
|
( string(ProgramCall0) ->
|
|
ProgramCall = ProgramCall0
|
|
;
|
|
term_string(ProgramCall0, ProgramCall)
|
|
),
|
|
% Checks program calls of the form "path/call(arg1,arg2,...)"
|
|
pathname(ProgramCall, _, CallArgsStr),
|
|
term_string(CallArgs, CallArgsStr),
|
|
CallArgs =.. [Call | ArgList],
|
|
maplist(atom_string, ArgList, _).
|
|
|
|
|
|
% split_string(String, List) :- split_string(String, " ", " ", List).
|
|
% We redefine it here because split_string/4 is not part of Eclipse3.5.2
|
|
split_string(String, List) :-
|
|
string_list(String, L),
|
|
split_string2(L, [], LL),
|
|
maplist(list_string, LL, List).
|
|
|
|
split_string2([], Acc, [Acc]) :-
|
|
!.
|
|
split_string2([32|Xs], Acc, LL) :-
|
|
!,
|
|
split_string2(Xs, [], LL0),
|
|
(
|
|
Acc = [], !,
|
|
LL = LL0
|
|
;
|
|
LL = [Acc|LL0]
|
|
).
|
|
split_string2([X|Xs], Acc, LL) :-
|
|
!,
|
|
append(Acc, [X], NewAcc),
|
|
split_string2(Xs, NewAcc, LL).
|
|
|
|
list_string(L, S) :-
|
|
string_list(S, L).
|
|
|
|
%------------------------------------------------------------------------------%
|
|
% opium_command(
|
|
% name : run_remote,
|
|
% arg_list : [MachineName, ProgramCall],
|
|
% arg_type_list : [string, is_atom_or_string],
|
|
% abbrev : _,
|
|
% interface : button,
|
|
% command_type : opium,
|
|
% implementation : run_remote_Op,
|
|
% parameters : [],
|
|
% message :
|
|
% 'Executes a Mercury program from Morphine on a remote machine. \n\
|
|
% \n\
|
|
% Example: run_remote(\"cripure.irisa.fr\",\"~mercury/sample/hello\") will \
|
|
% run the mercury program \"hello\" on the machine cripure.\
|
|
% '
|
|
% ).
|
|
|
|
% XXX Not yet working... But that is not that useful...
|
|
run_remote_Op(MachineName, ProgramCall) :-
|
|
pathname(ProgramCall, Path, Name),
|
|
run_remote(MachineName, Path, Name).
|
|
|
|
run_remote(MachineName, ProgramPathStr, ProgramCallStr) :-
|
|
(
|
|
% we store the argument of run/2 in order to restart easily
|
|
% the execution of the program with rerun/0 command.
|
|
setval(re_run_program,
|
|
run_remote(MachineName, ProgramPathStr, ProgramCallStr)),
|
|
|
|
term_string(ProgramCall, ProgramCallStr),
|
|
|
|
ProgramCall =.. [ProgramName | ListArgs],
|
|
start_connection(ProgramName, SocketAddress),
|
|
|
|
term_string(ProgramName, ProgramNameStr),
|
|
term_string(SocketAddress, SocketAddressStr),
|
|
list_args_to_string(ListArgs, ListArgsStr),
|
|
set_parameter(socket_domain, [inet]),
|
|
|
|
% Run the program "ProgramName" in an other window
|
|
|
|
run_program(ProgramPathStr, ProgramNameStr, ListArgsStr,
|
|
SocketAddressStr, " inet ", MachineName),
|
|
|
|
accept(sock, _, newsock),
|
|
|
|
% state_of_morphine = running | not_running | eot (| bot)
|
|
setval(state_of_morphine, running),
|
|
|
|
read_message_from_socket(response_hello),
|
|
send_message_to_socket(hello_reply),
|
|
read_message_from_socket(response_start)
|
|
->
|
|
true
|
|
;
|
|
write(stderr, "error in run/1"),
|
|
end_connection
|
|
).
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : abort_trace,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : a,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : abort_trace_Op,
|
|
parameters : [],
|
|
message :
|
|
'Aborts the current execution in the traced session.\
|
|
'
|
|
).
|
|
|
|
%:- pred abort_trace.
|
|
%:- mode abort_trace is det.
|
|
abort_trace_Op :-
|
|
send_message_to_socket(abort_prog),
|
|
end_connection.
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : no_trace,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : o,
|
|
interface : hidden,
|
|
command_type : opium,
|
|
implementation : no_trace_Op,
|
|
parameters : [],
|
|
message :
|
|
'Continues execution until it reaches the end of the \
|
|
current execution without printing any further trace information.\
|
|
'
|
|
).
|
|
|
|
%:- pred no_trace.
|
|
%:- mode no_trace is det.
|
|
no_trace_Op :-
|
|
send_message_to_socket(no_trace),
|
|
read_message_from_socket(response_forward_move_match_not_found),
|
|
ec.
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : rerun,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : r,
|
|
interface : button,
|
|
command_type : opium,
|
|
implementation : rerun_Op,
|
|
parameters : [],
|
|
message :
|
|
'Runs again the last executed program.\
|
|
').
|
|
|
|
% XX if the connection with the debuggee process ended with a crash,
|
|
% this command may not work properly because the global variable state_of_morphine
|
|
% would be set to running instead of not running. I should intercept the CTRL-C
|
|
% to fix that.
|
|
|
|
%:- pred rerun.
|
|
%:- mode rerun is det.
|
|
rerun_Op :-
|
|
getval(a_program_has_been_run, yes),
|
|
getval(re_run_program, ReStartCommand),
|
|
getval(state_of_morphine, State),
|
|
write(ReStartCommand),nl,
|
|
(
|
|
State = eot
|
|
->
|
|
ec
|
|
;
|
|
State = running
|
|
->
|
|
abort_trace
|
|
;
|
|
% State = not_running
|
|
true
|
|
),
|
|
ReStartCommand,
|
|
!.
|
|
|
|
rerun_Op :-
|
|
write("No program have ever been run ; "),
|
|
write("you can't use rerun/0 command.\n"),
|
|
write("You need to invoque the command run/1 at least once to be "),
|
|
write("able to use rerun/0.\n"),
|
|
fail.
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : goto,
|
|
arg_list : [Chrono],
|
|
arg_type_list : [integer],
|
|
abbrev : _,
|
|
interface : menu,
|
|
command_type : trace,
|
|
implementation : goto_Op,
|
|
parameters : [],
|
|
message :
|
|
"Moves forwards the trace pointer to the event with chronological event \
|
|
number `Chrono'. Fails if the current event number is larger than `Chrono'.").
|
|
|
|
%:- pred goto(integer).
|
|
%:- mode goto(in) is semidet.
|
|
goto_Op(Chrono) :-
|
|
current(chrono = C),
|
|
( (C < Chrono) ->
|
|
fget_np(chrono = Chrono)
|
|
;
|
|
write(user, "You can not move forward to event number number "),
|
|
write(user, Chrono),
|
|
write(user, " because current_event is "),
|
|
write(user, C),
|
|
write(user, "\n"),
|
|
fail
|
|
).
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_parameter(
|
|
name : socket_domain,
|
|
arg_list : [Domain],
|
|
arg_type_list : [is_member([unix, inet])],
|
|
parameter_type : single,
|
|
default : [unix],
|
|
commands : [run, rerun],
|
|
message :
|
|
"Specifies which domain is used by the socket communication \
|
|
between the two processes.\
|
|
"
|
|
).
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_parameter(
|
|
name : window_command,
|
|
arg_list : [String],
|
|
arg_type_list : [string],
|
|
parameter_type : single,
|
|
default : [""],
|
|
commands : [run, rerun],
|
|
message :
|
|
"Specifies the command used to fork a new window to execute the \
|
|
Mercury program in. By default, no other window is used. \
|
|
For example, if one wants to execute a Mercury program within a xterm window, \
|
|
one just needs to use the command: \
|
|
`set_parameter(window_command, [\"xterm -e \"])'.\
|
|
"
|
|
).
|
|
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : no_window,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : _,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : no_window_Op,
|
|
parameters : [window_command],
|
|
message :
|
|
"Sets the `window_command' parameter to `\"\"' (its default value). \
|
|
The Mercury program then executes in the same window as Morphine."
|
|
).
|
|
|
|
no_window_Op :-
|
|
set_parameter(window_command, [""]).
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : use_xterm,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : _,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : use_xterm_Op,
|
|
parameters : [window_command],
|
|
message :
|
|
"Sets the `window_command' parameter to `\"xterm -e \"', which makes the Mercury \
|
|
program executes in a new xterm window."
|
|
).
|
|
|
|
use_xterm_Op :-
|
|
set_parameter(window_command, ["xterm -e "]).
|
|
|
|
%------------------------------------------------------------------------------%
|
|
opium_command(
|
|
name : use_gdb,
|
|
arg_list : [],
|
|
arg_type_list : [],
|
|
abbrev : _,
|
|
interface : menu,
|
|
command_type : opium,
|
|
implementation : use_gdb_Op,
|
|
parameters : [window_command],
|
|
message :
|
|
"Sets the `window_command' parameter to `\"xterm -e gdb \"'. This is to be able \
|
|
to use both gdb and Morphine. Note that to use gdb, you will need to compile \
|
|
your mercury program with the option `--c-debug'."
|
|
).
|
|
|
|
use_gdb_Op :-
|
|
set_parameter(window_command, ["xterm -e gdb "]).
|
|
|
|
|