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.
1488 lines
64 KiB
Mathematica
1488 lines
64 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2009, 2011 The University of Melbourne.
|
|
% Copyright (C) 2014-2017, 2019-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: read_modules.m.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.read_modules.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.timestamp.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.parse_error.
|
|
:- import_module parse_tree.prog_parse_tree.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module term.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% After we have read in Mercury code from a source file, interface file or
|
|
% optimization file, we record the parse tree we get from it, so we can
|
|
% avoid having to read it again.
|
|
% XXX ITEM_LIST We seem to sometimes re-read it anyway. Fix this.
|
|
%
|
|
% Since we use different types to represent the parse trees of source,
|
|
% interface and optimization files, we use three maps, one for each
|
|
% parse tree type. Each map maps a key, which consists of a module name
|
|
% and the kind of a file (e.g. .int0 vs .int2 for interface files)
|
|
% to the parse tree we got for that file.
|
|
%
|
|
% XXX ITEM_LIST The code that reads in optimization files does not
|
|
% record its results in hptm_opt. I (zs) don't know whether that is
|
|
% a bug (leading to duplicate reads of optimization files) or a feature
|
|
% (keeping files that are by construction read exactly once out of a map
|
|
% where they won't be needed again).
|
|
%
|
|
|
|
:- type have_parse_tree_maps
|
|
---> have_parse_tree_maps(
|
|
hptm_src :: have_parse_tree_src_map,
|
|
|
|
hptm_module_src :: have_parse_tree_msrc_map,
|
|
|
|
hptm_int0 :: have_parse_tree_int0_map,
|
|
hptm_int1 :: have_parse_tree_int1_map,
|
|
hptm_int2 :: have_parse_tree_int2_map,
|
|
hptm_int3 :: have_parse_tree_int3_map,
|
|
|
|
hptm_plain_opt :: have_parse_tree_plain_opt_map,
|
|
hptm_trans_opt :: have_parse_tree_trans_opt_map
|
|
).
|
|
|
|
:- func init_have_parse_tree_maps = have_parse_tree_maps.
|
|
|
|
:- type have_parse_tree_src_map ==
|
|
have_parse_tree_map(parse_tree_src).
|
|
|
|
:- type have_parse_tree_key(Kind)
|
|
---> have_parse_tree_key(module_name, Kind).
|
|
|
|
:- type have_parse_tree_msrc_map ==
|
|
map(module_name, parse_tree_module_src).
|
|
|
|
:- type have_parse_tree_int0_map ==
|
|
have_parse_tree_map(parse_tree_int0).
|
|
:- type have_parse_tree_int1_map ==
|
|
have_parse_tree_map(parse_tree_int1).
|
|
:- type have_parse_tree_int2_map ==
|
|
have_parse_tree_map(parse_tree_int2).
|
|
:- type have_parse_tree_int3_map ==
|
|
have_parse_tree_map(parse_tree_int3).
|
|
|
|
:- type have_parse_tree_plain_opt_map ==
|
|
have_parse_tree_map(parse_tree_plain_opt).
|
|
:- type have_parse_tree_trans_opt_map ==
|
|
have_parse_tree_map(parse_tree_trans_opt).
|
|
|
|
:- type have_parse_tree_map(PT) == map(module_name, have_module(PT)).
|
|
|
|
% This type records the result of one of the read_module_<filekind>
|
|
% predicates below. There are three possible outcomes:
|
|
%
|
|
% - We have tried to read the module and succeeded.
|
|
% - We have tried to read the module and failed.
|
|
% - We have not tried to read the module.
|
|
%
|
|
% The first will return have_module(...), while the second and
|
|
% third will return have_not_read_module(...).
|
|
%
|
|
% The reason for not having a separate function symbol for the third
|
|
% outcome is that it can happen only for the small minority of calls
|
|
% that ask that the file not be read in the event of a timestamp match,
|
|
% but a third function symbol would force *all* calls to handle a situation
|
|
% that cannot arise for them.
|
|
:- type have_module(PT)
|
|
---> have_module(
|
|
% We have read, or constructed, the module.
|
|
|
|
% The name of the file that either
|
|
% - we read the parse tree from, or
|
|
% - we have written the parse tree to.
|
|
file_name,
|
|
|
|
% The parse tree of the file.
|
|
PT,
|
|
|
|
% Where did we get the parse tree from? And what other info,
|
|
% if any, did the "getting" process give us?
|
|
have_parse_tree_source
|
|
|
|
)
|
|
; have_not_read_module(
|
|
% We have tried to read the module, but did not do so.
|
|
|
|
% The name of the file that we have either tried to read,
|
|
% or whose timestamp indicated we did not have to read it.
|
|
file_name,
|
|
|
|
% The errors we got in the attempt to read the file.
|
|
% If we did not attempt to read the file, this will contain
|
|
% no errors at all. (This is how you can tell these two cases
|
|
% apart.)
|
|
read_module_errors
|
|
).
|
|
|
|
:- type have_read_module(PT) =< have_module(PT)
|
|
---> have_module(file_name, PT, have_parse_tree_read)
|
|
; have_not_read_module(file_name, read_module_errors).
|
|
|
|
% How did we get access to this parse tree: did we read it in
|
|
% from the file system, or did we construct it? If we read it in,
|
|
% then record any errors we found during parsing. The read_module_errors
|
|
% field should contain neither frme_could_not_open_file nor
|
|
% frme_could_not_read_file, but may contain any other errors.
|
|
% In addition, we record the timestamp of the file we read in,
|
|
% *if* the compiler component that decided to read the file
|
|
% requested that the timestamp be returned. Not all do.
|
|
:- type have_parse_tree_source
|
|
---> was_read(maybe(timestamp), read_module_errors)
|
|
; was_constructed.
|
|
|
|
:- type have_parse_tree_read =< have_parse_tree_source
|
|
---> was_read(maybe(timestamp), read_module_errors).
|
|
|
|
:- pred have_parse_tree_source_get_maybe_timestamp_errors(
|
|
have_parse_tree_source::in,
|
|
maybe(timestamp)::out, read_module_errors::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Why are we attempting to read and parse a file?
|
|
:- type read_reason_msg
|
|
---> rrm_file
|
|
% Because the compiler has been asked to compile the named file
|
|
% in some fashion. (This could be generating target code for it,
|
|
% making its interface files, making its optimization files, etc.)
|
|
; rrm_std
|
|
% Because the named file belongs to this module (as a source file,
|
|
% interface file, or optimization file), and the compiler has been
|
|
% asked to compile that module in some fashion.
|
|
; rrm_old
|
|
% Because the named file belongs to this module, and we need
|
|
% the old contents of the file, so that we can write out
|
|
% what we *now* think its contents should be, but *only*
|
|
% if the "new" contents differ from the old. The difference
|
|
% between whether (a) we keep the old contents as is, or
|
|
% (b) we overwrite them with identical contents, is the
|
|
% timestamp on the file. Keeping the old timestamp will
|
|
% prevent unnecessary rebuilds of other files that depend
|
|
% on that one.
|
|
; rrm_get_deps.
|
|
% Because the named file belongs to this module, and we need
|
|
% to get its dependencies.
|
|
|
|
% read_module_src(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
% ModuleName, FileName, ReadModuleAndTimestamps, HaveModule, !IO):
|
|
%
|
|
% Given a module name, read in and parse the source code of that file,
|
|
% printing progress messages along the way if the verbosity level
|
|
% calls for that.
|
|
%
|
|
% If Search is do_search, search all directories given by the option
|
|
% search_directories for the module;
|
|
% otherwise, search for those filenames only in the current directory.
|
|
% Return in the FileName part of HaveModule the actual source file
|
|
% name found (excluding the directory part). If the actual module name
|
|
% (as determined by the `:- module' declaration) does not match
|
|
% the specified module name, then report an error message,
|
|
% but record the *expected* module name in the parse tree,
|
|
% not the one we actually found. This is because most parts
|
|
% of the compiler (including deps_map.m and make.module_dep_file.m)
|
|
% rely on the invariant which says that if Errors does not contain
|
|
% any fatal errors, then the returned ParseTreeSrc contains the
|
|
% module with the expected name. Invocations of the compiler
|
|
% that don't specify --make or request dependency map don't really
|
|
% care which module name we return here; they will work either way,
|
|
% the only difference being whether the names of the files they generate
|
|
% are based on the expected or the actual module name.
|
|
%
|
|
% N.B. This reads a module given the MODULE name. If you want to read
|
|
% a module given the FILE name, use `read_module_src_from_file'.
|
|
%
|
|
% If ReadModuleAndTimestamps is
|
|
% always_read_module(do_not_return_timestamp), return `no' in the
|
|
% MaybeTimestamp field of HaveModule.
|
|
%
|
|
% If ReadModuleAndTimestamps is always_read_module(do_return_timestamp),
|
|
% attempt to return the modification time of the file in the MaybeTimestamp
|
|
% field of HaveModule.
|
|
%
|
|
% If ReadModuleAndTimestamps is do_not_read_module_if_match(OldTimeStamp),
|
|
% then
|
|
%
|
|
% - if the timestamp of that file is exactly OldTimestamp, then
|
|
% don't read the file, and return have_not_read_module with no errors,
|
|
% while
|
|
% - if the timestamp of that file differs from OldTimestamp (virtually
|
|
% always because it is newer), then read the module from the file
|
|
% as usual, parse and return its contents as usual, and also return
|
|
% its actual timestamp.
|
|
%
|
|
:- pred read_module_src(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, maybe_search::in,
|
|
module_name::in, list(term.context)::in, read_module_and_timestamps::in,
|
|
have_read_module(parse_tree_src)::out, io::di, io::uo) is det.
|
|
|
|
% read_module_src_from_file(ProgressStream, Globals,
|
|
% FileName, FileNameDotM, ReadReasonMsg, Search, ReadModuleAndTimestamps,
|
|
% HaveModule, !IO):
|
|
%
|
|
% Does pretty much the same job as read_module_src, but its job is
|
|
% to read the module stored in a specified file (FileNameDotM),
|
|
% discovering the name of the module stored there by reading the file,
|
|
% as opposed to looking for the file containing a module with a specified
|
|
% name. It does not search for the right filename (that is FileNameDotM),
|
|
% but if Search is do_search, it does search for that filename in the
|
|
% specified directories.
|
|
%
|
|
% The rest of the argument list has the same meaning as in read_module_src.
|
|
%
|
|
:- pred read_module_src_from_file(io.text_output_stream::in, globals::in,
|
|
file_name::in, file_name::in, read_reason_msg::in, maybe_search::in,
|
|
read_module_and_timestamps::in, have_read_module(parse_tree_src)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% maybe_read_module_intN(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
% ModuleName, IntFileKind, ReturnTimestamp, HaveModule,
|
|
% !HaveParseTreeMaps, !IO):
|
|
%
|
|
% If !.HaveParseTreeMaps contains the already-read contents of the
|
|
% relevant kind of interface file for ModuleName, then return
|
|
% the information stored in !.HaveParseTreeMaps for that file.
|
|
% If it is not there, read that interface file using read_module_intN,
|
|
% regardless of its timestamp.
|
|
%
|
|
:- pred maybe_read_module_int0(io.text_output_stream::in, globals::in,
|
|
maybe_search::in, module_name::in, maybe_return_timestamp::in,
|
|
have_module(parse_tree_int0)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
:- pred maybe_read_module_int1(io.text_output_stream::in, globals::in,
|
|
maybe_search::in, module_name::in, maybe_return_timestamp::in,
|
|
have_module(parse_tree_int1)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
:- pred maybe_read_module_int2(io.text_output_stream::in, globals::in,
|
|
maybe_search::in, module_name::in, maybe_return_timestamp::in,
|
|
have_module(parse_tree_int2)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
:- pred maybe_read_module_int3(io.text_output_stream::in, globals::in,
|
|
maybe_search::in, module_name::in, maybe_return_timestamp::in,
|
|
have_module(parse_tree_int3)::out,
|
|
have_parse_tree_maps::in, have_parse_tree_maps::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% read_module_intN(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
% ModuleName, FileName, ReadModuleAndTimestamps, HaveModule, !IO):
|
|
%
|
|
% Given a module name, read in and parse the specified kind of interface
|
|
% file for that module, printing progress messages along the way
|
|
% if the verbosity level calls for that.
|
|
%
|
|
% The meanings of the arguments are pretty much the same as for
|
|
% read_module_src, but while the names of the files that contain source
|
|
% files may not be fully module qualified, the names of interface files
|
|
% are always fully module qualified, so read_module_int does not search
|
|
% for the right filename. It knows what filename it looks for; the only
|
|
% search it does, if Search is do_search, is to decide which directory
|
|
% among the search directories contains the file with that filename.
|
|
%
|
|
:- pred read_module_int0(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, maybe_search::in,
|
|
module_name::in, read_module_and_timestamps::in,
|
|
have_module(parse_tree_int0)::out, io::di, io::uo) is det.
|
|
:- pred read_module_int1(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, maybe_search::in,
|
|
module_name::in, read_module_and_timestamps::in,
|
|
have_module(parse_tree_int1)::out, io::di, io::uo) is det.
|
|
:- pred read_module_int2(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, maybe_search::in,
|
|
module_name::in, read_module_and_timestamps::in,
|
|
have_module(parse_tree_int2)::out, io::di, io::uo) is det.
|
|
:- pred read_module_int3(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, maybe_search::in,
|
|
module_name::in, read_module_and_timestamps::in,
|
|
have_module(parse_tree_int3)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% read_module_{plain,trans}_opt(ProgressStream, Globals, ModuleName,
|
|
% FileName, HaveModule, !IO):
|
|
%
|
|
% Given a module name, read in and parse the specified kind of optimization
|
|
% file for that module, printing progress messages along the way
|
|
% if the verbosity level calls for that.
|
|
%
|
|
% These predicates do a very similar job to read_module_intN,
|
|
% but there are several differences.
|
|
%
|
|
% - We do not do anything with errors in .opt and .trans_opt files;
|
|
% we leave that up to the caller. The reason for this is that
|
|
% a missing .opt file is not an error, unlike a missing .intN file.
|
|
%
|
|
% - We do always do search for .opt and .trans_opt files, but
|
|
% in the directories named by the intermod_directories option, *not*
|
|
% in the directories named by the search_directories option.
|
|
%
|
|
% - None of our callers are ever interested in timestamps,
|
|
% so these predicates never return them.
|
|
%
|
|
:- pred read_module_plain_opt(io.text_output_stream::in, globals::in,
|
|
module_name::in, have_module(parse_tree_plain_opt)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_module_trans_opt(io.text_output_stream::in, globals::in,
|
|
module_name::in, have_module(parse_tree_trans_opt)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% get_default_module_name_for_file(FileName, FileNameDotM,
|
|
% DefaultModuleName, !IO):
|
|
%
|
|
% Return the default module name for a file, based either on the
|
|
% entry for FileNameDotM in the source file map (Mercury.modules)
|
|
% if that is available, and otherwise based just on the file name FileName.
|
|
% XXX Having two separate filenames here is old behavior. I (zs)
|
|
% don't know the reason for it. It can't be a distinction between
|
|
% expected and actual filename, since the caller is calling us
|
|
% because it does not know the actual module name, and thus has
|
|
% no basis on which to decide what filename to expect.
|
|
%
|
|
:- pred get_default_module_name_for_file(file_name::in, file_name::in,
|
|
module_name::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred return_timestamp_if_needed(maybe_return_timestamp::in,
|
|
maybe(timestamp)::in, maybe(timestamp)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.file_kind.
|
|
:- import_module parse_tree.find_module.
|
|
:- import_module parse_tree.maybe_error.
|
|
:- import_module parse_tree.parse_module.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.source_file_map.
|
|
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module dir.
|
|
:- import_module io.file.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init_have_parse_tree_maps =
|
|
have_parse_tree_maps(map.init, map.init, map.init,
|
|
map.init, map.init, map.init, map.init, map.init).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
have_parse_tree_source_get_maybe_timestamp_errors(Source,
|
|
MaybeTimestamp, Errors) :-
|
|
(
|
|
Source = was_read(MaybeTimestamp, Errors)
|
|
;
|
|
Source = was_constructed,
|
|
MaybeTimestamp = no,
|
|
Errors = read_module_errors(set.init, [], set.init, [], [])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
read_module_src(ProgressStream, Globals, ReadReasonMsg, Search, ModuleName,
|
|
ExpectationContexts, ReadModuleAndTimestamps, HaveModule, !IO) :-
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_src, FileName0, ReadDoneMsg, SearchAuthDirs, !IO),
|
|
% For `.m' files, we need to deal with the case where the module name
|
|
% does not match the file name.
|
|
search_for_module_source_and_stream(SearchAuthDirs, ModuleName,
|
|
_SearchDirs, MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = ok(FileNameAndStream),
|
|
actually_read_module_src(Globals, FileNameAndStream, ModuleName,
|
|
ExpectationContexts, ReadModuleAndTimestamps, MaybeTimestampRes,
|
|
MaybeParseTreeSrc0, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals,
|
|
mfas_ok(FileNameAndStream), fk_src, ReadDoneMsg,
|
|
FileName0, FileName, MaybeTimestampRes, MaybeTimestamp,
|
|
Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeSrc0 = yes(ParseTreeSrc0),
|
|
% If ModuleName = ParseTreeSrc0 ^ pts_module_name, this obviously
|
|
% does the right thing.
|
|
% If ModuleName != ParseTreeSrc0 ^ pts_module_name, then
|
|
% we must include ModuleName in ParseTreeSrc (see the comment
|
|
% above), and including recording its context as
|
|
% ParseTreeSrc0 ^ pts_module_name_context shouldn't mislead anyone
|
|
% who reads the error spec (which should be in Errors0) about
|
|
% the unexpected module name.
|
|
ParseTreeSrc = ParseTreeSrc0 ^ pts_module_name := ModuleName,
|
|
HaveModule = have_module(FileName, ParseTreeSrc,
|
|
was_read(MaybeTimestamp, Errors))
|
|
;
|
|
MaybeParseTreeSrc0 = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = error(ErrorMsg),
|
|
io_error_to_read_module_errors(frme_could_not_open_file,
|
|
phase_find_files(FileName0), ErrorMsg, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals, mfas_error(Errors0),
|
|
fk_src, ReadDoneMsg, FileName0, FileName,
|
|
no, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
read_module_src_from_file(ProgressStream, Globals, FileName, FileNameDotM,
|
|
ReadReasonMsg, Search, ReadModuleAndTimestamps, HaveModule, !IO) :-
|
|
read_module_begin_from_file(ProgressStream, ife_src, Globals,
|
|
ReadReasonMsg, Search, FileName, FileNameDotM, DefaultModuleName,
|
|
ReadDoneMsg, SearchWhichDirs, !IO),
|
|
search_for_file_and_stream(SearchWhichDirs, FileNameDotM,
|
|
_SearchDirs, MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = ok(FileNameAndStream),
|
|
actually_read_module_src(Globals, FileNameAndStream,
|
|
DefaultModuleName, [], ReadModuleAndTimestamps, MaybeTimestampRes,
|
|
MaybeParseTreeSrc, Errors0, !IO),
|
|
read_module_end_file(Globals, fk_src, ReadDoneMsg, FileNameDotM,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeSrc = yes(ParseTreeSrc),
|
|
HaveModule = have_module(FileNameDotM, ParseTreeSrc,
|
|
was_read(MaybeTimestamp, Errors))
|
|
;
|
|
MaybeParseTreeSrc = no,
|
|
HaveModule = have_not_read_module(FileNameDotM, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = error(ErrorMsg),
|
|
io_error_to_read_module_errors(frme_could_not_open_file,
|
|
phase_find_files(FileNameDotM), ErrorMsg, Errors0, !IO),
|
|
read_module_end_file(Globals, fk_src, ReadDoneMsg, FileNameDotM,
|
|
no, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileNameDotM, Errors)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
maybe_read_module_int0(ProgressStream, Globals, Search, ModuleName,
|
|
ReturnTimestamp, HaveModule, !HaveParseTreeMaps, !IO) :-
|
|
OrigHPTM = !.HaveParseTreeMaps ^ hptm_int0,
|
|
( if
|
|
search_module_name_timestamp_if_needed(OrigHPTM, ModuleName,
|
|
ReturnTimestamp, HaveReadModulePrime)
|
|
then
|
|
HaveModule = HaveReadModulePrime
|
|
else
|
|
read_module_int0(ProgressStream, Globals, rrm_std, Search, ModuleName,
|
|
always_read_module(ReturnTimestamp), HaveModule, !IO),
|
|
map.set(ModuleName, HaveModule, OrigHPTM, HPTM),
|
|
!HaveParseTreeMaps ^ hptm_int0 := HPTM
|
|
).
|
|
|
|
maybe_read_module_int1(ProgressStream, Globals, Search, ModuleName,
|
|
ReturnTimestamp, HaveModule, !HaveParseTreeMaps, !IO) :-
|
|
OrigHPTM = !.HaveParseTreeMaps ^ hptm_int1,
|
|
( if
|
|
search_module_name_timestamp_if_needed(OrigHPTM, ModuleName,
|
|
ReturnTimestamp, HaveReadModulePrime)
|
|
then
|
|
HaveModule = HaveReadModulePrime
|
|
else
|
|
read_module_int1(ProgressStream, Globals, rrm_std, Search, ModuleName,
|
|
always_read_module(ReturnTimestamp), HaveModule, !IO),
|
|
map.set(ModuleName, HaveModule, OrigHPTM, HPTM),
|
|
!HaveParseTreeMaps ^ hptm_int1 := HPTM
|
|
).
|
|
|
|
maybe_read_module_int2(ProgressStream, Globals, Search, ModuleName,
|
|
ReturnTimestamp, HaveModule, !HaveParseTreeMaps, !IO) :-
|
|
OrigHPTM = !.HaveParseTreeMaps ^ hptm_int2,
|
|
( if
|
|
search_module_name_timestamp_if_needed(OrigHPTM, ModuleName,
|
|
ReturnTimestamp, HaveReadModulePrime)
|
|
then
|
|
HaveModule = HaveReadModulePrime
|
|
else
|
|
read_module_int2(ProgressStream, Globals, rrm_std, Search, ModuleName,
|
|
always_read_module(ReturnTimestamp), HaveModule, !IO),
|
|
map.set(ModuleName, HaveModule, OrigHPTM, HPTM),
|
|
!HaveParseTreeMaps ^ hptm_int2 := HPTM
|
|
).
|
|
|
|
maybe_read_module_int3(ProgressStream, Globals, Search, ModuleName,
|
|
ReturnTimestamp, HaveModule, !HaveParseTreeMaps, !IO) :-
|
|
OrigHPTM = !.HaveParseTreeMaps ^ hptm_int3,
|
|
( if
|
|
search_module_name_timestamp_if_needed(OrigHPTM, ModuleName,
|
|
ReturnTimestamp, HaveReadModulePrime)
|
|
then
|
|
HaveModule = HaveReadModulePrime
|
|
else
|
|
read_module_int3(ProgressStream, Globals, rrm_std, Search, ModuleName,
|
|
always_read_module(ReturnTimestamp), HaveModule, !IO),
|
|
map.set(ModuleName, HaveModule, OrigHPTM, HPTM),
|
|
!HaveParseTreeMaps ^ hptm_int3 := HPTM
|
|
).
|
|
|
|
:- pred search_module_name_timestamp_if_needed(have_parse_tree_map(PT)::in,
|
|
module_name::in, maybe_return_timestamp::in, have_module(PT)::out)
|
|
is semidet.
|
|
|
|
search_module_name_timestamp_if_needed(HPTM, ModuleName, ReturnTimestamp,
|
|
HaveModule) :-
|
|
map.search(HPTM, ModuleName, HaveReadModule0),
|
|
HaveReadModule0 = have_module(FN, PT, Source0),
|
|
(
|
|
Source0 = was_read(MaybeTimeStamp0, E),
|
|
return_timestamp_if_needed(ReturnTimestamp,
|
|
MaybeTimeStamp0, MaybeTimeStamp),
|
|
Source = was_read(MaybeTimeStamp, E)
|
|
;
|
|
Source0 = was_constructed,
|
|
(
|
|
ReturnTimestamp = do_not_return_timestamp,
|
|
Source = Source0
|
|
;
|
|
ReturnTimestamp = do_return_timestamp,
|
|
unexpected($pred, "was_constructed")
|
|
)
|
|
),
|
|
HaveModule = have_module(FN, PT, Source).
|
|
|
|
%---------------------%
|
|
|
|
read_module_int0(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, ReadModuleAndTimestamps, HaveModule, !IO) :-
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_int(ifk_int0), FileName0, ReadDoneMsg, SearchDirs, !IO),
|
|
search_for_file_and_stream_or_error(SearchDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream),
|
|
actually_read_module_int0(Globals, FileNameAndStream, ModuleName, [],
|
|
ReadModuleAndTimestamps, MaybeTimestampRes,
|
|
MaybeParseTreeInt0, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int0), ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeInt0 = yes(ParseTreeInt0),
|
|
HaveModule = have_module(FileName, ParseTreeInt0,
|
|
was_read(MaybeTimestamp, Errors))
|
|
;
|
|
MaybeParseTreeInt0 = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(Errors0),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int0), ReadDoneMsg, FileName0, FileName,
|
|
no, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
read_module_int1(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, ReadModuleAndTimestamps, HaveModule, !IO) :-
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_int(ifk_int1), FileName0, ReadDoneMsg, SearchDirs, !IO),
|
|
search_for_file_and_stream_or_error(SearchDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream),
|
|
actually_read_module_int1(Globals, FileNameAndStream, ModuleName, [],
|
|
ReadModuleAndTimestamps, MaybeTimestampRes,
|
|
MaybeParseTreeInt1, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int1), ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeInt1 = yes(ParseTreeInt1),
|
|
HaveModule = have_module(FileName, ParseTreeInt1,
|
|
was_read(MaybeTimestamp, Errors))
|
|
;
|
|
MaybeParseTreeInt1 = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(Errors0),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int1), ReadDoneMsg, FileName0, FileName,
|
|
no, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
read_module_int2(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, ReadModuleAndTimestamps, HaveModule, !IO) :-
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_int(ifk_int2), FileName0, ReadDoneMsg, SearchDirs, !IO),
|
|
search_for_file_and_stream_or_error(SearchDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream),
|
|
actually_read_module_int2(Globals, FileNameAndStream, ModuleName, [],
|
|
ReadModuleAndTimestamps, MaybeTimestampRes,
|
|
MaybeParseTreeInt2, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int2), ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeInt2 = yes(ParseTreeInt2),
|
|
HaveModule = have_module(FileName, ParseTreeInt2,
|
|
was_read(MaybeTimestamp, Errors))
|
|
;
|
|
MaybeParseTreeInt2 = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(Errors0),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int2), ReadDoneMsg, FileName0, FileName,
|
|
no, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
read_module_int3(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, ReadModuleAndTimestamps, HaveModule, !IO) :-
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_int(ifk_int3), FileName0, ReadDoneMsg, SearchDirs, !IO),
|
|
search_for_file_and_stream_or_error(SearchDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream),
|
|
actually_read_module_int3(Globals, FileNameAndStream, ModuleName, [],
|
|
ReadModuleAndTimestamps, MaybeTimestampRes,
|
|
MaybeParseTreeInt3, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int3), ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeInt3 = yes(ParseTreeInt3),
|
|
HaveModule = have_module(FileName, ParseTreeInt3,
|
|
was_read(MaybeTimestamp, Errors))
|
|
;
|
|
MaybeParseTreeInt3 = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(Errors0),
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
fk_int(ifk_int3), ReadDoneMsg, FileName0, FileName,
|
|
no, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_module_plain_opt(ProgressStream, Globals, ModuleName,
|
|
HaveModule, !IO) :-
|
|
ReadReasonMsg = rrm_std,
|
|
Search = do_search,
|
|
MaybeTimestampRes = no,
|
|
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_opt(ofk_opt), FileName0, ReadDoneMsg, SearchDirs, !IO),
|
|
search_for_file_and_stream_or_error(SearchDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream),
|
|
actually_read_module_plain_opt(Globals, FileNameAndStream, ModuleName,
|
|
MaybeParseTreePlainOpt, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals,
|
|
MaybeFileNameAndStream, fk_opt(ofk_opt), ReadDoneMsg,
|
|
FileName0, FileName, MaybeTimestampRes, _MaybeTimestamp,
|
|
Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreePlainOpt = yes(ParseTreePlainOpt),
|
|
HaveModule = have_module(FileName, ParseTreePlainOpt,
|
|
was_read(no, Errors))
|
|
;
|
|
MaybeParseTreePlainOpt = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(Errors0),
|
|
read_module_end_module(ProgressStream, Globals,
|
|
MaybeFileNameAndStream, fk_opt(ofk_opt), ReadDoneMsg,
|
|
FileName0, FileName, MaybeTimestampRes, _MaybeTimestamp,
|
|
Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
read_module_trans_opt(ProgressStream, Globals, ModuleName,
|
|
HaveModule, !IO) :-
|
|
ReadReasonMsg = rrm_std,
|
|
Search = do_search,
|
|
MaybeTimestampRes = no,
|
|
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, fk_opt(ofk_trans_opt), FileName0, ReadDoneMsg,
|
|
SearchAuthDirs, !IO),
|
|
search_for_file_and_stream_or_error(SearchAuthDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO),
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream),
|
|
actually_read_module_trans_opt(Globals, FileNameAndStream, ModuleName,
|
|
MaybeParseTreeTransOpt, Errors0, !IO),
|
|
read_module_end_module(ProgressStream, Globals,
|
|
MaybeFileNameAndStream, fk_opt(ofk_trans_opt),
|
|
ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
FileNameAndStream = path_name_and_stream(_FilePathName, FileStream),
|
|
io.close_input(FileStream, !IO),
|
|
(
|
|
MaybeParseTreeTransOpt = yes(ParseTreeTransOpt),
|
|
HaveModule = have_module(FileName, ParseTreeTransOpt,
|
|
was_read(no, Errors))
|
|
;
|
|
MaybeParseTreeTransOpt = no,
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
)
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(Errors0),
|
|
read_module_end_module(ProgressStream, Globals,
|
|
MaybeFileNameAndStream, fk_opt(ofk_trans_opt),
|
|
ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, _MaybeTimestamp, Errors0, Errors, !IO),
|
|
HaveModule = have_not_read_module(FileName, Errors)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% actually_read_module_src(Globals, FileNameAndStream,
|
|
% DefaultModuleName, DefaultExpectationContexts,
|
|
% ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
% ParseTree, Errors, !IO):
|
|
%
|
|
% Read a Mercury source program from FileNameAndStream.
|
|
% Close the stream when the reading is done. Return the parse tree
|
|
% of that module in ParseTree (which may be a dummy if the file
|
|
% couldn't be opened), and an indication of the errors found
|
|
% in Specs and Errors.
|
|
%
|
|
% For the meaning of ReadModuleAndTimestamps and MaybeModuleTimestampRes,
|
|
% read the comments on read_module_src in read_modules.m.
|
|
%
|
|
:- pred actually_read_module_src(globals::in, path_name_and_stream::in,
|
|
module_name::in, list(prog_context)::in,
|
|
read_module_and_timestamps::in, maybe(io.res(timestamp))::out,
|
|
maybe(parse_tree_src)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_src(_Globals, FileNameAndStream,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
MaybeParseTreeSrc, Errors, !IO) :-
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, MaybeModuleTimestampRes),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_src_file(FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeSrc, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, MaybeModuleTimestampRes),
|
|
MaybeParseTreeSrc = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% actually_read_module_intN(Globals, FileNameAndStream,
|
|
% DefaultModuleName, DefaultExpectationContexts,
|
|
% ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
% ParseTree, Errors, !IO):
|
|
%
|
|
% Analogous to actually_read_module_src, but opens the specified kind
|
|
% of interface file for DefaultModuleName.
|
|
%
|
|
|
|
:- pred actually_read_module_int0(globals::in, path_name_and_stream::in,
|
|
module_name::in, list(prog_context)::in,
|
|
read_module_and_timestamps::in, maybe(io.res(timestamp))::out,
|
|
maybe(parse_tree_int0)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_int0(Globals, FileNameAndStream,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
MaybeParseTreeInt0, Errors, !IO) :-
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, MaybeModuleTimestampRes),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_int0_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt0, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, MaybeModuleTimestampRes),
|
|
MaybeParseTreeInt0 = no
|
|
).
|
|
|
|
:- pred actually_read_module_int1(globals::in, path_name_and_stream::in,
|
|
module_name::in, list(prog_context)::in,
|
|
read_module_and_timestamps::in, maybe(io.res(timestamp))::out,
|
|
maybe(parse_tree_int1)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_int1(Globals, FileNameAndStream,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
MaybeParseTreeInt1, Errors, !IO) :-
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, MaybeModuleTimestampRes),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_int1_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt1, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, MaybeModuleTimestampRes),
|
|
MaybeParseTreeInt1 = no
|
|
).
|
|
|
|
:- pred actually_read_module_int2(globals::in, path_name_and_stream::in,
|
|
module_name::in, list(prog_context)::in,
|
|
read_module_and_timestamps::in, maybe(io.res(timestamp))::out,
|
|
maybe(parse_tree_int2)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_int2(Globals, FileNameAndStream,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
MaybeParseTreeInt2, Errors, !IO) :-
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, MaybeModuleTimestampRes),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_int2_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt2, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, MaybeModuleTimestampRes),
|
|
MaybeParseTreeInt2 = no
|
|
).
|
|
|
|
:- pred actually_read_module_int3(globals::in, path_name_and_stream::in,
|
|
module_name::in, list(prog_context)::in,
|
|
read_module_and_timestamps::in, maybe(io.res(timestamp))::out,
|
|
maybe(parse_tree_int3)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_int3(Globals, FileNameAndStream,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
ReadModuleAndTimestamps, MaybeModuleTimestampRes,
|
|
MaybeParseTreeInt3, Errors, !IO) :-
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, MaybeModuleTimestampRes),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_int3_file(Globals, FileName, FileStr, FileStrLen,
|
|
DefaultModuleName, DefaultExpectationContexts,
|
|
MaybeParseTreeInt3, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, MaybeModuleTimestampRes),
|
|
MaybeParseTreeInt3 = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% actually_read_module_{plain,trans}_opt(Globals, FileNameAndStream,
|
|
% DefaultModuleName, ParseTree, Errors, !IO):
|
|
%
|
|
% Analogous to actually_read_module_src, but opens the specified kind
|
|
% of optimization file for DefaultModuleName.
|
|
%
|
|
|
|
:- pred actually_read_module_plain_opt(globals::in, path_name_and_stream::in,
|
|
module_name::in, maybe(parse_tree_plain_opt)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_plain_opt(_Globals, FileNameAndStream, DefaultModuleName,
|
|
MaybeParseTreePlainOpt, Errors, !IO) :-
|
|
ReadModuleAndTimestamps = always_read_module(do_not_return_timestamp),
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, _),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_plain_opt_file(FileName, FileStr, FileStrLen, DefaultModuleName,
|
|
MaybeParseTreePlainOpt, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, _),
|
|
MaybeParseTreePlainOpt = no
|
|
).
|
|
|
|
:- pred actually_read_module_trans_opt(globals::in, path_name_and_stream::in,
|
|
module_name::in, maybe(parse_tree_trans_opt)::out, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
actually_read_module_trans_opt(_Globals, FileNameAndStream, DefaultModuleName,
|
|
MaybeParseTreeTransOpt, Errors, !IO) :-
|
|
ReadModuleAndTimestamps = always_read_module(do_not_return_timestamp),
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
ReadFileResult, !IO),
|
|
(
|
|
ReadFileResult = drfr_ok(FileStr, FileStrLen, _),
|
|
FileNameAndStream = path_name_and_stream(FileName, _FileStream),
|
|
parse_trans_opt_file(FileName, FileStr, FileStrLen, DefaultModuleName,
|
|
MaybeParseTreeTransOpt, Errors)
|
|
;
|
|
ReadFileResult = drfr_error(Errors, _),
|
|
MaybeParseTreeTransOpt = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type do_read_file_result
|
|
---> drfr_ok(
|
|
% The contents of the file, and its length.
|
|
%
|
|
% XXX When the compiler is compiled to C, this string will be
|
|
% byte-for-byte identical to the contents of the file.
|
|
% But when the compiler is compiled to C# or Java, the byte
|
|
% sequence in the file will need to be TRANSLATED from UTF-8
|
|
% to UTF-16. When the only reason we want to read e.g. a .intN
|
|
% file is to compare its old contents to its new intended
|
|
% contents, which will have to be converted from its UTF-16
|
|
% version to UTF-8 anyway, this is wasteful, because it
|
|
% requires the sequence
|
|
%
|
|
% - create new contents as UTF-16
|
|
% - read old contents of the file, which is UTF-8
|
|
% - convert old contents to UTF-16 (CONVERSION 1)
|
|
% - test whether the old UTF-16 contents as the same as the new
|
|
% - if the same then
|
|
% - done
|
|
% - otherwise
|
|
% - convert the UTF-16 new contents to UTF-8 (CONVERSION 2)
|
|
% - write out the resulting UTF-8 string
|
|
%
|
|
% whereas if we returned the raw UTF-8 string directly as
|
|
% a byte array, we could use the sequence
|
|
%
|
|
% - create new contents as UTF-16
|
|
% - convert the UTF-16 new contents to UTF-8 (CONVERSION 1)
|
|
% - read old contents of the file, which is UTF-8
|
|
% - test whether the old UTF-8 contents as the same as the new
|
|
% - if the same then
|
|
% - done
|
|
% - otherwise
|
|
% - write out the new UTF-8 string
|
|
%
|
|
% This does the same number of conversions in the case where
|
|
% the old and the new contents are the same, i.e. one
|
|
% (though that conversion is in the opposite direction,
|
|
% and the string it is applied to may be either shorter
|
|
% or longer), but in the frequent case of the new contents
|
|
% differing from the old, it does one fewer conversion.
|
|
drfro_file_contents :: string,
|
|
drfro_num_code_units :: int,
|
|
|
|
% The timestamp of the file, if our caller requested it,
|
|
drfro_maybe_file_timestamp :: maybe(io.res(timestamp))
|
|
)
|
|
; drfr_error(
|
|
drfre_errors :: read_module_errors,
|
|
|
|
% The timestamp of the file, if our caller requested it,
|
|
% XXX This should not be needed if we can't read the file,
|
|
% since it means nothing useful.
|
|
drfre_maybe_file_timestamp :: maybe(io.res(timestamp))
|
|
).
|
|
|
|
:- pred do_actually_read_file(path_name_and_stream::in,
|
|
read_module_and_timestamps::in, do_read_file_result::out,
|
|
io::di, io::uo) is det.
|
|
|
|
do_actually_read_file(FileNameAndStream, ReadModuleAndTimestamps,
|
|
Result, !IO) :-
|
|
FileNameAndStream = path_name_and_stream(FileName, FileStream),
|
|
(
|
|
( ReadModuleAndTimestamps = always_read_module(do_return_timestamp)
|
|
; ReadModuleAndTimestamps = do_not_read_module_if_match(_)
|
|
),
|
|
io.file.file_modification_time(FileName, TimestampResult, !IO),
|
|
(
|
|
TimestampResult = ok(Timestamp),
|
|
MaybeModuleTimestampRes =
|
|
yes(ok(time_t_to_timestamp(Timestamp)))
|
|
;
|
|
TimestampResult = error(IOError),
|
|
MaybeModuleTimestampRes = yes(error(IOError))
|
|
)
|
|
;
|
|
ReadModuleAndTimestamps = always_read_module(do_not_return_timestamp),
|
|
MaybeModuleTimestampRes = no
|
|
),
|
|
( if
|
|
ReadModuleAndTimestamps = do_not_read_module_if_match(OldTimestamp),
|
|
MaybeModuleTimestampRes = yes(ok(OldTimestamp))
|
|
then
|
|
% XXX Currently smart recompilation won't work
|
|
% if ModuleName \= DefaultModuleName.
|
|
% In that case, smart recompilation will be disabled
|
|
% and actually_read_module should never be passed an old timestamp.
|
|
Result = drfr_error(init_read_module_errors, MaybeModuleTimestampRes)
|
|
else
|
|
io.read_file_as_string_and_num_code_units(FileStream,
|
|
MaybeResult, !IO),
|
|
(
|
|
MaybeResult = ok2(FileString, NumCodeUnits),
|
|
FileStringLen = string.length(FileString),
|
|
( if NumCodeUnits = FileStringLen then
|
|
true
|
|
else
|
|
Msg = string.format(
|
|
"NumCodeUnits = %d, FileStringLen = %d\n<<<\n%s>>>\n",
|
|
[i(NumCodeUnits), i(FileStringLen), s(FileString)]),
|
|
unexpected($pred, Msg)
|
|
),
|
|
Result = drfr_ok(FileString, NumCodeUnits, MaybeModuleTimestampRes)
|
|
;
|
|
MaybeResult = error2(_PartialStr, _PartialLen, ErrorCode),
|
|
io.error_message(ErrorCode, ErrorMsg0),
|
|
ErrorMsg = "I/O error: " ++ ErrorMsg0,
|
|
io_error_to_read_module_errors(frme_could_not_read_file,
|
|
phase_read_files, ErrorMsg, Errors, !IO),
|
|
Result = drfr_error(Errors, MaybeModuleTimestampRes)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type maybe_file_and_stream
|
|
---> mfas_ok(path_name_and_stream)
|
|
; mfas_error(read_module_errors).
|
|
|
|
% search_for_file_and_stream_or_error(Dirs, FileName,
|
|
% MaybeFilePathNameAndStream, !IO):
|
|
%
|
|
% Search Dirs for FileName. If found, return the path name of the file
|
|
% and an open input stream reading from that file. Closing that stream
|
|
% is the caller's responsibility.
|
|
%
|
|
:- pred search_for_file_and_stream_or_error(search_auth_dirs::in,
|
|
file_name::in, maybe_file_and_stream::out, io::di, io::uo) is det.
|
|
|
|
search_for_file_and_stream_or_error(SearchAuthDirs, FileName0,
|
|
MaybeFileNameAndStream, !IO) :-
|
|
% NB. Consider using search_for_file_returning_dir_and_stream,
|
|
% which does not canonicalise the path, and is therefore more efficient.
|
|
search_for_file_and_stream(SearchAuthDirs, FileName0,
|
|
_SearchDirs, RawMaybeFileNameAndStream, !IO),
|
|
(
|
|
RawMaybeFileNameAndStream = ok(FileNameAndStream),
|
|
MaybeFileNameAndStream = mfas_ok(FileNameAndStream)
|
|
;
|
|
RawMaybeFileNameAndStream = error(ErrorMsg),
|
|
% XXX SEARCH_ERROR _SearchDirs
|
|
io_error_to_read_module_errors(frme_could_not_find_file,
|
|
phase_find_files(FileName0), ErrorMsg, Errors, !IO),
|
|
MaybeFileNameAndStream = mfas_error(Errors)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_default_module_name_for_file(FileName, FileNameDotM,
|
|
DefaultModuleName, !IO) :-
|
|
( if dir.basename(FileName, BaseFileNamePrime) then
|
|
BaseFileName = BaseFileNamePrime
|
|
else
|
|
BaseFileName = ""
|
|
),
|
|
have_source_file_map(HaveMap, !IO),
|
|
(
|
|
HaveMap = not_found,
|
|
file_name_to_module_name(BaseFileName, DefaultModuleName)
|
|
;
|
|
HaveMap = found,
|
|
lookup_source_file_maybe_module(FileNameDotM, MaybeModuleName, !IO),
|
|
(
|
|
MaybeModuleName = yes(DefaultModuleName)
|
|
;
|
|
MaybeModuleName = no,
|
|
file_name_to_module_name(BaseFileName, DefaultModuleName)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type read_done_msg
|
|
---> rdm_none
|
|
% Do not print a "done" message.
|
|
; rdm_progress(io.text_output_stream).
|
|
% Print a "done" message to the specified progress output stream.
|
|
|
|
%---------------------%
|
|
|
|
:- pred read_module_begin_from_file(io.text_output_stream::in,
|
|
interface_ext::in, globals::in, read_reason_msg::in, maybe_search::in,
|
|
file_name::in, file_name::in, module_name::out, read_done_msg::out,
|
|
search_auth_dirs::out, io::di, io::uo) is det.
|
|
|
|
read_module_begin_from_file(ProgressStream, InterfaceExt, Globals,
|
|
ReadReasonMsg, Search, FileName, FileNameDotM, DefaultModuleName,
|
|
ReadDoneMsg, SearchAuthDirs, !IO) :-
|
|
% XXX Do not assume that the name of FileNameDotM guarantees
|
|
% that the string it holds ends in ".m".
|
|
get_default_module_name_for_file(FileName, FileNameDotM,
|
|
DefaultModuleName, !IO),
|
|
% The rest of this predicate should be kept in sync
|
|
% with read_module_begin.
|
|
(
|
|
Search = do_search,
|
|
SearchAuthDirs = get_search_auth_interface_dirs(InterfaceExt, Globals)
|
|
;
|
|
Search = do_not_search,
|
|
SearchAuthDirs = search_auth_cur_dir
|
|
),
|
|
output_read_reason_msg(ProgressStream, Globals, ReadReasonMsg,
|
|
FileNameDotM, ReadDoneMsg, !IO).
|
|
|
|
:- pred read_module_begin(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, maybe_search::in, module_name::in, file_kind::in,
|
|
file_name::out, read_done_msg::out, search_auth_dirs::out,
|
|
io::di, io::uo) is det.
|
|
|
|
read_module_begin(ProgressStream, Globals, ReadReasonMsg, Search,
|
|
ModuleName, FileKind, FileName, ReadDoneMsg, SearchAuthDirs, !IO) :-
|
|
(
|
|
FileKind = fk_src,
|
|
% For the call to module_name_to_source_file_name, the value of Search
|
|
% does not matter.
|
|
module_name_to_source_file_name(ModuleName, FileName, !IO),
|
|
(
|
|
Search = do_search,
|
|
SearchAuthDirs = get_search_auth_interface_dirs(ife_src, Globals)
|
|
;
|
|
Search = do_not_search,
|
|
SearchAuthDirs = search_auth_cur_dir
|
|
)
|
|
;
|
|
FileKind = fk_int(IntFileKind),
|
|
int_file_kind_to_extension(IntFileKind, _ExtStr, Ext),
|
|
% The rest of this predicate should be kept in sync
|
|
% with read_module_begin_from_file.
|
|
% NOTE: we use the same code for fk_int and fk_opt, but we need
|
|
% separate copies, because the calls to module_name_to_search_file_name
|
|
% check whether the insts of Ext match the values of SearchWhichDirs.
|
|
(
|
|
Search = do_search,
|
|
SearchWhichDirs = search_interface_dirs,
|
|
% XXX LEGACY
|
|
module_name_to_search_file_name(Globals, $pred, Ext, ModuleName,
|
|
SearchWhichDirs, SearchAuthDirs, FileName, _FileNameProposed)
|
|
;
|
|
Search = do_not_search,
|
|
% XXX LEGACY
|
|
module_name_to_file_name(Globals, $pred, Ext,
|
|
ModuleName, FileName, _FileNameProposed),
|
|
SearchAuthDirs = search_auth_cur_dir
|
|
)
|
|
;
|
|
FileKind = fk_opt(OptFileKind),
|
|
opt_file_kind_to_extension(OptFileKind, _ExtStr, Ext),
|
|
% The rest of this predicate should be kept in sync
|
|
% with read_module_begin_from_file.
|
|
(
|
|
Search = do_search,
|
|
SearchWhichDirs = search_intermod_dirs,
|
|
% XXX LEGACY
|
|
module_name_to_search_file_name(Globals, $pred, Ext, ModuleName,
|
|
SearchWhichDirs, SearchAuthDirs, FileName, _FileNameProposed)
|
|
;
|
|
Search = do_not_search,
|
|
% XXX LEGACY
|
|
module_name_to_file_name(Globals, $pred, Ext,
|
|
ModuleName, FileName, _FileNameProposed),
|
|
SearchAuthDirs = search_auth_cur_dir
|
|
)
|
|
),
|
|
output_read_reason_msg(ProgressStream, Globals, ReadReasonMsg,
|
|
FileName, ReadDoneMsg, !IO).
|
|
|
|
:- pred read_module_end_module(io.text_output_stream::in, globals::in,
|
|
maybe_file_and_stream::in, file_kind::in, read_done_msg::in,
|
|
file_name::in, file_name::out,
|
|
maybe(io.res(timestamp))::in, maybe(timestamp)::out,
|
|
read_module_errors::in, read_module_errors::out, io::di, io::uo) is det.
|
|
|
|
read_module_end_module(ProgressStream, Globals, MaybeFileNameAndStream,
|
|
FileKind, ReadDoneMsg, FileName0, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO) :-
|
|
% The code of read_module_end_module and read_module_end_file
|
|
% should be kept in sync.
|
|
(
|
|
MaybeFileNameAndStream = mfas_ok(path_name_and_stream(FileName, _))
|
|
;
|
|
MaybeFileNameAndStream = mfas_error(_),
|
|
FileName = FileName0
|
|
),
|
|
check_timestamp_report_if_needed_and_missing(Globals, FileName0,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors1, !IO),
|
|
handle_any_read_module_errors(FileKind, ReadDoneMsg, Errors1, Errors, !IO),
|
|
globals.lookup_bool_option(Globals, detailed_statistics, Statistics),
|
|
maybe_report_stats(ProgressStream, Statistics, !IO).
|
|
|
|
:- pred read_module_end_file(globals::in, file_kind::in, read_done_msg::in,
|
|
file_name::in, maybe(io.res(timestamp))::in, maybe(timestamp)::out,
|
|
read_module_errors::in, read_module_errors::out, io::di, io::uo) is det.
|
|
|
|
read_module_end_file(Globals, FileKind, ReadDoneMsg, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors, !IO) :-
|
|
% The code of read_module_end_module and read_module_end_file
|
|
% should be kept in sync.
|
|
check_timestamp_report_if_needed_and_missing(Globals, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, Errors0, Errors1, !IO),
|
|
% Unlike read_module_end_module, we assume do_not_ignore_errors.
|
|
handle_any_read_module_errors(FileKind, ReadDoneMsg,
|
|
Errors1, Errors, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred handle_any_read_module_errors(file_kind::in, read_done_msg::in,
|
|
read_module_errors::in, read_module_errors::out, io::di, io::uo) is det.
|
|
|
|
handle_any_read_module_errors(FileKind, ReadDoneMsg, Errors0, Errors, !IO) :-
|
|
FatalErrors0 = Errors0 ^ rm_fatal_errors,
|
|
NonFatalErrors0 = Errors0 ^ rm_nonfatal_errors,
|
|
( if
|
|
( set.is_non_empty(FatalErrors0)
|
|
; set.is_non_empty(NonFatalErrors0)
|
|
)
|
|
then
|
|
( if set.is_non_empty(FatalErrors0) then
|
|
( if set.contains(FatalErrors0, frme_could_not_open_file) then
|
|
Msg = "not found.\n"
|
|
else
|
|
Msg = "fatal error(s).\n"
|
|
)
|
|
else
|
|
% Any errors must be nonfatal. Are they syntax errors?
|
|
( if
|
|
( set.contains(NonFatalErrors0,
|
|
rme_no_module_decl_at_start)
|
|
; set.contains(NonFatalErrors0,
|
|
rme_no_section_decl_at_start)
|
|
; set.contains(NonFatalErrors0,
|
|
rme_end_module_not_at_end_of_src)
|
|
; set.contains(NonFatalErrors0,
|
|
rme_unexpected_term_in_int_or_opt)
|
|
; set.contains(NonFatalErrors0, rme_could_not_read_term)
|
|
; set.contains(NonFatalErrors0, rme_could_not_parse_item)
|
|
)
|
|
then
|
|
Msg = "parse error(s).\n"
|
|
else
|
|
Msg = "nonfatal error(s).\n"
|
|
)
|
|
),
|
|
output_read_done_msg(ReadDoneMsg, Msg, !IO),
|
|
(
|
|
FileKind = fk_opt(_),
|
|
Errors = Errors0
|
|
;
|
|
( FileKind = fk_src
|
|
; FileKind = fk_int(_)
|
|
),
|
|
Errors = Errors0
|
|
)
|
|
else
|
|
Errors = Errors0,
|
|
% XXX CLEANUP This should just print "done".
|
|
output_read_done_msg(ReadDoneMsg, "successful parse.\n", !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred output_read_reason_msg(io.text_output_stream::in, globals::in,
|
|
read_reason_msg::in, string::in, read_done_msg::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_read_reason_msg(ProgressStream, Globals, ReadReasonMsg, FileName,
|
|
ReadDoneMsg, !IO) :-
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
(
|
|
VeryVerbose = no,
|
|
ReadDoneMsg = rdm_none
|
|
;
|
|
VeryVerbose = yes,
|
|
(
|
|
ReadReasonMsg = rrm_file,
|
|
string.format("%% Reading `%s'... ", [s(FileName)], Msg)
|
|
;
|
|
ReadReasonMsg = rrm_std,
|
|
string.format("%% Reading `%s'... ", [s(FileName)], Msg)
|
|
;
|
|
ReadReasonMsg = rrm_old,
|
|
string.format("%% Reading old version of `%s'... ",
|
|
[s(FileName)], Msg)
|
|
;
|
|
ReadReasonMsg = rrm_get_deps,
|
|
string.format("%% Getting dependencies for `%s'... ",
|
|
[s(FileName)], Msg)
|
|
),
|
|
ReadDoneMsg = rdm_progress(ProgressStream),
|
|
io.write_string(ProgressStream, Msg, !IO),
|
|
io.flush_output(ProgressStream, !IO)
|
|
).
|
|
|
|
:- pred output_read_done_msg(read_done_msg::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_read_done_msg(ReadDoneMsg, Msg, !IO) :-
|
|
(
|
|
ReadDoneMsg = rdm_none
|
|
;
|
|
ReadDoneMsg = rdm_progress(ProgressStream),
|
|
io.write_string(ProgressStream, Msg, !IO),
|
|
io.flush_output(ProgressStream, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
return_timestamp_if_needed(ReturnTimestamp, MaybeTimestamp0, MaybeTimestamp) :-
|
|
(
|
|
ReturnTimestamp = do_return_timestamp,
|
|
(
|
|
MaybeTimestamp0 = no,
|
|
% This can happen if
|
|
%
|
|
% - code that does not need a timestamp enters a parse tree
|
|
% into the have_module_map, and then later
|
|
%
|
|
% - code that does need a timestamp finds the parse tree there.
|
|
%
|
|
% We abort because I (zs) don't think this should happen:
|
|
% the use of have_parse_tree_maps in module_imports.m never
|
|
% needs timestamps, the smart recompilation modules always
|
|
% need timestamps, but the have_parse_tree_maps they use
|
|
% are completely separate (for now). If it turns out I am wrong,
|
|
% or we *do* want these two subsystems to use the same
|
|
% have_parse_tree_maps, then there are two obvious possibilities:
|
|
% either *always* store the timestamp of a file we read in, or
|
|
% get the timestamp from the OS the first time it is needed
|
|
% (have_parse_tree_maps entries include the filename, so this
|
|
% is possible). The first solution is simpler, the second can
|
|
% execute fewer system calls.
|
|
unexpected($pred, "do_return_timestamp but no timestamp")
|
|
;
|
|
MaybeTimestamp0 = yes(_),
|
|
MaybeTimestamp = MaybeTimestamp0
|
|
)
|
|
;
|
|
ReturnTimestamp = do_not_return_timestamp,
|
|
MaybeTimestamp = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred check_timestamp_report_if_needed_and_missing(globals::in,
|
|
file_name::in, maybe(io.res(timestamp))::in, maybe(timestamp)::out,
|
|
read_module_errors::in, read_module_errors::out, io::di, io::uo) is det.
|
|
|
|
check_timestamp_report_if_needed_and_missing(Globals, FileName,
|
|
MaybeTimestampRes, MaybeTimestamp, !Errors, !IO) :-
|
|
(
|
|
MaybeTimestampRes = yes(TimestampRes),
|
|
(
|
|
TimestampRes = ok(Timestamp),
|
|
MaybeTimestamp = yes(Timestamp)
|
|
;
|
|
TimestampRes = error(IOError),
|
|
MaybeTimestamp = no,
|
|
globals.lookup_bool_option(Globals, smart_recompilation,
|
|
SmartRecompilation),
|
|
% Should we print the warning if smart recompilation has
|
|
% already been disabled by an earlier error? At the moment, we do.
|
|
(
|
|
SmartRecompilation = yes,
|
|
record_and_report_missing_timestamp(Globals, FileName,
|
|
IOError, !Errors, !IO)
|
|
;
|
|
SmartRecompilation = no
|
|
)
|
|
)
|
|
;
|
|
MaybeTimestampRes = no,
|
|
MaybeTimestamp = no
|
|
).
|
|
|
|
:- pred record_and_report_missing_timestamp(globals::in, file_name::in,
|
|
io.error::in, read_module_errors::in, read_module_errors::out,
|
|
io::di, io::uo) is det.
|
|
|
|
record_and_report_missing_timestamp(Globals, FileName, IOError,
|
|
!Errors, !IO) :-
|
|
io_set_disable_smart_recompilation(disable_smart_recompilation, !IO),
|
|
io_set_disable_generate_item_version_numbers(disable_item_version_numbers,
|
|
!IO),
|
|
globals.lookup_bool_option(Globals, warn_smart_recompilation, Warn),
|
|
(
|
|
Warn = yes,
|
|
io.error_message(IOError, IOErrorMsg),
|
|
Pieces = [words("Warning: cannot find modification time for"),
|
|
quote(FileName), suffix(":"), nl_indent_delta(1),
|
|
words(IOErrorMsg), suffix("."), nl_indent_delta(-1),
|
|
words("Smart recompilation will not work."), nl],
|
|
Severity = severity_warning(warn_smart_recompilation),
|
|
Spec = no_ctxt_spec($pred, Severity, phase_read_files, Pieces),
|
|
add_nonfatal_error(rme_cannot_find_modify_time, [Spec], !Errors)
|
|
;
|
|
Warn = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.read_modules.
|
|
%---------------------------------------------------------------------------%
|