[m-rev.] for review: Allow external files to be included in foreign_decl and foreign_code.

Peter Wang novalazy at gmail.com
Mon Mar 17 17:18:11 AEDT 2014


On Sat, 15 Mar 2014 15:59:48 +1100, Paul Bone <paul at bone.id.au> wrote:
> On Thu, Mar 13, 2014 at 03:28:17PM +1100, Peter Wang wrote:
> > 
> > compiler/file_names.m:
> > 	Add a convenience to get a module's source file name.
> > 
> 
> Missing word?
> 

No, but I'll change it.

> > 	Add make_include_file_path.
> > 
> > 	Reorder a predicate.
> 
> reorder it's contents or it's position with respect to other predicates?
> 

The latter.

> > diff --git a/compiler/elds_to_erlang.m b/compiler/elds_to_erlang.m
> > index c91151b..3a9b808 100644
> > --- a/compiler/elds_to_erlang.m
> > +++ b/compiler/elds_to_erlang.m
> > @@ -29,7 +30,8 @@
> >      % and exported foreign_decls to the corresponding .hrl file.
> >      % The file names are determined by the module name.
> >      %
> > -:- pred output_elds(module_info::in, elds::in, io::di, io::uo) is det.
> > +:- pred output_elds(module_info::in, elds::in, bool::out, io::di, io::uo)
> > +    is det.
> 
> Would it be better to create a new type to represent the meaning of the bool
> output.  I guess this is for success/failure:
> 
>     :- type success
>         --->    success
>         ;       failure.
> 
> Although this is equivalent to bool it allows someone reading the
> code to clearly see if true means success or if true meas failure - by not
> using true/false or yes/no at all.
> 

Right, but the compiler already uses bool for success in quite a number
of places so I didn't want to introduce a new convention.  Not in this
commit anyway.

> > diff --git a/compiler/make.module_dep_file.m b/compiler/make.module_dep_file.m
> > index bc4ea81..8c2bb40 100644
> > --- a/compiler/make.module_dep_file.m
> > +++ b/compiler/make.module_dep_file.m
> > @@ -63,6 +63,22 @@
> >  :- import_module term.
> >  :- import_module term_io.
> >  
> > +    % The version 1 module_dep file format is the same as version 2 except that
> > +    % it does not include a list of files included by `pragma foreign_decl' and
> > +    % `pragma foreign_code'. We continue to write version 1 files when
> > +    % possible.
> > +    %
> 
> Why bother?  I don't think that there's a need to share .dep files between
> Mercury versions, so it's be simpler to always use version 2 files.

It ensures I didn't break parsing of version 1 files.  It may be very
slightly handy for developers jumping between older and newer versions
of the compiler (git bisect?).  It's not a great bother.

> > +        SearchResult = error(_),
> > +        % XXX should use the error message.
> > +        read_module_dependencies_remake(Globals, RebuildModuleDeps, ModuleName,
> > +            "couldn't find `.module_dep' file", !Info, !IO)
> > +    ).
> 
> Did you forget this before committing?

Code movement; I didn't write that.

> > diff --git a/compiler/mercury_compile.m b/compiler/mercury_compile.m
> > index 82626d3..1d51907 100644
> > --- a/compiler/mercury_compile.m
> > +++ b/compiler/mercury_compile.m
> > @@ -1654,18 +1659,24 @@ mercury_compile_after_front_end(NestedSubModules, FindTimestampFiles,
> >              % than stdout.
> >              io.stdout_stream(Stdout, !IO),
> >              output_x86_64_asm(Stdout, X86_64_Asm, !IO),
> > +            Succeeded = yes,
> >              ExtraObjFiles = []
> >          ;
> >              Target = target_erlang,
> >              erlang_backend(!.HLDS, ELDS, !DumpInfo, !IO),
> > -            elds_to_erlang(!.HLDS, ELDS, !IO),
> > +            elds_to_erlang(!.HLDS, ELDS, Succeeded, !IO),
> >              ExtraObjFiles = []
> >          ),
> > +        (
> > +            Succeeded = yes,
> >              recompilation.usage.write_usage_file(!.HLDS, NestedSubModules,
> >                  MaybeTimestamps, !IO),
> >              FindTimestampFiles(ModuleName, TimestampFiles, !IO),
> >              list.foldl(touch_datestamp(Globals), TimestampFiles, !IO)
> >          ;
> > +            Succeeded = no
> > +        )
> 
> I assume this error is raised elsewhere.  I'm not saying that this is wrong,
> just that it looks suspicious and a comment could re-assure the reader of
> the context doesn't make it clear enough.

You mean?

    Succeeded = no
    % An error should have been reported earlier.

> > diff --git a/compiler/mlds_to_java.m b/compiler/mlds_to_java.m
> > index fcf3b90..867a64c 100644
> > --- a/compiler/mlds_to_java.m
> > +++ b/compiler/mlds_to_java.m
> > @@ -5239,14 +5268,16 @@ indent_line(N, !IO) :-
> >      string::in, prog_context::in, io::di, io::uo) is det.
> >  
> >  write_string_with_context_block(Info, Indent, Code, Context, !IO) :-
> > -    indent_line(Info, marker_begin_block, mlds_make_context(Context),
> > -        Indent, !IO),
> > +    indent_line_prog_context(Info, marker_begin_block, Context, Indent, !IO),
> >      io.write_string(Code, !IO),
> >      io.nl(!IO),
> > +    % The num_lines(Code) call is supposed to count the number of lines
> > +    % occupied by Code in the source file. The result will be incorrect if
> > +    % there were any escape sequences representing CR or LF characters --
> > +    % they are expanded out in Code.
> >      Context = context(File, Lines0),
> >      ContextEnd = context(File, Lines0 + num_lines(Code)),
> > -    indent_line(Info, marker_end_block, mlds_make_context(ContextEnd),
> > -        Indent, !IO).
> > +    indent_line_prog_context(Info, marker_end_block, ContextEnd, Indent, !IO).
> 
> I can look into this.  I was wondering the line number markers which are
> used by mfilterjavac are compatible with including foreign code from
> external files, it looks like they are because the context includes File.

