mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-27 15:24:00 +00:00
... and change the coloring done in many other modules.
compiler/typecheck_error_undef.m:
Add color to the diagnostics generated by this module.
In a few cases, improve the wording of the diagnostic.
Make the name of a function and of a function symbol more descriptive.
Convert some predicates from using many clauses to using
an explicit disjunction.
Delete a function that was sort-of a specialize version of a
utility function in error_spec.m.
compiler/hlds_error_util.m:
Change the functions that return descriptions of predicates and procedures,
mostly for use in diagnostics, to allow the parts of those descriptions
specific to an individual predicate or procedure to be colored *without*
coloring the generic parts (such as the word "predicate" or "function").
Add simpler versions of the affected functions for use cases that
do not need any coloring.
compiler/accumulator.m:
compiler/add_clause.m:
compiler/add_pragma.m:
compiler/check_pragma_format_call.m:
compiler/check_typeclass.m:
compiler/dead_proc_elim.m:
compiler/det_analysis.m:
compiler/det_report.m:
compiler/direct_arg_in_out.m:
compiler/fact_table.m:
compiler/float_regs.m:
compiler/format_call.m:
compiler/hlds_out_module.m:
compiler/hlds_statistics.m:
compiler/inst_mode_type_prop.m:
compiler/make_hlds_error.m:
compiler/mode_errors.m:
compiler/modes.m:
compiler/oisu_check.m:
compiler/old_type_constraints.m:
compiler/ordering_mode_constraints.m:
compiler/parse_module.m:
compiler/post_typecheck.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/simplify_goal_call.m:
compiler/stratify.m:
compiler/style_checks.m:
compiler/table_gen.m:
compiler/tabling_analysis.m:
compiler/term_constr_errors.m:
compiler/term_errors.m:
compiler/termination.m:
compiler/trailing_analysis.m:
compiler/typecheck.m:
compiler/typecheck_clauses.m:
compiler/typecheck_error_overload.m:
compiler/typecheck_error_util.m:
compiler/typecheck_errors.m:
compiler/typecheck_msgs.m:
Conform to the changes in hlds_error_util.m.
In many cases, improve the affected diagnostics, and maybe other nearby
diagnostics, in other ways as well.
compiler/hlds_data.m:
Fix comments.
tests/invalid/bad_exported_mode.err_exp:
tests/invalid/bad_fact_table_data.err_exp:
tests/invalid/bad_fact_table_data.err_exp2:
tests/invalid/bad_fact_table_decls.err_exp:
tests/invalid/bad_format_call.err_exp:
tests/invalid/bad_pred_arity.err_exp:
tests/invalid/bad_sv_unify_msg.err_exp:
tests/invalid/bug10.err_exp:
tests/invalid/bug113.err_exp:
tests/invalid/bug150.err_exp:
tests/invalid/bug184.err_exp:
tests/invalid/bug197.err_exp:
tests/invalid/bug214.err_exp:
tests/invalid/bug238.err_exp:
tests/invalid/bug257.err_exp:
tests/invalid/bug476.err_exp:
tests/invalid/bug496.err_exp:
tests/invalid/builtin_proc.err_exp:
tests/invalid/coerce_syntax.err_exp:
tests/invalid/coerce_void.err_exp:
tests/invalid/constructor_warning.err_exp:
tests/invalid/det_atomic_goal_msgs.err_exp:
tests/invalid/det_errors.err_exp:
tests/invalid/det_errors_and_io.err_exp:
tests/invalid/det_errors_cc.err_exp:
tests/invalid/erroneous_throw_promise.err_exp:
tests/invalid/exist_foreign_error.err_exp:
tests/invalid/exported_mode.err_exp:
tests/invalid/exported_unify.err_exp:
tests/invalid/field_syntax_error.err_exp:
tests/invalid/foreign_purity_mismatch.err_exp:
tests/invalid/foreign_purity_mismatch.err_exp2:
tests/invalid/foreign_purity_mismatch.err_exp3:
tests/invalid/foreign_type_2.err_exp:
tests/invalid/freefree.err_exp:
tests/invalid/getopt_io_old.err_exp:
tests/invalid/getopt_old_se.err_exp:
tests/invalid/gh72_errors.err_exp:
tests/invalid/hawkins_mm_fail_reset.err_exp:
tests/invalid/ho_unique_error.err_exp:
tests/invalid/impure_method_impl.err_exp:
tests/invalid/invalid_event.err_exp:
tests/invalid/invalid_new.err_exp:
tests/invalid/io_in_ite_cond.err_exp:
tests/invalid/loopcheck.err_exp:
tests/invalid/magicbox.err_exp:
tests/invalid/make_opt_error.err_exp:
tests/invalid/method_impl.err_exp:
tests/invalid/missing_det_decls.err_exp:
tests/invalid/mode_decl_in_wrong_section.err_exp:
tests/invalid/mostly_uniq1.err_exp:
tests/invalid/mostly_uniq2.err_exp:
tests/invalid/multimode_missing_impure.err_exp:
tests/invalid/multimode_syntax.err_exp:
tests/invalid/multiply_star.err_exp:
tests/invalid/no_method.err_exp:
tests/invalid/not_a_switch.err_exp:
tests/invalid/one_member.err_exp:
tests/invalid/pragma_c_code_dup_var.err_exp:
tests/invalid/pragma_c_code_no_det.err_exp:
tests/invalid/pragma_c_code_no_det.err_exp2:
tests/invalid/pragma_c_code_no_det.err_exp3:
tests/invalid/pragma_qual_error.err_exp:
tests/invalid/qual_basic_test2.err_exp:
tests/invalid/qualified_cons_id2.err_exp:
tests/invalid/quant_constraint_1.err_exp:
tests/invalid/quant_constraint_2.err_exp:
tests/invalid/record_syntax_errors.err_exp:
tests/invalid/ref_to_implicit_comma.err_exp:
tests/invalid/ref_to_implicit_pred.err_exp:
tests/invalid/spurious_mode_error.err_exp:
tests/invalid/state_vars_test_3.err_exp:
tests/invalid/string_format_bad.err_exp:
tests/invalid/string_format_unknown.err_exp:
tests/invalid/test_promise_equivalent_clauses.err_exp:
tests/invalid/test_type_spec.err_exp:
tests/invalid/transitive_import_class.err_exp:
tests/invalid/try_detism.err_exp:
tests/invalid/type_error_use_module.err_exp:
tests/invalid/type_inf_loop.err_exp:
tests/invalid/typeclass_dup_method_mode.err_exp:
tests/invalid/typeclass_mode_2.err_exp:
tests/invalid/typeclass_mode_3.err_exp:
tests/invalid/typeclass_mode_4.err_exp:
tests/invalid/typeclass_test_8.err_exp:
tests/invalid/types2.err_exp:
tests/invalid/undeclared_mode.err_exp:
tests/invalid/undef_mode_and_no_clauses.err_exp:
tests/invalid/undef_symbol.err_exp:
tests/invalid/unsatisfiable_constraint.err_exp:
tests/invalid/user_field_access_decl_override_1.err_exp:
tests/invalid/wrong_arity_function.err_exp:
tests/invalid_make_int/bad_end_module.int_err_exp:
tests/invalid_make_int/missing_initial_section.int_err_exp:
tests/invalid_nodepend/after_end_module.err_exp:
tests/invalid_nodepend/bad_fact_table.err_exp:
tests/invalid_nodepend/bigtest.err_exp:
tests/invalid_nodepend/bug410.err_exp:
tests/invalid_nodepend/constrained_poly_insts.err_exp:
tests/invalid_nodepend/duplicate_modes.err_exp:
tests/invalid_nodepend/errors_1.err_exp:
tests/invalid_nodepend/errors_2.err_exp:
tests/invalid_nodepend/errors_3.err_exp:
tests/invalid_nodepend/external.err_exp:
tests/invalid_nodepend/funcs_as_preds.err_exp:
tests/invalid_nodepend/impl_def_literal_syntax.err_exp:
tests/invalid_nodepend/invalid_binary_literal.err_exp:
tests/invalid_nodepend/invalid_decimal_literal.err_exp:
tests/invalid_nodepend/invalid_float_literal.err_exp:
tests/invalid_nodepend/invalid_hex_literal.err_exp:
tests/invalid_nodepend/invalid_main.err_exp:
tests/invalid_nodepend/invalid_octal_literal.err_exp:
tests/invalid_nodepend/no_exports.err_exp:
tests/invalid_nodepend/null_char.err_exp:
tests/invalid_nodepend/occurs.err_exp:
tests/invalid_nodepend/pragma_export.err_exp:
tests/invalid_nodepend/prog_io_erroneous.err_exp:
tests/invalid_nodepend/reserved_type_name.err_exp:
tests/invalid_nodepend/test_with_type.err_exp:
tests/invalid_nodepend/typeclass_test_1.err_exp:
tests/invalid_nodepend/typeclass_test_2.err_exp:
tests/invalid_nodepend/types.err_exp:
tests/invalid_nodepend/unbound_type_vars.err_exp:
tests/invalid_nodepend/unterminated_octal_escape.err_exp:
tests/invalid_nodepend/vars_in_wrong_places.err_exp:
tests/invalid_purity/impure_func_t2.err_exp:
tests/invalid_purity/impure_func_t3.err_exp:
tests/invalid_purity/impure_func_t4.err_exp:
tests/invalid_purity/pragma_c_and_mercury.err_exp:
tests/invalid_purity/purity.err_exp:
tests/invalid_purity/purity_nonsense_1.err_exp:
tests/invalid_purity/purity_nonsense_2.err_exp:
tests/invalid_submodules/exported_unify3.err_exp:
tests/invalid_submodules/func_class.err_exp:
tests/invalid_submodules/undef_mod_qual.err_exp:
tests/recompilation/typeclass_method_pragma_r.err_exp.2:
tests/recompilation/with_type_re.err_exp.2:
tests/warnings/arg_order_rearrangment.err_exp:
tests/warnings/bug477.err_exp:
tests/warnings/det_infer_warning.err_exp:
tests/warnings/disabled_warning.err_exp:
tests/warnings/foreign_term_invalid.err_exp:
tests/warnings/format_call_multi.err_exp:
tests/warnings/format_call_warning.err_exp:
tests/warnings/infinite_recursion.err_exp:
tests/warnings/non_contiguous_decls.err_exp:
tests/warnings/non_stratification.err_exp:
tests/warnings/obsolete_proc_pragma.err_exp:
tests/warnings/pragma_term_conflict.err_exp:
tests/warnings/purity_warnings.err_exp:
tests/warnings/save.err_exp:
tests/warnings/simple_code.err_exp:
tests/warnings/singleton_test.err_exp:
tests/warnings/spurious_obsolete.err_exp:
tests/warnings/suspicious_recursion.err_exp:
tests/warnings/unneeded_mode_specific_clause.err_exp:
tests/warnings/unsigned_zero_cmp.err_exp:
tests/warnings/warn_dead_procs.err_exp:
tests/warnings/warn_dead_procs_trace.err_exp:
tests/warnings/warn_non_contiguous.err_exp:
tests/warnings/warn_non_contiguous_foreign.err_exp:
tests/warnings/warn_stubs.err_exp:
Expect updated diagnostics.
1729 lines
78 KiB
Mathematica
1729 lines
78 KiB
Mathematica
%-----------------------------------------------------------------------------e
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------e
|
|
% Copyright (C) 1993-2012 The University of Melbourne.
|
|
% Copyright (C) 2016-2024 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: parse_module.m.
|
|
% Main author of original version: fjh.
|
|
% Main author of current version: zs.
|
|
%
|
|
% This module defines the top level predicates for parsing Mercury programs.
|
|
%
|
|
% The main predicates of this module, actually_read_module_{src,int,opt},
|
|
% read in and parse the contents of source files, interface files and
|
|
% optimization files respectively.
|
|
%
|
|
% The original design of this module represented all three kinds of files
|
|
% as simple lists of items. The design of the items themselves was made
|
|
% considerably more complex than is necessary for the compiler, because
|
|
% one objective was to preserve as much information about the source code
|
|
% as possible, to allow tools such as prettyprinters to reconstruct the
|
|
% source code as closely as possible. (For example, this is why each item
|
|
% has a sequence number.) The only information that was designed to be lost
|
|
% was the stripping of comments, whitespace and redundant parenthesization,
|
|
% the standardization of the spellings of the names of operators (such as
|
|
% rewriting "\+" to "not"), and the expansion of DCG clauses.
|
|
%
|
|
% We have not found a need for such prettyprinters in more than twenty years,
|
|
% so the original concern for minimizing the differences between the source
|
|
% code and the AST, which was Fergus's argument for keeping the AST a simple
|
|
% item list, has been shown to be irrelevant.
|
|
%
|
|
% We therefore now use a representation for the parse tree that is more suited
|
|
% to the needs of the compiler itself, even though it is more complex
|
|
% that a simple list of items. Part of this complexity is that source files,
|
|
% interface files and optimization files have different parse trees,
|
|
% and we accordingly have different predicates for creating those parse trees.
|
|
% The main predicates for reading these three kinds of files are
|
|
%
|
|
% - parse_src_file,
|
|
% - parse_int_file, and
|
|
% - parse_opt_file.
|
|
%
|
|
% Each of these kinds of files has its grammar describing the structure
|
|
% its items should follow. The predicates parsing parts of those structures
|
|
% each have a comment before them specifying what part of the relevant file
|
|
% kind they are designed to parse. The grammar is simplest for opt files, and
|
|
% next simplest for int files, so the order of those predicates in this module
|
|
% is parse_opt_file, parse_int_file, and then parse_src_file.
|
|
%
|
|
% Our parsing process has four stages instead of the usual two.
|
|
%
|
|
% The usual stages are:
|
|
% lexical analysis: chars -> tokens
|
|
% parsing: tokens -> structured parse tree
|
|
%
|
|
% Our stages are:
|
|
% lexical analysis: chars -> tokens
|
|
% parsing stage 1: tokens -> terms
|
|
% parsing stage 2: terms -> items and markers
|
|
% parsing stage 3: items and markers -> structured parse tree
|
|
%
|
|
% An item represents a clause or a declaration. A marker represents
|
|
% a declaration that affects the structure of the parse tree, usually by
|
|
% controlling what section or what (sub)module the following items belong to.
|
|
%
|
|
% We never materialize the intermediate representations (a token list,
|
|
% a term list or an item/marker list) all at once. Instead, we read in the
|
|
% contents of the relevant file one term at a time, and convert that
|
|
% to an item or marker before reading in the next term.
|
|
%
|
|
% Some predicates, when they parse a term, discover that it represents an
|
|
% item or marker that it is not their job to handle. In such cases, they
|
|
% return it to their caller, for the next step in the caller to process.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.parse_module.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.maybe_error.
|
|
:- import_module parse_tree.parse_error.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_item.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% peek_at_file(FileStream, SourceFileName, DefaultModuleName,
|
|
% MaybeModuleName, !IO):
|
|
%
|
|
% "mmc -f", which creates the Mercury.module file that later compiler
|
|
% compiler invocations will use to map modules to the name of the file
|
|
% containing them, uses this predicate to peek into a file to try to read
|
|
% its first Mercury item.
|
|
%
|
|
% It this attempt succeeds and finds a ":- module" declaration giving
|
|
% the name of the module as ModuleName, then return ok1(ModuleName).
|
|
% If any part of this process fails, return error1(Spec) where Specs
|
|
% describes the problem.
|
|
%
|
|
:- pred peek_at_file(io.text_input_stream::in, file_name::in, module_name::in,
|
|
maybe1(module_name)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% parse_intN_file(Globals, FileName, FileStr, FileStrLen,
|
|
% DefaultModuleName, DefaultExpectationContexts,
|
|
% MaybeParseTreeIntN, Errors):
|
|
%
|
|
% Given FileName's its contents (FileStr, whose length is FileStrLen code
|
|
% units), try to parse those contents as a .intN file.
|
|
%
|
|
:- pred parse_int0_file(globals::in, file_name::in, string::in, int::in,
|
|
module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_int0)::out, read_module_errors::out) is det.
|
|
:- pred parse_int1_file(globals::in, file_name::in, string::in, int::in,
|
|
module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_int1)::out, read_module_errors::out) is det.
|
|
:- pred parse_int2_file(globals::in, file_name::in, string::in, int::in,
|
|
module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_int2)::out, read_module_errors::out) is det.
|
|
:- pred parse_int3_file(globals::in, file_name::in, string::in, int::in,
|
|
module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_int3)::out, read_module_errors::out) is det.
|
|
|
|
% parse_{plain,trans}_opt_file(FileName, FileStr, FileStrLen,
|
|
% DefaultModuleName, MaybeParseTree{Plain,Trans}Opt, Errors):
|
|
%
|
|
% Given FileName's its contents (FileStr, whose length is FileStrLen code
|
|
% units), try to parse those contents as a .*opt file.
|
|
%
|
|
:- pred parse_plain_opt_file(file_name::in, string::in, int::in,
|
|
module_name::in,
|
|
maybe(parse_tree_plain_opt)::out, read_module_errors::out) is det.
|
|
:- pred parse_trans_opt_file(file_name::in, string::in, int::in,
|
|
module_name::in,
|
|
maybe(parse_tree_trans_opt)::out, read_module_errors::out) is det.
|
|
|
|
% parse_src_file(FileName, FileString, FileStringLen,
|
|
% DefaultModuleName, DefaultExpectationContexts,
|
|
% MaybeParseTreeSrc, Errors):
|
|
%
|
|
% Given FileName's contents (FileStr, whose length is FileStrLen code
|
|
% units), try to parse those contents as a Mercury source file.
|
|
%
|
|
:- pred parse_src_file(file_name::in, string::in, int::in,
|
|
module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_src)::out, read_module_errors::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.convert_parse_tree.
|
|
:- import_module parse_tree.file_kind.
|
|
:- import_module parse_tree.item_util.
|
|
:- import_module parse_tree.parse_item.
|
|
:- import_module parse_tree.parse_types.
|
|
:- import_module recompilation.
|
|
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module counter.
|
|
:- import_module int.
|
|
:- import_module mercury_term_lexer.
|
|
:- import_module mercury_term_parser.
|
|
:- import_module one_or_more.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module term_context.
|
|
:- import_module varset.
|
|
|
|
:- type maybe_require_module_decl
|
|
---> dont_require_module_decl
|
|
; require_module_decl.
|
|
|
|
:- type missing_section_start_warning
|
|
---> have_not_given_missing_section_start_warning
|
|
; have_given_missing_section_start_warning.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
peek_at_file(FileStream, SourceFileName0, DefaultModuleName,
|
|
MaybeModuleName, !IO) :-
|
|
io.read_file_as_string_and_num_code_units(FileStream, MaybeResult, !IO),
|
|
(
|
|
MaybeResult = ok2(FileString, FileStringLen),
|
|
DefaultExpectationContexts = [],
|
|
counter.init(1, SeqNumCounter0),
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
parse_first_module_decl(FileString, FileStringLen,
|
|
dont_require_module_decl, DefaultModuleName,
|
|
DefaultExpectationContexts, ModuleDeclPresent,
|
|
may_change_source_file_name, SourceFileName0, _SourceFileName,
|
|
SeqNumCounter0, _SeqNumCounter,
|
|
LineContext0, _LineContext, LinePosn0, _LinePosn),
|
|
(
|
|
ModuleDeclPresent = no_module_decl_present(_MaybeLookAhead,
|
|
_Context, _NoModuleSpec),
|
|
Pieces = [words("Error:")] ++
|
|
color_as_subject([quote(SourceFileName0)]) ++
|
|
color_as_incorrect([words("does not start with a"),
|
|
decl("module"), words("declaration.")]) ++
|
|
[nl],
|
|
Spec = no_ctxt_spec($pred, severity_error, phase_read_files,
|
|
Pieces),
|
|
MaybeModuleName = error1([Spec])
|
|
;
|
|
ModuleDeclPresent = wrong_module_decl_present(ModuleName,
|
|
_ModuleNameContext, _WrongSpec),
|
|
MaybeModuleName = ok1(ModuleName)
|
|
;
|
|
ModuleDeclPresent = right_module_decl_present(ModuleName,
|
|
_ModuleNameContext),
|
|
MaybeModuleName = ok1(ModuleName)
|
|
)
|
|
;
|
|
MaybeResult = error2(_PartialFileString, _FileStringLen, ErrorCode),
|
|
io.error_message(ErrorCode, ErrorMsg0),
|
|
ErrorMsg = "I/O error: " ++ ErrorMsg0,
|
|
io_error_to_error_spec(phase_read_files, ErrorMsg, Spec, !IO),
|
|
MaybeModuleName = error1([Spec])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
parse_int0_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt0, Errors) :-
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
parse_int_file(ifk_int0, FileName, FileStr, FileStrLen,
|
|
LineContext0, LinePosn0, DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt, Errors0),
|
|
(
|
|
MaybeParseTreeInt = no,
|
|
MaybeParseTreeInt0 = no,
|
|
Errors = Errors0
|
|
;
|
|
MaybeParseTreeInt = yes(ParseTreeInt),
|
|
check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0,
|
|
[], ConvertSpecs),
|
|
MaybeParseTreeInt0 = yes(ParseTreeInt0),
|
|
maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
|
|
).
|
|
|
|
parse_int1_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt1, Errors) :-
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
parse_int_file(ifk_int1, FileName, FileStr, FileStrLen,
|
|
LineContext0, LinePosn0, DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt, Errors0),
|
|
(
|
|
MaybeParseTreeInt = no,
|
|
MaybeParseTreeInt1 = no,
|
|
Errors = Errors0
|
|
;
|
|
MaybeParseTreeInt = yes(ParseTreeInt),
|
|
check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1,
|
|
[], ConvertSpecs),
|
|
MaybeParseTreeInt1 = yes(ParseTreeInt1),
|
|
maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
|
|
).
|
|
|
|
parse_int2_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt2, Errors) :-
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
parse_int_file(ifk_int2, FileName, FileStr, FileStrLen,
|
|
LineContext0, LinePosn0, DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt, Errors0),
|
|
(
|
|
MaybeParseTreeInt = no,
|
|
MaybeParseTreeInt2 = no,
|
|
Errors = Errors0
|
|
;
|
|
MaybeParseTreeInt = yes(ParseTreeInt),
|
|
check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2,
|
|
[], ConvertSpecs),
|
|
MaybeParseTreeInt2 = yes(ParseTreeInt2),
|
|
maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
|
|
).
|
|
|
|
parse_int3_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt3, Errors) :-
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
parse_int_file(ifk_int3, FileName, FileStr, FileStrLen,
|
|
LineContext0, LinePosn0, DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt, Errors0),
|
|
(
|
|
MaybeParseTreeInt = no,
|
|
MaybeParseTreeInt3 = no,
|
|
Errors = Errors0
|
|
;
|
|
MaybeParseTreeInt = yes(ParseTreeInt),
|
|
check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3,
|
|
[], ConvertSpecs),
|
|
MaybeParseTreeInt3 = yes(ParseTreeInt3),
|
|
maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
parse_plain_opt_file(FileName, FileStr, FileStrLen, DefaultModuleName,
|
|
MaybeParseTreePlainOpt, Errors) :-
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
DefaultExpectationContexts = [],
|
|
parse_opt_file(ofk_opt, FileName, FileStr, FileStrLen,
|
|
LineContext0, LinePosn0,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeOpt, Errors0),
|
|
(
|
|
MaybeParseTreeOpt = no,
|
|
MaybeParseTreePlainOpt = no,
|
|
Errors = Errors0
|
|
;
|
|
MaybeParseTreeOpt = yes(ParseTreeOpt),
|
|
check_convert_parse_tree_opt_to_plain_opt(ParseTreeOpt,
|
|
ParseTreePlainOpt, [], ConvertSpecs),
|
|
MaybeParseTreePlainOpt = yes(ParseTreePlainOpt),
|
|
add_any_nec_errors(ConvertSpecs, Errors0, Errors)
|
|
).
|
|
|
|
parse_trans_opt_file(FileName, FileStr, FileStrLen, DefaultModuleName,
|
|
MaybeParseTreeTransOpt, Errors) :-
|
|
LineContext0 = line_context(1, 0),
|
|
LinePosn0 = line_posn(0),
|
|
DefaultExpectationContexts = [],
|
|
parse_opt_file(ofk_trans_opt, FileName, FileStr, FileStrLen,
|
|
LineContext0, LinePosn0,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeOpt, Errors0),
|
|
(
|
|
MaybeParseTreeOpt = no,
|
|
MaybeParseTreeTransOpt = no,
|
|
Errors = Errors0
|
|
;
|
|
MaybeParseTreeOpt = yes(ParseTreeOpt),
|
|
check_convert_parse_tree_opt_to_trans_opt(ParseTreeOpt,
|
|
ParseTreeTransOpt, [], ConvertSpecs),
|
|
MaybeParseTreeTransOpt = yes(ParseTreeTransOpt),
|
|
add_any_nec_errors(ConvertSpecs, Errors0, Errors)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred maybe_add_convert_specs(globals::in, list(error_spec)::in,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
maybe_add_convert_specs(Globals, ConvertSpecs, !Errors) :-
|
|
globals.lookup_bool_option(Globals, halt_at_invalid_interface,
|
|
HaltAtInvalidInterface),
|
|
(
|
|
HaltAtInvalidInterface = no
|
|
;
|
|
HaltAtInvalidInterface = yes,
|
|
add_any_nec_errors(ConvertSpecs, !Errors)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred report_module_has_unexpected_name(file_name::in,
|
|
module_name::in, list(prog_context)::in,
|
|
module_name::in, maybe(term.context)::in, error_spec::out) is det.
|
|
|
|
report_module_has_unexpected_name(FileName, ExpectedName, ExpectationContexts,
|
|
ActualName, MaybeActualContext, Spec) :-
|
|
( if
|
|
MaybeActualContext = yes(ActualContext),
|
|
not term_context.is_dummy_context(ActualContext)
|
|
then
|
|
MaybeContext = MaybeActualContext
|
|
else
|
|
MaybeContext = maybe.no
|
|
),
|
|
MainPieces = [words("Error: file"), quote(FileName),
|
|
words("contains the wrong module."),
|
|
words("Expected module")] ++
|
|
color_as_correct([qual_sym_name(ExpectedName), suffix(",")]) ++
|
|
[words("found module")] ++
|
|
color_as_incorrect([qual_sym_name(ActualName), suffix(".")]) ++
|
|
[nl],
|
|
MainMsg = error_msg(MaybeContext, always_treat_as_first, 0,
|
|
[always(MainPieces)]),
|
|
list.sort_and_remove_dups(ExpectationContexts, SortedExpectationContexts0),
|
|
list.delete_all(SortedExpectationContexts0, dummy_context,
|
|
SortedExpectationContexts),
|
|
list.map(expectation_context_to_msg, SortedExpectationContexts, SubMsgs),
|
|
% We make the warning conditional on the warn_wrong_module_name option.
|
|
% This option is turned on by default, and it is turned off automatically
|
|
% by the compiler only in situations where it clearly makes sense to do so
|
|
% (in handle_options.m and options.m). If it is turned off manually
|
|
% by the user, he/she presumably has a good reason.
|
|
%
|
|
% Despite the option name having the "warn_" prefix,
|
|
% the severity is an error. The severity is deliberate.
|
|
% XXX The option should be renamed, but there is no obvious
|
|
% non-misleading name.
|
|
Spec = conditional_spec($pred, warn_wrong_module_name, yes,
|
|
severity_error, phase_module_name, [MainMsg | SubMsgs]).
|
|
|
|
:- pred expectation_context_to_msg(prog_context::in, error_msg::out) is det.
|
|
|
|
expectation_context_to_msg(Context, SubMsg) :-
|
|
SubPieces = [words("The expected name is specified here."), nl],
|
|
SubMsg = msg(Context, SubPieces).
|
|
|
|
%---------------------%
|
|
|
|
:- type read_parse_tree(PT) ==
|
|
pred(file_name, string, int, line_context, line_posn, module_name,
|
|
list(prog_context), maybe(PT), read_module_errors).
|
|
:- inst read_parse_tree
|
|
== (pred(in, in, in, in, in, in, in, out, out) is det).
|
|
|
|
:- type make_dummy_parse_tree(PT) == pred(module_name, PT).
|
|
:- inst make_dummy_parse_tree == (pred(in, out) is det).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
% This part of the module parses optimization files.
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% opt: STARTHERE module_start, item* ENDHERE
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Read an optimization file (.opt or .trans_opt) from standard input.
|
|
%
|
|
:- pred parse_opt_file(opt_file_kind::in, file_name::in, string::in, int::in,
|
|
line_context::in, line_posn::in, module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_opt)::out, read_module_errors::out) is det.
|
|
|
|
parse_opt_file(OptFileKind, SourceFileName0, FileString, FileStringLen,
|
|
!.LineContext, !.LinePosn,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTree, !:Errors) :-
|
|
parse_module_header(FileString, FileStringLen,
|
|
DefaultModuleName, DefaultExpectationContexts, SourceFileName0,
|
|
MaybeModuleHeader, SeqNumCounter1, !LineContext, !LinePosn),
|
|
(
|
|
MaybeModuleHeader = no_valid_module_header(!:Errors),
|
|
MaybeParseTree = no
|
|
;
|
|
MaybeModuleHeader = valid_module_header(ModuleName, ModuleNameContext),
|
|
% XXX We should allow the update of SourceFileName.
|
|
parse_item_sequence(FileString, FileStringLen, ModuleName,
|
|
no_lookahead, FinalLookAhead,
|
|
cord.init, InclsCord, cord.init, AvailsCord,
|
|
cord.init, FIMsCord, cord.init, ItemsCord,
|
|
SourceFileName0, SourceFileName, SeqNumCounter1, SeqNumCounter,
|
|
init_read_module_errors, !:Errors, !LineContext, !LinePosn),
|
|
check_for_unexpected_item_at_end(SourceFileName, FileString,
|
|
FileStringLen, ModuleName, fk_opt(OptFileKind), FinalLookAhead,
|
|
SeqNumCounter, !Errors, !.LineContext, !.LinePosn),
|
|
expect(cord.is_empty(InclsCord), $pred, "Incls != []"),
|
|
Avails = cord.list(AvailsCord),
|
|
avail_imports_uses(Avails, Imports, Uses),
|
|
expect(unify(Imports, []), $pred, "Imports != []"),
|
|
FIMs = cord.list(FIMsCord),
|
|
Items = cord.list(ItemsCord),
|
|
ParseTree = parse_tree_opt(ModuleName, OptFileKind, ModuleNameContext,
|
|
Uses, FIMs, Items),
|
|
MaybeParseTree = yes(ParseTree)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
% This part of the module parses interface files.
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% int: STARTHERE module_start, vns? section, section? ENDHERE
|
|
%
|
|
% section: interface_marker, item*
|
|
% implementation_marker, item*
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Read an interface file (.int0, .int3, .int2 or .int).
|
|
%
|
|
:- pred parse_int_file(int_file_kind::in, file_name::in, string::in, int::in,
|
|
line_context::in, line_posn::in, module_name::in, list(prog_context)::in,
|
|
maybe(parse_tree_int)::out, read_module_errors::out) is det.
|
|
|
|
parse_int_file(IntFileKind, SourceFileName, FileString, FileStringLen,
|
|
!.LineContext, !.LinePosn,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt, !:Errors) :-
|
|
some [!SeqNumCounter, !LookAhead] (
|
|
parse_module_header(FileString, FileStringLen,
|
|
DefaultModuleName, DefaultExpectationContexts, SourceFileName,
|
|
MaybeModuleHeader, !:SeqNumCounter, !LineContext, !LinePosn),
|
|
(
|
|
MaybeModuleHeader = no_valid_module_header(!:Errors),
|
|
MaybeParseTreeInt = no
|
|
;
|
|
MaybeModuleHeader =
|
|
valid_module_header(ModuleName, ModuleNameContext),
|
|
!:LookAhead = no_lookahead,
|
|
parse_any_version_number_item(FileString, FileStringLen,
|
|
ModuleName, SourceFileName, !LookAhead, VersionNumbersResult,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
(
|
|
VersionNumbersResult = vnr_error(Spec, Error),
|
|
!:Errors = init_read_module_errors,
|
|
add_nonfatal_error(Error, [Spec], !Errors),
|
|
MaybeParseTreeInt = no
|
|
;
|
|
VersionNumbersResult = vnr_ok(MaybeVersionNumbers),
|
|
parse_int_file_sections(FileString, FileStringLen,
|
|
ModuleName, ModuleNameContext, IntFileKind,
|
|
SourceFileName, MaybeVersionNumbers,
|
|
!LookAhead, MaybeParseTreeInt, !SeqNumCounter,
|
|
!:Errors, !LineContext, !LinePosn),
|
|
check_for_unexpected_item_at_end(SourceFileName,
|
|
FileString, FileStringLen, ModuleName, fk_int(IntFileKind),
|
|
!.LookAhead, !.SeqNumCounter, !Errors,
|
|
!.LineContext, !.LinePosn)
|
|
)
|
|
)
|
|
).
|
|
|
|
:- type version_number_result
|
|
---> vnr_ok(maybe_version_numbers)
|
|
; vnr_error(error_spec, nonfatal_read_module_error).
|
|
|
|
:- pred parse_any_version_number_item(string::in, int::in,
|
|
module_name::in, file_name::in, maybe_lookahead::in, maybe_lookahead::out,
|
|
version_number_result::out, counter::in, counter::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_any_version_number_item(FileString, FileStringLen,
|
|
ModuleName, SourceFileName, InitLookAhead, FinalLookAhead,
|
|
VersionNumberResult, !SeqNumCounter, !LineContext, !LinePosn) :-
|
|
get_next_item_or_marker(SourceFileName, FileString, FileStringLen,
|
|
InitLookAhead, ModuleName, ReadIOMResult,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
(
|
|
ReadIOMResult = read_iom_eof,
|
|
% If we have found end-of-file, then we are done.
|
|
FinalLookAhead = no_lookahead,
|
|
VersionNumberResult = vnr_ok(no_version_numbers)
|
|
;
|
|
ReadIOMResult = read_iom_parse_term_error(ItemSpec),
|
|
% We used to continue looking for a version number in this situation,
|
|
% but (a) given that version numbers are put into .intN files
|
|
% by automatic processes, *any* error detected in them renders
|
|
% the entire contents of the file suspect, and (b) when we are
|
|
% expecting a section marker but find read_iom_parse_term_error,
|
|
% we don't continue looking.
|
|
FinalLookAhead = no_lookahead,
|
|
VersionNumberResult = vnr_error(ItemSpec, rme_could_not_read_term)
|
|
;
|
|
ReadIOMResult = read_iom_parse_item_errors(_, _, _),
|
|
% Ignore the errors; our caller will compute them again,
|
|
% and record them, if and when it parses FinalLookAhead again.
|
|
FinalLookAhead = lookahead(ReadIOMResult),
|
|
VersionNumberResult = vnr_ok(no_version_numbers)
|
|
;
|
|
ReadIOMResult = read_iom_ok(_IOMVarSet, _IOMTerm, IOM),
|
|
% If the term we have read in is a version number item, return it.
|
|
% If the term is anything else, leave it in the input to be handled
|
|
% later.
|
|
(
|
|
IOM = iom_marker_version_numbers(VN),
|
|
FinalLookAhead = no_lookahead,
|
|
VersionNumberResult = vnr_ok(version_numbers(VN))
|
|
;
|
|
( IOM = iom_marker_module_start(_, _, _)
|
|
; IOM = iom_marker_module_end(_, _, _)
|
|
; IOM = iom_marker_src_file(_)
|
|
; IOM = iom_marker_section(_, _, _)
|
|
; IOM = iom_marker_include(_)
|
|
; IOM = iom_marker_avail(_)
|
|
; IOM = iom_marker_fim(_)
|
|
; IOM = iom_item(_)
|
|
; IOM = iom_item_and_error_specs(_, _)
|
|
% The reasoning for read_iom_parse_item_errors also applies
|
|
% to iom_item_and_specs.
|
|
; IOM = iom_handled_no_error
|
|
; IOM = iom_handled_error(_)
|
|
),
|
|
FinalLookAhead = lookahead(ReadIOMResult),
|
|
VersionNumberResult = vnr_ok(no_version_numbers)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% int: module_start, vns? STARTHERE int_section, int_section? ENDHERE
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% XXX ITEM_LIST We should return *either* a ParseTreeInt *or* some errors,
|
|
% but *not* both.
|
|
%
|
|
:- pred parse_int_file_sections(string::in, int::in,
|
|
module_name::in, prog_context::in, int_file_kind::in, file_name::in,
|
|
maybe_version_numbers::in, maybe_lookahead::in, maybe_lookahead::out,
|
|
maybe(parse_tree_int)::out, counter::in, counter::out,
|
|
read_module_errors::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_int_file_sections(FileString, FileStringLen,
|
|
ModuleName, ModuleNameContext, IntFileKind, SourceFileName,
|
|
MaybeVersionNumbers, !LookAhead, MaybeParseTreeInt, !SeqNumCounter,
|
|
!:Errors, !LineContext, !LinePosn) :-
|
|
parse_int_file_section(FileString, FileStringLen,
|
|
ModuleName, SourceFileName, "interface", !LookAhead,
|
|
MaybeFirstRawItemBlock, !SeqNumCounter,
|
|
init_read_module_errors, !:Errors, !LineContext, !LinePosn),
|
|
(
|
|
MaybeFirstRawItemBlock = no,
|
|
% Ignore MaybeVersionNumbers if the interface is empty,
|
|
% since there are no items whose version numbers we may be
|
|
% interested in.
|
|
ParseTreeInt = parse_tree_int(ModuleName, IntFileKind,
|
|
ModuleNameContext, no_version_numbers,
|
|
[], [], [], [], [], [], [], []),
|
|
MaybeParseTreeInt = yes(ParseTreeInt)
|
|
;
|
|
MaybeFirstRawItemBlock = yes({FirstRawItemBlock, _}),
|
|
FirstRawItemBlock = item_block(_, FirstSectionKind,
|
|
FirstIncls, FirstAvails, FirstFIMs, FirstItems),
|
|
(
|
|
FirstSectionKind = ms_interface,
|
|
parse_int_file_section(FileString, FileStringLen,
|
|
ModuleName, SourceFileName, "implementation", !LookAhead,
|
|
MaybeSecondRawItemBlock, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn),
|
|
(
|
|
MaybeSecondRawItemBlock = no,
|
|
ParseTreeInt = parse_tree_int(ModuleName, IntFileKind,
|
|
ModuleNameContext, MaybeVersionNumbers,
|
|
FirstIncls, [], FirstAvails, [],
|
|
FirstFIMs, [], FirstItems, []),
|
|
MaybeParseTreeInt = yes(ParseTreeInt)
|
|
;
|
|
MaybeSecondRawItemBlock =
|
|
yes({SecondRawItemBlock, SectionContext}),
|
|
SecondRawItemBlock = item_block(_, SecondSectionKind,
|
|
SecondIncls, SecondAvails, SecondFIMs, SecondItems),
|
|
(
|
|
SecondSectionKind = ms_interface,
|
|
Pieces = [words("Error: an interface file"),
|
|
words("should not have two consecutive"),
|
|
words("interface sections."), nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt,
|
|
SectionContext, Pieces),
|
|
add_nonfatal_error(rme_nec, [Spec], !Errors),
|
|
MaybeParseTreeInt = no
|
|
;
|
|
SecondSectionKind = ms_implementation,
|
|
ParseTreeInt = parse_tree_int(ModuleName, IntFileKind,
|
|
ModuleNameContext, MaybeVersionNumbers,
|
|
FirstIncls, SecondIncls, FirstAvails, SecondAvails,
|
|
FirstFIMs, SecondFIMs, FirstItems, SecondItems),
|
|
MaybeParseTreeInt = yes(ParseTreeInt)
|
|
)
|
|
)
|
|
;
|
|
FirstSectionKind = ms_implementation,
|
|
% This should not happen, but I (zs) cannot come up
|
|
% with a convincing argument for *why*.
|
|
ParseTreeInt = parse_tree_int(ModuleName, IntFileKind,
|
|
ModuleNameContext, MaybeVersionNumbers,
|
|
[], FirstIncls, [], FirstAvails,
|
|
[], FirstFIMs, [], FirstItems),
|
|
MaybeParseTreeInt = yes(ParseTreeInt)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% int_section:
|
|
% STARTHERE interface_marker, item* ENDHERE
|
|
% STARTHERE implementation_marker, item* ENDHERE
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred parse_int_file_section(string::in, int::in,
|
|
module_name::in, file_name::in, string::in,
|
|
maybe_lookahead::in, maybe_lookahead::out,
|
|
maybe({raw_item_block, prog_context})::out,
|
|
counter::in, counter::out, read_module_errors::in, read_module_errors::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_int_file_section(FileString, FileStringLen,
|
|
ModuleName, SourceFileName, ExpectedSectionKindStr,
|
|
InitLookAhead, FinalLookAhead, MaybeRawItemBlock,
|
|
!SeqNumCounter, !Errors, !LineContext, !LinePosn) :-
|
|
get_next_item_or_marker(SourceFileName, FileString, FileStringLen,
|
|
InitLookAhead, ModuleName, ReadIOMResult, !SeqNumCounter,
|
|
!LineContext, !LinePosn),
|
|
(
|
|
(
|
|
ReadIOMResult = read_iom_eof
|
|
;
|
|
ReadIOMResult = read_iom_parse_term_error(ItemSpec),
|
|
add_nonfatal_error(rme_could_not_read_term, [ItemSpec], !Errors)
|
|
;
|
|
ReadIOMResult = read_iom_parse_item_errors(_IOMVarSet, _IOMTerm,
|
|
ItemSpecs),
|
|
add_nonfatal_error(rme_could_not_parse_item, ItemSpecs, !Errors)
|
|
),
|
|
MaybeRawItemBlock = no,
|
|
FinalLookAhead = no_lookahead
|
|
;
|
|
ReadIOMResult = read_iom_ok(_IOMVarSet, IOMTerm, IOM),
|
|
(
|
|
IOM = iom_marker_section(SectionKind, SectionContext,
|
|
_SectionSeqNum),
|
|
parse_item_sequence(FileString, FileStringLen,
|
|
ModuleName, no_lookahead, FinalLookAhead,
|
|
cord.init, InclsCord, cord.init, AvailsCord,
|
|
cord.init, FIMsCord, cord.init, ItemsCord,
|
|
SourceFileName, _UpdatedSourceFileName,
|
|
!SeqNumCounter, !Errors, !LineContext, !LinePosn),
|
|
RawItemBlock = item_block(ModuleName, SectionKind,
|
|
cord.list(InclsCord), cord.list(AvailsCord),
|
|
cord.list(FIMsCord), cord.list(ItemsCord)),
|
|
MaybeRawItemBlock = yes({RawItemBlock, SectionContext})
|
|
;
|
|
( IOM = iom_marker_src_file(_)
|
|
; IOM = iom_marker_module_start(_, _, _)
|
|
; IOM = iom_marker_module_end(_, _, _)
|
|
; IOM = iom_marker_version_numbers(_)
|
|
; IOM = iom_marker_include(_)
|
|
; IOM = iom_marker_avail(_)
|
|
; IOM = iom_marker_fim(_)
|
|
; IOM = iom_item(_)
|
|
% The fact that IOM is not a section marker trumps any error_specs
|
|
% in iom_item_and_error_specs, and in iom_handled_error.
|
|
; IOM = iom_item_and_error_specs(_, _)
|
|
; IOM = iom_handled_no_error
|
|
; IOM = iom_handled_error(_)
|
|
),
|
|
Context = get_term_context(IOMTerm),
|
|
IOMPieces = iom_desc_pieces(IOM),
|
|
Pieces = [words("Error: expected the start of an")] ++
|
|
color_as_correct([words(ExpectedSectionKindStr),
|
|
words("section,")]) ++
|
|
[words("got")] ++
|
|
color_as_incorrect(IOMPieces ++ [suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
|
|
add_nonfatal_error(rme_nec, [Spec], !Errors),
|
|
FinalLookAhead = lookahead(ReadIOMResult),
|
|
MaybeRawItemBlock = no
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
% This part of the module parses source files.
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% src: STARTHERE module_start, component*, (module_end | epsilon) ENDHERE
|
|
%
|
|
% component: (interface_marker | epsilon), item*
|
|
% (implementation_marker | epsilon), item*
|
|
% module_start, component*, (module_end | epsilon)
|
|
%
|
|
% The marker that starts a component may be missing if the previous components
|
|
% were (one or more) nested submodules, and before those nested submodules,
|
|
% there was an interface or implementation section. That previous section
|
|
% may have started with an explicit section marker, or it may have been
|
|
% preceded by other nested submodules, and identified as an interface or
|
|
% implementation section by the preceding section, and so on.
|
|
%
|
|
% A submodule may have its final end_module marker missing if there is nothing
|
|
% following it: no item, no marker, only the implicit EOF.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
parse_src_file(!.SourceFileName, FileString, FileStringLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTree, !:Errors) :-
|
|
some [!LineContext, !LinePosn, !SeqNumCounter] (
|
|
!:LineContext = line_context(1, 0),
|
|
!:LinePosn = line_posn(0),
|
|
|
|
!:Errors = init_read_module_errors,
|
|
counter.init(1, !:SeqNumCounter),
|
|
|
|
% We handle the first module declaration specially. Read the
|
|
% documentation on parse_first_module_decl for the reason.
|
|
parse_first_module_decl(FileString, FileStringLen,
|
|
dont_require_module_decl, DefaultModuleName,
|
|
DefaultExpectationContexts, ModuleDeclPresent,
|
|
may_change_source_file_name, !SourceFileName,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
(
|
|
ModuleDeclPresent = no_module_decl_present(InitLookAhead,
|
|
InitLookAheadContext, NoModuleSpec),
|
|
add_nonfatal_error(rme_no_module_decl_at_start, [NoModuleSpec],
|
|
!Errors),
|
|
ModuleName = DefaultModuleName,
|
|
ModuleNameContext = InitLookAheadContext
|
|
;
|
|
ModuleDeclPresent = wrong_module_decl_present(ModuleName,
|
|
ModuleNameContext, WrongSpec),
|
|
add_nonfatal_error(rme_unexpected_module_name, [WrongSpec],
|
|
!Errors),
|
|
InitLookAhead = no_lookahead
|
|
;
|
|
ModuleDeclPresent =
|
|
right_module_decl_present(ModuleName, ModuleNameContext),
|
|
InitLookAhead = no_lookahead
|
|
),
|
|
|
|
ContainingModules = [],
|
|
MaybePrevSection = no,
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
ModuleName, ContainingModules, MaybePrevSection,
|
|
have_not_given_missing_section_start_warning,
|
|
InitLookAhead, FinalLookAhead, cord.init, ModuleComponents,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn),
|
|
check_for_unexpected_item_at_end(!.SourceFileName, FileString,
|
|
FileStringLen, ModuleName, fk_src, FinalLookAhead, !.SeqNumCounter,
|
|
!Errors, !.LineContext, !.LinePosn),
|
|
ParseTree = parse_tree_src(ModuleName, ModuleNameContext,
|
|
ModuleComponents),
|
|
MaybeParseTree = yes(ParseTree)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% src: module_start, STARTHERE component*, (module_end | epsilon) ENDHERE
|
|
%
|
|
% component: (interface_marker | epsilon), item*
|
|
% (implementation_marker | epsilon), item*
|
|
% module_start, STARTHERE component*, (module_end | epsilon) ENDHERE
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred parse_src_file_components(string::in, int::in,
|
|
module_name::in, list(module_name)::in,
|
|
maybe(pair(module_section, prog_context))::in,
|
|
missing_section_start_warning::in,
|
|
maybe_lookahead::in, maybe_lookahead::out,
|
|
cord(module_component)::in, cord(module_component)::out,
|
|
file_name::in, file_name::out, counter::in, counter::out,
|
|
read_module_errors::in, read_module_errors::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules,
|
|
MaybePrevSection, !.MissingStartSectionWarning,
|
|
InitLookAhead, FinalLookAhead, !ModuleComponents, !SourceFileName,
|
|
!SeqNumCounter, !Errors, !LineContext, !LinePosn) :-
|
|
get_next_item_or_marker(!.SourceFileName, FileString, FileStringLen,
|
|
InitLookAhead, CurModuleName, ReadIOMResult, !SeqNumCounter,
|
|
!LineContext, !LinePosn),
|
|
(
|
|
ReadIOMResult = read_iom_eof,
|
|
% If we have found end-of-file, then we are done.
|
|
FinalLookAhead = no_lookahead
|
|
;
|
|
ReadIOMResult = read_iom_parse_term_error(ItemSpec),
|
|
add_nonfatal_error(rme_could_not_read_term, [ItemSpec], !Errors),
|
|
% Continue looking for a section marker.
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules,
|
|
MaybePrevSection, !.MissingStartSectionWarning,
|
|
no_lookahead, FinalLookAhead, !ModuleComponents, !SourceFileName,
|
|
!SeqNumCounter, !Errors, !LineContext, !LinePosn)
|
|
;
|
|
ReadIOMResult = read_iom_parse_item_errors(_IOMVarSet, IOMTerm,
|
|
_Specs),
|
|
% Generate an error for the missing section marker.
|
|
% Leave the term in the lookahead, but otherwise handle the term
|
|
% as it were an unexpected but perfectly parseable term, i.e. follow
|
|
% the pattern of the iom_item case below.
|
|
Context = get_term_context(IOMTerm),
|
|
generate_missing_start_section_warning_src(CurModuleName,
|
|
Context, !.MissingStartSectionWarning, _MissingStartSectionWarning,
|
|
!Errors),
|
|
SectionKind = ms_implementation,
|
|
SectionContext = dummy_context,
|
|
ItemSeqInitLookAhead = lookahead(ReadIOMResult),
|
|
parse_item_sequence(FileString, FileStringLen, CurModuleName,
|
|
ItemSeqInitLookAhead, ItemSeqFinalLookAhead,
|
|
cord.init, InclsCord, cord.init, AvailsCord,
|
|
cord.init, FIMsCord, cord.init, ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn),
|
|
add_section_component(CurModuleName, SectionKind, SectionContext,
|
|
InclsCord, AvailsCord, FIMsCord, ItemsCord, !ModuleComponents),
|
|
% We have read in one component; recurse to read in other components.
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules,
|
|
yes(SectionKind - SectionContext),
|
|
have_not_given_missing_section_start_warning,
|
|
ItemSeqFinalLookAhead, FinalLookAhead, !ModuleComponents,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn)
|
|
;
|
|
ReadIOMResult = read_iom_ok(_IOMVarSet, IOMTerm, IOM),
|
|
(
|
|
IOM = iom_marker_src_file(!:SourceFileName),
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules, MaybePrevSection,
|
|
!.MissingStartSectionWarning, no_lookahead, FinalLookAhead,
|
|
!ModuleComponents, !SourceFileName, !SeqNumCounter,
|
|
!Errors, !LineContext, !LinePosn)
|
|
;
|
|
IOM = iom_marker_version_numbers(_),
|
|
Pieces = [words("Error:")] ++
|
|
color_as_incorrect([words("unexpected version_numbers record"),
|
|
words("in source file.")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_read_files,
|
|
get_term_context(IOMTerm), Pieces),
|
|
add_nonfatal_error(rme_nec, [Spec], !Errors),
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules, MaybePrevSection,
|
|
!.MissingStartSectionWarning, no_lookahead, FinalLookAhead,
|
|
!ModuleComponents, !SourceFileName, !SeqNumCounter,
|
|
!Errors, !LineContext, !LinePosn)
|
|
;
|
|
IOM = iom_marker_module_start(RawStartModuleName, StartContext,
|
|
_StartSeqNum),
|
|
(
|
|
RawStartModuleName = unqualified(RawBaseName),
|
|
StartModuleName = qualified(CurModuleName, RawBaseName)
|
|
;
|
|
RawStartModuleName = qualified(RawModuleName, RawBaseName),
|
|
( if
|
|
partial_sym_name_matches_full(RawModuleName, CurModuleName)
|
|
then
|
|
StartModuleName = qualified(CurModuleName, RawBaseName)
|
|
else
|
|
Pieces = [words("Error: module qualification of"),
|
|
words("nested submodule")] ++
|
|
color_as_incorrect(
|
|
[qual_sym_name(RawStartModuleName)]) ++
|
|
[words("does not match the then-current module,")] ++
|
|
color_as_correct([qual_sym_name(CurModuleName),
|
|
suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt,
|
|
StartContext, Pieces),
|
|
add_nonfatal_error(rme_nec, [Spec], !Errors),
|
|
% Recover partially by ignoring the bad module
|
|
% qualification. The recovery is only partial because
|
|
% an end_module marker that matches the incorrect module
|
|
% name will get another error message about the
|
|
% `:- end_module' not matching the `:- module' declaration,
|
|
% which will be at least a bit misleading.
|
|
StartModuleName = qualified(CurModuleName, RawBaseName)
|
|
)
|
|
),
|
|
parse_src_file_submodule(FileString, FileStringLen,
|
|
ContainingModules, MaybePrevSection, CurModuleName,
|
|
StartModuleName, StartContext,
|
|
no_lookahead, SubModuleFinalLookAhead, !ModuleComponents,
|
|
!SourceFileName, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn),
|
|
% We have read in one component; recurse to read in others.
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules, MaybePrevSection,
|
|
!.MissingStartSectionWarning,
|
|
SubModuleFinalLookAhead, FinalLookAhead, !ModuleComponents,
|
|
!SourceFileName, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn)
|
|
;
|
|
( IOM = iom_marker_section(_, _, _)
|
|
; IOM = iom_marker_include(_)
|
|
; IOM = iom_marker_avail(_)
|
|
; IOM = iom_marker_fim(_)
|
|
; IOM = iom_item(_)
|
|
; IOM = iom_item_and_error_specs(_, _)
|
|
; IOM = iom_handled_no_error
|
|
; IOM = iom_handled_error(_)
|
|
),
|
|
(
|
|
IOM = iom_marker_section(SectionKind, SectionContext,
|
|
_SectionSeqNum),
|
|
ItemSeqInitLookAhead = no_lookahead
|
|
;
|
|
(
|
|
( IOM = iom_marker_include(_)
|
|
; IOM = iom_marker_avail(_)
|
|
; IOM = iom_marker_fim(_)
|
|
; IOM = iom_item(_)
|
|
; IOM = iom_handled_no_error
|
|
)
|
|
;
|
|
IOM = iom_handled_error(ItemSpecs),
|
|
add_nonfatal_error(rme_nec, ItemSpecs, !Errors)
|
|
;
|
|
IOM = iom_item_and_error_specs(_, ItemSpecs),
|
|
add_nonfatal_error(rme_nec, ItemSpecs, !Errors)
|
|
),
|
|
(
|
|
MaybePrevSection = yes(SectionKind - SectionContext)
|
|
% When a nested module occurs in a section, the section
|
|
% continues after the nested module without the need
|
|
% for a new section declaration.
|
|
;
|
|
MaybePrevSection = no,
|
|
Context = get_term_context(IOMTerm),
|
|
generate_missing_start_section_warning_src(CurModuleName,
|
|
Context, !.MissingStartSectionWarning,
|
|
_MissingStartSectionWarning, !Errors),
|
|
% The following code is duplicated in the case for
|
|
% read_iom_parse_item_errors above.
|
|
SectionKind = ms_implementation,
|
|
SectionContext = dummy_context
|
|
),
|
|
ItemSeqInitLookAhead = lookahead(ReadIOMResult)
|
|
),
|
|
% The following code is duplicated in the case for
|
|
% read_iom_parse_item_errors above.
|
|
parse_item_sequence(FileString, FileStringLen, CurModuleName,
|
|
ItemSeqInitLookAhead, ItemSeqFinalLookAhead,
|
|
cord.init, InclsCord, cord.init, AvailsCord,
|
|
cord.init, FIMsCord, cord.init, ItemsCord, !SourceFileName,
|
|
!SeqNumCounter, !Errors, !LineContext, !LinePosn),
|
|
add_section_component(CurModuleName, SectionKind, SectionContext,
|
|
InclsCord, AvailsCord, FIMsCord, ItemsCord, !ModuleComponents),
|
|
% We have read in one component; recurse to read in other
|
|
% components.
|
|
parse_src_file_components(FileString, FileStringLen,
|
|
CurModuleName, ContainingModules,
|
|
yes(SectionKind - SectionContext),
|
|
have_not_given_missing_section_start_warning,
|
|
ItemSeqFinalLookAhead, FinalLookAhead, !ModuleComponents,
|
|
!SourceFileName, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn)
|
|
;
|
|
IOM = iom_marker_module_end(EndedModuleName, EndContext,
|
|
_EndSeqNum),
|
|
handle_module_end_marker(CurModuleName, ContainingModules,
|
|
ReadIOMResult, EndedModuleName, EndContext, FinalLookAhead,
|
|
!Errors)
|
|
)
|
|
).
|
|
|
|
:- pred add_section_component(module_name::in, module_section::in,
|
|
prog_context::in, cord(item_include)::in, cord(item_avail)::in,
|
|
cord(item_fim)::in, cord(item)::in,
|
|
cord(module_component)::in, cord(module_component)::out) is det.
|
|
|
|
add_section_component(ModuleName, SectionKind, SectionContext,
|
|
InclsCord, AvailsCord, FIMsCord, ItemsCord, !ModuleComponents) :-
|
|
( if
|
|
cord.is_empty(InclsCord),
|
|
cord.is_empty(AvailsCord),
|
|
cord.is_empty(FIMsCord),
|
|
cord.is_empty(ItemsCord)
|
|
then
|
|
true
|
|
else
|
|
Component = mc_section(ModuleName, SectionKind, SectionContext,
|
|
InclsCord, AvailsCord, FIMsCord, ItemsCord),
|
|
!:ModuleComponents = cord.snoc(!.ModuleComponents, Component)
|
|
).
|
|
|
|
:- pred generate_missing_start_section_warning_src(module_name::in,
|
|
prog_context::in,
|
|
missing_section_start_warning::in, missing_section_start_warning::out,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
generate_missing_start_section_warning_src(CurModuleName,
|
|
Context, !MissingStartSectionWarning, !Errors) :-
|
|
(
|
|
!.MissingStartSectionWarning =
|
|
have_not_given_missing_section_start_warning,
|
|
!:MissingStartSectionWarning =
|
|
have_given_missing_section_start_warning,
|
|
Pieces = [invis_order_default_start(1, ""),
|
|
words("Error: module"), qual_sym_name(CurModuleName)] ++
|
|
color_as_incorrect([words("should start with")]) ++
|
|
[words("either an")] ++
|
|
color_as_correct([decl("interface"), words("declaration")]) ++
|
|
[words("or an")] ++
|
|
color_as_correct([decl("implementation"),
|
|
words("declaration.")]) ++
|
|
[nl,
|
|
words("The following assumes that"),
|
|
words("the missing declaration is an"),
|
|
decl("implementation"), words("declaration."), nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
|
|
add_nonfatal_error(rme_no_section_decl_at_start, [Spec], !Errors)
|
|
;
|
|
!.MissingStartSectionWarning =
|
|
have_given_missing_section_start_warning
|
|
% Do not generate duplicate warnings.
|
|
).
|
|
|
|
:- pred parse_src_file_submodule(string::in, int::in,
|
|
list(module_name)::in, maybe(pair(module_section, prog_context))::in,
|
|
module_name::in, module_name::in, prog_context::in,
|
|
maybe_lookahead::in, maybe_lookahead::out,
|
|
cord(module_component)::in, cord(module_component)::out,
|
|
file_name::in, file_name::out, counter::in, counter::out,
|
|
read_module_errors::in, read_module_errors::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_src_file_submodule(FileString, FileStringLen, ContainingModules,
|
|
MaybePrevSection, ContainingModuleName, StartModuleName, StartContext,
|
|
InitLookAhead, FinalLookAhead, !ModuleComponents, !SourceFileName,
|
|
!SeqNumCounter, !Errors, !LineContext, !LinePosn) :-
|
|
(
|
|
MaybePrevSection = yes(SectionKind - SectionContext)
|
|
;
|
|
MaybePrevSection = no,
|
|
NoSectionPieces = [words("Error: nested submodule"),
|
|
qual_sym_name(StartModuleName)] ++
|
|
color_as_incorrect([words("should be preceded")]) ++
|
|
[words("by either an")] ++
|
|
color_as_correct([decl("interface"), words("declaration")]) ++
|
|
[words("or an")] ++
|
|
color_as_correct([decl("implementation"),
|
|
words("declaration.")]) ++
|
|
[nl,
|
|
words("The following assumes that"),
|
|
words("the missing declaration is an"),
|
|
decl("interface"), words("declaration."), nl],
|
|
NoSectionSpec = spec($pred, severity_error, phase_t2pt,
|
|
StartContext, NoSectionPieces),
|
|
% XXX ITEM_LIST Should this be a situation-specific rme_X value?
|
|
add_nonfatal_error(rme_no_section_decl_at_start, [NoSectionSpec],
|
|
!Errors),
|
|
SectionKind = ms_interface,
|
|
SectionContext = dummy_context
|
|
),
|
|
NestedContainingModules = [StartModuleName | ContainingModules],
|
|
NestedMaybePrevSection = no,
|
|
parse_src_file_components(FileString, FileStringLen, StartModuleName,
|
|
NestedContainingModules, NestedMaybePrevSection,
|
|
have_not_given_missing_section_start_warning,
|
|
InitLookAhead, FinalLookAhead, cord.init, NestedModuleComponents,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn),
|
|
SubModuleParseTreeSrc = parse_tree_src(StartModuleName, StartContext,
|
|
NestedModuleComponents),
|
|
Component = mc_nested_submodule(ContainingModuleName, SectionKind,
|
|
SectionContext, SubModuleParseTreeSrc),
|
|
!:ModuleComponents = cord.snoc(!.ModuleComponents, Component).
|
|
|
|
:- pred handle_module_end_marker(module_name::in, list(module_name)::in,
|
|
read_iom_result::in, module_name::in, prog_context::in,
|
|
maybe_lookahead::out, read_module_errors::in, read_module_errors::out)
|
|
is det.
|
|
|
|
handle_module_end_marker(CurModuleName, ContainingModules, ReadIOMResult,
|
|
EndedModuleName, EndContext, FinalLookAhead, !Errors) :-
|
|
( if CurModuleName = EndedModuleName then
|
|
FinalLookAhead = no_lookahead
|
|
else if partial_sym_name_matches_full(EndedModuleName, CurModuleName) then
|
|
% XXX ITEM_LIST Should this be an error? Warning?
|
|
FinalLookAhead = no_lookahead
|
|
else if is_for_containing_module(EndedModuleName, ContainingModules) then
|
|
Pieces = [words("Error:")] ++
|
|
color_as_incorrect([words("missing"), decl("end_module"),
|
|
words("declaration")]) ++
|
|
[words("for")] ++
|
|
color_as_subject([qual_sym_name(CurModuleName), suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, EndContext, Pieces),
|
|
add_fatal_error(frme_bad_module_end, [Spec], !Errors),
|
|
FinalLookAhead = lookahead(ReadIOMResult)
|
|
else
|
|
Pieces = [words("Error: this")] ++
|
|
color_as_subject([decl("end_module"), words("declaration for"),
|
|
qual_sym_name(EndedModuleName)]) ++
|
|
color_as_incorrect([words("is not for the module"),
|
|
words("at whose end it appears,")]) ++
|
|
[words("which is"),
|
|
qual_sym_name(CurModuleName), suffix("."), nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, EndContext, Pieces),
|
|
add_fatal_error(frme_bad_module_end, [Spec], !Errors),
|
|
% Eat the bad end_module declaration.
|
|
FinalLookAhead = no_lookahead
|
|
).
|
|
|
|
:- pred is_for_containing_module(module_name::in, list(module_name)::in)
|
|
is semidet.
|
|
|
|
is_for_containing_module(EndedModuleName,
|
|
[ContainingModule | ContainingModules]) :-
|
|
( if partial_sym_name_matches_full(EndedModuleName, ContainingModule) then
|
|
true
|
|
else
|
|
is_for_containing_module(EndedModuleName, ContainingModules)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
% This part of the module contains utility predicates.
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type maybe_module_header
|
|
---> no_valid_module_header(
|
|
% A complete description of the errors involved.
|
|
read_module_errors
|
|
)
|
|
; valid_module_header(
|
|
% The name in the ":- module" decl, and its context.
|
|
module_name,
|
|
prog_context
|
|
).
|
|
|
|
:- pred parse_module_header(string::in, int::in,
|
|
module_name::in, list(prog_context)::in, file_name::in,
|
|
maybe_module_header::out, counter::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_module_header(FileString, FileStringLen,
|
|
DefaultModuleName, DefaultExpectationContexts, SourceFileName,
|
|
MaybeModuleHeader, !:SeqNumCounter,
|
|
!LineContext, !LinePosn) :-
|
|
counter.init(1, !:SeqNumCounter),
|
|
parse_first_module_decl(FileString, FileStringLen, require_module_decl,
|
|
DefaultModuleName, DefaultExpectationContexts, ModuleDeclPresent,
|
|
may_not_change_source_file_name, SourceFileName, _SourceFileName,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
(
|
|
ModuleDeclPresent = no_module_decl_present(_MaybeLookAhead, _Context,
|
|
NoModuleSpec),
|
|
Errors0 = init_read_module_errors,
|
|
add_nonfatal_error(rme_no_module_decl_at_start,
|
|
[NoModuleSpec], Errors0, Errors),
|
|
MaybeModuleHeader = no_valid_module_header(Errors)
|
|
;
|
|
ModuleDeclPresent = wrong_module_decl_present(ModuleName,
|
|
ModuleNameContext, WrongModuleSpec),
|
|
NoModuleSpec = report_wrong_module_start(ModuleNameContext,
|
|
DefaultModuleName, ModuleName),
|
|
Errors0 = init_read_module_errors,
|
|
add_nonfatal_error(rme_no_module_decl_at_start,
|
|
[NoModuleSpec], Errors0, Errors1),
|
|
add_nonfatal_error(rme_unexpected_module_name,
|
|
[WrongModuleSpec], Errors1, Errors),
|
|
MaybeModuleHeader = no_valid_module_header(Errors)
|
|
;
|
|
ModuleDeclPresent =
|
|
right_module_decl_present(ModuleName, ModuleNameContext),
|
|
MaybeModuleHeader = valid_module_header(ModuleName, ModuleNameContext)
|
|
).
|
|
|
|
:- type maybe_module_decl_present
|
|
---> no_module_decl_present(
|
|
% Any lookahead left from the input. This lookahead is needed
|
|
% ONLY to allow us to continue parsing .m files after
|
|
% a missing initial ":- module" decl.
|
|
maybe_lookahead,
|
|
|
|
% The context of the term that is there instead of the module
|
|
% declaration. Will contain term.context_init if there is
|
|
% no such term.
|
|
prog_context,
|
|
|
|
% A message for the error. The error category is
|
|
% always rme_no_module_decl_at_start.
|
|
error_spec
|
|
)
|
|
; wrong_module_decl_present(
|
|
% The name in the ":- module" decl, and its context.
|
|
module_name,
|
|
prog_context,
|
|
|
|
% A message for the error, which may be conditional.
|
|
% The category is always rme_unexpected_module_name.
|
|
error_spec
|
|
)
|
|
; right_module_decl_present(
|
|
% The name in the ":- module" decl, and its context.
|
|
module_name,
|
|
prog_context
|
|
).
|
|
|
|
% Files written by users may contain source_file pragmas, which change
|
|
% the parser's notion of the current filename. For these, callers should
|
|
% therefore pass may_change_source_file_name. On the other hand, files
|
|
% automatically generated by the compiler (.int* and .*opt files)
|
|
% never contain source_file pragmas. For these, callers should pass
|
|
% may_not_change_source_file_name, which calls for any occurrence of
|
|
% a source_file pragma to be treated as the error it is.
|
|
%
|
|
:- type may_change_source_file_name
|
|
---> may_not_change_source_file_name
|
|
; may_change_source_file_name.
|
|
|
|
% We used to have to jump through a few hoops when reading the first item,
|
|
% to allow us to recover from a missing initial `:- module' declaration.
|
|
% Now we don't bother trying to recover in such cases. The only special
|
|
% treatment that the first declaration gets is that we check whether
|
|
% the actual module name matches the expected (default) module name.
|
|
%
|
|
:- pred parse_first_module_decl(string::in, int::in,
|
|
maybe_require_module_decl::in, module_name::in, list(prog_context)::in,
|
|
maybe_module_decl_present::out, may_change_source_file_name::in,
|
|
file_name::in, file_name::out, counter::in, counter::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_first_module_decl(FileString, FileStringLen, RequireModuleDecl,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
ModuleDeclPresent, MayChangeSourceFileName, !SourceFileName,
|
|
!SeqNumCounter, !LineContext, !LinePosn) :-
|
|
mercury_term_parser.read_term_from_linestr(!.SourceFileName,
|
|
FileString, FileStringLen, !LineContext, !LinePosn, FirstReadTerm),
|
|
read_term_to_iom_result(DefaultModuleName, !.SourceFileName,
|
|
FirstReadTerm, MaybeFirstIOM, !SeqNumCounter),
|
|
(
|
|
MaybeFirstIOM = read_iom_ok(_FirstVarSet, FirstTerm, FirstIOM),
|
|
(
|
|
FirstIOM = iom_marker_src_file(!:SourceFileName),
|
|
(
|
|
MayChangeSourceFileName = may_not_change_source_file_name,
|
|
FirstLookAhead = lookahead(MaybeFirstIOM),
|
|
FirstContext = get_term_context(FirstTerm),
|
|
ModuleDeclPresent = no_module_decl_present(FirstLookAhead,
|
|
FirstContext, report_missing_module_start(FirstContext))
|
|
;
|
|
MayChangeSourceFileName = may_change_source_file_name,
|
|
% Apply and then skip `pragma source_file' decls, by calling
|
|
% ourselves recursively with the new source file name.
|
|
parse_first_module_decl(FileString, FileStringLen,
|
|
RequireModuleDecl, DefaultModuleName,
|
|
DefaultExpectationContexts, ModuleDeclPresent,
|
|
MayChangeSourceFileName, !SourceFileName,
|
|
!SeqNumCounter, !LineContext, !LinePosn)
|
|
)
|
|
;
|
|
FirstIOM = iom_marker_module_start(StartModuleName,
|
|
ModuleNameContext, _ModuleNameSeqNum),
|
|
% The first term is a `:- module' decl, as expected.
|
|
% Check whether it matches the expected module name.
|
|
( if DefaultModuleName = StartModuleName then
|
|
ModuleDeclPresent = right_module_decl_present(StartModuleName,
|
|
ModuleNameContext)
|
|
else
|
|
report_module_has_unexpected_name(!.SourceFileName,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
StartModuleName, yes(ModuleNameContext), NameSpec),
|
|
ModuleDeclPresent = wrong_module_decl_present(StartModuleName,
|
|
ModuleNameContext, NameSpec)
|
|
)
|
|
;
|
|
( FirstIOM = iom_marker_module_end(_, _, _)
|
|
; FirstIOM = iom_marker_version_numbers(_)
|
|
; FirstIOM = iom_marker_section(_, _, _)
|
|
; FirstIOM = iom_marker_include(_)
|
|
; FirstIOM = iom_marker_avail(_)
|
|
; FirstIOM = iom_marker_fim(_)
|
|
; FirstIOM = iom_item(_)
|
|
% Ignore the error_specs.
|
|
; FirstIOM = iom_item_and_error_specs(_, _)
|
|
; FirstIOM = iom_handled_no_error
|
|
% Ignore the error_specs.
|
|
; FirstIOM = iom_handled_error(_)
|
|
),
|
|
FirstLookAhead = lookahead(MaybeFirstIOM),
|
|
FirstContext = get_term_context(FirstTerm),
|
|
ModuleDeclPresent = no_module_decl_present(FirstLookAhead,
|
|
get_term_context(FirstTerm),
|
|
report_missing_module_start(FirstContext))
|
|
)
|
|
;
|
|
MaybeFirstIOM = read_iom_parse_item_errors(_, FirstTerm, _),
|
|
LookAhead = lookahead(MaybeFirstIOM),
|
|
FirstContext = get_term_context(FirstTerm),
|
|
ModuleDeclPresent = no_module_decl_present(LookAhead,
|
|
get_term_context(FirstTerm),
|
|
report_missing_module_start(FirstContext))
|
|
;
|
|
( MaybeFirstIOM = read_iom_eof
|
|
; MaybeFirstIOM = read_iom_parse_term_error(_)
|
|
),
|
|
FirstContext = term_context.context_init(!.SourceFileName, 1),
|
|
ModuleDeclPresent = no_module_decl_present(no_lookahead,
|
|
dummy_context, report_missing_module_start(FirstContext))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Read a sequence of items, until we find a marker that indicates
|
|
% a change in section or module. If and when we find such a marker,
|
|
% we stop reading, and return the term of that marker as the final
|
|
% lookahead.
|
|
%
|
|
% We use the standard two level loop to avoid running out of stack
|
|
% on long item sequences in grades that do not allow tail recursion.
|
|
%
|
|
:- pred parse_item_sequence(string::in, int::in, module_name::in,
|
|
maybe_lookahead::in, maybe_lookahead::out,
|
|
cord(item_include)::in, cord(item_include)::out,
|
|
cord(item_avail)::in, cord(item_avail)::out,
|
|
cord(item_fim)::in, cord(item_fim)::out,
|
|
cord(item)::in, cord(item)::out,
|
|
file_name::in, file_name::out, counter::in, counter::out,
|
|
read_module_errors::in, read_module_errors::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_item_sequence(FileString, FileStringLen, ModuleName,
|
|
InitLookAhead, FinalLookAhead,
|
|
!InclsCord, !AvailsCord, !FIMsCord, !ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn) :-
|
|
get_next_item_or_marker(!.SourceFileName, FileString, FileStringLen,
|
|
InitLookAhead, ModuleName, ReadIOMResult,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
parse_item_sequence_inner(FileString, FileStringLen, ModuleName,
|
|
1024, NumItemsLeft, ReadIOMResult, MidLookAhead,
|
|
!InclsCord, !AvailsCord, !FIMsCord, !ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn),
|
|
( if NumItemsLeft = 0 then
|
|
parse_item_sequence(FileString, FileStringLen, ModuleName,
|
|
MidLookAhead, FinalLookAhead,
|
|
!InclsCord, !AvailsCord, !FIMsCord, !ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn)
|
|
else
|
|
FinalLookAhead = MidLookAhead
|
|
).
|
|
|
|
:- pred parse_item_sequence_inner(string::in, int::in,
|
|
module_name::in, int::in, int::out,
|
|
read_iom_result::in, maybe_lookahead::out,
|
|
cord(item_include)::in, cord(item_include)::out,
|
|
cord(item_avail)::in, cord(item_avail)::out,
|
|
cord(item_fim)::in, cord(item_fim)::out,
|
|
cord(item)::in, cord(item)::out, file_name::in, file_name::out,
|
|
counter::in, counter::out, read_module_errors::in, read_module_errors::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_item_sequence_inner(FileString, FileStringLen, ModuleName,
|
|
!NumItemsLeft, ReadIOMResult, FinalLookAhead,
|
|
!InclsCord, !AvailsCord, !FIMsCord, !ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors, !LineContext, !LinePosn) :-
|
|
( if !.NumItemsLeft =< 0 then
|
|
FinalLookAhead = lookahead(ReadIOMResult)
|
|
else
|
|
(
|
|
ReadIOMResult = read_iom_eof,
|
|
FinalLookAhead = no_lookahead
|
|
;
|
|
(
|
|
ReadIOMResult = read_iom_parse_term_error(ItemSpec),
|
|
add_nonfatal_error(rme_could_not_read_term, [ItemSpec],
|
|
!Errors)
|
|
;
|
|
ReadIOMResult = read_iom_parse_item_errors(_, _, ItemSpecs),
|
|
add_nonfatal_error(rme_could_not_parse_item, ItemSpecs,
|
|
!Errors)
|
|
),
|
|
parse_next_item_or_marker(!.SourceFileName,
|
|
FileString, FileStringLen, ModuleName, NextReadIOMResult,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
parse_item_sequence_inner(FileString, FileStringLen, ModuleName,
|
|
!NumItemsLeft, NextReadIOMResult, FinalLookAhead,
|
|
!InclsCord, !AvailsCord, !FIMsCord, !ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn)
|
|
;
|
|
ReadIOMResult = read_iom_ok(_IOMVarSet, IOMTerm, IOM),
|
|
!:NumItemsLeft = !.NumItemsLeft - 1,
|
|
(
|
|
( IOM = iom_marker_module_start(_, _, _)
|
|
; IOM = iom_marker_module_end(_, _, _)
|
|
; IOM = iom_marker_section(_, _, _)
|
|
),
|
|
FinalLookAhead = lookahead(ReadIOMResult)
|
|
;
|
|
(
|
|
IOM = iom_marker_src_file(!:SourceFileName)
|
|
;
|
|
IOM = iom_marker_version_numbers(_),
|
|
Pieces = [words("Error:")] ++
|
|
color_as_subject([words("version number records")]) ++
|
|
color_as_incorrect([words("should not appear"),
|
|
words("anywhere except in automaticly"),
|
|
words("generated interface files.")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_read_files,
|
|
get_term_context(IOMTerm), Pieces),
|
|
add_nonfatal_error(rme_nec, [Spec], !Errors)
|
|
;
|
|
IOM = iom_marker_include(Incls),
|
|
Incls = one_or_more(HeadIncl, TailIncls),
|
|
!:InclsCord = !.InclsCord ++
|
|
cord.from_list([HeadIncl | TailIncls])
|
|
;
|
|
IOM = iom_marker_avail(Avails),
|
|
Avails = one_or_more(HeadAvail, TailAvails),
|
|
!:AvailsCord = !.AvailsCord ++
|
|
cord.from_list([HeadAvail | TailAvails])
|
|
;
|
|
IOM = iom_marker_fim(FIM),
|
|
!:FIMsCord = cord.snoc(!.FIMsCord, FIM)
|
|
;
|
|
IOM = iom_item(Item),
|
|
!:ItemsCord = cord.snoc(!.ItemsCord, Item)
|
|
;
|
|
IOM = iom_item_and_error_specs(Item, ItemSpecs),
|
|
!:ItemsCord = cord.snoc(!.ItemsCord, Item),
|
|
add_nonfatal_error(rme_nec, ItemSpecs, !Errors)
|
|
;
|
|
IOM = iom_handled_no_error
|
|
;
|
|
IOM = iom_handled_error(HandledSpecs),
|
|
add_nonfatal_error(rme_nec, HandledSpecs, !Errors)
|
|
),
|
|
parse_next_item_or_marker(!.SourceFileName,
|
|
FileString, FileStringLen, ModuleName, NextReadIOMResult,
|
|
!SeqNumCounter, !LineContext, !LinePosn),
|
|
parse_item_sequence_inner(FileString, FileStringLen, ModuleName,
|
|
!NumItemsLeft, NextReadIOMResult, FinalLookAhead,
|
|
!InclsCord, !AvailsCord, !FIMsCord, !ItemsCord,
|
|
!SourceFileName, !SeqNumCounter, !Errors,
|
|
!LineContext, !LinePosn)
|
|
)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type maybe_lookahead
|
|
---> no_lookahead
|
|
; lookahead(read_iom_result).
|
|
|
|
:- pred get_next_item_or_marker(file_name::in, string::in, int::in,
|
|
maybe_lookahead::in, module_name::in, read_iom_result::out,
|
|
counter::in, counter::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
get_next_item_or_marker(FileName, FileString, FileStringLen, InitLookAhead,
|
|
ModuleName, ReadIOMResult, !SeqNumCounter, !LineContext, !LinePosn) :-
|
|
(
|
|
InitLookAhead = no_lookahead,
|
|
parse_next_item_or_marker(FileName, FileString, FileStringLen,
|
|
ModuleName, ReadIOMResult, !SeqNumCounter,
|
|
!LineContext, !LinePosn)
|
|
;
|
|
InitLookAhead = lookahead(ReadIOMResult)
|
|
).
|
|
|
|
:- pred parse_next_item_or_marker(file_name::in, string::in, int::in,
|
|
module_name::in, read_iom_result::out, counter::in, counter::out,
|
|
line_context::in, line_context::out, line_posn::in, line_posn::out) is det.
|
|
|
|
parse_next_item_or_marker(FileName, FileString, FileStringLen, ModuleName,
|
|
ReadIOMResult, !SeqNumCounter, !LineContext, !LinePosn) :-
|
|
mercury_term_parser.read_term_from_linestr(FileName,
|
|
FileString, FileStringLen, !LineContext, !LinePosn, ReadTermResult),
|
|
read_term_to_iom_result(ModuleName, FileName, ReadTermResult,
|
|
ReadIOMResult, !SeqNumCounter).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type read_iom_result
|
|
---> read_iom_eof
|
|
% We have reached end-of-file.
|
|
; read_iom_parse_term_error(error_spec)
|
|
% The call to mercury_term_parser.read_term_from_linestr
|
|
% has failed, which means that what we found in the file string
|
|
% is not a valid term.
|
|
; read_iom_parse_item_errors(varset, term, list(error_spec))
|
|
% We have successfully read a term from the file string,
|
|
% but could not parse it as an item or marker.
|
|
% The error category is implicitly rme_could_not_parse_item.
|
|
; read_iom_ok(varset, term, item_or_marker).
|
|
% We have successfully read a term from the file string,
|
|
% and parsed it as an item or marker.
|
|
|
|
:- pred read_term_to_iom_result(module_name::in, string::in, read_term::in,
|
|
read_iom_result::out, counter::in, counter::out) is det.
|
|
|
|
read_term_to_iom_result(ModuleName, FileName, ReadTermResult, ReadIOMResult,
|
|
!SeqNumCounter) :-
|
|
% XXX ITEM_LIST Should add a prefix to eof, error, and term
|
|
% in library/term_io.m?
|
|
(
|
|
ReadTermResult = eof,
|
|
ReadIOMResult = read_iom_eof
|
|
;
|
|
ReadTermResult = error(ErrorMsg, LineNumber),
|
|
Context = term_context.context_init(FileName, LineNumber),
|
|
% XXX Do we need to add an "Error:" prefix?
|
|
% Answer: only if we update all the values of ErrorMsg
|
|
% that the lexer and the parser can generate to avoid text
|
|
% that would clash with that. For example, we do not want to stick
|
|
% "Error:" in front of messages of the form "Syntax error: ...".
|
|
%
|
|
% XXX It would be nice to add color to ErrorMsg, but that would
|
|
% require making the representation of lexer and parser errors
|
|
% more complex than a simple string.
|
|
Pieces = [words(ErrorMsg), suffix("."), nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
|
|
ReadIOMResult = read_iom_parse_term_error(Spec)
|
|
;
|
|
ReadTermResult = term(VarSet, Term),
|
|
counter.allocate(SeqNum, !SeqNumCounter),
|
|
parse_item_or_marker(ModuleName, VarSet, Term, item_seq_num(SeqNum),
|
|
MaybeItemOrMarker),
|
|
(
|
|
MaybeItemOrMarker = ok1(ItemOrMarker),
|
|
ReadIOMResult = read_iom_ok(VarSet, Term, ItemOrMarker)
|
|
;
|
|
MaybeItemOrMarker = error1(Specs),
|
|
ReadIOMResult = read_iom_parse_item_errors(VarSet, Term, Specs)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func report_missing_module_start(prog_context) = error_spec.
|
|
|
|
report_missing_module_start(FirstContext) = Spec :-
|
|
Pieces = [invis_order_default_start(0, ""),
|
|
words("Error:")] ++
|
|
color_as_incorrect([words("module must start with a"),
|
|
decl("module"), words("declaration.")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, FirstContext, Pieces).
|
|
|
|
:- func report_wrong_module_start(prog_context, module_name, module_name)
|
|
= error_spec.
|
|
|
|
report_wrong_module_start(FirstContext, Expected, Actual) = Spec :-
|
|
Pieces = [words("Error: module starts with a"), decl("module"),
|
|
words("declaration for the wrong module"), nl,
|
|
words("Expected module")] ++
|
|
color_as_correct([qual_sym_name(Expected), suffix(",")]) ++
|
|
[words("got moduile")] ++
|
|
color_as_incorrect([qual_sym_name(Actual), suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt, FirstContext, Pieces).
|
|
|
|
% The predicate that reads in source file handles all items and markers
|
|
% it reads in, and stops only at an end_module declaration that matches
|
|
% the name of the top level module in the file. If FileKind is
|
|
% fk_src, we look for any items after this end_module marker.
|
|
%
|
|
% The predicates that read in interface and optimization files
|
|
% handle only the items they expect in those files, since their contents
|
|
% should be automatically generated by mmc itself, stopping (and returning
|
|
% as lookahead) at items that don't fit the expected structure of those
|
|
% files. If FileKind is fk_int or fk_opt, we look for any such unexpected
|
|
% items.
|
|
%
|
|
:- pred check_for_unexpected_item_at_end(file_name::in, string::in, int::in,
|
|
module_name::in, file_kind::in,
|
|
maybe_lookahead::in, counter::in,
|
|
read_module_errors::in, read_module_errors::out,
|
|
line_context::in, line_posn::in) is det.
|
|
|
|
check_for_unexpected_item_at_end(SourceFileName, FileString, FileStringLen,
|
|
ModuleName, FileKind, FinalLookAhead, SeqNumCounter0,
|
|
!Errors, !.LineContext, !.LinePosn) :-
|
|
get_next_item_or_marker(SourceFileName, FileString, FileStringLen,
|
|
FinalLookAhead, ModuleName, IOMResult,
|
|
SeqNumCounter0, _SeqNumCounter, !.LineContext, _, !.LinePosn, _),
|
|
(
|
|
IOMResult = read_iom_eof
|
|
;
|
|
IOMResult = read_iom_parse_term_error(ItemSpec),
|
|
add_nonfatal_error(rme_could_not_read_term, [ItemSpec], !Errors)
|
|
;
|
|
IOMResult = read_iom_parse_item_errors(_VarSet, Term, ItemSpecs),
|
|
add_nonfatal_error(rme_could_not_parse_item, ItemSpecs, !Errors),
|
|
report_unexpected_term_at_end(FileKind, Term, !Errors)
|
|
;
|
|
IOMResult = read_iom_ok(_IOMVarSet, IOMTerm, _IOM),
|
|
report_unexpected_term_at_end(FileKind, IOMTerm, !Errors)
|
|
).
|
|
|
|
:- pred report_unexpected_term_at_end(file_kind::in, term::in,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
report_unexpected_term_at_end(FileKind, Term, !Errors) :-
|
|
Context = get_term_context(Term),
|
|
(
|
|
FileKind = fk_src,
|
|
Error = rme_end_module_not_at_end_of_src,
|
|
Pieces = [words("Error: there should be no code")] ++
|
|
color_as_incorrect([words("after the"),
|
|
decl("end_module"), words("declaration.")]) ++
|
|
[nl]
|
|
;
|
|
FileKind = fk_int(_IntFileKind),
|
|
Error = rme_unexpected_term_in_int_or_opt,
|
|
Pieces = [words("Error: unexpected item in interface file"), nl]
|
|
;
|
|
FileKind = fk_opt(_OptFileKind),
|
|
Error = rme_unexpected_term_in_int_or_opt,
|
|
Pieces = [words("Error: unexpected item in optimization file"), nl]
|
|
),
|
|
Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
|
|
add_nonfatal_error(Error, [Spec], !Errors).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.parse_module.
|
|
%---------------------------------------------------------------------------%
|