mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 14:57:03 +00:00
Estimated hours taken: 16 Branches: main The file modules.m contains lots of different kinds of functionality. While much of it belongs together, much of it does not. This diff moves most of the functionality that does not belong with the rest to several new modules: libs.file_util parse_tree.deps_map parse_tree.file_names parse_tree.module_cmds parse_tree.module_imports parse_tree.read_module parse_tree.write_deps_file To make them coherent, move some predicates from hlds.passes_aux, parse_tree.prog_io and parse_tree.prog_out to the new modules, making them more accessible, reducing the required access from the hlds package to parse_tree, or from the parse_tree package to libs. In the same spirit, this diff also moves some simple predicates and functions dealing with sym_names from prog_util.m to mdbcomp/prim_data.m. This allows several modules to avoid depending on parse_tree.prog_util. Rename some of the moved predicates and function symbols where this avoids ambiguity. (There were several that differed from other predicates or function symbols only in arity.) Replace several uses of bools with purpose-specific types. This makes some of the code significantly easier to read. This diff moves modules.m from being by far the largest module, to being only the seventh largest, from 8900+ lines to just 4200+. It also reduces the number of modules that import parse_tree.modules considerably; most modules that imported it now import only one or two of the new modules instead. Despite the size of the diff, there should be no algorithmic changes. compiler/modules.m: compiler/passes_aux.m: compiler/prog_io.m: compiler/prog_out.m: Delete the moved functionality. compiler/file_util.m: New module in the libs package. Its predicates search for files and do simple error or progress reporting. compiler/file_names.m: New module in the parse_tree package. It contains predicates for converting module names to file names. compiler/module_cmds.m: New module in the parse_tree package. Its predicates handle the commands for manipulating interface files of various kinds. compiler/module_import.m: New module in the parse_tree package. It contains the module_imports type and its access predicates, and the predicates that compute various sorts of direct dependencies (those caused by imports) between modules. compiler/deps_map.m: New module in the parse_tree package. It contains the data structure for recording indirect dependencies between modules, and the predicates for creating it. compiler/read_module.m: New module in the parse_tree package. Its job is reading in modules, both human-written and machine-written (such as interface and optimization files). compiler/write_deps_file.m: New module in the parse_tree package. Its job is writing out makefile fragments. compiler/libs.m: compiler/parse_tree.m: Include the new modules. compiler/notes/compiler_design.m: Document the new modules. mdbcomp/prim_data.m: compiler/prog_util.m: Move the predicates that operate on nothing but sym_names from prog_util to prim_data. Move get_ancestors from modules to prim_data. compiler/prog_item.m: Move stuff that looks for foreign code in a list of items here from modules.m. compiler/source_file_map.m: Note why this module needs to be in the parse_tree package. compiler/add_pred.m: compiler/add_special_pred.m: compiler/analysis.file.m: compiler/analysis.m: compiler/assertion.m: compiler/check_typeclass.m: compiler/compile_target_code.m: compiler/cse_detection.m: compiler/det_analysis.m: compiler/elds_to_erlang.m: compiler/exception_analysis.m: compiler/export.m: compiler/fact_table.m: compiler/higher_order.m: compiler/hlds_module.m: compiler/hlds_pred.m: compiler/intermod.m: compiler/llds_out.m: compiler/make.dependencies.m: compiler/make.m: compiler/make.module_dep_file.m: compiler/make.module_target.m: compiler/make.program_target.m: compiler/make.util.m: compiler/make_hlds_passes.m: compiler/maybe_mlds_to_gcc.pp: compiler/mercury_compile.m: compiler/mlds.m: compiler/mlds_to_c.m: compiler/mlds_to_gcc.m: compiler/mlds_to_ilasm.m: compiler/mlds_to_java.m: compiler/mmc_analysis.m: compiler/mode_constraints.m: compiler/mode_debug.m: compiler/modes.m: compiler/module_qual.m: compiler/optimize.m: compiler/passes_aux.m: compiler/proc_gen.m: compiler/prog_foreign.m: compiler/prog_io.m: compiler/prog_io_util.m: compiler/prog_mutable.m: compiler/prog_out.m: compiler/pseudo_type_info.m: compiler/purity.m: compiler/recompilation.check.m: compiler/recompilation.usage.m: compiler/simplify.m: compiler/structure_reuse.analysis.m: compiler/structure_reuse.direct.detect_garbage.m: compiler/structure_reuse.direct.m: compiler/structure_sharing.analysis.m: compiler/tabling_analysis.m: compiler/term_constr_main.m: compiler/termination.m: compiler/trailing_analysis.m: compiler/trans_opt.m: compiler/type_util.m: compiler/typecheck.m: compiler/typecheck_info.m: compiler/unify_proc.m: compiler/unused_args.m: compiler/unused_imports.m: compiler/xml_documentation.m: Minor changes to conform to the changes above.
821 lines
30 KiB
Mathematica
821 lines
30 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2006-2008 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Module: xml_documentation.m.
|
|
% Main authors: petdr.
|
|
%
|
|
% This module outputs an XML representation of a module,
|
|
% which can then be transformed by a stylesheet into some other
|
|
% documentation format.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.xml_documentation.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
|
|
:- import_module io.
|
|
|
|
% Output a representation of the module in XML which can be used
|
|
% to document the module.
|
|
%
|
|
:- pred xml_documentation(module_info::in, io::di, io::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module libs.
|
|
:- import_module libs.compiler_util.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_util.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.source_file_map.
|
|
|
|
:- import_module bool.
|
|
:- import_module char.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module svmap.
|
|
:- import_module term.
|
|
:- import_module term_to_xml.
|
|
:- import_module varset.
|
|
|
|
% Record all the locations of comments in a file.
|
|
%
|
|
:- type comments
|
|
---> comments(
|
|
% For each line record what is on the line.
|
|
line_types :: map(int, line_type)
|
|
).
|
|
|
|
:- type line_type
|
|
---> blank
|
|
% A line containing only whitespace.
|
|
|
|
; comment(string)
|
|
% A line containing just a comment.
|
|
|
|
; code_and_comment(string)
|
|
% A line which contains both a comment and code.
|
|
|
|
; code.
|
|
% A line containing code.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
xml_documentation(ModuleInfo, !IO) :-
|
|
module_info_get_name(ModuleInfo, ModuleName),
|
|
module_name_to_file_name(ModuleName, ".xml", do_create_dirs, FileName,
|
|
!IO),
|
|
|
|
lookup_module_source_file(ModuleName, SrcFileName, !IO),
|
|
io.open_input(SrcFileName, SrcResult, !IO),
|
|
(
|
|
SrcResult = ok(SrcStream),
|
|
build_comments(SrcStream, comments(map.init), Comments, !IO),
|
|
|
|
%
|
|
% XXX We should find the ":- module " declaration
|
|
% and get the comment from there.
|
|
%
|
|
ModuleComment = get_comment_forwards(Comments, 1),
|
|
|
|
io.open_output(FileName, OpenResult, !IO),
|
|
(
|
|
OpenResult = ok(Stream),
|
|
MIXmlDoc = module_info_xml_doc(Comments, ModuleComment,
|
|
ModuleInfo),
|
|
write_xml_doc(Stream, MIXmlDoc, !IO)
|
|
;
|
|
OpenResult = error(Err),
|
|
unable_to_open_file(FileName, Err, !IO)
|
|
)
|
|
;
|
|
SrcResult = error(SrcErr),
|
|
unable_to_open_file(SrcFileName, SrcErr, !IO)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Given the input_stream build the comments datastructure which
|
|
% represents this stream.
|
|
%
|
|
:- pred build_comments(io.input_stream::in, comments::in, comments::out,
|
|
io::di, io::uo) is det.
|
|
|
|
build_comments(S, comments(!.C), comments(!:C), !IO) :-
|
|
io.get_line_number(S, LineNumber, !IO),
|
|
io.read_line(S, LineResult, !IO),
|
|
(
|
|
LineResult = ok(Line),
|
|
svmap.set(LineNumber, line_type(Line), !C),
|
|
build_comments(S, comments(!.C), comments(!:C), !IO)
|
|
;
|
|
LineResult = eof
|
|
;
|
|
LineResult = error(E),
|
|
% XXX we should recover more gracefully from this error.
|
|
unexpected(this_file, io.error_message(E))
|
|
).
|
|
|
|
% Given a list of characters representing one line,
|
|
% return the type of the line.
|
|
%
|
|
% Note this predicate is pretty stupid at the moment.
|
|
% It only recognizes lines which contains % comments.
|
|
% It also is confused by % characters in strings, etc. etc.
|
|
%
|
|
:- func line_type(list(character)) = line_type.
|
|
|
|
line_type(Line) = LineType :-
|
|
list.takewhile(char.is_whitespace, Line, _WhiteSpace, Rest),
|
|
list.takewhile(is_not_comment_char, Rest, Decl, Comment),
|
|
(
|
|
Rest = [],
|
|
LineType = blank
|
|
;
|
|
Rest = [_ | _],
|
|
(
|
|
Comment = [],
|
|
LineType = code
|
|
;
|
|
Comment = [_ | _],
|
|
(
|
|
Decl = [],
|
|
LineType = comment(string.from_char_list(Comment))
|
|
;
|
|
Decl = [_ | _],
|
|
LineType = code_and_comment(string.from_char_list(Comment))
|
|
)
|
|
)
|
|
).
|
|
|
|
:- pred is_not_comment_char(char::in) is semidet.
|
|
|
|
is_not_comment_char(C) :-
|
|
C \= '%'.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Comment selection strategies
|
|
|
|
% If the prog_context given has a comment associated with it
|
|
% add a child element which contains the comment to the given XML.
|
|
%
|
|
:- func maybe_add_comment(comments, prog_context, xml) = xml.
|
|
|
|
maybe_add_comment(Comments, Context, Xml) =
|
|
( Xml = elem(N, As, Cs) ->
|
|
( Comment = get_comment(Comments, Context), Comment \= "" ->
|
|
elem(N, As, [elem("comment", [], [data(Comment)]) | Cs])
|
|
;
|
|
Xml
|
|
)
|
|
;
|
|
unexpected(this_file, "maybe_add_comment: not an element")
|
|
).
|
|
|
|
% Get the comment string associated with the given prog_context.
|
|
%
|
|
:- func get_comment(comments, prog_context) = string.
|
|
|
|
get_comment(Comments, context(_, Line)) =
|
|
%
|
|
% XXX at a later date this hard-coded strategy should
|
|
% be made more flexible. What I imagine is that the
|
|
% user would pass a string saying in what order
|
|
% they wish to search for comments.
|
|
%
|
|
( comment_on_current_line(Comments, Line, C) ->
|
|
C
|
|
; comment_directly_above(Comments, Line, C) ->
|
|
C
|
|
;
|
|
""
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Succeeds if the current line has a comment.
|
|
% The comment is extended with all the lines following
|
|
% the current line which just contain a comment.
|
|
%
|
|
:- pred comment_on_current_line(comments::in, int::in, string::out) is semidet.
|
|
|
|
comment_on_current_line(Comments, Line, Comment) :-
|
|
map.search(Comments ^ line_types, Line, code_and_comment(Comment0)),
|
|
RestComment = get_comment_forwards(Comments, Line + 1),
|
|
Comment = Comment0 ++ RestComment.
|
|
|
|
% Succeeds if the comment is directly above the current line.
|
|
% The comment above ends when we find a line above the current line
|
|
% which doesn't just contain a comment.
|
|
%
|
|
:- pred comment_directly_above(comments::in, int::in, string::out) is semidet.
|
|
|
|
comment_directly_above(Comments, Line, Comment) :-
|
|
map.search(Comments ^ line_types, Line - 1, comment(_)),
|
|
Comment = get_comment_backwards(Comments, Line - 1).
|
|
|
|
% Return the string which represents the comment starting at the given
|
|
% line. The comment ends when a line which is not a plain comment line
|
|
% is found.
|
|
%
|
|
:- func get_comment_forwards(comments, int) = string.
|
|
|
|
get_comment_forwards(Comments, Line) = Comment :-
|
|
( map.search(Comments ^ line_types, Line, LineType) ->
|
|
(
|
|
LineType = comment(CurrentComment),
|
|
CommentBelow = get_comment_forwards(Comments, Line + 1),
|
|
Comment = CurrentComment ++ CommentBelow
|
|
;
|
|
( LineType = blank
|
|
; LineType = code
|
|
; LineType = code_and_comment(_)
|
|
),
|
|
Comment = ""
|
|
)
|
|
;
|
|
Comment = ""
|
|
).
|
|
|
|
% Return the string which represents the comment ending at the given line.
|
|
% The comment extends backwards until the the line above the given
|
|
% line is not a comment only line.
|
|
%
|
|
:- func get_comment_backwards(comments, int) = string.
|
|
|
|
get_comment_backwards(Comments, Line) = Comment :-
|
|
( map.search(Comments ^ line_types, Line, LineType) ->
|
|
(
|
|
LineType = comment(CurrentComment),
|
|
CommentAbove = get_comment_backwards(Comments, Line - 1),
|
|
Comment = CommentAbove ++ CurrentComment
|
|
;
|
|
( LineType = blank
|
|
; LineType = code
|
|
; LineType = code_and_comment(_)
|
|
),
|
|
Comment = ""
|
|
)
|
|
;
|
|
Comment = ""
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type module_info_xml_doc
|
|
---> module_info_xml_doc(comments, string, module_info).
|
|
|
|
:- instance xmlable(module_info_xml_doc) where [
|
|
(to_xml(module_info_xml_doc(Comments, ModuleComment, ModuleInfo)) = Xml :-
|
|
CommentXml = elem("comment", [], [data(ModuleComment)]),
|
|
|
|
module_info_get_interface_module_specifiers(ModuleInfo,
|
|
InterfaceImports),
|
|
module_info_get_imported_module_specifiers(ModuleInfo,
|
|
ImportedModules0),
|
|
ImportedModules = ImportedModules0 `difference` set(all_builtin_modules),
|
|
set.fold(import_documentation(InterfaceImports),
|
|
ImportedModules, [], ImportsXml),
|
|
ImportXml = elem("imports", [], ImportsXml),
|
|
|
|
module_info_get_type_table(ModuleInfo, TypeTable),
|
|
map.foldl(type_documentation(Comments), TypeTable, [], TypeXmls),
|
|
TypeXml = elem("types", [], TypeXmls),
|
|
|
|
module_info_preds(ModuleInfo, PredTable),
|
|
map.foldl(pred_documentation(Comments), PredTable, [], PredXmls),
|
|
PredXml = elem("preds", [], PredXmls),
|
|
|
|
module_info_get_class_table(ModuleInfo, ClassTable),
|
|
map.foldl(class_documentation(Comments, PredTable), ClassTable,
|
|
[], ClassXmls),
|
|
ClassXml = elem("typeclasses", [], ClassXmls),
|
|
|
|
Children = [CommentXml, ImportXml, TypeXml, PredXml, ClassXml],
|
|
Xml = elem("module", [], Children)
|
|
)
|
|
].
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Output the documentation for one import
|
|
%
|
|
:- pred import_documentation(set(module_specifier)::in, module_specifier::in,
|
|
list(xml)::in, list(xml)::out) is det.
|
|
|
|
import_documentation(InterfaceImportedModules, ImportedModule, !Xmls) :-
|
|
XmlName = name(ImportedModule),
|
|
( ImportedModule `set.member` InterfaceImportedModules ->
|
|
XmlVisibility = visibility(status_exported)
|
|
;
|
|
XmlVisibility = visibility(status_local)
|
|
),
|
|
Xml = elem("import", [], [XmlName, XmlVisibility]),
|
|
!:Xmls = [Xml | !.Xmls].
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Output the documentation of one type.
|
|
%
|
|
:- pred type_documentation(comments::in, type_ctor::in, hlds_type_defn::in,
|
|
list(xml)::in, list(xml)::out) is det.
|
|
|
|
type_documentation(C, type_ctor(TypeName, TypeArity), TypeDefn, !Xmls) :-
|
|
get_type_defn_status(TypeDefn, ImportStatus),
|
|
|
|
( status_defined_in_this_module(ImportStatus) = yes ->
|
|
get_type_defn_body(TypeDefn, TypeBody),
|
|
get_type_defn_tvarset(TypeDefn, TVarset),
|
|
get_type_defn_context(TypeDefn, Context),
|
|
get_type_defn_tparams(TypeDefn, TParams),
|
|
|
|
XmlName = name(TypeName),
|
|
XmlTypeParams = xml_list("type_params", type_param(TVarset), TParams),
|
|
XmlVisibility = visibility(ImportStatus),
|
|
|
|
Tag = type_xml_tag(TypeBody),
|
|
Id = attr("id", sym_name_and_arity_to_id("type", TypeName, TypeArity)),
|
|
Children = [XmlName, XmlTypeParams, XmlVisibility,
|
|
prog_context(Context) | type_body(C, TVarset, TypeBody)],
|
|
Xml0 = elem(Tag, [Id], Children),
|
|
Xml = maybe_add_comment(C, Context, Xml0),
|
|
|
|
!:Xmls = [Xml | !.Xmls]
|
|
;
|
|
true
|
|
).
|
|
|
|
:- func type_xml_tag(hlds_type_body) = string.
|
|
|
|
type_xml_tag(hlds_du_type(_, _, _, _, _, _, _, _)) = "du_type".
|
|
type_xml_tag(hlds_eqv_type(_)) = "eqv_type".
|
|
type_xml_tag(hlds_foreign_type(_)) = "foreign_type".
|
|
type_xml_tag(hlds_solver_type(_, _)) = "solver_type".
|
|
type_xml_tag(hlds_abstract_type(_)) = "abstract_type".
|
|
|
|
:- func type_param(tvarset, type_param) = xml.
|
|
|
|
type_param(TVarset, TVar) = Xml :-
|
|
TVarName = varset.lookup_name(TVarset, TVar),
|
|
Xml = tagged_string("type_variable", TVarName).
|
|
|
|
:- func type_body(comments, tvarset, hlds_type_body) = list(xml).
|
|
|
|
type_body(C, TVarset, hlds_du_type(Ctors, _, _, _, _, _, _, _)) =
|
|
[xml_list("constructors", constructor(C, TVarset), Ctors)].
|
|
type_body(_, TVarset, hlds_eqv_type(Type)) =
|
|
[elem("equivalent_type", [], [mer_type(TVarset, Type)])].
|
|
|
|
% XXX TODO
|
|
type_body(_, _, hlds_foreign_type(_)) = [nyi("hlds_foreign_type")].
|
|
type_body(_, _, hlds_solver_type(_, _)) = [nyi("hlds_solver_type")].
|
|
type_body(_, _, hlds_abstract_type(_)) = [nyi("hlds_abstract_type")].
|
|
|
|
:- func constructor(comments, tvarset, constructor) = xml.
|
|
|
|
constructor(C, TVarset,
|
|
ctor(Exists, Constraints, Name, Args, Context)) = Xml :-
|
|
Id = attr("id", sym_name_and_arity_to_id("ctor", Name, length(Args))),
|
|
XmlName = name(Name),
|
|
XmlContext = prog_context(Context),
|
|
XmlArgs = xml_list("ctor_args", constructor_arg(C, TVarset), Args),
|
|
XmlExistVars = xml_list("ctor_exist_vars", type_param(TVarset), Exists),
|
|
XmlConstraints =
|
|
xml_list("ctor_constraints", prog_constraint(TVarset), Constraints),
|
|
Xml0 = elem("constructor", [Id],
|
|
[XmlName, XmlContext, XmlArgs, XmlExistVars, XmlConstraints]),
|
|
Xml = maybe_add_comment(C, Context, Xml0).
|
|
|
|
:- func constructor_arg(comments, tvarset, constructor_arg) = xml.
|
|
|
|
constructor_arg(C, TVarset, ctor_arg(MaybeFieldName, Type, Context)) = Xml :-
|
|
XmlType = elem("arg_type", [], [mer_type(TVarset, Type)]),
|
|
XmlContext = prog_context(Context),
|
|
(
|
|
MaybeFieldName = yes(FieldName),
|
|
Id = attr("id", sym_name_to_id("field", FieldName)),
|
|
XmlMaybeFieldName = [elem("field", [Id], [name(FieldName)])]
|
|
;
|
|
MaybeFieldName = no,
|
|
XmlMaybeFieldName = []
|
|
),
|
|
|
|
Xml0 = elem("ctor_arg", [], [XmlType, XmlContext | XmlMaybeFieldName]),
|
|
Xml = maybe_add_comment(C, Context, Xml0).
|
|
|
|
:- func mer_type(tvarset, mer_type) = xml.
|
|
|
|
mer_type(TVarset, type_variable(TVar, _)) = type_param(TVarset, TVar).
|
|
mer_type(TVarset, defined_type(TypeName, Args, _)) = Xml :-
|
|
Ref = attr("ref", sym_name_and_arity_to_id("type", TypeName, length(Args))),
|
|
XmlName = name(TypeName),
|
|
XmlArgs = xml_list("type_args", mer_type(TVarset), Args),
|
|
Xml = elem("type", [Ref], [XmlName, XmlArgs]).
|
|
mer_type(_, builtin_type(builtin_type_int)) = elem("int", [], []).
|
|
mer_type(_, builtin_type(builtin_type_float)) = elem("float", [], []).
|
|
mer_type(_, builtin_type(builtin_type_string)) = elem("string", [], []).
|
|
mer_type(_, builtin_type(builtin_type_character)) = elem("character", [], []).
|
|
mer_type(TVarset, higher_order_type(Types, MaybeResult, _, _)) = Xml :-
|
|
XmlTypes = xml_list("higher_order_type_args", mer_type(TVarset), Types),
|
|
( MaybeResult = yes(ResultType),
|
|
XmlReturn = elem("return_type", [], [mer_type(TVarset, ResultType)]),
|
|
XmlChildren = [XmlTypes, XmlReturn]
|
|
; MaybeResult = no,
|
|
XmlChildren = [XmlTypes]
|
|
),
|
|
Xml = elem("higher_order_type", [], XmlChildren).
|
|
mer_type(TVarset, tuple_type(Types, _)) = Xml :-
|
|
XmlArgs = xml_list("tuple_types", mer_type(TVarset), Types),
|
|
Xml = elem("tuple", [], [XmlArgs]).
|
|
mer_type(_, apply_n_type(_, _, _)) = nyi("apply_n_type").
|
|
mer_type(_, kinded_type(_, _)) = nyi("kinded_type").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred pred_documentation(comments::in, pred_id::in, pred_info::in,
|
|
list(xml)::in, list(xml)::out) is det.
|
|
|
|
pred_documentation(C, _PredId, PredInfo, !Xml) :-
|
|
pred_info_get_import_status(PredInfo, ImportStatus),
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
pred_info_get_markers(PredInfo, Markers),
|
|
|
|
(
|
|
status_defined_in_this_module(ImportStatus) = yes,
|
|
Origin = origin_user(_),
|
|
not check_marker(Markers, marker_class_method)
|
|
->
|
|
Xml = predicate_documentation(C, PredInfo),
|
|
!:Xml = [Xml | !.Xml]
|
|
;
|
|
true
|
|
).
|
|
|
|
:- func predicate_documentation(comments, pred_info) = xml.
|
|
|
|
predicate_documentation(C, PredInfo) = Xml :-
|
|
pred_info_get_typevarset(PredInfo, TVarset),
|
|
pred_info_get_exist_quant_tvars(PredInfo, Exists),
|
|
|
|
IsPredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
Module = pred_info_module(PredInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
PredName = qualified(Module, Name),
|
|
Arity = pred_info_orig_arity(PredInfo),
|
|
pred_info_get_import_status(PredInfo, ImportStatus),
|
|
|
|
Types = get_orig_arg_types(PredInfo),
|
|
pred_info_get_class_context(PredInfo, Constraints),
|
|
pred_info_get_context(PredInfo, Context),
|
|
(
|
|
IsPredOrFunc = pf_predicate,
|
|
Tag = "predicate"
|
|
;
|
|
IsPredOrFunc = pf_function,
|
|
Tag = "function"
|
|
),
|
|
Id = sym_name_and_arity_to_id(Tag, PredName, Arity),
|
|
|
|
XmlName = name(PredName),
|
|
XmlContext = prog_context(Context),
|
|
XmlTypes = xml_list("pred_types", mer_type(TVarset), Types),
|
|
XmlExistVars = xml_list("pred_exist_vars", type_param(TVarset), Exists),
|
|
XmlConstraints = prog_constraints(TVarset, Constraints),
|
|
XmlVisibility = visibility(ImportStatus),
|
|
|
|
pred_info_get_procedures(PredInfo, ProcTable),
|
|
map.foldl(pred_mode_documentation(C), ProcTable, [], XmlProcs),
|
|
XmlModes = elem("pred_modes", [], XmlProcs),
|
|
|
|
Xml0 = elem(Tag, [attr("id", Id)],
|
|
[XmlName, XmlTypes, XmlContext,
|
|
XmlExistVars, XmlConstraints, XmlVisibility, XmlModes]),
|
|
|
|
Xml = maybe_add_comment(C, Context, Xml0).
|
|
|
|
:- func get_orig_arg_types(pred_info) = list(mer_type).
|
|
|
|
get_orig_arg_types(PredInfo) = Types :-
|
|
pred_info_get_arg_types(PredInfo, Types0),
|
|
Types = keep_last_n(pred_info_orig_arity(PredInfo), Types0).
|
|
|
|
:- import_module require.
|
|
|
|
:- func keep_last_n(int, list(T)) = list(T).
|
|
|
|
keep_last_n(N, L0) =
|
|
( list.drop(list.length(L0) - N, L0, L) ->
|
|
L
|
|
;
|
|
func_error("keep_last_n")
|
|
).
|
|
|
|
:- func prog_constraints(tvarset, prog_constraints) = xml.
|
|
|
|
prog_constraints(TVarset, constraints(Univs, Exists)) = Xml :-
|
|
XmlUnivs = xml_list("pred_universal", prog_constraint(TVarset), Univs),
|
|
XmlExists = xml_list("pred_exist", prog_constraint(TVarset), Exists),
|
|
|
|
Xml = elem("pred_constraints", [], [XmlUnivs, XmlExists]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred pred_mode_documentation(comments::in, proc_id::in, proc_info::in,
|
|
list(xml)::in, list(xml)::out) is det.
|
|
|
|
pred_mode_documentation(_C, _ProcId, ProcInfo, !Xml) :-
|
|
% XXX do we ever need to remove arguments here?
|
|
proc_info_get_inst_varset(ProcInfo, IVarSet),
|
|
proc_info_declared_argmodes(ProcInfo, Modes),
|
|
proc_info_interface_determinism(ProcInfo, Determinism),
|
|
|
|
XmlModes = xml_list("modes", mer_mode(IVarSet), Modes),
|
|
XmlDet = determinism(Determinism),
|
|
Xml = elem("pred_mode", [], [XmlModes, XmlDet]),
|
|
|
|
!:Xml = [Xml | !.Xml].
|
|
|
|
:- func mer_mode(inst_varset, mer_mode) = xml.
|
|
|
|
mer_mode(IVarset, A -> B) = Xml :-
|
|
XmlFrom = xml_list("from", mer_inst(IVarset), [A]),
|
|
XmlTo = xml_list("to", mer_inst(IVarset), [B]),
|
|
Xml = elem("inst_to_inst", [], [XmlFrom, XmlTo]).
|
|
mer_mode(IVarset, user_defined_mode(Name, Args)) = Xml :-
|
|
Ref = attr("ref", sym_name_and_arity_to_id("mode", Name, length(Args))),
|
|
XmlArgs = xml_list("mode_args", mer_inst(IVarset), Args),
|
|
Xml = elem("user_defined_mode", [Ref], [name(Name), XmlArgs]).
|
|
|
|
:- func mer_inst(inst_varset, mer_inst) = xml.
|
|
|
|
mer_inst(_, any(U, _)) = elem("any", [], [uniqueness(U)]).
|
|
mer_inst(_, free) = elem("free", [], []).
|
|
mer_inst(_, free(_)) = elem("free", [], []).
|
|
mer_inst(IVarset, bound(U, BoundInsts)) = Xml :-
|
|
XmlUniq = uniqueness(U),
|
|
XmlInsts = xml_list("bound_insts", bound_inst(IVarset), BoundInsts),
|
|
Xml = elem("bound", [], [XmlUniq, XmlInsts]).
|
|
mer_inst(_, ground(U, _)) = elem("ground", [], [uniqueness(U)]).
|
|
mer_inst(_, not_reached) = elem("not_reached", [], []).
|
|
mer_inst(IVarset, inst_var(IVar)) = Xml :-
|
|
IVarName = varset.lookup_name(IVarset, IVar),
|
|
Xml = tagged_string("inst_var", IVarName).
|
|
mer_inst(IVarSet, constrained_inst_vars(_, Inst)) = mer_inst(IVarSet, Inst).
|
|
mer_inst(IVarset, defined_inst(Name)) = Xml :-
|
|
XmlName = inst_name(IVarset, Name),
|
|
Xml = elem("defined_inst", [], [XmlName]).
|
|
mer_inst(IVarset, abstract_inst(SymName, Insts)) =
|
|
mer_inst(IVarset, defined_inst(user_inst(SymName, Insts))).
|
|
|
|
:- func inst_name(inst_varset, inst_name) = xml.
|
|
|
|
inst_name(IVarset, user_inst(Name, Insts)) = Xml :-
|
|
Ref = attr("ref", sym_name_and_arity_to_id("inst", Name, length(Insts))),
|
|
XmlName = name(Name),
|
|
XmlInsts = xml_list("inst_args", mer_inst(IVarset), Insts),
|
|
Xml = elem("user_inst", [Ref], [XmlName, XmlInsts]).
|
|
inst_name(_, merge_inst(_, _)) = nyi("merge_inst").
|
|
inst_name(_, unify_inst(_, _, _, _)) = nyi("unify_inst").
|
|
inst_name(_, ground_inst(_, _, _, _)) = nyi("ground_inst").
|
|
inst_name(_, any_inst(_, _, _, _)) = nyi("any_inst").
|
|
inst_name(_, shared_inst(_)) = nyi("shared_inst").
|
|
inst_name(_, mostly_uniq_inst(_)) = nyi("mostly_uniq_inst").
|
|
inst_name(_, typed_ground(_, _)) = nyi("typed_ground").
|
|
inst_name(_, typed_inst(_, _)) = nyi("typed_inst").
|
|
|
|
:- func uniqueness(uniqueness) = xml.
|
|
|
|
uniqueness(U) = tagged_string("uniqueness", string(U)).
|
|
|
|
:- func bound_inst(inst_varset, bound_inst) = xml.
|
|
|
|
bound_inst(IVarset, bound_functor(ConsId, Insts)) = Xml :-
|
|
XmlCons = cons_id(ConsId),
|
|
XmlInsts = xml_list("insts", mer_inst(IVarset), Insts),
|
|
Xml = elem("bound_functor", [], [XmlCons, XmlInsts]).
|
|
|
|
:- func cons_id(cons_id) = xml.
|
|
|
|
cons_id(cons(Name, Arity)) = elem("cons", [], [name(Name), arity(Arity)]).
|
|
cons_id(int_const(I)) = tagged_int("int", I).
|
|
cons_id(string_const(S)) = tagged_string("string", S).
|
|
cons_id(float_const(F)) = tagged_float("float", F).
|
|
cons_id(implementation_defined_const(_)) = nyi("implementation_defined_const").
|
|
cons_id(pred_const(_, _)) = nyi("pred_const").
|
|
cons_id(type_ctor_info_const(_, _, _)) = nyi("type_ctor_info_const").
|
|
cons_id(base_typeclass_info_const(_,_,_,_)) = nyi("base_typeclass_info_const").
|
|
cons_id(type_info_cell_constructor(_)) = nyi("type_info_cell_constructor").
|
|
cons_id(typeclass_info_cell_constructor) =
|
|
nyi("typeclass_info_cell_constructor").
|
|
cons_id(tabling_info_const(_)) = nyi("tabling_info_const").
|
|
cons_id(deep_profiling_proc_layout(_)) = nyi("deep_profiling_proc_layout").
|
|
cons_id(table_io_decl(_)) = nyi("table_io_decl").
|
|
|
|
:- func arity(int) = xml.
|
|
|
|
arity(Arity) = tagged_int("arity", Arity).
|
|
|
|
:- func determinism(determinism) = xml.
|
|
|
|
determinism(detism_det) = tagged_string("determinism", "det").
|
|
determinism(detism_semi) = tagged_string("determinism", "semidet").
|
|
determinism(detism_multi) = tagged_string("determinism", "multi").
|
|
determinism(detism_non) = tagged_string("determinism", "nondet").
|
|
determinism(detism_cc_non) = tagged_string("determinism", "cc_nondet").
|
|
determinism(detism_cc_multi) = tagged_string("determinism", "cc_multi").
|
|
determinism(detism_erroneous) = tagged_string("determinism", "erroneous").
|
|
determinism(detism_failure) = tagged_string("determinism", "failure").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred class_documentation(comments::in, pred_table::in,
|
|
class_id::in, hlds_class_defn::in,
|
|
list(xml)::in, list(xml)::out) is det.
|
|
|
|
class_documentation(C, PredTable, class_id(Name, Arity), ClassDefn, !Xml) :-
|
|
ImportStatus = ClassDefn ^ class_status,
|
|
( status_defined_in_this_module(ImportStatus) = yes ->
|
|
Id = sym_name_and_arity_to_id("class", Name, Arity),
|
|
|
|
Context = ClassDefn ^ class_context,
|
|
TVarset = ClassDefn ^ class_tvarset,
|
|
Vars = ClassDefn ^ class_vars,
|
|
|
|
XmlName = name(Name),
|
|
XmlClassVars = xml_list("class_vars", type_param(TVarset), Vars),
|
|
XmlSupers = xml_list("superclasses",
|
|
prog_constraint(TVarset), ClassDefn ^ class_supers),
|
|
XmlFundeps = xml_list("fundeps",
|
|
fundep(TVarset, Vars), ClassDefn ^ class_fundeps),
|
|
XmlMethods = class_methods(C,
|
|
PredTable, ClassDefn ^ class_hlds_interface),
|
|
XmlVisibility = visibility(ImportStatus),
|
|
XmlContext = prog_context(Context),
|
|
|
|
Xml0 = elem("typeclass", [attr("id", Id)],
|
|
[XmlName, XmlClassVars, XmlSupers,
|
|
XmlFundeps, XmlMethods, XmlVisibility, XmlContext]),
|
|
|
|
Xml = maybe_add_comment(C, Context, Xml0),
|
|
|
|
!:Xml = [Xml | !.Xml]
|
|
;
|
|
true
|
|
).
|
|
|
|
:- func fundep(tvarset, list(tvar), hlds_class_fundep) = xml.
|
|
|
|
fundep(TVarset, Vars, fundep(Domain, Range)) = Xml :-
|
|
XmlDomain = fundep_2("domain", TVarset, Vars, Domain),
|
|
XmlRange = fundep_2("range", TVarset, Vars, Range),
|
|
Xml = elem("fundep", [], [XmlDomain, XmlRange]).
|
|
|
|
:- func fundep_2(string, tvarset, list(tvar), set(hlds_class_argpos)) = xml.
|
|
|
|
fundep_2(Tag, TVarset, Vars, Set) =
|
|
xml_list(Tag, type_param(TVarset), restrict_list_elements(Set, Vars)).
|
|
|
|
:- func class_methods(comments, pred_table, hlds_class_interface) = xml.
|
|
|
|
class_methods(C, PredTable, Methods) = Xml :-
|
|
AllPredIds = list.map(func(hlds_class_proc(PredId, _)) = PredId, Methods),
|
|
PredIds = list.sort_and_remove_dups(AllPredIds),
|
|
PredInfos = list.map(func(Id) = map.lookup(PredTable, Id), PredIds),
|
|
Xml = xml_list("methods", predicate_documentation(C), PredInfos).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func name(sym_name) = xml.
|
|
|
|
name(unqualified(Name)) = tagged_string("unqualified", Name).
|
|
name(qualified(Module, Name)) =
|
|
elem("qualified", [], [
|
|
tagged_string("module", sym_name_to_string(Module)),
|
|
tagged_string("name", Name)]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func prog_context(prog_context) = xml.
|
|
|
|
prog_context(context(FileName, LineNumber)) =
|
|
elem("context", [], [
|
|
tagged_string("filename", FileName),
|
|
tagged_int("line", LineNumber)]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func prog_constraint(tvarset, prog_constraint) = xml.
|
|
|
|
prog_constraint(TVarset, constraint(ClassName, Types)) = Xml :-
|
|
Id = sym_name_and_arity_to_id("constraint", ClassName, list.length(Types)),
|
|
XmlName = name(ClassName),
|
|
XmlTypes = xml_list("constraint_types", mer_type(TVarset), Types),
|
|
Xml = elem("constraint", [attr("ref", Id)], [XmlName, XmlTypes]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func visibility(import_status) = xml.
|
|
|
|
visibility(Status) = tagged_string("visibility", Visibility) :-
|
|
( status_defined_in_impl_section(Status) = yes ->
|
|
( Status = status_abstract_exported ->
|
|
Visibility = "abstract"
|
|
;
|
|
Visibility = "implementation"
|
|
)
|
|
;
|
|
Visibility = "interface"
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% sym_name_to_id(P, S) converts the sym_name, S, into
|
|
% a string with prefix, P, prefixed to the generated name.
|
|
%
|
|
:- func sym_name_to_id(string, sym_name) = string.
|
|
|
|
sym_name_to_id(Prefix, Name) = prefixed_sym_name(Prefix, Name).
|
|
|
|
% sym_name_to_id(P, S, A) converts the sym_name, S, with
|
|
% arity, A, into a string with prefix, P, prefixed to the
|
|
% generated name.
|
|
%
|
|
:- func sym_name_and_arity_to_id(string, sym_name, int) = string.
|
|
|
|
sym_name_and_arity_to_id(Prefix, Name, Arity) =
|
|
prefixed_sym_name(Prefix, Name) ++ "-" ++ int_to_string(Arity).
|
|
|
|
:- func prefixed_sym_name(string, sym_name) = string.
|
|
|
|
prefixed_sym_name(Prefix, Name) = Prefix ++ "." ++ sym_name_to_string(Name).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func tagged_string(string, string) = xml.
|
|
|
|
tagged_string(E, S) = elem(E, [], [data(S)]).
|
|
|
|
:- func tagged_int(string, int) = xml.
|
|
|
|
tagged_int(E, I) = elem(E, [], [data(int_to_string(I))]).
|
|
|
|
:- func tagged_float(string, float) = xml.
|
|
|
|
tagged_float(E, F) = elem(E, [], [data(float_to_string(F))]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func xml_list(string, func(T) = xml, list(T)) = xml.
|
|
|
|
xml_list(Tag, F, L) = elem(Tag, [], list.map(F, L)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func nyi(string) = xml.
|
|
|
|
nyi(Tag) = tagged_string(Tag, "Not yet implemented!").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "xml_documentation.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|