mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 18:03:36 +00:00
browser/browse.m:
browser/browser_info.m:
browser/collect_lib.m:
browser/declarative_debugger.m:
browser/declarative_oracle.m:
browser/declarative_user.m:
browser/diff.m:
browser/help.m:
browser/interactive_query.m:
browser/parse.m:
browser/util.m:
Replace implicit streams with explicit streams.
Shorten lines longer than 79 chars.
In some places, simplify some code, often using constructs such as
string.format that either did not exist or were too expensive to use
when the original code was written.
In some places, change predicate names that were not meaningful
without module qualification by *including* the module qualification
in the name (e.g. init -> browser_info_init).
In some places, add XXXs.
In browser_info.m, make the output stream *part* of the debugger type,
because without this, having the debugger type belong to the stream
typeclass does NOT make sense. (The typeclass instance for debugger
used to always write to the current output stream, which this diff
is replacing with the use of explicitly specified streams.)
In browse.m, consistently put stream arguments before other arguments.
In browse.m, when exporting Mercury predicates to C, export them
under names with the standard ML_BROWSE_ prefix, NOT under the name
of a *different* predicate with that prefix.
In diff.m, eliminate an unnecessary difference between what we print
when the difference between two terms is at the root, vs what we print
when the difference between two terms is lower down.
In interactive_query.m, when trying to write a program out to a file,
do NOT write the program to the current output stream if we cannot open
the file, since that would accomplish nothing useful.
Also in interactive_query.m, cleanup .dylib instead of .so on MacOS.
In util.m, delete some unused predicates.
In collect_lib.m, document why some code is not worth updating.
In declarative_oracle.m, rename predicates with previously-ambiguous
names.
browser/MDBFLAGS.in:
Specify --warn-implicit-stream-calls for all Mercury modules
in the browser directory from now.
trace/mercury_trace_browse.c:
trace/mercury_trace_cmd_browsing.c:
ssdb/ssdb.m:
Conform to the changes in browser/*.m.
tests/debugger/queens.{exp,exp2}:
Expect the extra output from browser/diff.m.
196 lines
7.9 KiB
Mathematica
196 lines
7.9 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2002, 2005-2006 The University of Melbourne.
|
|
% Copyright (C) 2015-2018 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: collect_lib.m.
|
|
% Author: jahier.
|
|
% Purpose:
|
|
% This module defines functions that are needed to implement the
|
|
% `collect' primitive.
|
|
%
|
|
% `collect' collects runtime information from Mercury program executions.
|
|
% It is intended to let users easily implement their own monitors with
|
|
% acceptable performances.
|
|
%
|
|
% To use it, users just need to define 4 things in a file, using the
|
|
% Mercury syntax:
|
|
% 1) `accumulator_type' which is the type of the accumulator.
|
|
% 2) The predicate initialize/1 which initializes the
|
|
% collecting variable. initialize/1 should respect the
|
|
% following declarations:
|
|
% :- pred initialize(accumulator_type).
|
|
% :- mode initialize(out) is det.
|
|
% 3) The predicate filter/4 which updates the collecting
|
|
% variable at each execution event. filter/4 also outputs
|
|
% a variable that indicates whether to stop collecting.
|
|
% If this variable is set to `stop', the collect process
|
|
% stops; if it is set to `continue', it continues. If this
|
|
% variable is always set to `continue', the collecting will
|
|
% process until the last event is reached. filter/4 should
|
|
% respect the following declarations:
|
|
% :- pred filter(event, accumulator_type, accumulator_type,
|
|
% stop_or_continue).
|
|
% :- mode filter(in, di, uo, out) is det.
|
|
% 4) Optionally, a `post_process/2' function that lets
|
|
% one post-process the final value of the
|
|
% accumulator. `post_process/2' should respect the
|
|
% following declarations:
|
|
% :- pred post_process(accumulator_type, collected_type).
|
|
% :- mode post_process(in, out) is det.
|
|
% If `collected_type' is different from `accumulator_type',
|
|
% the `accumulator_type' should also be defined; otherwise
|
|
% by default, `accumulator_type' is automatically defined as
|
|
% being the same type as `collected_type'.
|
|
% 5) And optionally the mode definition of the second and the
|
|
% third arguments of filter/4: `acc_in' and `acc_out'. Those
|
|
% mode have `di' and `uo' respectively as default values.
|
|
%
|
|
% Then, this file is used to generate the Mercury module `collect.m',
|
|
% which is compiled and dynamically linked with the current execution.
|
|
% When a `collect' request is made from the external debugger, a variable
|
|
% of type accumulator_type is first initialized (with initialize/1) and
|
|
% then updated (with filter/4) for all the events of the remaining
|
|
% execution. When the end of the execution is reached, the last value of
|
|
% the collecting variable is send to the debugger.
|
|
|
|
:- module mdb.collect_lib.
|
|
:- interface.
|
|
|
|
:- pred dummy_pred_to_avoid_warning_about_nothing_exported is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module mdb.dl.
|
|
|
|
:- import_module char.
|
|
:- import_module io.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
dummy_pred_to_avoid_warning_about_nothing_exported.
|
|
|
|
:- pragma foreign_export("C",
|
|
link_collect(in, out, out, out, out, out, out, out, di, uo),
|
|
"ML_CL_link_collect").
|
|
|
|
:- pragma foreign_export("C", unlink_collect(in, di, uo),
|
|
"ML_CL_unlink_collect").
|
|
|
|
% We need Handle to be able to close the shared object (dl.close) later on.
|
|
% When the link failed, we output NULL pointers instead of maybe pointers
|
|
% for performance reasons; indeed, filter will be called at every event
|
|
% so we don't want to pay the price of the maybe variable de-construction
|
|
% at each event.
|
|
|
|
% dynamically link the collect module;
|
|
:- pred link_collect(string::in, c_pointer::out, c_pointer::out,
|
|
c_pointer::out, c_pointer::out, c_pointer::out, dl_result(handle)::out,
|
|
char::out, io::di, io::uo) is det.
|
|
|
|
link_collect(ObjectFile, Filter, Initialize, PostProcess, SendResult,
|
|
GetCollectType, MaybeHandle, Result, !IO) :-
|
|
% Link in the object code for the module `collect' from ObjectFile.
|
|
dl.open(ObjectFile, lazy, scope_local, MaybeHandle, !IO),
|
|
(
|
|
MaybeHandle = dl_error(Msg),
|
|
% XXX Our caller should tell us on what stream we should print
|
|
% any error messages, but
|
|
%
|
|
% - since link_collect is exported to C, that would require changes
|
|
% to the relevant C code, and
|
|
%
|
|
% - that C code has not been used in a long time, so there is
|
|
% no good way to test such changes.
|
|
%
|
|
% The code here preserves old behavior.
|
|
io.output_stream(Stream, !IO),
|
|
io.print(Stream, "dlopen failed: ", !IO),
|
|
io.print(Stream, Msg, !IO),
|
|
io.nl(Stream, !IO),
|
|
set_to_null_pointer(Initialize),
|
|
set_to_null_pointer(Filter),
|
|
set_to_null_pointer(PostProcess),
|
|
set_to_null_pointer(SendResult),
|
|
set_to_null_pointer(GetCollectType),
|
|
Result = 'n'
|
|
;
|
|
MaybeHandle = dl_ok(Handle),
|
|
|
|
% Look up the address of the C functions corresponding to the
|
|
% initialize/1 and filter/15 predicates in the collect module.
|
|
dl.sym(Handle, "ML_COLLECT_initialize", MaybeInitialize, !IO),
|
|
dl.sym(Handle, "ML_COLLECT_filter", MaybeFilter, !IO),
|
|
dl.sym(Handle, "ML_COLLECT_post_process", MaybePostProcess, !IO),
|
|
dl.sym(Handle, "ML_COLLECT_send_collect_result", MaybeSendResult, !IO),
|
|
dl.sym(Handle, "ML_COLLECT_collected_variable_type", MaybeType, !IO),
|
|
( if
|
|
MaybeInitialize = dl_ok(Initialize0),
|
|
MaybeFilter = dl_ok(Filter0),
|
|
MaybePostProcess = dl_ok(PostProcess0),
|
|
MaybeSendResult = dl_ok(SendResult0),
|
|
MaybeType = dl_ok(Type0)
|
|
then
|
|
Result = 'y',
|
|
Initialize = Initialize0,
|
|
Filter = Filter0,
|
|
PostProcess = PostProcess0,
|
|
GetCollectType = Type0,
|
|
SendResult = SendResult0
|
|
else
|
|
set_to_null_pointer(Initialize),
|
|
set_to_null_pointer(Filter),
|
|
set_to_null_pointer(PostProcess),
|
|
set_to_null_pointer(SendResult),
|
|
set_to_null_pointer(GetCollectType),
|
|
Result = 'n'
|
|
)
|
|
).
|
|
|
|
:- pred set_to_null_pointer(c_pointer::out) is det.
|
|
:- pragma no_determinism_warning(set_to_null_pointer/1).
|
|
|
|
:- pragma foreign_proc("C",
|
|
set_to_null_pointer(Pointer::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
(Pointer = (MR_Word) NULL)
|
|
").
|
|
|
|
set_to_null_pointer(_) :-
|
|
private_builtin.sorry("collect_lib.set_to_null_pointer").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Dynamically unlink a module that was dynamically linked in
|
|
% using `link_collect'.
|
|
%
|
|
:- pred unlink_collect(dl_result(handle)::in, io::di, io::uo) is det.
|
|
|
|
unlink_collect(MaybeHandle, !IO) :-
|
|
(
|
|
MaybeHandle = dl_error(_)
|
|
% There is nothing to close since an error(_) here means that
|
|
% the dlopen failed.
|
|
;
|
|
MaybeHandle = dl_ok(Handle),
|
|
dl.close(Handle, Result, !IO),
|
|
% XXX See the comment in link_collect about streams.
|
|
io.output_stream(Stream, !IO),
|
|
display_close_result(Stream, Result, !IO)
|
|
).
|
|
|
|
:- pred display_close_result(io.text_output_stream::in, dl_result::in,
|
|
io::di, io::uo) is det.
|
|
|
|
display_close_result(_Stream, dl_ok, !IO).
|
|
display_close_result(Stream, dl_error(String), !IO) :-
|
|
io.print(Stream, String, !IO),
|
|
io.nl(Stream, !IO).
|