The other backends just reset the context to the line in the _target_
file at the end of the foreign code block, which is what you want.
The C and Erlang backends use the line number of the output stream as
tracked by the Mercury standard library.  The C# backend writes "#line
default" which the C# compiler understands.  Either would work for
mfilterjavac.

> > diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m
> > index bc7e0f9..33b6e77 100644
> > --- a/compiler/write_deps_file.m
> > +++ b/compiler/write_deps_file.m
> > @@ -36,6 +36,9 @@
> >      % `.trans_opt' file may depend on.  This is set to `no' if the
> >      % dependency list is not available.
> >      %
> > +    % XXX we do not yet write dependencies on files referenced by pragma
> > +    % foreign_decl or pragma foreign_code
> > +    %
> >  :- pred write_dependency_file(globals::in, module_and_imports::in,
> >      set(module_name)::in, maybe(list(module_name))::in, io::di, io::uo) is det.
> > 
> 
> Does this mean that if my pragma says use the file "foo.c" that mmc doesn't
> know if foo.c depends upon bar.c?  That seems okay to me.  If I
> misunderstand please let me know.
> 

That's true, but not what the comment refers to.

write_deps_file.m deals with mmake.  mmake wouldn't know that foo.m
includes foo_code.c, so if you edit foo_code.c then run mmake foo,
it would incorrectly assume that foo is already up-to-date.
The problem is fixed in the subsequent patch.

> > diff --git a/doc/reference_manual.texi b/doc/reference_manual.texi
> > index a7a34b2..525aa26 100644
> > --- a/doc/reference_manual.texi
> > +++ b/doc/reference_manual.texi
> > @@ -9522,6 +9522,7 @@ The University of Melbourne Mercury implementation supports the following
> >  extensions to the Mercury language:
> >  
> >  @menu
> > +* Foreign include files::       Including foreign code from external files.
> >  * Fact tables::                 Support for very large tables of facts.
> >  @c XXX STM
> >  @c The documentation of STM is commented out because its support is
> > @@ -9545,6 +9546,29 @@ extensions to the Mercury language:
> >  @c     implementation-specific...
> >  @c * Reserved tag::		Support for Herbrand constraint solvers.
> >  
> > + at node Foreign include files
> > + at section Foreign include files
> > +
> > +Foreign declarations and code may be included from external files
> > +using extensions of the @samp{pragma foreign_decl} and
> > + at samp{pragma foreign_code} declarations:
> 
> I'd say "...using the @samp{pragma foreign_decl}...".  This might be an
> implementation specific extension to the Mercury language, but I don't think
> it needs to be explained as an extension to this syntax.

I'll change it to:

    Foreign declarations and code may be included from external files
    in @samp{pragma foreign_decl} and @samp{pragma foreign_code} declarations:

> 
> > +
> > + at example
> > +:- pragma foreign_decl("@var{Lang}", include_file("@var{Path}")).
> > +:- pragma foreign_decl("@var{Lang}", local, include_file("@var{Path}")).
> > +:- pragma foreign_code("@var{Lang}", include_file("@var{Path}")).
> > + at end example
> > +
> > +These have the same effects as the standard forms except that the
> > +contents of the file referenced by @var{Path} are included in place of
> > +the string literal in the last argument, without further interpretation.
> > + at var{Path} may be an absolute path to a file or a path relative to the
> > +directory that contains the source file of the module containing the
> > +declaration. The interpretation of the path is platform-dependent.
> 
> This is a little hard to parse and readers my interpret it to mean that Path
> is either a file (absolute path to a file) or a directory (when relative).
> I suggest:
> 
>     @var{Path} refers to the file to be included during compilation, it may
>     either be absolute or relative to the directory that contains the source
>     file of the module containing the declaration.

I'll change it to:

    @var{Path} may be an absolute path to a file, or a path to a file
    relative to the directory that contains the source file of the
    module containing the declaration.

> > diff --git a/tests/mmc_make/Mmakefile b/tests/mmc_make/Mmakefile
> > index 7fe6bc6..00dc31d 100644
> > --- a/tests/mmc_make/Mmakefile
> > +++ b/tests/mmc_make/Mmakefile
> > @@ -30,6 +32,12 @@ include $(TESTS_DIR)/Mmake.common
> >  
> >  complex_test.log: install_libs
> >  
> > +# Check that included files are identified as dependencies of the target code.
> > +include_file2.runtest: include_file
> > +	sleep 1 && touch inc/code.c inc/code.java inc/code.cs inc/code.erl
> > +	$(MCM) --verbose-make include_file > include_file2.err 2>&1
> > +	grep '^Making Mercury/.*/include_file[.]' include_file2.err
> > +
> 
> s/MCM/MMC ?

MCM

> 
> Please document why this should "sleep 1".

Done.

> 
> Thanks Peter, the rest of the patch looks good.
> 

Thanks for the review.

Peter



More information about the reviews mailing list