mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
The objective of this step is two-fold:
- to fix --inhibit-warnings, making it shut up all warning
and informational messages; and
- to ensure that it *stays* fixed, even when after new diagnostics
are added.
As part of this fix, this diff adds a whole bunch of new warning
options, in order to control the warnings that previously were
not controlled by any option. (There was no need for new
informational options.)
As it happens, we have long used severity_informational for messages
that did not report any information about the code being compiled,
but to report actions that the compiler was taking. Create a new
option category, oc_report, for the new options that now control
those diagnostics.
---------------------
compiler/error_spec.m:
Change severity_warning and severity_informational to take an option
as as argument. The semantics is that the diagnostic in which
the severity occurs is conditional on that option, meaning that
it is printed only if that option is set to "yes".
Delete the severity_conditional function symbol from the severity
type, since the mechanism just above handles its only use case.
Define subtypes to represent error_specs in a standard form.
compiler/error_sort.m:
Provide operations to convert error specs into their standard form.
Make the sorting operation itself operate on the standard form.
compiler/write_error_spec.m:
Convert error_specs to standard form before writing them out,
in order to avoid duplicating the code for their standardization.
Change the code that writes out error_specs to operate on the
standard form. Implement the test implicit in the warning and
and informational severities in this code.
compiler/error_util.m:
compiler/compiler_util.m:
Delete operations that do not make sense with the new severity type.
---------------------
compiler/options.m:
Add new options to control all the previously-uncontrolled
warning and informational messages.
NEWS.md:
Announce the *public* new options.
compiler/option_categories.m:
compiler/print_help.m:
Add the new option category, and fake-include it in the help text
and the user guide. (The inclusion is fake because none of the
options in the new category are user visible, meaning the section
containing them is not visible either.)
---------------------
compiler/det_infer_goal.m:
Start a severity warning diagnostic with "Warning:"
instead of "Error:".
compiler/mark_trace_goals.m:
Fix an incorrect error message.
compiler/purity.m:
Replace a correct/incorrect color pair with two inconsistent colors,
because there is a reasonable probability of each one being right.
---------------------
compiler/accumulator.m:
compiler/add_clause.m:
compiler/add_mode.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pred.m:
compiler/add_type.m:
compiler/check_module_interface.m:
compiler/check_type_inst_mode_defns.m:
compiler/check_typeclass.m:
compiler/color_schemes.m:
compiler/common.m:
compiler/convert_import_use.m:
compiler/convert_parse_tree.m:
compiler/dead_proc_elim.m:
compiler/det_check_proc.m:
compiler/det_check_switch.m:
compiler/det_infer_goal.m:
compiler/du_type_layout.m:
compiler/format_call_errors.m:
compiler/grab_modules.m:
compiler/hlds_call_tree.m:
compiler/inst_check.m:
compiler/introduce_parallelism.m:
compiler/make_hlds_error.m:
compiler/make_hlds_warn.m:
compiler/mark_tail_calls.m:
compiler/mark_trace_goals.m:
compiler/mercury_compile_main.m:
compiler/mercury_compile_make_hlds.m:
compiler/mode_errors.m:
compiler/modes.m:
compiler/module_qual.qual_errors.m:
compiler/opt_deps_spec.m:
compiler/options_file.m:
compiler/parse_goal.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/pre_typecheck.m:
compiler/purity.m:
compiler/read_modules.m:
compiler/recompilation.check.m:
compiler/simplify_goal.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/split_parse_tree_src.m:
compiler/state_var.m:
compiler/stratify.m:
compiler/style_checks.m:
compiler/superhomogeneous.m:
compiler/table_gen.m:
compiler/term_constr_errors.m:
compiler/term_errors.m:
compiler/termination.m:
compiler/typecheck_clauses.m:
compiler/typecheck_error_overload.m:
compiler/typecheck_error_undef.m:
compiler/typecheck_errors.m:
compiler/typecheck_msgs.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/warn_unread_modules.m:
compiler/write_module_interface_files.m:
Conform to the changes above, mostly by either
- adding an option to all warning and informational messages,
sometimes using existing warning options and sometimes new ones,
or
- turning already explicitly-conditional-on-an-option messages
into implicitly-conditional-on-that-option messages.
---------------------
tests/invalid/one_member.m:
Conform to the change in det_infer_goal.m.
tests/invalid/require_tailrec_1.err_exp:
tests/invalid/require_tailrec_2.err_exp:
Actually obey the options for these modules in Mercury.options.
tests/invalid_purity/purity.err_exp:
tests/warnings/purity_warnings.err_exp:
Conform to the change in purity.m.
tests/warnings/moved_trace_goal.err_exp:
Conform to the change in mark_trace_goals.m.
tests/warnings/help_text.err_exp:
Expect the documentation of all the new options.
691 lines
31 KiB
Mathematica
691 lines
31 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2014-2025 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: write_module_interface_files.m.
|
|
% Main author: fjh (when this code was in modules.m).
|
|
%
|
|
% This module writes the automatically generated .int3, .int2 and .int files
|
|
% (and if needed, the .int0 file) for each Mercury source module.
|
|
%
|
|
% The interface file system works as follows:
|
|
%
|
|
% 1. a .int3 file is written, which contains all the types, typeclasses, insts
|
|
% and modes defined in the interface. Equivalence types, solver types, insts
|
|
% and modes are written in full, others are written in abstract form. These
|
|
% are module qualified as far as possible given the information present in the
|
|
% current module.
|
|
%
|
|
% 2. The .int and .int2 files are created, using the .int3 files
|
|
% of imported modules to fully module qualify all items.
|
|
% The .int2 file is mostly just a fully qualified version of the .int3 file,
|
|
% however it also includes some extra information, such as functors for
|
|
% discriminated union types, which may be needed for mode analysis.
|
|
%
|
|
% 3. The .int0 file is similar to the .int file except that it also
|
|
% includes declarations (but not clauses) from the implementation section.
|
|
% It is generated only for modules that have submodules.
|
|
%
|
|
% NOTE The above is only a summary, and may be out of date. An attempt
|
|
% at an up-to-date and much more detailed description can be found in
|
|
% notes/interface_files.html.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% The datestamp on the .date3 file gives the last time
|
|
% the .int3 file was checked for consistency.
|
|
%
|
|
% The datestamp on the .date file gives the last time
|
|
% the .int and .int2 files were checked for consistency.
|
|
%
|
|
% The datestamp on the .date0 file gives the last time
|
|
% the .int0 file was checked for consistency.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.write_module_interface_files.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.maybe_util.
|
|
:- import_module parse_tree.comp_unit_interface.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.module_baggage.
|
|
:- import_module parse_tree.read_modules.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% generate_and_write_interface_file_int3(ProgressStream, Globals,
|
|
% AddToHptm, BurdenedModule, Succeeded, Specs, !HaveParseTreeMaps, !IO):
|
|
%
|
|
% Output the unqualified short interface file to <module>.int3.
|
|
%
|
|
% Specs will contain any error and/or warning messages resulting
|
|
% - from the process of constructing the contents of the .int3 file,
|
|
% - from the process of writing it out, and
|
|
% - updating the associated timestamp file.
|
|
%
|
|
% We bind Succeeded to "succeeded" only if all three of those processes
|
|
% succeeded without errors. (Specs may contain warnings even then.)
|
|
%
|
|
% We add the contents of the .int3 file to !HaveParseTreeMaps if we could
|
|
% construct it without any errors, *and* AddToHptm says we should.
|
|
%
|
|
:- pred generate_and_write_interface_file_int3(io.text_output_stream::in,
|
|
globals::in, maybe_add_to_hptm::in, burdened_module::in,
|
|
maybe_succeeded::out, list(error_spec)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% generate_and_write_interface_file_int0(ProgressStream, Globals,
|
|
% AddToHptm, BurdenedModule, Succeeded, Specs, !HaveParseTreeMaps, !IO):
|
|
%
|
|
% Given a burdened_module, output the private (`.int0') interface file
|
|
% for the module. (The private interface contains all the declarations
|
|
% in the module, including those in the `implementation' section;
|
|
% it is used when compiling submodules.)
|
|
%
|
|
:- pred generate_and_write_interface_file_int0(io.text_output_stream::in,
|
|
globals::in, maybe_add_to_hptm::in, burdened_module::in,
|
|
maybe_succeeded::out, list(error_spec)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% generate_and_write_interface_file_int1_int2(ProgressStream, Globals,
|
|
% AddToHptm, BurdenedModule, Succeeded, Specs, !HaveParseTreeMaps, !IO):
|
|
%
|
|
% Given a burdened_module, output the long (`.int') and short (`.int2')
|
|
% interface files for the module.
|
|
%
|
|
:- pred generate_and_write_interface_file_int1_int2(io.text_output_stream::in,
|
|
globals::in, maybe_add_to_hptm::in, burdened_module::in,
|
|
maybe_succeeded::out, list(error_spec)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.options.
|
|
:- import_module libs.timestamp.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.module_cmds.
|
|
:- import_module parse_tree.parse_error.
|
|
:- import_module parse_tree.parse_module.
|
|
:- import_module parse_tree.parse_tree_out.
|
|
:- import_module parse_tree.parse_tree_out_info.
|
|
:- import_module parse_tree.prog_item.
|
|
:- import_module parse_tree.prog_parse_tree.
|
|
:- import_module recompilation.
|
|
:- import_module recompilation.version.
|
|
|
|
:- import_module bool.
|
|
:- import_module dir.
|
|
:- import_module getopt.
|
|
:- import_module io.file.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out .int3 files.
|
|
%
|
|
|
|
generate_and_write_interface_file_int3(ProgressStream, Globals, AddToHptm,
|
|
BurdenedModule, Succeeded, Specs, !HaveParseTreeMaps, !IO) :-
|
|
generate_parse_tree_int3(Globals, AddToHptm,
|
|
BurdenedModule, GenerateResult, !HaveParseTreeMaps, !IO),
|
|
write_parse_tree_int3(ProgressStream, Globals, GenerateResult,
|
|
Specs, Succeeded, !IO).
|
|
|
|
:- pred write_parse_tree_int3(io.text_output_stream::in, globals::in,
|
|
generate_int3_result::in, list(error_spec)::out, maybe_succeeded::out,
|
|
io::di, io::uo) is det.
|
|
|
|
write_parse_tree_int3(ProgressStream, Globals, GenerateResult,
|
|
Specs, Succeeded, !IO) :-
|
|
(
|
|
GenerateResult = gpti3_ok(ParseTreeInt3, FileName, Specs),
|
|
ModuleName = ParseTreeInt3 ^ pti3_module_name,
|
|
actually_write_interface_file3(ProgressStream, Globals, ParseTreeInt3,
|
|
FileName, OutputSucceeded, !IO),
|
|
touch_module_ext_datestamp(Globals, ProgressStream, ModuleName,
|
|
ext_cur_ngs(ext_cur_ngs_int_date_int3), TouchSucceeded, !IO),
|
|
Succeeded = OutputSucceeded `and` TouchSucceeded
|
|
;
|
|
GenerateResult = gpti3_error(ModuleName, PrefixPieces, GenerateSpecs),
|
|
ExtInt3 = ext_cur_ngs(ext_cur_ngs_int_int3),
|
|
ExtDate3 = ext_cur_ngs(ext_cur_ngs_int_date_int3),
|
|
report_file_not_written(Globals, PrefixPieces, ModuleName,
|
|
ExtInt3, no, ExtDate3, GenerateSpecs, Specs, !IO),
|
|
Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out .int0 files.
|
|
%
|
|
|
|
generate_and_write_interface_file_int0(ProgressStream, Globals, AddToHptm,
|
|
BurdenedModule, Succeeded, Specs, !HaveParseTreeMaps, !IO) :-
|
|
generate_parse_tree_int0(ProgressStream, Globals, AddToHptm,
|
|
BurdenedModule, GenerateResult, !HaveParseTreeMaps, !IO),
|
|
write_parse_tree_int0(ProgressStream, Globals, GenerateResult,
|
|
Specs, Succeeded, !IO).
|
|
|
|
:- pred write_parse_tree_int0(io.text_output_stream::in, globals::in,
|
|
generate_int0_result::in, list(error_spec)::out, maybe_succeeded::out,
|
|
io::di, io::uo) is det.
|
|
|
|
write_parse_tree_int0(ProgressStream, Globals, GenerateResult,
|
|
Specs, Succeeded, !IO) :-
|
|
(
|
|
GenerateResult = gpti0_ok(ParseTreeInt0, MaybeTimestamp,
|
|
FileName, Specs),
|
|
ModuleName = ParseTreeInt0 ^ pti0_module_name,
|
|
actually_write_interface_file0(ProgressStream, Globals, ParseTreeInt0,
|
|
FileName, MaybeTimestamp, OutputSucceeded, !IO),
|
|
touch_module_ext_datestamp(Globals, ProgressStream, ModuleName,
|
|
ext_cur_ngs(ext_cur_ngs_int_date_int0), TouchSucceeded, !IO),
|
|
Succeeded = OutputSucceeded `and` TouchSucceeded
|
|
;
|
|
GenerateResult = gpti0_error(ModuleName, PrefixPieces, GenerateSpecs),
|
|
ExtInt0 = ext_cur_ngs(ext_cur_ngs_int_int0),
|
|
ExtDate0 = ext_cur_ngs(ext_cur_ngs_int_date_int0),
|
|
report_file_not_written(Globals, PrefixPieces, ModuleName,
|
|
ExtInt0, no, ExtDate0, GenerateSpecs, Specs, !IO),
|
|
Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out .int and .int2 files.
|
|
%
|
|
|
|
generate_and_write_interface_file_int1_int2(ProgressStream, Globals, AddToHptm,
|
|
BurdenedModule, Succeeded, Specs, !HaveParseTreeMaps, !IO) :-
|
|
generate_parse_tree_int12(ProgressStream, Globals, AddToHptm,
|
|
BurdenedModule, GenerateResult, !HaveParseTreeMaps, !IO),
|
|
write_parse_tree_int12(ProgressStream, Globals, GenerateResult,
|
|
Specs, Succeeded, !IO).
|
|
|
|
:- pred write_parse_tree_int12(io.text_output_stream::in, globals::in,
|
|
generate_int12_result::in, list(error_spec)::out, maybe_succeeded::out,
|
|
io::di, io::uo) is det.
|
|
|
|
write_parse_tree_int12(ProgressStream, Globals, GenerateResult,
|
|
Specs, Succeeded, !IO) :-
|
|
(
|
|
GenerateResult = gpti12_ok(ParseTreeInt1, ParseTreeInt2,
|
|
MaybeSourceFileTimestamp, FileName1, FileName2, Specs),
|
|
ModuleName = ParseTreeInt1 ^ pti1_module_name,
|
|
actually_write_interface_file1(ProgressStream, Globals,
|
|
ParseTreeInt1, FileName1, MaybeSourceFileTimestamp,
|
|
OutputSucceeded1, !IO),
|
|
actually_write_interface_file2(ProgressStream, Globals,
|
|
ParseTreeInt2, FileName2, MaybeSourceFileTimestamp,
|
|
OutputSucceeded2, !IO),
|
|
touch_module_ext_datestamp(Globals, ProgressStream, ModuleName,
|
|
ext_cur_ngs(ext_cur_ngs_int_date_int12), TouchSucceeded, !IO),
|
|
Succeeded = OutputSucceeded1 `and` OutputSucceeded2 `and`
|
|
TouchSucceeded
|
|
;
|
|
GenerateResult = gpti12_error(ModuleName, PrefixPieces, GenerateSpecs),
|
|
ExtInt1 = ext_cur_ngs(ext_cur_ngs_int_int1),
|
|
ExtInt2 = ext_cur_ngs(ext_cur_ngs_int_int2),
|
|
ExtDate12 = ext_cur_ngs(ext_cur_ngs_int_date_int12),
|
|
report_file_not_written(Globals, PrefixPieces, ModuleName,
|
|
ExtInt1, yes(ExtInt2), ExtDate12, GenerateSpecs, Specs, !IO),
|
|
Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% The following three predicates operate on parse_tree_int0s, parse_tree_int1s
|
|
% and parse_tree_int2s. They do exactly the same thing with all three,
|
|
% so their codes are identical, except for the fact that
|
|
%
|
|
% - they operate on values of different types, and
|
|
% - they call predicates that perform the same operations on those different
|
|
% types.
|
|
%
|
|
% The fourth operates on parse_tree_int3s, and is also *almost* identical
|
|
% in the above sense, except that it has one additional difference, which is
|
|
% that it does not deal with version numbers for smart recompilation, since
|
|
% .int3 files do not contain version numbers.
|
|
%
|
|
% The difference in types is why this common code cannot be factored out.
|
|
%
|
|
|
|
:- pred actually_write_interface_file0(io.text_output_stream::in, globals::in,
|
|
parse_tree_int0::in, file_name::in, maybe(timestamp)::in,
|
|
maybe_succeeded::out, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file0(ProgressStream, Globals, GenParseTreeInt0,
|
|
FileName, MaybeSourceFileTimestamp, Succeeded, !IO) :-
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
Info = init_merc_out_info(NoLineNumGlobals, unqualified_item_names,
|
|
output_mercury),
|
|
should_generate_item_version_numbers(NoLineNumGlobals,
|
|
WantVersionNumbers, !IO),
|
|
globals.lookup_bool_option(NoLineNumGlobals, verbose, Verbose),
|
|
string.format("%% Reading old version of `%s'... ",
|
|
[s(FileName)], ReadOldStartMsg),
|
|
maybe_write_string(ProgressStream, Verbose, ReadOldStartMsg, !IO),
|
|
io.read_named_file_as_string(FileName, ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = ok(OldFileStr),
|
|
maybe_parse_old_int0_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, yes(OldFileStr),
|
|
MaybeSourceFileTimestamp, GenParseTreeInt0, NewParseTreeInt0),
|
|
maybe_write_string(ProgressStream, Verbose, "done.\n", !IO),
|
|
NewParseTreeStr = parse_tree_int0_to_string(Info, NewParseTreeInt0),
|
|
( if OldFileStr = NewParseTreeStr then
|
|
string.format("%% `%s' has not changed.\n",
|
|
[s(FileName)], NoChangeMsg),
|
|
maybe_write_string(ProgressStream, Verbose, NoChangeMsg, !IO),
|
|
Succeeded = succeeded
|
|
else
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
)
|
|
;
|
|
ReadFileResult = error(_),
|
|
maybe_write_string(ProgressStream, Verbose, "unsuccessful.\n", !IO),
|
|
MaybeOldFileStr = maybe.no,
|
|
maybe_parse_old_int0_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, MaybeOldFileStr,
|
|
MaybeSourceFileTimestamp, GenParseTreeInt0, NewParseTreeInt0),
|
|
NewParseTreeStr = parse_tree_int0_to_string(Info, NewParseTreeInt0),
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
).
|
|
|
|
:- pred actually_write_interface_file1(io.text_output_stream::in, globals::in,
|
|
parse_tree_int1::in, file_name::in, maybe(timestamp)::in,
|
|
maybe_succeeded::out, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file1(ProgressStream, Globals, GenParseTreeInt1,
|
|
FileName, MaybeSourceFileTimestamp, Succeeded, !IO) :-
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
Info = init_merc_out_info(NoLineNumGlobals, unqualified_item_names,
|
|
output_mercury),
|
|
should_generate_item_version_numbers(NoLineNumGlobals,
|
|
WantVersionNumbers, !IO),
|
|
globals.lookup_bool_option(NoLineNumGlobals, verbose, Verbose),
|
|
string.format("%% Reading old version of `%s'... ",
|
|
[s(FileName)], ReadOldStartMsg),
|
|
maybe_write_string(ProgressStream, Verbose, ReadOldStartMsg, !IO),
|
|
io.read_named_file_as_string(FileName, ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = ok(OldFileStr),
|
|
maybe_parse_old_int1_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, yes(OldFileStr),
|
|
MaybeSourceFileTimestamp, GenParseTreeInt1, NewParseTreeInt1),
|
|
maybe_write_string(ProgressStream, Verbose, "done.\n", !IO),
|
|
NewParseTreeStr = parse_tree_int1_to_string(Info, NewParseTreeInt1),
|
|
( if OldFileStr = NewParseTreeStr then
|
|
string.format("%% `%s' has not changed.\n",
|
|
[s(FileName)], NoChangeMsg),
|
|
maybe_write_string(ProgressStream, Verbose, NoChangeMsg, !IO),
|
|
Succeeded = succeeded
|
|
else
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
)
|
|
;
|
|
ReadFileResult = error(_),
|
|
maybe_write_string(ProgressStream, Verbose, "unsuccessful.\n", !IO),
|
|
MaybeOldFileStr = maybe.no,
|
|
maybe_parse_old_int1_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, MaybeOldFileStr,
|
|
MaybeSourceFileTimestamp, GenParseTreeInt1, NewParseTreeInt1),
|
|
NewParseTreeStr = parse_tree_int1_to_string(Info, NewParseTreeInt1),
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
).
|
|
|
|
:- pred actually_write_interface_file2(io.text_output_stream::in, globals::in,
|
|
parse_tree_int2::in, file_name::in, maybe(timestamp)::in,
|
|
maybe_succeeded::out, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file2(ProgressStream, Globals, GenParseTreeInt2,
|
|
FileName, MaybeSourceFileTimestamp, Succeeded, !IO) :-
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
Info = init_merc_out_info(NoLineNumGlobals, unqualified_item_names,
|
|
output_mercury),
|
|
should_generate_item_version_numbers(NoLineNumGlobals,
|
|
WantVersionNumbers, !IO),
|
|
globals.lookup_bool_option(NoLineNumGlobals, verbose, Verbose),
|
|
string.format("%% Reading old version of `%s'... ",
|
|
[s(FileName)], ReadOldStartMsg),
|
|
maybe_write_string(ProgressStream, Verbose, ReadOldStartMsg, !IO),
|
|
io.read_named_file_as_string(FileName, ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = ok(OldFileStr),
|
|
maybe_parse_old_int2_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, yes(OldFileStr),
|
|
MaybeSourceFileTimestamp, GenParseTreeInt2, NewParseTreeInt2),
|
|
maybe_write_string(ProgressStream, Verbose, "done.\n", !IO),
|
|
NewParseTreeStr = parse_tree_int2_to_string(Info, NewParseTreeInt2),
|
|
( if OldFileStr = NewParseTreeStr then
|
|
string.format("%% `%s' has not changed.\n",
|
|
[s(FileName)], NoChangeMsg),
|
|
maybe_write_string(ProgressStream, Verbose, NoChangeMsg, !IO),
|
|
Succeeded = succeeded
|
|
else
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
)
|
|
;
|
|
ReadFileResult = error(_),
|
|
maybe_write_string(ProgressStream, Verbose, "unsuccessful.\n", !IO),
|
|
MaybeOldFileStr = maybe.no,
|
|
maybe_parse_old_int2_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, MaybeOldFileStr,
|
|
MaybeSourceFileTimestamp, GenParseTreeInt2, NewParseTreeInt2),
|
|
NewParseTreeStr = parse_tree_int2_to_string(Info, NewParseTreeInt2),
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
).
|
|
|
|
:- pred actually_write_interface_file3(io.text_output_stream::in, globals::in,
|
|
parse_tree_int3::in, file_name::in, maybe_succeeded::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file3(ProgressStream, Globals, NewParseTreeInt3,
|
|
FileName, Succeeded, !IO) :-
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
Info = init_merc_out_info(NoLineNumGlobals, unqualified_item_names,
|
|
output_mercury),
|
|
globals.lookup_bool_option(NoLineNumGlobals, verbose, Verbose),
|
|
string.format("%% Reading old version of `%s'... ",
|
|
[s(FileName)], ReadOldStartMsg),
|
|
maybe_write_string(ProgressStream, Verbose, ReadOldStartMsg, !IO),
|
|
io.read_named_file_as_string(FileName, ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = ok(OldFileStr),
|
|
maybe_write_string(ProgressStream, Verbose, "done.\n", !IO),
|
|
NewParseTreeStr = parse_tree_int3_to_string(Info, NewParseTreeInt3),
|
|
( if OldFileStr = NewParseTreeStr then
|
|
string.format("%% `%s' has not changed.\n",
|
|
[s(FileName)], NoChangeMsg),
|
|
maybe_write_string(ProgressStream, Verbose, NoChangeMsg, !IO),
|
|
Succeeded = succeeded
|
|
else
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
)
|
|
;
|
|
ReadFileResult = error(_),
|
|
maybe_write_string(ProgressStream, Verbose, "unsuccessful.\n", !IO),
|
|
NewParseTreeStr = parse_tree_int3_to_string(Info, NewParseTreeInt3),
|
|
% This prints a progress message if --verbose is enabled.
|
|
output_parse_tree_string(ProgressStream, NoLineNumGlobals,
|
|
FileName, NewParseTreeStr, Succeeded, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred disable_all_line_numbers(globals::in, globals::out) is det.
|
|
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals) :-
|
|
globals.set_option(line_numbers, bool(no),
|
|
Globals, NoLineNumGlobals0),
|
|
globals.set_option(line_numbers_around_foreign_code, bool(no),
|
|
NoLineNumGlobals0, NoLineNumGlobals).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% The following three predicates operate on parse_tree_int0s, parse_tree_int1s
|
|
% and parse_tree_int2s. They do exactly the same thing with all three,
|
|
% so their codes are identical, except for the fact that
|
|
%
|
|
% - they operate on values of different types, and
|
|
% - they call predicates that perform the same operations on those different
|
|
% types.
|
|
%
|
|
% The difference in types is why this common code cannot be factored out.
|
|
%
|
|
|
|
:- pred maybe_parse_old_int0_and_compare_for_smart_recomp(globals::in,
|
|
maybe_generate_version_numbers::in, file_name::in, maybe(string)::in,
|
|
maybe(timestamp)::in, parse_tree_int0::in, parse_tree_int0::out) is det.
|
|
|
|
maybe_parse_old_int0_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, MaybeOldFileStr,
|
|
MaybeSourceFileTimestamp, GenParseTreeInt0, NewParseTreeInt0) :-
|
|
(
|
|
WantVersionNumbers = generate_version_numbers,
|
|
ModuleName = GenParseTreeInt0 ^ pti0_module_name,
|
|
(
|
|
MaybeOldFileStr = no,
|
|
MaybeOldParseTreeInt0 = maybe.no
|
|
;
|
|
MaybeOldFileStr = yes(OldFileStr),
|
|
% Parse the previous version of the file.
|
|
string.count_code_units(OldFileStr, OldFileStrLen),
|
|
parse_int0_file(NoLineNumGlobals, FileName,
|
|
OldFileStr, OldFileStrLen, ModuleName, [],
|
|
MaybeOldParseTreeInt0Prime, OldModuleErrors),
|
|
( if there_are_no_errors(OldModuleErrors) then
|
|
MaybeOldParseTreeInt0 = MaybeOldParseTreeInt0Prime
|
|
else
|
|
MaybeOldParseTreeInt0 = no
|
|
)
|
|
),
|
|
% If we couldn't read in, or can't parse in the old .int file,
|
|
% we will set all the timestamps to the modification time
|
|
% of the source file. Insist on our caller giving us that time.
|
|
insist_on_timestamp(MaybeSourceFileTimestamp, SourceFileTimestamp),
|
|
recompilation.version.compute_version_numbers_int0(
|
|
MaybeOldParseTreeInt0, SourceFileTimestamp, GenParseTreeInt0,
|
|
VersionNumbers),
|
|
MaybeVersionNumbers = version_numbers(VersionNumbers)
|
|
;
|
|
WantVersionNumbers = do_not_generate_version_numbers,
|
|
MaybeVersionNumbers = no_version_numbers
|
|
),
|
|
NewParseTreeInt0 = GenParseTreeInt0 ^ pti0_maybe_version_numbers
|
|
:= MaybeVersionNumbers.
|
|
|
|
:- pred maybe_parse_old_int1_and_compare_for_smart_recomp(globals::in,
|
|
maybe_generate_version_numbers::in, file_name::in, maybe(string)::in,
|
|
maybe(timestamp)::in, parse_tree_int1::in, parse_tree_int1::out) is det.
|
|
|
|
maybe_parse_old_int1_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, MaybeOldFileStr,
|
|
MaybeSourceFileTimestamp, GenParseTreeInt1, NewParseTreeInt1) :-
|
|
(
|
|
WantVersionNumbers = generate_version_numbers,
|
|
ModuleName = GenParseTreeInt1 ^ pti1_module_name,
|
|
(
|
|
MaybeOldFileStr = no,
|
|
MaybeOldParseTreeInt1 = maybe.no
|
|
;
|
|
MaybeOldFileStr = yes(OldFileStr),
|
|
% Parse the previous version of the file.
|
|
string.count_code_units(OldFileStr, OldFileStrLen),
|
|
parse_int1_file(NoLineNumGlobals, FileName,
|
|
OldFileStr, OldFileStrLen, ModuleName, [],
|
|
MaybeOldParseTreeInt1Prime, OldModuleErrors),
|
|
( if there_are_no_errors(OldModuleErrors) then
|
|
MaybeOldParseTreeInt1 = MaybeOldParseTreeInt1Prime
|
|
else
|
|
MaybeOldParseTreeInt1 = no
|
|
)
|
|
),
|
|
% If we couldn't read in, or can't parse in the old .int file,
|
|
% we will set all the timestamps to the modification time
|
|
% of the source file. Insist on our caller giving us that time.
|
|
insist_on_timestamp(MaybeSourceFileTimestamp, SourceFileTimestamp),
|
|
recompilation.version.compute_version_numbers_int1(
|
|
MaybeOldParseTreeInt1, SourceFileTimestamp, GenParseTreeInt1,
|
|
VersionNumbers),
|
|
MaybeVersionNumbers = version_numbers(VersionNumbers)
|
|
;
|
|
WantVersionNumbers = do_not_generate_version_numbers,
|
|
MaybeVersionNumbers = no_version_numbers
|
|
),
|
|
NewParseTreeInt1 = GenParseTreeInt1 ^ pti1_maybe_version_numbers
|
|
:= MaybeVersionNumbers.
|
|
|
|
:- pred maybe_parse_old_int2_and_compare_for_smart_recomp(globals::in,
|
|
maybe_generate_version_numbers::in, file_name::in, maybe(string)::in,
|
|
maybe(timestamp)::in, parse_tree_int2::in, parse_tree_int2::out) is det.
|
|
|
|
maybe_parse_old_int2_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
WantVersionNumbers, FileName, MaybeOldFileStr,
|
|
MaybeSourceFileTimestamp, GenParseTreeInt2, NewParseTreeInt2) :-
|
|
(
|
|
WantVersionNumbers = generate_version_numbers,
|
|
ModuleName = GenParseTreeInt2 ^ pti2_module_name,
|
|
(
|
|
MaybeOldFileStr = no,
|
|
MaybeOldParseTreeInt2 = maybe.no
|
|
;
|
|
MaybeOldFileStr = yes(OldFileStr),
|
|
% Parse the previous version of the file.
|
|
string.count_code_units(OldFileStr, OldFileStrLen),
|
|
parse_int2_file(NoLineNumGlobals, FileName,
|
|
OldFileStr, OldFileStrLen, ModuleName, [],
|
|
MaybeOldParseTreeInt2Prime, OldModuleErrors),
|
|
( if there_are_no_errors(OldModuleErrors) then
|
|
MaybeOldParseTreeInt2 = MaybeOldParseTreeInt2Prime
|
|
else
|
|
MaybeOldParseTreeInt2 = no
|
|
)
|
|
),
|
|
% If we couldn't read in, or can't parse in the old .int2 file,
|
|
% we will set all the timestamps to the modification time
|
|
% of the source file. Insist on our caller giving us that time.
|
|
insist_on_timestamp(MaybeSourceFileTimestamp, SourceFileTimestamp),
|
|
recompilation.version.compute_version_numbers_int2(
|
|
MaybeOldParseTreeInt2, SourceFileTimestamp, GenParseTreeInt2,
|
|
VersionNumbers),
|
|
MaybeVersionNumbers = version_numbers(VersionNumbers)
|
|
;
|
|
WantVersionNumbers = do_not_generate_version_numbers,
|
|
MaybeVersionNumbers = no_version_numbers
|
|
),
|
|
NewParseTreeInt2 = GenParseTreeInt2 ^ pti2_maybe_version_numbers
|
|
:= MaybeVersionNumbers.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type maybe_generate_version_numbers
|
|
---> do_not_generate_version_numbers
|
|
; generate_version_numbers.
|
|
|
|
:- pred should_generate_item_version_numbers(globals::in,
|
|
maybe_generate_version_numbers::out, io::di, io::uo) is det.
|
|
|
|
should_generate_item_version_numbers(Globals, ShouldGenVersionNumbers, !IO) :-
|
|
globals.lookup_bool_option(Globals, generate_item_version_numbers,
|
|
GenerateVersionNumbers),
|
|
io_get_disable_generate_item_version_numbers(DisableVersionNumbers, !IO),
|
|
( if
|
|
GenerateVersionNumbers = yes,
|
|
DisableVersionNumbers = do_not_disable_item_version_numbers
|
|
then
|
|
ShouldGenVersionNumbers = generate_version_numbers
|
|
else
|
|
ShouldGenVersionNumbers = do_not_generate_version_numbers
|
|
).
|
|
|
|
:- pred insist_on_timestamp(maybe(timestamp)::in, timestamp::out) is det.
|
|
|
|
insist_on_timestamp(MaybeTimestamp, Timestamp) :-
|
|
% Find the timestamp of the current module.
|
|
(
|
|
MaybeTimestamp = no,
|
|
unexpected($pred, "timestamp not read with `--smart-recompilation'")
|
|
;
|
|
MaybeTimestamp = yes(Timestamp)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred report_file_not_written(globals::in, list(format_piece)::in,
|
|
module_name::in, ext::in, maybe(ext)::in, ext::in,
|
|
list(error_spec)::in, list(error_spec)::out, io::di, io::uo) is det.
|
|
|
|
report_file_not_written(Globals, PrefixPieces, ModuleName,
|
|
ExtA, MaybeExtB, ExtDate, Specs0, Specs, !IO) :-
|
|
% XXX LEGACY
|
|
module_name_to_file_name(Globals, $pred,
|
|
ExtA, ModuleName, IntAFileName, _IntAFileNameProposed),
|
|
module_name_to_file_name(Globals, $pred,
|
|
ExtDate, ModuleName, DateFileName, _DateFileNameProposed),
|
|
StdIntAFileName = standardize_filename_if_asked(Globals, IntAFileName),
|
|
(
|
|
MaybeExtB = no,
|
|
NotWrittenPieces = [quote(StdIntAFileName), words("not written."), nl],
|
|
ToRemoveFileNames = [IntAFileName, DateFileName]
|
|
;
|
|
MaybeExtB = yes(ExtB),
|
|
% XXX LEGACY
|
|
module_name_to_file_name(Globals, $pred,
|
|
ExtB, ModuleName, IntBFileName, _IntBFileNameProposed),
|
|
StdIntBFileName = standardize_filename_if_asked(Globals, IntBFileName),
|
|
NotWrittenPieces = [quote(StdIntAFileName), words("and"),
|
|
quote(StdIntBFileName), words("not written."), nl],
|
|
ToRemoveFileNames = [IntAFileName, IntBFileName, DateFileName]
|
|
),
|
|
ModuleNameStr = sym_name_to_string(ModuleName),
|
|
InvisPiece = invis_order_default_end(0, ModuleNameStr),
|
|
Severity = severity_informational(report_not_written),
|
|
NotWrittenSpec = no_ctxt_spec($pred, Severity, phase_make_int,
|
|
[InvisPiece | PrefixPieces] ++ NotWrittenPieces),
|
|
Specs = [NotWrittenSpec | Specs0],
|
|
% We remove the interface file(s) the errors prevented us from generating,
|
|
% as well as the file indicating when they were last successfully written,
|
|
% for the same reason: to prevent any previous versions of those files
|
|
% being used in other compilations despite the fact that they are now
|
|
% out-of-date. If we did not do this, compilations that read in the
|
|
% now-obsolete interface files could generate error messages about
|
|
% errors that do not now exist in the source files at all.
|
|
list.map_foldl(io.file.remove_file,
|
|
ToRemoveFileNames, _RemoveResults, !IO).
|
|
|
|
:- func standardize_filename_if_asked(globals, string) = string.
|
|
|
|
standardize_filename_if_asked(Globals, FileName) = StdFileName :-
|
|
globals.lookup_bool_option(Globals, std_int_file_not_written_msgs, Std),
|
|
(
|
|
Std = no,
|
|
StdFileName = FileName
|
|
;
|
|
Std = yes,
|
|
( if dir.basename(FileName, BaseName) then
|
|
StdFileName = BaseName
|
|
else
|
|
StdFileName = FileName
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.write_module_interface_files.
|
|
%---------------------------------------------------------------------------%
|