mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
compiler/error_spec.m:
Delete conditional_spec from the error_spec type, which had
exactly one use left in the compiler. Replace it with a conditional form
of severity_error, which handles that use case.
Rename error_severity to spec_severity, since obviously not all severities
represent errors.
For the same reason, rename error_phase to spec_phase.
compiler/error_util.m:
Export a predicate for write_error_spec.m.
compiler/write_error_spec.m:
Use that export to delete what used to be duplicate code.
compiler/add_pragma.m:
compiler/check_typeclass.m:
compiler/compiler_util.m:
compiler/error_sort.m:
compiler/mark_tail_calls.m:
compiler/parse_error.m:
compiler/parse_item.m:
Conform to the changes above.
275 lines
11 KiB
Mathematica
275 lines
11 KiB
Mathematica
%-----------------------------------------------------------------------------e
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------e
|
|
% Copyright (C) 2014, 2016, 2019, 2022-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.
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- 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(spec_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,
|
|
spec_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 = no_ctxt_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.
|
|
%---------------------------------------------------------------------------%
|