Files
mercury/compiler/parse_types.m
Zoltan Somogyi cb5a1d5d6e Parse interface files via bespoke representations.
We used to read all kinds of interface files (.int0, .int, .int2 and .int3)
into the same representation, parse_tree_int. This diff makes the first step
towards returning the contents of each kind of interface file in its own
bespoke parse tree type, parse_tree_intN for N in {0,1,2,3}.

compiler/parse_module.m:
    Read in the contents of interface files using a cut-down grammar.
    The main changes are:

    - the file must start with a ":- module" declaration;
    - the start of each section must be an explicit section marker;
    - there can be at most two sections, the first an interface section
      and the second an implementation section, in that order,
      either (or both) of which can be missing;
    - version number maps are expected to be *before* the first section;
    - there cannot be any submodules;
    - there cannot be any source_file pragmas anywhere.

    Each of these changes enforces an invariant that is observed by the code
    constructing and writing out the automatically generated interface files.
    The change makes many invalid interface file contents unrepresentable.

    Add predicates for reading each kind interface file to its own
    bespoke parse tree type. These new predicates are not yet used.

    Change the generic predicate for reading in interface files
    to convert the generic parse_tree_int it generates to the given interface
    file's own specific parse tree type, and back. This *should* be an
    identity operation, but it generates an error message whenever it finds
    an entity of a kind that shouldn't be there. Print these messages
    unless inhibited by an option.

    This back-and-forth is intended to be temporary. Once we have sufficient
    experience with the system to be confident it works, i.e. it does not
    miscompile anything and never generates any of these diagnostics,
    we should be able to switch to using the kind-specific parse tree types
    exclusively.

compiler/options.m:
    Add that option, halt-at-invalid-interface, for now, enabled by default.
    We should be able to delete the option, making its effects permanent,
    when we make the switch mentioned above.

compiler/prog_item.m:
    Modify the representation of import_module and use_module declarations
    in .int0 files a bit to match their representations in other kinds of
    interface files.

    Add predicates to convert a parse_tree_int to each parse_tree_intN
    for N in {0,1,2,3}, generating error messages if they contain
    any kind of entity that they shouldn't contain.

    Add functions for describing such entities in the error messages.

    Add some other auxiliary functions, and field names, needed by
    the rest of this change.

compiler/file_kind.m:
    Replace ifk_int with ifk_int1, because we consistently use numeric
    suffixes after interface file kinds everywhere else. (Partly this is
    to disambiguate "int" as short for "interface file", not for
    "interface section of a module".

compiler/parse_types.m:
    Provide a mechanism to describe all entities read in during parsing,
    not just those that end up in parse trees, for use in error messages
    in parse_module.m.

compiler/comp_unit_interface.m:
compiler/deps_map.m:
compiler/grab_modules.m:
compiler/make_hlds_error.m:
compiler/module_qual.qual_errors.m:
    Conform to the changes above.
2019-09-05 11:49:17 +10:00

134 lines
5.1 KiB
Mathematica

%-----------------------------------------------------------------------------e
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------e
% Copyright (C) 2015 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% This module defines a type used by several modules that parse items
% and/or markers.
%
%---------------------------------------------------------------------------%
:- module parse_tree.parse_types.
:- interface.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.error_util.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_item.
:- import_module recompilation.
:- import_module list.
% This type represents the result of parsing one term.
:- type item_or_marker
---> iom_item(item)
% The term contains an item.
; iom_marker_include(one_or_more(item_include))
% The term contains an `:- include_module' declaration.
; iom_marker_avail(one_or_more(item_avail))
% The term contains an `:- import_module' or `:- use_module'
% declaration.
; iom_marker_fim(item_fim)
% The term contains a `:- pragma foreign_import_module'
% declaration.
; iom_marker_version_numbers(version_numbers)
% The term was a record of the version numbers of the items
% in an interface file.
; iom_marker_src_file(string)
% The term was a pragma specifying the new filename.
; iom_marker_module_start(module_name, prog_context, int)
% The term was a `:- module' declaration. The arguments give
% the module's name, and the context and sequence number of the
% declaration. The module name is exactly what was in the
% declaration; it is NOT implicitly module qualified by the
% enclosing module.
; iom_marker_module_end(module_name, prog_context, int)
% The term was a `:- end_module' declaration. The arguments give
% the module's name, and the context and sequence number of the
% declaration. Again, the module name as is, and not implicitly
% module qualified.
; iom_marker_section(module_section, prog_context, int)
% The term was a `:- interface' or `:- implementation' declaration.
% The arguments give the section's kind, and the context
% and sequence number of the declaration.
; iom_handled(list(error_spec)).
% The term was completely dealt with during parsing, which
% may have generated some messages. If it did, they are attached;
% otherwise, the list will be empty.
%
% As of this writing, this is used only for require_feature_set
% pragmas that don't require any features, and for version_number
% items recorded by old compiler versions in a now-obsolete format.
:- func iom_desc_pieces(item_or_marker) = list(format_component).
%---------------------------------------------------------------------------%
:- implementation.
iom_desc_pieces(IOM) = Pieces :-
(
IOM = iom_item(Item),
Pieces = item_desc_pieces(Item)
;
IOM = iom_marker_include(_),
Pieces = [words("an"), decl("include_module"), words("declaration")]
;
IOM = iom_marker_avail(one_or_more(HeadAvail, _TailAvails)),
(
HeadAvail = avail_import(_),
Pieces = [words("an"), decl("import_module"),
words("declaration")]
;
HeadAvail = avail_use(_),
Pieces = [words("a"), decl("use_module"), words("declaration")]
)
;
IOM = iom_marker_fim(_),
Pieces = [words("a"), pragma_decl("foreign_import_module"),
words("declaration")]
;
IOM = iom_marker_version_numbers(_),
Pieces = [words("a version number map")]
;
IOM = iom_marker_src_file(_),
Pieces = [words("a"), pragma_decl("source_file"), words("declaration")]
;
IOM = iom_marker_module_start(_, _, _),
Pieces = [words("a"), decl("module"), words("declaration")]
;
IOM = iom_marker_module_end(_, _, _),
Pieces = [words("an"), decl("end_module"), words("declaration")]
;
IOM = iom_marker_section(SectionKind, _, _),
(
SectionKind = ms_interface,
Pieces = [words("an"), decl("interface"), words("declaration")]
;
SectionKind = ms_implementation,
Pieces = [words("an"), decl("implementation"),
words("declaration")]
)
;
IOM = iom_handled(_Specs),
Pieces = []
).
%---------------------------------------------------------------------------%
:- end_module parse_tree.parse_types.
%---------------------------------------------------------------------------%