mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-11 20:03:28 +00:00
Estimated hours taken: 120
Branches: main
Library changes required to make the compiler work on Windows
without Cygwin. (Compiler changes to come separately).
library/dir.m:
Handle Windows-style paths.
Change the determinism of dir.basename and dir.split_name.
dir.basename now fails for root directories (a new function
dir.basename_det calls error/1 rather than failing).
dir.split_name fails for root directories or if the pathname
passed doesn't contain a directory separator.
Add predicates dir.make_directory, dir.path_name_is_absolute
and dir.path_name_is_root_directory.
Add a multi predicate dir.is_directory separator which
returns all separators for the platform (including '/' on
Windows), not just the standard one.
Add a function dir.parent_directory (returns "..").
Add dir.foldl2 and dir.recursive_foldl2, to iterate through
the entries in a directory (and maybe its subdirectories).
Change '/' to correctly handle Windows paths of the form
"C:"/"foo" and "\"/"foo".
Don't add repeated directory separators in '/'.
library/io.m:
Add io.file_type and io.check_file_accessibility.
Add predicates to deal with symlinks -- io.have_symlinks,
io.make_symlink and io.follow_symlink.
Add io.file_id for use by dir.foldl2 to detect
symlink loops. This is a bit low level, so it's
not included in the user documentation.
Add io.(binary_)input_stream_foldl2_io_maybe_stop, which
is like io.(binary_)input_stream_foldl2_io, but allows
stopping part of the way through. This is useful for
implementing `diff'-like functionality to replace
mercury_update_interface.
Use Windows-style paths when generating temporary file
names on Windows.
Add versions of the predicates to generate error messages
to handle Win32 errors.
Add versions of the predicates to generate error messages
which take a system error code, rather than looking up
errno. This simplifies things where the error we
are interested in was not from the last system call.
library/exception.m:
Add a predicate finally/6 which performs the same function
as the `finally' clause in languages such as C# and Java.
Add predicates try_det, try_io_det and try_store_det,
which only have one mode so they are more convenient
to pass to promise_only solution.
library/Mmakefile:
Add dependencies on runtime/mercury_conf.h for files which
use the MR_HAVE_* macros.
library/string.m:
Add a function version of string__index.
NEWS:
Document the new predicates and functions and the change
of determinism of dir.split_name and dir.basename.
configure.in:
runtime/mercury_conf.h.in:
Test for lstat, mkdir, symlink and readlink.
runtime/mercury_conf_param.h:
Add a macro MR_BROKEN_ST_INO, which is true if the st_ino
field of `struct stat' is garbage. Currently defined iff
MR_WIN32 is defined.
compiler/compile_target_code.m:
compiler/modules.m:
compiler/options_file.m:
compiler/prog_io.m:
compiler/source_file_map.m:
Changes required by the change of determinism of
dir.split_name and dir.basename.
tests/hard_coded/Mmakefile:
tests/hard_coded/dir_test.{m,exp,exp2}:
Test case.
217 lines
6.4 KiB
Mathematica
217 lines
6.4 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2002-2003 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: source_file_map.m
|
|
% Author: stayl
|
|
%
|
|
% Maintain a mapping from module name to source file name.
|
|
%-----------------------------------------------------------------------------%
|
|
:- module parse_tree__source_file_map.
|
|
|
|
:- interface.
|
|
|
|
:- import_module parse_tree__prog_data.
|
|
:- import_module parse_tree__prog_io.
|
|
|
|
:- import_module bool, io, list.
|
|
|
|
% lookup_module_source_file(ModuleName, FileName, FileNameIsMapped).
|
|
%
|
|
% FileNameIsMapped is `yes' if ModuleName is in
|
|
% the Mercury.modules file.
|
|
:- pred lookup_module_source_file(module_name::in, file_name::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
% Return `yes' if there is a valid Mercury.modules file.
|
|
:- pred have_source_file_map(bool::out, io__state::di, io__state::uo) is det.
|
|
|
|
% Return the default fully-qualified source file name.
|
|
:- func default_source_file(module_name) = file_name.
|
|
|
|
% Given a list of file names, produce the Mercury.modules file.
|
|
:- pred write_source_file_map(list(string)::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs__globals.
|
|
:- import_module libs__options.
|
|
:- import_module parse_tree__modules.
|
|
:- import_module parse_tree__prog_out.
|
|
:- import_module parse_tree__prog_util.
|
|
|
|
:- import_module char, dir, map, std_util, string.
|
|
|
|
lookup_module_source_file(ModuleName, FileName) -->
|
|
get_source_file_map(SourceFileMap),
|
|
{ map__search(SourceFileMap, ModuleName, FileName0) ->
|
|
FileName = FileName0
|
|
;
|
|
FileName = default_source_file(ModuleName)
|
|
}.
|
|
|
|
default_source_file(ModuleName) = BaseFileName ++ ".m" :-
|
|
prog_out__sym_name_to_string(ModuleName, ".", BaseFileName).
|
|
|
|
have_source_file_map(HaveMap) -->
|
|
get_source_file_map(_),
|
|
globals__io_get_globals(Globals),
|
|
{ globals__get_source_file_map(Globals, MaybeSourceFileMap) },
|
|
{ MaybeSourceFileMap = yes(Map), \+ map__is_empty(Map) ->
|
|
HaveMap = yes
|
|
;
|
|
HaveMap = no
|
|
}.
|
|
|
|
% Read the Mercury.modules file (if it exists) to find
|
|
% the mapping from module name to file name.
|
|
:- pred get_source_file_map(source_file_map::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
get_source_file_map(SourceFileMap) -->
|
|
globals__io_get_globals(Globals0),
|
|
{ globals__get_source_file_map(Globals0, MaybeSourceFileMap0) },
|
|
( { MaybeSourceFileMap0 = yes(SourceFileMap0) } ->
|
|
{ SourceFileMap = SourceFileMap0 }
|
|
;
|
|
io__open_input(modules_file_name, OpenRes),
|
|
(
|
|
{ OpenRes = ok(Stream) },
|
|
io__set_input_stream(Stream, OldStream),
|
|
read_source_file_map([], map__init, SourceFileMap),
|
|
io__set_input_stream(OldStream, _),
|
|
io__close_input(Stream)
|
|
;
|
|
{ OpenRes = error(_) },
|
|
% If the file doesn't exist, then the mapping is empty.
|
|
{ SourceFileMap = map__init }
|
|
),
|
|
globals__io_get_globals(Globals1),
|
|
{ globals__set_source_file_map(Globals1,
|
|
yes(SourceFileMap), Globals2) },
|
|
{ unsafe_promise_unique(Globals2, Globals) },
|
|
globals__io_set_globals(Globals)
|
|
).
|
|
|
|
:- pred read_source_file_map(list(char)::in, source_file_map::in,
|
|
source_file_map::out, io__state::di, io__state::uo) is det.
|
|
|
|
read_source_file_map(ModuleChars, Map0, Map) -->
|
|
read_until_char('\t', [], ModuleCharsResult),
|
|
(
|
|
{ ModuleCharsResult = ok(RevModuleChars) },
|
|
{ string__from_rev_char_list(RevModuleChars, ModuleStr) },
|
|
{ string_to_sym_name(ModuleStr, ".", ModuleName) },
|
|
read_until_char('\n', [], FileNameCharsResult),
|
|
(
|
|
{ FileNameCharsResult = ok(FileNameChars) },
|
|
{ string__from_rev_char_list(FileNameChars,
|
|
FileName) },
|
|
{ map__set(Map0, ModuleName, FileName, Map1) },
|
|
read_source_file_map(ModuleChars, Map1, Map)
|
|
;
|
|
{ FileNameCharsResult = eof },
|
|
{ Map = Map0 },
|
|
io__set_exit_status(1),
|
|
io__write_string(
|
|
"mercury_compile: unexpected end of file in Mercury.modules file.\n")
|
|
;
|
|
{ FileNameCharsResult = error(Error) },
|
|
{ Map = Map0 },
|
|
io__set_exit_status(1),
|
|
io__write_string(
|
|
"mercury_compile: error in Mercury.modules file: "),
|
|
io__write_string(io__error_message(Error)),
|
|
io__nl
|
|
)
|
|
;
|
|
{ ModuleCharsResult = eof },
|
|
{ Map = Map0 }
|
|
;
|
|
{ ModuleCharsResult = error(Error) },
|
|
{ Map = Map0 },
|
|
io__set_exit_status(1),
|
|
io__write_string(
|
|
"mercury_compile: error in Mercury.modules file: "),
|
|
io__write_string(io__error_message(Error)),
|
|
io__nl
|
|
).
|
|
|
|
:- pred read_until_char(char::in, list(char)::in, io__result(list(char))::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
read_until_char(EndChar, Chars0, Result) -->
|
|
io__read_char(CharRes),
|
|
(
|
|
{ CharRes = ok(Char) },
|
|
( { Char = EndChar } ->
|
|
{ Result = ok(Chars0) }
|
|
;
|
|
read_until_char(EndChar, [Char | Chars0], Result)
|
|
)
|
|
;
|
|
{ CharRes = eof },
|
|
{ Result = ( Chars0 = [] -> eof ; ok(Chars0) ) }
|
|
;
|
|
{ CharRes = error(Error) },
|
|
{ Result = error(Error) }
|
|
).
|
|
|
|
write_source_file_map(FileNames) -->
|
|
{ ModulesFileName = modules_file_name },
|
|
io__open_output(ModulesFileName, OpenRes),
|
|
(
|
|
{ OpenRes = ok(Stream) },
|
|
list__foldl(write_source_file_map_2(Stream), FileNames),
|
|
io__close_output(Stream)
|
|
;
|
|
{ OpenRes = error(Error) },
|
|
io__set_exit_status(1),
|
|
io__write_string("mercury_compile: error opening `"),
|
|
io__write_string(ModulesFileName),
|
|
io__write_string("' for output: "),
|
|
io__write_string(io__error_message(Error))
|
|
).
|
|
|
|
:- pred write_source_file_map_2(io__output_stream::in, file_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
write_source_file_map_2(MapStream, FileName) -->
|
|
find_module_name(FileName, MaybeModuleName),
|
|
(
|
|
{ MaybeModuleName = yes(ModuleName) },
|
|
{ string__remove_suffix(FileName, ".m", PartialFileName0) ->
|
|
PartialFileName = PartialFileName0
|
|
;
|
|
PartialFileName = FileName
|
|
},
|
|
{ file_name_to_module_name(dir__basename_det(PartialFileName),
|
|
DefaultModuleName) },
|
|
(
|
|
% Only include a module in the mapping if the
|
|
% name doesn't match the default.
|
|
{ dir__dirname(PartialFileName) =
|
|
dir__this_directory `with_type` string },
|
|
{ ModuleName = DefaultModuleName }
|
|
->
|
|
[]
|
|
;
|
|
io__set_output_stream(MapStream, OldStream),
|
|
prog_out__write_sym_name(ModuleName),
|
|
io__write_string("\t"),
|
|
io__write_string(FileName),
|
|
io__nl,
|
|
io__set_output_stream(OldStream, _)
|
|
)
|
|
;
|
|
{ MaybeModuleName = no }
|
|
).
|
|
|
|
:- func modules_file_name = string.
|
|
|
|
modules_file_name = "Mercury.modules".
|