mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 10:23:46 +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.
287 lines
9.7 KiB
Mathematica
287 lines
9.7 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-2000, 2003-2006 The University of Melbourne.
|
|
% Copyright (C) 2015, 2017-2018 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: help.m.
|
|
% Author: zs.
|
|
% Stability: low.
|
|
%
|
|
% This file provides a basic help system that stores information in help nodes
|
|
% which are organized as a tree structure of arbitrary depth.
|
|
%
|
|
% The help system consists of a list of help list entries. Each entry
|
|
% has a name, an index (an integer that determines its position in the list),
|
|
% and a help node. Each node contains text that should shed some light
|
|
% on the topic named by the node's entry. Each node also has an associated
|
|
% list of child entries; this list may of course be empty.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module mdb.help.
|
|
|
|
:- interface.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module type_desc.
|
|
|
|
:- type help_system.
|
|
|
|
:- type path == list(string).
|
|
|
|
:- type help_res
|
|
---> help_ok
|
|
; help_error(string).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Initialize an empty help system.
|
|
%
|
|
:- pred init(help_system::out) is det.
|
|
|
|
% Add a node to the given help system, at the given path, and with
|
|
% the given name and index. If successful, return help_ok and the
|
|
% updated help system; if not, return an error message and the
|
|
% original help system.
|
|
%
|
|
:- pred add_help_node(path::in, int::in, string::in, string::in,
|
|
help_res::out, help_system::in, help_system::out) is det.
|
|
|
|
% Print the top-level help nodes. This should give an overview
|
|
% of the main topics for which help is available.
|
|
%
|
|
:- pred print_top_level_help_nodes(io.output_stream::in, help_system::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% Print the help node at the given path. If there is none,
|
|
% print the top-level nodes.
|
|
%
|
|
:- pred print_help_node_at_path(io.output_stream::in, help_system::in,
|
|
path::in, help_res::out, io::di, io::uo) is det.
|
|
|
|
% Print all help nodes with the given name. If there are none,
|
|
% print the top-level nodes.
|
|
%
|
|
:- pred print_help_for_name(io.output_stream::in, help_system::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Return the type_info for the type system, for use by C code.
|
|
%
|
|
:- pred help_system_type(type_desc::out) is det.
|
|
|
|
% Help interpret a help_res for C code.
|
|
%
|
|
:- pred result_is_error(help_res::in, string::out) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
|
|
:- type help_system == list(help_node).
|
|
|
|
:- type help_node
|
|
---> help_node(
|
|
% The index of the node, which determines the position
|
|
% of the node in the node list of its parent (if any) or
|
|
% or in the system node list (if it has no parent).
|
|
% Every node list is always sorted on this field.
|
|
helpnode_index :: int,
|
|
|
|
% The name of the node, which should be one word or phrase.
|
|
% It must be unique within the list of nodes containing it,
|
|
% but need not be unique globally.
|
|
helpnode_name :: string,
|
|
|
|
% The actual help text in the node. Should be one or more
|
|
% complete lines.
|
|
helpnode_text :: string,
|
|
|
|
helpnode_children :: list(help_node)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pragma foreign_export("C", init(out), "ML_HELP_init").
|
|
:- pragma foreign_export("C", add_help_node(in, in, in, in, out, in, out),
|
|
"ML_HELP_add_help_node").
|
|
:- pragma foreign_export("C", print_top_level_help_nodes(in, in, di, uo),
|
|
"ML_HELP_print_top_level_help_nodes").
|
|
:- pragma foreign_export("C", print_help_node_at_path(in, in, in, out, di, uo),
|
|
"ML_HELP_print_help_node_at_path").
|
|
:- pragma foreign_export("C", print_help_for_name(in, in, in, di, uo),
|
|
"ML_HELP_print_help_for_name").
|
|
:- pragma foreign_export("C", help_system_type(out),
|
|
"ML_HELP_help_system_type").
|
|
:- pragma foreign_export("C", result_is_error(in, out),
|
|
"ML_HELP_result_is_error").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init([]).
|
|
|
|
add_help_node(Path, Index, Name, Text, Res, !Sys) :-
|
|
Node = help_node(Index, Name, Text, []),
|
|
add_node(Path, Node, Res, !Sys).
|
|
|
|
:- pred add_node(path::in, help_node::in, help_res::out,
|
|
list(help_node)::in, list(help_node)::out) is det.
|
|
|
|
add_node([Step | Steps], NewNode, Res, Nodes0, Nodes) :-
|
|
( if one_path_step(Nodes0, Step, Node0) then
|
|
Node0 = help_node(NodeIndex, NodeName, Text, SubNodes0),
|
|
add_node(Steps, NewNode, Res, SubNodes0, SubNodes),
|
|
Node = help_node(NodeIndex, NodeName, Text, SubNodes),
|
|
replace_node_at_index(Node, Nodes0, Nodes)
|
|
else
|
|
Msg = "invalid path component " ++ Step,
|
|
Res = help_error(Msg),
|
|
Nodes = Nodes0
|
|
).
|
|
add_node([], NewNode, Res, Nodes0, Nodes) :-
|
|
( if
|
|
some [MemberNode] (
|
|
list.member(MemberNode, Nodes0),
|
|
MemberNode ^ helpnode_index = NewNode ^ helpnode_index
|
|
)
|
|
then
|
|
Res = help_error("entry with given index already exists"),
|
|
Nodes = Nodes0
|
|
else if
|
|
some [MemberNode] (
|
|
list.member(MemberNode, Nodes0),
|
|
MemberNode ^ helpnode_name = NewNode ^ helpnode_name
|
|
)
|
|
then
|
|
Res = help_error("entry with given name already exists"),
|
|
Nodes = Nodes0
|
|
else
|
|
Res = help_ok,
|
|
insert_into_node_list(NewNode, Nodes0, Nodes)
|
|
).
|
|
|
|
:- pred replace_node_at_index(help_node::in,
|
|
list(help_node)::in, list(help_node)::out) is det.
|
|
|
|
replace_node_at_index(_, [], _) :-
|
|
unexpected($pred, "node to be replaced not found").
|
|
replace_node_at_index(Node, [Head | Tail], List) :-
|
|
( if Head ^ helpnode_index = Node ^ helpnode_index then
|
|
List = [Node | Tail]
|
|
else
|
|
replace_node_at_index(Node, Tail, NewTail),
|
|
List = [Head | NewTail]
|
|
).
|
|
|
|
:- pred insert_into_node_list(help_node::in,
|
|
list(help_node)::in, list(help_node)::out) is det.
|
|
|
|
insert_into_node_list(Node, [], [Node]).
|
|
insert_into_node_list(Node, [Head | Tail], List) :-
|
|
( if Head ^ helpnode_index < Node ^ helpnode_index then
|
|
insert_into_node_list(Node, Tail, NewTail),
|
|
List = [Head | NewTail]
|
|
else
|
|
List = [Node, Head | Tail]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
print_top_level_help_nodes(Stream, Sys, !IO) :-
|
|
print_node_list(Stream, Sys, !IO).
|
|
|
|
print_help_node_at_path(Stream, Nodes, Path, Result, !IO) :-
|
|
(
|
|
Path = [Step | Tail],
|
|
( if one_path_step(Nodes, Step, Node) then
|
|
(
|
|
Tail = [],
|
|
print_node(Stream, Node, !IO),
|
|
Result = help_ok
|
|
;
|
|
Tail = [_ | _],
|
|
SubNodes = Node ^ helpnode_children,
|
|
print_help_node_at_path(Stream, SubNodes, Tail, Result, !IO)
|
|
)
|
|
else
|
|
Msg = "error at path component """ ++ Step ++ """",
|
|
Result = help_error(Msg)
|
|
)
|
|
;
|
|
Path = [],
|
|
Result = help_error("the path does not go that deep")
|
|
).
|
|
|
|
print_help_for_name(Stream, Sys, Name, !IO) :-
|
|
search_node_list(Sys, Name, [], RevMatchedNodes),
|
|
(
|
|
RevMatchedNodes = [],
|
|
io.write_string(Stream, "There is no such help topic.\n", !IO),
|
|
print_top_level_help_nodes(Stream, Sys, !IO)
|
|
;
|
|
RevMatchedNodes = [_ | _],
|
|
list.reverse(RevMatchedNodes, MatchedNodes),
|
|
print_node_list(Stream, MatchedNodes, !IO)
|
|
).
|
|
|
|
:- pred search_node_list(list(help_node)::in, string::in,
|
|
list(help_node)::in, list(help_node)::out) is det.
|
|
|
|
search_node_list([], _, !RevMatchedNodes).
|
|
search_node_list([Node | Nodes], Name, !RevMatchedNodes) :-
|
|
( if Name = Node ^ helpnode_name then
|
|
!:RevMatchedNodes = [Node | !.RevMatchedNodes]
|
|
else
|
|
search_node_list(Node ^ helpnode_children, Name, !RevMatchedNodes),
|
|
search_node_list(Nodes, Name, !RevMatchedNodes)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred print_node_list(io.output_stream::in, list(help_node)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
print_node_list(_, [], !IO).
|
|
print_node_list(Stream, [Node | Nodes], !IO) :-
|
|
print_node(Stream, Node, !IO),
|
|
print_node_list(Stream, Nodes, !IO).
|
|
|
|
:- pred print_node(io.output_stream::in, help_node::in, io::di, io::uo) is det.
|
|
|
|
print_node(Stream, Node, !IO) :-
|
|
Node = help_node(_, _, Text, _),
|
|
io.write_string(Stream, Text, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred one_path_step(list(help_node)::in, string::in, help_node::out)
|
|
is semidet.
|
|
|
|
one_path_step([Head | Tail], Name, Node) :-
|
|
( if Head ^ helpnode_name = Name then
|
|
Node = Head
|
|
else
|
|
one_path_step(Tail, Name, Node)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
help_system_type(Type) :-
|
|
init(HelpInit),
|
|
Type = type_of(HelpInit).
|
|
|
|
result_is_error(help_error(Msg), Msg).
|
|
|
|
%---------------------------------------------------------------------------%
|