mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 10:23:46 +00:00
scripts/Mmake.rules:
Add a rule for the pattern target %.depend_ints which invokes mmc
with --generate-dependencies-ints, just as %.depend invokes mmc
with --generate-dependencies.
Document the reason why this addition requires yet more code duplication.
scripts/Mmake.vars.in:
Add the make variable definitions needed by the new code in Mmake.rules.
compiler/mercury_compile_main.m:
Make it practical to use --generate-dependencies-ints in a multi-directory
project like the Mercury implementation, in which some directories
may use --generate-dependencies-ints as the target of "mmake depend",
while other directories, which come earlier in the build process,
still do "mmake depend" using just --generate-dependencies.
In such cases, mmc --generate-dependencies-ints in the later directory
may fail to generate .int0, .int or .int2 files simply because
the .int3 file of a module they import (from an earlier directory
in which "mmake depend" uses just --generate-dependencies) hasn't been
made yet. (This is what would happen if someone executed "mmake depend"
at the top level in a freshly checked out workspace.)
The practical fix is to simply report this fix using an error message
that still allows the compiler to exit with an exit status that
indicates success.
Most of the rest of this diff is there to make this possible.
compiler/error_spec.m:
Add a new phase, phase_find_files, that specifically indicates
that we couldn't read a file because we couldn't find it.
Give it a string argument naming the file, to allow mercury_compile_main.m
to replace several error_specs that each report not being able to find
one file with a single error_spec that reports not being able to find
many files.
Add a utility function for use by mercury_compile_main.m to construct
that error message.
Add another new phase, phase_make_int, that indicates a problem
we discovered in the code of a Mercury source file while trying
to decide what should got into one of the that module's interface files.
compiler/parse_error.m:
Here also use separate function symbols in the fatal_module_read_error
type for the situations "couldn't find a file" and "couldn't read a file".
Update the predicates constructing error_specs to handle this distinction
(which the callers make using the new function symbol in the above type).
compiler/compile_target_code.m:
compiler/error_util.m:
compiler/grab_modules.m:
compiler/options_file.m:
compiler/parse_module.m:
compiler/read_modules.m:
compiler/recompilation.check.m:
compiler/write_module_interface_files.m:
Conform to the changes above.
compiler/options.m:
Add a way to detect the presence of this diff in an installed compiler.
275 lines
11 KiB
Mathematica
275 lines
11 KiB
Mathematica
%-----------------------------------------------------------------------------e
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------e
|
|
% Copyright (C) 2014 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.
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.parse_error.
|
|
:- interface.
|
|
|
|
:- import_module parse_tree.error_spec.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module set.
|
|
|
|
% 1. We obviously cannot process the module if we could not read it.
|
|
%
|
|
% 2. If the module contains some bad ":- module" declarations, then
|
|
% the identity of the module that contains any items following
|
|
% such declarations will be in doubt. The compiler can guess the
|
|
% identity of the module intended by the programmer only by chance,
|
|
% and any mistake will typically lead to an avalanche of misleading
|
|
% errors.
|
|
%
|
|
% 3. If the module contains some bad ":- end_module" declarations,
|
|
% then the same is true for any items following those declarations.
|
|
%
|
|
% Items follow most ":- module" declarations, but not most ":- end_module"
|
|
% declarations, and if no items follow a bad ":- end_module" declaration,
|
|
% then the badness of the declaration has no further consequences.
|
|
% It would therefore be worthwhile making a distinction between bad
|
|
% ":- end_module" declarations that have items following them, and those
|
|
% that don't. Unfortunately, since each item is processed independently,
|
|
% that is not trivial to do.
|
|
%
|
|
:- type fatal_read_module_error
|
|
---> frme_could_not_find_file
|
|
% We could not find the specified file.
|
|
|
|
; frme_could_not_open_file
|
|
% We could not open the specified file.
|
|
|
|
; frme_could_not_read_file
|
|
% We could open the specified file, but could not read its
|
|
% contents.
|
|
|
|
; frme_bad_submodule_start
|
|
% We encountered a declaration for the start of a submodule,
|
|
% but the name of the new submodule is not one that
|
|
% can be immediately nested inside the current module.
|
|
% NOTE This error can happen only for submodules of the main
|
|
% module in the file. For the main module itself, we would generate
|
|
% the rme_unexpected_module_name error.
|
|
|
|
; frme_bad_module_end.
|
|
% We encountered a declaration for the end of a module,
|
|
% but the name of the ended module is not the name of the
|
|
% until-then-current module.
|
|
% NOTE This error can happen both for the main module of the
|
|
% file and for its submodules.
|
|
|
|
% This type represents the kinds of nonfatal errors that can happen
|
|
% when we read in a Mercury module (which will be either a source file,
|
|
% or an interface file).
|
|
%
|
|
:- type nonfatal_read_module_error
|
|
---> rme_unexpected_module_name
|
|
% The file starts with a module declaration for a module
|
|
% other than the one we expected.
|
|
|
|
; rme_no_module_decl_at_start
|
|
% The file does not start with a module declaration at all.
|
|
|
|
; rme_no_section_decl_at_start
|
|
% The module does not start with either an interface or an
|
|
% implementation section marker.
|
|
|
|
; rme_end_module_not_at_end_of_src
|
|
% The source code of a module has at least one term
|
|
% after the end_module marker for the main module.
|
|
|
|
; rme_unexpected_term_in_int_or_opt
|
|
% The interface or optimization file of a module has at least one
|
|
% term that is not expected in such a file.
|
|
|
|
; rme_could_not_read_term
|
|
; rme_could_not_parse_item
|
|
% When we attempted to read an item from the file, we got a failure
|
|
% either in the first stage of parsing (reading in a term, i.e.
|
|
% converting a subsequence of the character in the file to a term),
|
|
% or the second stage of parsing (converting that term to an item).
|
|
% Since the rest of the compiler should not care whether parsing
|
|
% is done in one or two stages, it should treat both these errors
|
|
% the same. We distinguish them only for completeness.
|
|
|
|
; rme_cannot_find_modify_time
|
|
% We cannot find out the modification time of he file.
|
|
% This error is not fatal, because its only effect is
|
|
% to disable smart recompilation, whose implementation
|
|
% is not completed yet.
|
|
|
|
; rme_nec.
|
|
% A read module error that is Not Elsewhere Classified, i.e.
|
|
% is not one of the error kinds listed above.
|
|
%
|
|
% Before the change away from read_module_errors being just a set
|
|
% of read_module_error values, we used to not include these errors
|
|
% in the set at all, which could lead to an empty set of
|
|
% read_module_error values being paired with a nonempty list
|
|
% of severity_error error_specs.
|
|
|
|
% This type represents the set of errors that were encountered
|
|
% during an attempt to read in a Mercury module's source file,
|
|
% interface file, or optimization file.
|
|
%
|
|
% There are two kinds of tests that code will typically perform
|
|
% on values of this type.
|
|
%
|
|
% 1. Are there any errors?
|
|
% 2. Are there any FATAL errors?
|
|
%
|
|
% You can use there_are_no_errors and there_are_some_errors for
|
|
% the first kind of test, and a direct invocation of an emptiness test
|
|
% on the rm_fatal_errors field for the second kind.
|
|
%
|
|
:- type read_module_errors
|
|
---> read_module_errors(
|
|
% The fatal errors we have encountered, and their messages.
|
|
% All these error_specs should have severity_error.
|
|
rm_fatal_errors :: set(fatal_read_module_error),
|
|
rm_fatal_error_specs :: list(error_spec),
|
|
|
|
% The nonfatal errors we have encountered, and their messages.
|
|
% All these error_specs should have severity_error.
|
|
rm_nonfatal_errors :: set(nonfatal_read_module_error),
|
|
rm_nonfatal_error_specs :: list(error_spec),
|
|
|
|
% The warnings we have encountered. All these should have
|
|
% severity levels *below* severity_error.
|
|
rm_warning_specs :: list(error_spec)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
% Return a structure that records no errors (so far).
|
|
%
|
|
:- func init_read_module_errors = read_module_errors.
|
|
|
|
%---------------------%
|
|
|
|
% Add a fatal error, and its message.
|
|
%
|
|
:- pred add_fatal_error(fatal_read_module_error::in, list(error_spec)::in,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
% Add a nonfatal error, and its message.
|
|
%
|
|
:- pred add_nonfatal_error(nonfatal_read_module_error::in,
|
|
list(error_spec)::in,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
% If there are any error_specs in the input list,
|
|
% record them as representing a not-elsewhere-classified nonfatal error.
|
|
%
|
|
:- pred add_any_nec_errors(list(error_spec)::in,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
% Add some warning messages.
|
|
%
|
|
:- pred add_warning(list(error_spec)::in,
|
|
read_module_errors::in, read_module_errors::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Succeed if the read_module_errors structure records zero errors.
|
|
% (Though it may contain warnings.)
|
|
%
|
|
:- pred there_are_no_errors(read_module_errors::in) is semidet.
|
|
|
|
% Succeed if the read_module_errors structure records at least one error.
|
|
%
|
|
:- pred there_are_some_errors(read_module_errors::in) is semidet.
|
|
|
|
%---------------------%
|
|
|
|
% Return all the error_specs in the argument, regardless of severity.
|
|
%
|
|
:- func get_read_module_specs(read_module_errors) = list(error_spec).
|
|
|
|
%---------------------%
|
|
|
|
:- pred io_error_to_error_spec(error_phase::in, string::in, error_spec::out,
|
|
io::di, io::uo) is det.
|
|
|
|
:- pred io_error_to_read_module_errors(fatal_read_module_error::in,
|
|
error_phase::in, string::in, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- implementation.
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init_read_module_errors = read_module_errors(set.init, [], set.init, [], []).
|
|
|
|
%---------------------%
|
|
|
|
add_fatal_error(Error, Specs, Errors0, Errors) :-
|
|
Errors0 = read_module_errors(FatalErrors0, FatalSpecs0,
|
|
NonFatalErrors, NonFatalSpecs, WarningSpecs),
|
|
set.insert(Error, FatalErrors0, FatalErrors),
|
|
FatalSpecs = Specs ++ FatalSpecs0,
|
|
Errors = read_module_errors(FatalErrors, FatalSpecs,
|
|
NonFatalErrors, NonFatalSpecs, WarningSpecs).
|
|
|
|
add_nonfatal_error(Error, Specs, Errors0, Errors) :-
|
|
Errors0 = read_module_errors(FatalErrors, FatalSpecs,
|
|
NonFatalErrors0, NonFatalSpecs0, WarningSpecs),
|
|
set.insert(Error, NonFatalErrors0, NonFatalErrors),
|
|
NonFatalSpecs = Specs ++ NonFatalSpecs0,
|
|
Errors = read_module_errors(FatalErrors, FatalSpecs,
|
|
NonFatalErrors, NonFatalSpecs, WarningSpecs).
|
|
|
|
add_any_nec_errors(Specs, !Errors) :-
|
|
(
|
|
Specs = []
|
|
;
|
|
Specs = [_ | _],
|
|
add_nonfatal_error(rme_nec, Specs, !Errors)
|
|
).
|
|
|
|
add_warning(Specs, Errors0, Errors) :-
|
|
Errors0 = read_module_errors(FatalErrors, FatalSpecs,
|
|
NonFatalErrors, NonFatalSpecs, WarningSpecs0),
|
|
WarningSpecs = Specs ++ WarningSpecs0,
|
|
Errors = read_module_errors(FatalErrors, FatalSpecs,
|
|
NonFatalErrors, NonFatalSpecs, WarningSpecs).
|
|
|
|
%---------------------%
|
|
|
|
there_are_no_errors(Errors) :-
|
|
Errors = read_module_errors(FatalErrors, _, NonFatalErrors, _, _),
|
|
set.is_empty(FatalErrors),
|
|
set.is_empty(NonFatalErrors).
|
|
|
|
there_are_some_errors(Errors) :-
|
|
Errors = read_module_errors(FatalErrors, _, NonFatalErrors, _, _),
|
|
( set.is_non_empty(FatalErrors)
|
|
; set.is_non_empty(NonFatalErrors)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
get_read_module_specs(Errors) = Specs :-
|
|
Errors = read_module_errors(_FatalErrors, FatalSpecs,
|
|
_NonFatalErrors, NonFatalSpecs, WarningSpecs),
|
|
Specs = FatalSpecs ++ NonFatalSpecs ++ WarningSpecs.
|
|
|
|
%---------------------%
|
|
|
|
io_error_to_error_spec(Phase, ErrorMsg, Spec, !IO) :-
|
|
io.progname_base("mercury_compile", ProgName, !IO),
|
|
Pieces = [fixed(ProgName), suffix(":"), words(ErrorMsg), nl],
|
|
Spec = simplest_no_context_spec($pred, severity_error, Phase, Pieces).
|
|
|
|
io_error_to_read_module_errors(FatalError, Phase, ErrorMsg, Errors, !IO) :-
|
|
io_error_to_error_spec(Phase, ErrorMsg, Spec, !IO),
|
|
Errors0 = init_read_module_errors,
|
|
add_fatal_error(FatalError, [Spec], Errors0, Errors).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.parse_error.
|
|
%---------------------------------------------------------------------------%
|