[m-rev.] for review: implement pragma foreign_export

Julien Fischer juliensf at csse.unimelb.edu.au
Wed Jul 12 18:34:57 AEST 2006


Estimated hours taken: 12
Branches: main

Implement `:- pragma foreign_export'.  This is intended to be a replacement
for `:- pragma export'.  The principle difference is that `:- pragma
foreign_export' allows you to restrict exports to a particular foreign
language.  This language will usually be the target language but in the case
of backends that support multiple foreign languages, e.g. the IL backend, it
also allows us to restrict the exports to a subset of the available foreign
languages.

Add some support for exporting procedures in the Java backend.  This is
currently undocumented because I cannot test it properly while the Java
backend is not working.  (The reason for adding the support was to make sure
that all of the MLDS backends were handling foreign_export declarations
correctly.)

Make the compiler emit warnings about exports for Java, IL, C# and MC++ not
yet being implemented.  For the latter two this is true.  As mentioned above
this change adds some support for exports in the Java backend and there was
some pre-existing (but undocumented) support for exports to IL.  (The warnings
can be deleted once exports for these languages are properly documented and/or
implemented.)

compiler/prog_item.m:
 	Rename the export item to foreign_export for consistency with the rest
 	of the items concerned with the foreign language interface.

 	Add an extra field to that item.  The new field stores the foreign
 	language that the pragma applies to.

compiler/prog_io_pragma.m:
 	Parse foreign_export pragmas.

 	Implement `:- pragma export' declarations as a special case of
 	`:- pragma foreign_export' declarations.

compiler/add_pramga.m:
 	Rename some predicates.

 	Emit warnings about foreign_exports to languages that we do not
 	currently support.

compiler/export.m:
 	Rename some of the predicates in this module to make them more C
 	specific.

 	Handle foreign exports for the lowlevel C backend.

compiler/hlds_module.m:
 	Add an extra field the pragma_exported_proc structure to hold the name
 	of the foreign language that the corresponding foreign_export
 	declaration is for.

compiler/mercury_to_mercury.m:
 	Add code to output foreign_export pragmas.

compiler/ml_code_gen.m:
 	Don't filter out exports for Java, C# and MC++.  The Java exports
 	can now be passed down to mlds_to_java.m and other two ought to
 	be caught by the frontend of the compiler.

compiler/mlds_to_java.m
 	Add a tentative implementation of pragma foreign_export for Java.
 	This is currently not documented in the reference manual because
 	it is (largely) untested.

compiler/mlds_to_c.m:
 	Change an if-then-else to a switch.

 	Add a sanity check.  Exports for languages other than C should not
 	reach here.

compiler/mlds_to_il.m:
 	Update the TODO list at the head of this file.

 	Add a sanity check.  Exports for languages other than IL should not
 	reach here.

compiler/dead_proc_elim.m:
compiler/det_analysis.m:
compiler/foreign.m:
compiler/handle_options.m:
compiler/make_hlds_passes.m:
compiler/mlds.m:
compiler/mlds_to_managed.m:
compiler/module_qual.m:
compiler/modules.m:
compiler/recompilation.version.m:
 	Conform to the above changes.

 	Minor formatting changes.

doc/reference_manual.texi:
 	Add a new section to the foreign language interface chapter
 	documenting the new pragma.

 	Update the descriptions of the language specific bindings to include
 	the new pragma.

tests/hard_coded/Mmakefile:
tests/hard_coded/pragma_foreign_export.{m,exp}:
 	Make sure that we can parse the new syntax and run a simple program
 	that uses exported procedures.

tests/invalid/invalid_export_detism.{m,err_exp}:
 	Update this test case to conform to the new pragma name.

Julien.

Index: compiler/add_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/add_pragma.m,v
retrieving revision 1.39
diff -u -r1.39 add_pragma.m
--- compiler/add_pragma.m	12 Jul 2006 06:15:30 -0000	1.39
+++ compiler/add_pragma.m	12 Jul 2006 06:27:27 -0000
@@ -13,6 +13,7 @@
  :- import_module hlds.hlds_pred.
  :- import_module hlds.make_hlds.make_hlds_passes.
  :- import_module hlds.make_hlds.qual_info.
+:- import_module libs.globals.
  :- import_module mdbcomp.prim_data.
  :- import_module parse_tree.prog_data.
  :- import_module parse_tree.mercury_to_mercury.
@@ -28,9 +29,10 @@
      item_status::in, item_status::out, module_info::in, module_info::out,
      io::di, io::uo) is det.

-:- pred add_pragma_export(item_origin::in, sym_name::in, pred_or_func::in,
-    list(mer_mode)::in, string::in, prog_context::in,
-    module_info::in, module_info::out, io::di, io::uo) is det.
+:- pred add_pragma_foreign_export(item_origin::in, foreign_language::in,
+    sym_name::in, pred_or_func::in, list(mer_mode)::in, string::in,
+    prog_context::in, module_info::in, module_info::out, io::di, io::uo)
+    is det.

  :- pred add_pragma_reserve_tag(sym_name::in, arity::in, import_status::in,
      prog_context::in, module_info::in, module_info::out,
@@ -227,9 +229,9 @@
          % clauses and pragma c_code).
          Pragma = import(_, _, _, _, _)
      ;
-        % Handle pragma export decls later on, after default
+        % Handle pragma foreign_export decls later on, after default
          % function modes have been added.
-        Pragma = export(_, _, _, _)
+        Pragma = foreign_export(_, _, _, _, _)
      ;
          % Used for inter-module unused argument elimination.
          % This can only appear in .opt files.
@@ -343,8 +345,8 @@
              !IO)
      ).

-add_pragma_export(Origin, Name, PredOrFunc, Modes, C_Function, Context,
-        !ModuleInfo, !IO) :-
+add_pragma_foreign_export(Origin, Lang, Name, PredOrFunc, Modes,
+        ExportedName, Context, !ModuleInfo, !IO) :-
      module_info_get_predicate_table(!.ModuleInfo, PredTable),
      list.length(Modes, Arity),
      (
@@ -361,37 +363,75 @@
          ->
              map.lookup(Procs, ProcId, ProcInfo),
              proc_info_get_declared_determinism(ProcInfo, MaybeDet),
-            % We cannot catch those multi or nondet procedures that
-            % don't have a determinism declaration until after
-            % determinism analysis.
+            % We cannot catch those multi or nondet procedures that don't have
+            % a determinism declaration until after determinism analysis.
              (
                  MaybeDet = yes(Det),
                  ( Det = detism_non ; Det = detism_multi )
              ->
                  Pieces = [words("Error: "),
-                    fixed("`:- pragma export' declaration"),
+                    fixed("`:- pragma foreign_export' declaration"),
                      words("for a procedure that has"),
                      words("a declared determinism of"),
                      fixed(hlds_out.determinism_to_string(Det) ++ ".")
                  ],
-                error_util.write_error_pieces(Context, 0, Pieces, !IO),
+                write_error_pieces(Context, 0, Pieces, !IO),
                  module_info_incr_errors(!ModuleInfo)
              ;
-                module_info_get_pragma_exported_procs(!.ModuleInfo,
-                    PragmaExportedProcs0),
-                NewExportedProc = pragma_exported_proc(PredId, ProcId,
-                    C_Function, Context),
-                PragmaExportedProcs = [NewExportedProc | PragmaExportedProcs0],
-                module_info_set_pragma_exported_procs(PragmaExportedProcs,
-                    !ModuleInfo)
+                % Emit a warning about using pragma foreign_export with
+                % a foreign language that is not supported.
+                % XXX That's currently all of them except C.
+                (
+                    ( Lang = lang_java
+                    ; Lang = lang_csharp
+                    ; Lang = lang_il
+                    ; Lang = lang_managed_cplusplus
+                    ),
+                    NotImplementedWarning = [
+                        words("Warning:"),
+                        fixed("`:- pragma foreign_export'"),
+                        words("declarations are not yet implemented"),
+                        words("for language"), 
+                        words(foreign_language_string(Lang)),
+                        suffix(".")
+                    ],
+                    report_warning(Context, 0, NotImplementedWarning, !IO)
+                ;
+                    Lang = lang_c
+                ),
+                %
+                % Only add the foreign export if the specified language
+                % matches one of the foreign languages available for this
+                % backend.
+                %
+                io_get_backend_foreign_languages(ForeignLanguages, !IO),
+                ( 
+                    % XXX C# and Managed C++ exports currently cause an
+                    %     assertion failure in the MLDS->IL code generator.
+                    %
+                    Lang \= lang_csharp,
+                    Lang \= lang_managed_cplusplus,
+                    list.member(Lang, ForeignLanguages)
+                ->
+                    module_info_get_pragma_exported_procs(!.ModuleInfo,
+                        PragmaExportedProcs0),
+                    NewExportedProc = pragma_exported_proc(Lang, PredId, ProcId,
+                        ExportedName, Context),
+                    PragmaExportedProcs =
+                        [NewExportedProc | PragmaExportedProcs0],
+                    module_info_set_pragma_exported_procs(PragmaExportedProcs,
+                        !ModuleInfo)
+                ;
+                    true
+                )
              )
          ;
-            % We warn about errors in export pragmas created by the compiler
-            % as part of a source-to-source transformation.
+            % We do not warn about errors in export pragmas created by the
+            % compiler as part of a source-to-source transformation.
              (
                  Origin = user,
                  undefined_mode_error(Name, Arity, Context,
-                    "`:- pragma export' declaration", !IO),
+                    "`:- pragma foreign_export' declaration", !IO),
                  module_info_incr_errors(!ModuleInfo)
              ;
                  Origin = compiler(Details),
@@ -406,7 +446,8 @@
                      ; Details = foreign_imports
                      ; Details = pragma_memo_attribute
                      ),
-                    unexpected(this_file, "Bad introduced export pragma.")
+                    unexpected(this_file,
+                        "Bad introduced foreign_export pragma.")
                  )
              )
          )
@@ -414,7 +455,7 @@
          (
              Origin = user,
              undefined_pred_or_func_error(Name, Arity, Context,
-                "`:- pragma export' declaration", !IO),
+                "`:- pragma foreign_export' declaration", !IO),
              module_info_incr_errors(!ModuleInfo)
          ;
              Origin = compiler(Details),
@@ -429,7 +470,7 @@
                  ; Details = foreign_imports
                  ; Details = pragma_memo_attribute
                  ),
-                unexpected(this_file, "Bad introduced export pragma.")
+                unexpected(this_file, "Bad introduced foreign_export pragma.")
              )
          )
      ).
Index: compiler/dead_proc_elim.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.112
diff -u -r1.112 dead_proc_elim.m
--- compiler/dead_proc_elim.m	29 Mar 2006 08:06:40 -0000	1.112
+++ compiler/dead_proc_elim.m	11 Jul 2006 04:41:10 -0000
@@ -5,10 +5,10 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
- 
+%
  % File: dead_proc_elim.m.
  % Main author: zs.
-
+%
  % The job of this module is to delete dead predicates, procedures and
  % type_ctor_gen_info structures from the HLDS.
  %
@@ -16,7 +16,8 @@
  % `--inline-single-use' option.
  %
  % It also issues warnings about unused procedures.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module transform_hlds.dead_proc_elim.
@@ -180,8 +181,8 @@
      svmap.set(proc(PredId, ProcId), no, !Needed),
      initialize_procs(PredId, ProcIds, !Queue, !Needed).

-    % Add procedures exported to C by a pragma(export, ...) declaration
-    % to the queue and map.
+    % Add procedures exported to foreign language by a `:- pragma
+    % foreign_export(...)' declaration to the queue and map.
      %
  :- pred initialize_pragma_exports(list(pragma_exported_proc)::in,
      entity_queue::in, entity_queue::out, needed_map::in, needed_map::out)
@@ -189,7 +190,8 @@

  initialize_pragma_exports([], !Queue, !Needed).
  initialize_pragma_exports([PragmaProc | PragmaProcs], !Queue, !Needed) :-
-    PragmaProc = pragma_exported_proc(PredId, ProcId, _CFunction, _Ctxt),
+    PragmaProc = pragma_exported_proc(_Lang, PredId, ProcId,
+        _ExportName, _Ctxt),
      svqueue.put(proc(PredId, ProcId), !Queue),
      svmap.set(proc(PredId, ProcId), no, !Needed),
      initialize_pragma_exports(PragmaProcs, !Queue, !Needed).
Index: compiler/det_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/det_analysis.m,v
retrieving revision 1.194
diff -u -r1.194 det_analysis.m
--- compiler/det_analysis.m	12 Jul 2006 02:50:57 -0000	1.194
+++ compiler/det_analysis.m	12 Jul 2006 05:21:34 -0000
@@ -5,10 +5,10 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: det_analysis.m - the determinism analysis pass.
  % Main authors: conway, fjh, zs.
-
+%
  % This pass has three components:
  %
  % - Segregate the procedures into those that have determinism declarations,
@@ -32,7 +32,7 @@
  % _make_ the predicate deterministic (or semideterministic) by inserting
  % run-time checking code which calls error/1 if the predicate really isn't
  % deterministic (semideterministic).
-
+%
  % Determinism has three components:
  %
  %   whether a goal can fail
@@ -43,7 +43,8 @@
  % The first two components are synthesized attributes: they are inferred
  % bottom-up. The last component is an inherited attribute: it is propagated
  % top-down.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module check_hlds.det_analysis.
@@ -306,14 +307,15 @@
          true
      ),

-    % Check to make sure that if this procedure is exported to C via a
-    % pragma export declaration then the determinism is not multi or nondet
-    % - pragma exported procs that have been declared to have these
-    % determinisms should have been picked up in make_hlds, so this is just
-    % to catch those whose determinisms need to be inferred.
+    % Check to make sure that if this procedure is exported via a pragma
+    % foreign_export declaration then the determinism is not multi or nondet -
+    % pragma exported procs that have been declared to have these determinisms
+    % should have been picked up in make_hlds, so this is just to catch those
+    % whose determinisms need to be inferred.
      module_info_get_pragma_exported_procs(!.ModuleInfo, ExportedProcs),
      (
-        list.member(pragma_exported_proc(PredId, ProcId, _, _), ExportedProcs),
+        list.member(pragma_exported_proc(_, PredId, ProcId, _, _),
+            ExportedProcs),
          ( NewDetism = detism_multi
          ; NewDetism = detism_non
          )
@@ -347,7 +349,7 @@
      pred_id::in, proc_id::in, prog_context::out) is semidet.

  get_exported_proc_context([Proc | Procs], PredId, ProcId, Context) :-
-    ( Proc = pragma_exported_proc(PredId, ProcId, _, Context0) ->
+    ( Proc = pragma_exported_proc(_, PredId, ProcId, _, Context0) ->
          Context = Context0
      ;
          get_exported_proc_context(Procs, PredId, ProcId, Context)
Index: compiler/export.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/export.m,v
retrieving revision 1.100
diff -u -r1.100 export.m
--- compiler/export.m	8 Jun 2006 08:19:11 -0000	1.100
+++ compiler/export.m	10 Jul 2006 08:45:14 -0000
@@ -5,16 +5,17 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: export.m.
  % Main author: dgj.
-
+%
  % This module defines predicates to produce the functions which are
-% exported to a foreign language via a `pragma export' declaration.
-
+% exported to a foreign language via a `pragma foreign_export' declaration.
+%
  % NOTE: any changes here might also require similar changes to the handling
  % of `pragma import' declarations, which are handled in make_hlds.m.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module backend_libs.export.
@@ -118,9 +119,9 @@
      module_info_get_pragma_exported_procs(HLDS, ExportedProcs),
      module_info_get_globals(HLDS, Globals),
      get_foreign_export_decls_2(Preds, ExportedProcs, Globals, HLDS,
-        C_ExportDecls),
+        ExportDecls),

-    ForeignExportDecls = foreign_export_decls(ForeignDecls, C_ExportDecls).
+    ForeignExportDecls = foreign_export_decls(ForeignDecls, ExportDecls).

  :- pred get_foreign_export_decls_2(pred_table::in,
      list(pragma_exported_proc)::in, globals::in, module_info::in,
@@ -128,17 +129,27 @@

  get_foreign_export_decls_2(_Preds, [], _, _, []).
  get_foreign_export_decls_2(Preds, [E | ExportedProcs], Globals,
-        ModuleInfo, C_ExportDecls) :-
-    E = pragma_exported_proc(PredId, ProcId, C_Function, _Ctxt),
-    get_export_info(Preds, PredId, ProcId, Globals, ModuleInfo, _HowToDeclare,
-        C_RetType, _DeclareReturnVal, _FailureAction, _SuccessAction,
-        HeadArgInfoTypes),
-    get_argument_declarations(HeadArgInfoTypes, no, ModuleInfo, ArgDecls),
-    C_ExportDecl =
-        foreign_export_decl(lang_c, C_RetType, C_Function, ArgDecls),
-    get_foreign_export_decls_2(Preds, ExportedProcs, Globals,
-        ModuleInfo, C_ExportDecls0),
-    C_ExportDecls = [C_ExportDecl | C_ExportDecls0].
+        ModuleInfo, ExportDecls) :-
+    E = pragma_exported_proc(Lang, PredId, ProcId, ExportName, _Ctxt),
+    (
+        Lang = lang_c,
+        get_export_info_for_lang_c(Preds, PredId, ProcId, Globals, ModuleInfo,
+            _HowToDeclare, RetType, _DeclareReturnVal, _FailureAction,
+            _SuccessAction, HeadArgInfoTypes),
+            get_argument_declarations_for_lang_c(HeadArgInfoTypes, no,
+                ModuleInfo, ArgDecls)
+    ;
+        ( Lang = lang_csharp
+        ; Lang = lang_managed_cplusplus
+        ; Lang = lang_java
+        ; Lang = lang_il
+        ),
+        sorry(this_file,  ":- pragma foreign_export for non-C backends.")
+    ), 
+    ExportDecl = foreign_export_decl(Lang, RetType, ExportName, ArgDecls),
+    get_foreign_export_decls_2(Preds, ExportedProcs, Globals, ModuleInfo,
+        ExportDecls0),
+    ExportDecls = [ExportDecl | ExportDecls0].

  %-----------------------------------------------------------------------------%

@@ -258,14 +269,18 @@

  to_c(_Preds, [], _ModuleInfo, []).
  to_c(Preds, [E | ExportedProcs], ModuleInfo, ExportedProcsCode) :-
-    E = pragma_exported_proc(PredId, ProcId, C_Function, _Ctxt),
+    E = pragma_exported_proc(Lang, PredId, ProcId, C_Function, _Ctxt),
+    expect(unify(Lang, lang_c), this_file, "foreign language other than C"),
      module_info_get_globals(ModuleInfo, Globals),
-    get_export_info(Preds, PredId, ProcId, Globals, ModuleInfo, DeclareString,
-        C_RetType, MaybeDeclareRetval, MaybeFail, MaybeSucceed, ArgInfoTypes),
-    get_argument_declarations(ArgInfoTypes, yes, ModuleInfo, ArgDecls),
-
-        % work out which arguments are input, and which are output,
-        % and copy to/from the mercury registers.
+    get_export_info_for_lang_c(Preds, PredId, ProcId, Globals, ModuleInfo,
+        DeclareString, C_RetType, MaybeDeclareRetval, MaybeFail, MaybeSucceed,
+        ArgInfoTypes),
+    get_argument_declarations_for_lang_c(ArgInfoTypes, yes, ModuleInfo,
+        ArgDecls),
+    %
+    % Work out which arguments are input, and which are output, and copy
+    % to/from the Mercury registers.
+    %
      get_input_args(ArgInfoTypes, 0, ModuleInfo, InputArgs),
      copy_output_args(ArgInfoTypes, 0, ModuleInfo, OutputArgs),

@@ -327,7 +342,8 @@
      to_c(Preds, ExportedProcs, ModuleInfo, TheRest),
      ExportedProcsCode = [Code | TheRest].

-    % get_export_info(Preds, PredId, ProcId, Globals, DeclareString, C_RetType,
+    % get_export_info_for_lang_c(Preds, PredId, ProcId, Globals,
+    %   DeclareString, C_RetType,
      %   MaybeDeclareRetval, MaybeFail, MaybeSuccess, ArgInfoTypes):
      %
      % For a given procedure, figure out the information about that procedure
@@ -338,13 +354,13 @@
      % - the actions on success and failure, and
      % - the argument locations/modes/types.
      %
-:- pred get_export_info(pred_table::in, pred_id::in, proc_id::in, globals::in,
-    module_info::in, string::out, string::out, string::out, string::out,
-    string::out, assoc_list(arg_info, mer_type)::out) is det.
-
-get_export_info(Preds, PredId, ProcId, _Globals, ModuleInfo, HowToDeclareLabel,
-        C_RetType, MaybeDeclareRetval, MaybeFail, MaybeSucceed,
-        ArgInfoTypes) :-
+:- pred get_export_info_for_lang_c(pred_table::in, pred_id::in, proc_id::in,
+    globals::in, module_info::in, string::out, string::out, string::out,
+    string::out, string::out, assoc_list(arg_info, mer_type)::out) is det.
+
+get_export_info_for_lang_c(Preds, PredId, ProcId, _Globals, ModuleInfo,
+        HowToDeclareLabel, C_RetType, MaybeDeclareRetval, MaybeFail,
+        MaybeSucceed, ArgInfoTypes) :-
      map.lookup(Preds, PredId, PredInfo),
      pred_info_get_import_status(PredInfo, Status),
      (
@@ -446,11 +462,12 @@
      % Build a string to declare the argument types (and if NameThem = yes,
      % the argument names) of a C function.
      %
-:- pred get_argument_declarations(assoc_list(arg_info, mer_type)::in, bool::in,
+:- pred get_argument_declarations_for_lang_c(
+    assoc_list(arg_info, mer_type)::in, bool::in,
      module_info::in, string::out) is det.

-get_argument_declarations([], _, _, "void").
-get_argument_declarations([X | Xs], NameThem, ModuleInfo, Result) :-
+get_argument_declarations_for_lang_c([], _, _, "void").
+get_argument_declarations_for_lang_c([X | Xs], NameThem, ModuleInfo, Result) :-
      get_argument_declarations_2([X | Xs], 0, NameThem, ModuleInfo, Result).

  :- pred get_argument_declarations_2(assoc_list(arg_info, mer_type)::in,
Index: compiler/foreign.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/foreign.m,v
retrieving revision 1.59
diff -u -r1.59 foreign.m
--- compiler/foreign.m	8 Jun 2006 08:19:11 -0000	1.59
+++ compiler/foreign.m	11 Jul 2006 04:54:36 -0000
@@ -5,17 +5,18 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: foreign.m.
  % Main authors: trd, dgj.
-
+%
  % This module defines predicates for interfacing with foreign languages.  In
  % particular, this module supports interfacing with languages other than the
  % target of compilation.
-
+%
  % Parts of this code were originally written by dgj, and have since been moved
  % here.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module backend_libs.foreign.
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.268
diff -u -r1.268 handle_options.m
--- compiler/handle_options.m	8 Jun 2006 08:19:12 -0000	1.268
+++ compiler/handle_options.m	11 Jul 2006 06:00:42 -0000
@@ -1658,7 +1658,7 @@
              set_option(optimize_constructor_last_call, bool(no), !Globals)
          ),

-            % only set the backend foreign languages if they are unset
+        % Only set the backend foreign languages if they are unset.
          globals.lookup_accumulating_option(!.Globals,
              backend_foreign_languages, CurrentBackendForeignLanguage),
          (
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.137
diff -u -r1.137 hlds_module.m
--- compiler/hlds_module.m	15 Jun 2006 19:36:58 -0000	1.137
+++ compiler/hlds_module.m	10 Jul 2006 08:18:59 -0000
@@ -77,9 +77,12 @@

  :- type pragma_exported_proc
      --->    pragma_exported_proc(
+                foreign_language,       % The language we are exporting to.
                  pred_id,
                  proc_id,
-                string,                 % the name of the C function
+                string,                 % The exported name of the procedure.
+                                        % i.e. the function name in C, method
+                                        % name in Java etc.
                  prog_context
              ).

Index: compiler/make_hlds_passes.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds_passes.m,v
retrieving revision 1.44
diff -u -r1.44 make_hlds_passes.m
--- compiler/make_hlds_passes.m	12 Jul 2006 02:51:02 -0000	1.44
+++ compiler/make_hlds_passes.m	12 Jul 2006 03:45:28 -0000
@@ -942,10 +942,10 @@
          add_pragma_reserve_tag(TypeName, TypeArity, !.Status, Context,
              !ModuleInfo, !IO)
      ;
-        Pragma = export(Name, PredOrFunc, Modes, C_Function)
+        Pragma = foreign_export(Lang, Name, PredOrFunc, Modes, C_Function)
      ->
-        add_pragma_export(Origin, Name, PredOrFunc, Modes, C_Function,
-            Context, !ModuleInfo, !IO)
+        add_pragma_foreign_export(Origin, Lang, Name, PredOrFunc, Modes,
+            C_Function, Context, !ModuleInfo, !IO)
      ;
          % Don't worry about any pragma declarations other than the
          % clause-like pragmas (c_code, tabling and fact_table),
@@ -999,6 +999,7 @@
              pred_info_get_arg_types(PredInfo, ArgTypes),
              pred_info_get_procedures(PredInfo, ProcTable),
              ProcInfos = map.values(ProcTable),
+            ExportLang = lang_c,
              (
                  ArgTypes = [Arg1Type, Arg2Type],
                  type_is_io_state(Arg1Type),
@@ -1016,7 +1017,8 @@
                  module_info_new_user_init_pred(SymName, CName, !ModuleInfo),
                  PragmaExportItem =
                      pragma(compiler(initialise_decl),
-                        export(SymName, predicate, [di_mode, uo_mode], CName)),
+                        foreign_export(ExportLang, SymName, predicate,
+                            [di_mode, uo_mode], CName)),
                  add_item_clause(PragmaExportItem, !Status, Context,
                      !ModuleInfo, !QualInfo, !IO)
              ;
@@ -1034,7 +1036,8 @@
                  module_info_new_user_init_pred(SymName, CName, !ModuleInfo),
                  PragmaExportedItem =
                      pragma(compiler(initialise_decl),
-                        export(SymName, predicate, [], CName)),
+                        foreign_export(ExportLang, SymName, predicate, [],
+                            CName)),
                  add_item_clause(PragmaExportedItem, !Status, Context,
                      !ModuleInfo, !QualInfo, !IO)
              ;
@@ -1067,16 +1070,17 @@
  add_item_clause(initialise(compiler(Details), SymName, _Arity),
          !Status, Context, !ModuleInfo, !QualInfo, !IO) :-
      %
-    % The compiler introduces initialise declarations that call
-    % impure predicates as part of the source-to-source transformation
-    % for mutable variables.  These predicates *must* be impure in order
-    % to prevent the compiler optimizing them away.
+    % The compiler introduces initialise declarations that call impure
+    % predicates as part of the source-to-source transformation for mutable
+    % variables.  These predicates *must* be impure in order to prevent the
+    % compiler optimizing them away.
      %
      ( Details = mutable_decl ->
          module_info_new_user_init_pred(SymName, CName, !ModuleInfo),
+        ExportLang = lang_c,    % XXX Implement for other backends.
          PragmaExportItem =
              pragma(compiler(mutable_decl),
-                export(SymName, predicate, [], CName)),
+                foreign_export(ExportLang, SymName, predicate, [], CName)),
          add_item_clause(PragmaExportItem, !Status, Context,
              !ModuleInfo, !QualInfo, !IO)
      ;
@@ -1087,7 +1091,7 @@
      %
      % To handle a `:- finalise finalpred.' declaration we need to:
      % (1) construct a new C function name, CName, to use to export finalpred,
-    % (2) add `:- pragma export(finalpred(di, uo), CName).',
+    % (2) add `:- pragma foreign_export("C", finalpred(di, uo), CName).',
      % (3) record the finalpred/cname pair in the ModuleInfo so that
      % code generation can ensure cname is called during module finalisation.
      %
@@ -1107,6 +1111,9 @@
              pred_info_get_arg_types(PredInfo, ArgTypes),
              pred_info_get_procedures(PredInfo, ProcTable),
              ProcInfos = map.values(ProcTable),
+            % XXX We currently only support finalise declarations for the C
+            % backends.
+            ExportLang = lang_c,
              (
                  ArgTypes = [Arg1Type, Arg2Type],
                  type_is_io_state(Arg1Type),
@@ -1124,7 +1131,8 @@
                  module_info_new_user_final_pred(SymName, CName, !ModuleInfo),
                  PragmaExportItem =
                      pragma(compiler(finalise_decl),
-                        export(SymName, predicate, [di_mode, uo_mode], CName)),
+                        foreign_export(ExportLang, SymName, predicate,
+                            [di_mode, uo_mode], CName)),
                  add_item_clause(PragmaExportItem, !Status, Context,
                      !ModuleInfo, !QualInfo, !IO)
              ;
@@ -1142,7 +1150,8 @@
                  module_info_new_user_final_pred(SymName, CName, !ModuleInfo),
                  PragmaExportItem =
                      pragma(compiler(finalise_decl),
-                        export(SymName, predicate, [], CName)),
+                        foreign_export(ExportLang, SymName, predicate, [],
+                            CName)),
                  add_item_clause(PragmaExportItem, !Status, Context,
                      !ModuleInfo, !QualInfo, !IO)
              ;
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.295
diff -u -r1.295 mercury_to_mercury.m
--- compiler/mercury_to_mercury.m	12 Jul 2006 06:15:32 -0000	1.295
+++ compiler/mercury_to_mercury.m	12 Jul 2006 06:27:29 -0000
@@ -5,10 +5,10 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: mercury_to_mercury.m.
  % Main author: fjh.
-
+%
  % This program converts the parse tree structure provided by prog_io
  % back into Mercury source text.
  %
@@ -39,7 +39,8 @@
  % represent appending to the string by consing onto the front of the list).
  % The complexity of an implementation like that can be linear in the size
  % of the string being built, although it will have a higher constant factor.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module parse_tree.mercury_to_mercury.
@@ -582,9 +583,9 @@
          mercury_format_pragma_import(Pred, PredOrFunc, ModeList,
              Attributes, C_Function, !IO)
      ;
-        Pragma = export(Pred, PredOrFunc, ModeList, C_Function),
-        mercury_format_pragma_export(Pred, PredOrFunc, ModeList, C_Function,
-            !IO)
+        Pragma = foreign_export(Lang, Pred, PredOrFunc, ModeList, ExportName),
+        mercury_format_pragma_foreign_export(Lang, Pred, PredOrFunc, ModeList,
+            ExportName, !IO)
      ;
          Pragma = obsolete(Pred, Arity),
          mercury_output_pragma_decl(Pred, Arity, predicate, "obsolete", no, !IO)
@@ -3500,13 +3501,17 @@
      add_string(C_Function, !U),
      add_string(""").\n", !U).

-:- pred mercury_format_pragma_export(sym_name::in, pred_or_func::in,
-    list(mer_mode)::in, string::in, U::di, U::uo) is det <= output(U).
+:- pred mercury_format_pragma_foreign_export(foreign_language::in,
+    sym_name::in, pred_or_func::in, list(mer_mode)::in, string::in,
+    U::di, U::uo) is det <= output(U).

-mercury_format_pragma_export(Name, PredOrFunc, ModeList, C_Function, !U) :-
-    varset.init(Varset), % the varset isn't really used.
+mercury_format_pragma_foreign_export(Lang, Name, PredOrFunc, ModeList,
+    ExportName, !U) :-
+    varset.init(Varset), % The varset isn't really used.
      InstInfo = simple_inst_info(Varset),
-    add_string(":- pragma export(", !U),
+    add_string(":- pragma foreign_export(", !U),
+    mercury_format_foreign_language_string(Lang, !U),
+    add_string(", ", !U),
      mercury_format_sym_name(Name, !U),
      (
          PredOrFunc = function,
@@ -3522,7 +3527,7 @@
          add_string(")", !U)
      ),
      add_string(", ", !U),
-    add_string(C_Function, !U),
+    add_string(ExportName, !U),
      add_string(").\n", !U).

  %-----------------------------------------------------------------------------%
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.178
diff -u -r1.178 ml_code_gen.m
--- compiler/ml_code_gen.m	8 Jun 2006 08:19:19 -0000	1.178
+++ compiler/ml_code_gen.m	11 Jul 2006 06:09:26 -0000
@@ -5,17 +5,17 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: ml_code_gen.m.
  % Main author: fjh.
-
+%
  % MLDS code generation -- convert from HLDS to MLDS.
-
+%
  % This module is an alternative to the original code generator.
  % The original code generator compiles from HLDS to LLDS, generating
  % very low-level code. This code generator instead compiles to MLDS,
  % generating much higher-level code than the original code generator.
-
+%
  % One of the aims of the MLDS is to be able to generated human-readable
  % code in languages like C or Java. This means that unlike the LLDS back-end,
  % we do not want to rely on macros or conditional compilation. If the
@@ -26,26 +26,26 @@
  % readability of the generated code, and to make sure that we can easily
  % adapt the MLDS code generator to target languages like Java that don't
  % support macros or conditional compilation.
-
+%
  % A big challenge in generating MLDS code is handling nondeterminism.
  % For nondeterministic procedures, we generate code using an explicit
  % continuation passing style. Each nondeterministic procedures gets
  % translated into a function which takes an extra parameter which is a
  % function pointer that points to the success continuation. On success,
  % the function calls its success continuation, and on failure it returns.
-
+%
  % To keep things easy, this pass generates code which may contain nested
  % functions; if the target language doesn't support nested functions (or
  % doesn't support them _efficiently_) then a later MLDS->MLDS simplification
  % pass will convert it to a form that does not use nested functions.
-
+%
  % Note that when we take the address of a nested function, we only ever
  % do two things with it: pass it as a continuation argument, or call it.
  % The continuations are never returned and never stored inside heap objects
  % or global variables. These conditions are sufficient to ensure that
  % we never keep the address of a nested function after the containing
  % functions has returned, so we won't get any dangling continuations.
-
+%
  %-----------------------------------------------------------------------------%
  % CODE GENERATION SUMMARY
  %-----------------------------------------------------------------------------%
@@ -115,7 +115,7 @@
  % for each subgoal must be done in the right order, so that the
  % const_num_map in the ml_gen_info holds the right sequence numbers
  % for the constants in scope.
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for wrapping goals
@@ -123,19 +123,19 @@
  % If a model_foo goal occurs in a model_bar context, where foo != bar,
  % then we need to modify the code that we emit for the goal so that
  % it conforms to the calling convenion expected for model_bar.
-
+%
  %   det goal in semidet context:
  %       <succeeded = Goal>
  %   ===>
  %       <do Goal>
  %       succeeded = MR_TRUE;
-
+%
  %   det goal in nondet context:
  %       <Goal && SUCCEED()>
  %   ===>
  %       <do Goal>
  %       SUCCEED();
-
+%
  %   semi goal in nondet context:
  %       <Goal && SUCCEED()>
  %   ===>
@@ -143,12 +143,12 @@
  %
  %       <succeeded = Goal>
  %       if (succeeded) SUCCEED();
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for commits
  %
-
+%
  % There's several different ways of handling commits:
  %   - using catch/throw
  %   - using setjmp/longjmp
@@ -177,7 +177,7 @@
  % would just set the flag and return. The flag could be in a global
  % (or thread-local) variable, or it could be an additional value returned
  % from each function.
-
+%
  %   model_non in semi context: (using try_commit/do_commit)
  %       <succeeded = Goal>
  %   ===>
@@ -191,7 +191,7 @@
  %       }, {
  %           succeeded = MR_TRUE;
  %       })
-
+%
  %   model_non in semi context: (using catch/throw)
  %       <succeeded = Goal>
  %   ===>
@@ -204,13 +204,13 @@
  %       } catch (COMMIT) {
  %           succeeded = MR_TRUE;
  %       }
-
+%
  % The above is using C++ syntax. Here COMMIT is an exception type, which
  % can be defined trivially (e.g. "class COMMIT {};"). Note that when using
  % catch/throw, we don't need the "ref" argument at all; the target language's
  % exception handling implementation keeps track of all the information needed
  % to unwind the stack.
-
+%
  %   model_non in semi context: (using setjmp/longjmp)
  %       <succeeded = Goal>
  %   ===>
@@ -224,7 +224,7 @@
  %           <Goal && success()>
  %           succeeded = MR_FALSE;
  %       }
-
+%
  %   model_non in semi context: (using GNU C nested functions,
  %               GNU C local labels, and exiting
  %               the nested function by a goto
@@ -242,7 +242,7 @@
  %       succeeded = MR_TRUE;
  %   commit_done:
  %       ;
-
+%
  %   model_non in det context: (using try_commit/do_commit)
  %       <do Goal>
  %   ===>
@@ -253,7 +253,7 @@
  %       MR_TRY_COMMIT(ref, {
  %           <Goal && success()>
  %       }, {})
-
+%
  %   model_non in det context (using GNU C nested functions,
  %               GNU C local labels, and exiting
  %               the nested function by a goto
@@ -266,7 +266,7 @@
  %       }
  %       <Goal && success()>
  %   done:   ;
-
+%
  %   model_non in det context (using catch/throw):
  %       <do Goal>
  %   ===>
@@ -276,7 +276,7 @@
  %       try {
  %           <Goal && success()>
  %       } catch (COMMIT) {}
-
+%
  %   model_non in det context (using setjmp/longjmp):
  %       <do Goal>
  %   ===>
@@ -287,36 +287,36 @@
  %       if (setjmp(ref) == 0) {
  %           <Goal && success()>
  %       }
-
+%
  % Note that for all of these versions, we must hoist any static declarations
  % generated for <Goal> out to the top level; this is needed so that such
  % declarations remain in scope for any following goals.
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for empty conjunctions (`true')
  %
-
+%
  %   model_det goal:
  %       <do true>
  %   ===>
  %       /* fall through */
-
+%
  %   model_semi goal:
  %       <succeeded = true>
  %   ===>
  %       succceeded = MR_TRUE;
-
+%
  %   model_non goal
  %       <true && CONT()>
  %   ===>
  %       CONT();
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for non-empty conjunctions
  %
-
+%
  % We need to handle the case where the first goal cannot succeed
  % specially:
  %
@@ -327,7 +327,7 @@
  %
  % The remaining cases for conjunction all assume that the first
  % goal's determinism is not `erroneous' or `failure'.
-
+%
  % If the first goal is model_det, it is straight-forward:
  %
  %   model_det Goal:
@@ -335,7 +335,7 @@
  %   ===>
  %       <do Goal>
  %       <Goals>
-
+%
  % If the first goal is model_semidet, then there are two cases:
  % if the conj as a whole is semidet, things are simple, and
  % if the conj as a whole is model_non, then we do the same as
@@ -365,7 +365,7 @@
  % rather than keeping them inside the `if', so that they remain in scope
  % for any later goals which follow this. This is needed for declarations
  % of static consts.
-
+%
  % For model_non goals, there are a couple of different ways that we could
  % generate code, depending on whether we are aiming to maximize readability,
  % or whether we prefer to generate code that may be more efficient but is
@@ -463,35 +463,35 @@
  % local, since accessing local variables is more efficient that accessing
  % variables in the environment from a nested function. So we only hoist
  % declarations of static constants.
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for empty disjunctions (`fail')
  %
-
+%
  %   model_semi goal:
  %       <succeeded = fail>
  %   ===>
  %       succeeded = MR_FALSE;
-
+%
  %   model_non goal:
  %       <fail && CONT()>
  %   ===>
  %       /* fall through */
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for non-empty disjunctions
  %
-
+%
  % model_det disj:
-
+%
  %   model_det Goal:
  %       <do (Goal ; Goals)>
  %   ===>
  %       <do Goal>
  %       /* <Goals> will never be reached */
-
+%
  %   model_semi Goal:
  %       <do (Goal ; Goals)>
  %   ===>
@@ -501,9 +501,9 @@
  %       if (!succeeded) {
  %           <do Goals>;
  %       }
-
+%
  % model_semi disj:
-
+%
  %   model_det Goal:
  %       <succeeded = (Goal ; Goals)>
  %   ===>
@@ -512,7 +512,7 @@
  %       <do Goal>
  %       succeeded = MR_TRUE
  %       /* <Goals> will never be reached */
-
+%
  %   model_semi Goal:
  %       <succeeded = (Goal ; Goals)>
  %   ===>
@@ -522,7 +522,7 @@
  %       if (!succeeded) {
  %           <succeeded = Goals>;
  %       }
-
+%
  % model_non disj:
  %
  %   model_det Goal:
@@ -546,18 +546,18 @@
  %   ===>
  %       <Goal && SUCCEED()>
  %       <Goals && SUCCEED()>
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for if-then-else
  %
-
+%
  %   model_det Cond:
  %       <(Cond -> Then ; Else)>
  %   ===>
  %       <Cond>
  %       <Then>
-
+%
  %   model_semi Cond:
  %       <(Cond -> Then ; Else)>
  %   ===>
@@ -569,7 +569,7 @@
  %       } else {
  %           <Else>
  %       }
-
+%
  % XXX The following transformation does not do as good a job of GC as it could.
  % Ideally we ought to ensure that stuff used only in the `Else' part will be
  % reclaimed if a GC occurs during the `Then' part. But that is a bit tricky
@@ -594,12 +594,12 @@
  % except that we hoist any declarations generated for <Cond> to the top
  % of the scope, so that they are in scope for the <Then> goal
  % (this is needed for declarations of static consts).
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for negation
  %
-
+%
  % model_det negation
  %       <not(Goal)>
  %   ===>
@@ -607,31 +607,31 @@
  %       <succeeded = Goal>
  %       /* now ignore the value of succeeded,
  %        which we know will be MR_FALSE */
-
+%
  % model_semi negation, model_det Goal:
  %       <succeeded = not(Goal)>
  %   ===>
  %       <do Goal>
  %       succeeded = MR_FALSE;
-
+%
  % model_semi negation, model_semi Goal:
  %       <succeeded = not(Goal)>
  %   ===>
  %       <succeeded = Goal>
  %       succeeded = !succeeded;
-
+%
  %-----------------------------------------------------------------------------%
  %
  % Code for deconstruction unifications
  %
-
+%
  %   det (cannot_fail) deconstruction:
  %       <succeeded = (X => f(A1, A2, ...))>
  %   ===>
  %       A1 = arg(X, f, 1);                  % extract arguments
  %       A2 = arg(X, f, 2);
  %       ...
-
+%
  %   semidet (can_fail) deconstruction:
  %       <X => f(A1, A2, ...)>
  %   ===>
@@ -641,9 +641,9 @@
  %           A2 = arg(X, f, 2);
  %           ...
  %       }
-
+%
  %-----------------------------------------------------------------------------%
-
+%
  % This back-end is still not yet 100% complete.
  %
  % Done:
@@ -701,7 +701,8 @@
  %     the need to access the outermost function's `succeeded'
  %     variable via the environment pointer
  %     (be careful about the interaction with setjmp(), though)
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module ml_backend.ml_code_gen.
@@ -849,16 +850,7 @@
      ConvBody = (func(foreign_body_code(L, S, C)) =
          user_foreign_code(L, S, C)),
      MLDSWantedForeignBodys = list.map(ConvBody, WantedForeignBodys),
-    % XXX Exports are only implemented for C and IL at the moment.
-    (
-        ( Lang = lang_c
-        ; Lang = lang_il
-        )
-    ->
-        ml_gen_pragma_export(ModuleInfo, MLDS_PragmaExports)
-    ;
-        MLDS_PragmaExports = []
-    ),
+    ml_gen_pragma_export(ModuleInfo, MLDS_PragmaExports),
      MLDS_ForeignCode = mlds_foreign_code(WantedForeignDecls,
          WantedForeignImports, MLDSWantedForeignBodys, MLDS_PragmaExports),
      map.det_insert(Map0, Lang, MLDS_ForeignCode, Map).
@@ -932,14 +924,14 @@
  :- pred ml_gen_pragma_export_proc(module_info::in, pragma_exported_proc::in,
      mlds_pragma_export::out) is det.

-ml_gen_pragma_export_proc(ModuleInfo,
-        pragma_exported_proc(PredId, ProcId, C_Name, ProgContext), Defn) :-
-
+ml_gen_pragma_export_proc(ModuleInfo, PragmaExportedProc, Defn) :-
+    PragmaExportedProc = pragma_exported_proc(Lang, PredId, ProcId,
+        ExportName, ProgContext),
      ml_gen_proc_label(ModuleInfo, PredId, ProcId, Name, ModuleName),
      FuncParams = ml_gen_proc_params(ModuleInfo, PredId, ProcId),
      MLDS_Context = mlds_make_context(ProgContext),
-    Defn = ml_pragma_export(C_Name, qual(ModuleName, module_qual, Name),
-        FuncParams, MLDS_Context).
+    Defn = ml_pragma_export(Lang, ExportName,
+        qual(ModuleName, module_qual, Name), FuncParams, MLDS_Context).

  %-----------------------------------------------------------------------------%
  %
Index: compiler/mlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds.m,v
retrieving revision 1.133
diff -u -r1.133 mlds.m
--- compiler/mlds.m	8 Jun 2006 08:19:22 -0000	1.133
+++ compiler/mlds.m	11 Jul 2006 07:25:15 -0000
@@ -5,10 +5,10 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % MLDS - The Medium-Level Data Structure.
  % Main author: fjh.
-
+%
  % This module defines the MLDS data structure itself.
  % The MLDS is an intermediate data structure used in compilation;
  % we compile Mercury source -> parse tree -> HLDS -> MLDS -> target (e.g. C).
@@ -612,10 +612,10 @@
  :- type mlds_arguments == list(mlds_argument).
  :- type mlds_argument
      --->    mlds_argument(
-                mlds_entity_name,          % argument name
-                mlds_type,                  % argument type
+                mlds_entity_name,          % Argument name.
+                mlds_type,                 % Argument type.
                  mlds_maybe_gc_trace_code   % GC tracing code for this argument,
-                                            % if needed
+                                           % if needed.
              ).

  :- type mlds_arg_types == list(mlds_type).
@@ -889,11 +889,13 @@
  %-----------------------------------------------------------------------------%
  %
  % Foreign code interfacing
+%

      % Foreign code required for the foreign language interface.
      % When compiling to a language other than the foreign language,
      % this part still needs to be generated as C (or whatever) code
      % and compiled with a C (or whatever) compiler.
+    %
  :- type mlds_foreign_code
      --->    mlds_foreign_code(
                  foreign_decl_info,
@@ -902,10 +904,12 @@
                  list(mlds_pragma_export)
              ).

-    % Information required to generate code for each `pragma export'.
+    % Information required to generate code for each `pragma foreign_export'.
+    %
  :- type mlds_pragma_export
      --->    ml_pragma_export(
-                string,                         % Exported name
+                foreign_language,
+                string,                        % Exported name
                  mlds_qualified_entity_name,    % MLDS name for exported entity
                  mlds_func_params,              % MLDS function parameters
                  mlds_context
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.190
diff -u -r1.190 mlds_to_c.m
--- compiler/mlds_to_c.m	8 Jun 2006 08:19:22 -0000	1.190
+++ compiler/mlds_to_c.m	11 Jul 2006 07:18:34 -0000
@@ -373,7 +373,8 @@
          mercury_import(compiler_visible_interface,
              mercury_module_name_to_mlds(ModuleName)), !IO),

-    % If there are `:- pragma export' declarations, #include the `.mh' file.
+    % If there are `:- pragma foreign_export' declarations,
+    % #include the `.mh' file.
      ( ForeignCode = mlds_foreign_code(_, _, _, []) ->
          true
      ;
@@ -783,11 +784,17 @@

  mlds_output_c_foreign_import_module(Indent, ForeignImport, !IO) :-
      ForeignImport = foreign_import_module(Lang, Import, _),
-    ( Lang = lang_c ->
+    ( 
+        Lang = lang_c,
          mlds_output_src_import(Indent,
              mercury_import(user_visible_interface,
                  mercury_module_name_to_mlds(Import)), !IO)
      ;
+        ( Lang = lang_il
+        ; Lang = lang_csharp
+        ; Lang = lang_managed_cplusplus
+        ; Lang = lang_java
+        ),
          sorry(this_file, "foreign code other than C")
      ).

@@ -811,8 +818,10 @@
      mlds_pragma_export::in, io::di, io::uo) is det.

  mlds_output_pragma_export_defn(ModuleName, Indent, PragmaExport, !IO) :-
-    PragmaExport = ml_pragma_export(_C_name, MLDS_Name, MLDS_Signature,
-        Context),
+    PragmaExport = ml_pragma_export(Lang, _ExportName, MLDS_Name,
+        MLDS_Signature, Context),
+    expect(unify(Lang, lang_c), this_file,
+        "foreign_export to language other than C."),
      mlds_output_pragma_export_func_name(ModuleName, Indent, PragmaExport, !IO),
      io.write_string("\n", !IO),
      mlds_indent(Context, Indent, !IO),
@@ -826,8 +835,10 @@
      mlds_pragma_export::in, io::di, io::uo) is det.

  mlds_output_pragma_export_func_name(ModuleName, Indent, Export, !IO) :-
-    Export = ml_pragma_export(C_name, _MLDS_Name, Signature, Context),
-    Name = qual(ModuleName, module_qual, export(C_name)),
+    Export = ml_pragma_export(Lang, ExportName, _MLDS_Name, Signature, Context),
+    expect(unify(Lang, lang_c), this_file,
+        "export to language other than C."),
+    Name = qual(ModuleName, module_qual, export(ExportName)),
      mlds_indent(Context, Indent, !IO),
      % For functions exported using `pragma export',
      % we use the default C calling convention.
@@ -919,10 +930,12 @@
      % parameters.
      IsCForeignType = (pred(Arg::in) is semidet :-
          Arg = mlds_argument(_Name, Type, _GCTraceCode),
-        Type = mlds_foreign_type(c(_))),
+        Type = mlds_foreign_type(c(_))
+    ),
      IsCForeignTypePtr = (pred(Arg::in) is semidet :-
          Arg = mlds_argument(_Name, Type, _GCTraceCode),
-        Type = mlds_ptr_type(mlds_foreign_type(c(_)))),
+        Type = mlds_ptr_type(mlds_foreign_type(c(_)))
+    ),
      CForeignTypeInputs = list.filter(IsCForeignType, Parameters),
      CForeignTypeOutputs = list.filter(IsCForeignTypePtr, Parameters),
      io.write_list(CForeignTypeInputs, "",
Index: compiler/mlds_to_il.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_il.m,v
retrieving revision 1.162
diff -u -r1.162 mlds_to_il.m
--- compiler/mlds_to_il.m	8 Jun 2006 08:19:22 -0000	1.162
+++ compiler/mlds_to_il.m	11 Jul 2006 07:51:55 -0000
@@ -5,10 +5,10 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: mlds_to_il.m - Convert MLDS to IL.
  % Main author: trd, petdr.
-
+%
  % This module generates IL from MLDS.  Currently it's pretty tuned
  % towards generating assembler -- to generate code using
  % Reflection::Emit it is likely some changes will need to be made.
@@ -37,8 +37,8 @@
  % [ ] High-level RTTI data
  % [ ] Test unused mode (we seem to create a byref for it)
  % [ ] auto dependency generation for IL and assembler
-% [ ] build environment improvements (support
-%   libraries/packages/namespaces better)
+% [ ] build environment improvements
+%       (support libraries/packages/namespaces better)
  % [ ] verifiable code
  %   [ ] verifiable function pointers
  % [ ] omit empty cctors
@@ -53,10 +53,12 @@
  % [ ] Add an option to do overflow checking.
  % [ ] Should replace hard-coded of int32 with a more abstract name such
  %     as `mercury_int_il_type'.
-
+% [ ] Document `pragma foreign_export' for IL.
+% [ ] Implement `pragma foreign_export' for C# and MC++.
+%
  % XXX We should rename this module to mlds_to_ilds, since that is what
  %     it actually does.
-
+%
  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

@@ -92,7 +94,7 @@
      % this file).
      %
      % XXX we should reduce the dependencies here to a bare minimum.
-
+    %
  :- func params_to_il_signature(il_data_rep, mlds_module_name,
      mlds_func_params) = signature.

@@ -1359,10 +1361,12 @@
  :- pred mlds_export_to_mlds_defn(mlds_pragma_export::in, mlds_defn::out)
      is det.

-mlds_export_to_mlds_defn(
-    ml_pragma_export(ExportName, EntityName, Params, Context), Defn) :-
+mlds_export_to_mlds_defn(ExportDefn, Defn) :-
+    ExportDefn = ml_pragma_export(Lang, ExportName, EntityName, Params,
+        Context),
      EntityName = qual(ModuleName, _QualKind, UnqualName),
-
+    expect(unify(Lang, lang_il), this_file,
+        "export for language other than IL."),
      Params = mlds_func_params(Inputs, RetTypes),
      list.map_foldl(
          (pred(RT::in, RV - Lval::out, N0::in, N0 + 1::out) is det :-
Index: compiler/mlds_to_java.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_java.m,v
retrieving revision 1.77
diff -u -r1.77 mlds_to_java.m
--- compiler/mlds_to_java.m	8 Jun 2006 08:19:23 -0000	1.77
+++ compiler/mlds_to_java.m	11 Jul 2006 07:54:18 -0000
@@ -5,12 +5,12 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: mlds_to_java.m.
  % Main authors: juliensf, mjwybrow, fjh.
-
+%
  % Convert MLDS to Java code.
-
+%
  % DONE:
  %   det and semidet predicates
  %   multiple output arguments
@@ -55,7 +55,7 @@
  %   and if a definition relies on another static variable for its constructor
  %   but said variable has not been initialized, then it is treated as `null'
  %   by the JVM with no warning. The problem with this approach is that it
-%   won't work for cyclic definitions.  eg:
+%   won't work for cyclic definitions.  e.g.:
  %
  %       :- type foo ---> f(bar) ; g.
  %       :- type bar ---> f2(foo) ; g2
@@ -78,7 +78,8 @@
  % due to the fact that the back-end generates `break' statements for cases
  % in switches as they are output, meaning that we can't remove them in
  % a pass over the MLDS.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module ml_backend.mlds_to_java.
@@ -119,6 +120,7 @@
  :- import_module ml_backend.ml_type_gen.   % for ml_gen_type_name
  :- import_module ml_backend.ml_util.
  :- import_module ml_backend.rtti_to_mlds.  % for mlds_rtti_type_name.
+:- import_module parse_tree.error_util.
  :- import_module parse_tree.modules.       % for mercury_std_library_name.
  :- import_module parse_tree.prog_data.
  :- import_module parse_tree.prog_foreign.
@@ -384,7 +386,6 @@
  :- pred output_import(mlds_import::in, io::di, io::uo) is det.

  output_import(Import, !IO) :-
-    % XXX Handle `:- pragma export' to Java.
      (
          Import = mercury_import(ImportType, ImportName),
          (
@@ -433,10 +434,10 @@
      Defns = WrapperDefns ++ Defns0,

      % Get the foreign code for Java
-    % XXX We should not ignore _RevImports and _ExportDefns
+    % XXX We should not ignore _RevImports.
      ForeignCode = mlds_get_java_foreign_code(AllForeignCode),
      ForeignCode = mlds_foreign_code(RevForeignDecls, _RevImports,
-        RevBodyCode, _ExportDefns),
+        RevBodyCode, ExportDefns),
      ForeignDecls = list.reverse(RevForeignDecls),
      ForeignBodyCode = list.reverse(RevBodyCode),

@@ -456,6 +457,8 @@
          RttiDefns, !IO),
      output_defns(Indent + 1, ModuleInfo, MLDS_ModuleName, CtorData,
          NonRttiDefns, !IO),
+    output_exports(Indent + 1, ModuleInfo, MLDS_ModuleName, CtorData,
+        ExportDefns, !IO),
      output_src_end(Indent, ModuleName, !IO).
      % XXX Need to handle non-Java foreign code at this point.

@@ -504,6 +507,67 @@

  %-----------------------------------------------------------------------------%
  %
+% Code for handling `pragma foreign_export' for Java
+%
+ 
+    % Exports are converted into forwarding methods that are given the
+    % specified name.  These simply call the exported procedure.
+    %
+    % NOTE: the forwarding methods must be declared public as they might
+    % be referred to within foreign_procs that are inlined across module
+    % boundaries.
+    % 
+:- pred output_exports(indent::in, module_info::in, mlds_module_name::in,
+    ctor_data::in, list(mlds_pragma_export)::in, io::di, io::uo) is det.
+
+output_exports(_, _, _, _, [], !IO).
+output_exports(Indent, ModuleInfo, MLDS_ModuleName, CtorData,
+        [Export | Exports], !IO) :-
+    Export = ml_pragma_export(Lang, ExportName, MLDS_Name, MLDS_Signature,
+        MLDS_Context),
+    expect(unify(Lang, lang_java), this_file,
+        "foreign_export for language other than Java."),
+    indent_line(Indent, !IO),
+    io.write_string("public static ", !IO),
+    MLDS_Signature = mlds_func_params(Parameters, ReturnTypes),
+    (
+        ReturnTypes = [],
+        io.write_string("void", !IO)
+    ;
+        ReturnTypes = [RetType],
+        output_type(RetType, !IO)
+    ;
+        ReturnTypes = [_, _ | _],
+        % For multiple outputs, we return an array of objects.
+        io.write_string("java.lang.Object []", !IO)
+    ),
+    io.write_string(" " ++ ExportName, !IO),
+    output_params(Indent + 1, MLDS_ModuleName, MLDS_Context, Parameters, !IO), 
+    io.nl(!IO),
+    indent_line(Indent, !IO),
+    io.write_string("{\n", !IO),
+    indent_line(Indent + 1, !IO),
+    (
+        ReturnTypes = []
+    ;
+        ReturnTypes = [_ | _],
+        io.write_string("return ", !IO)
+    ),
+    output_fully_qualified_name(MLDS_Name, !IO),
+    io.write_char('(', !IO),
+    WriteCallArg = (pred(Arg::in, !.IO::di, !:IO::uo) is det :-
+        Arg = mlds_argument(Name, _, _),
+        output_name(Name, !IO)
+    ),
+    io.write_list(Parameters, ", ", WriteCallArg, !IO),
+    io.write_string(");\n", !IO),
+    indent_line(Indent, !IO),
+    io.write_string("}\n", !IO),
+    output_exports(Indent, ModuleInfo, MLDS_ModuleName, CtorData, Exports,
+        !IO).
+
+%-----------------------------------------------------------------------------%
+%
  % Code to search MLDS for all uses of function pointers.
  %

@@ -1089,10 +1153,11 @@

      % Discriminated union which allows us to pass down the class name if
      % a definition is a constructor; this is needed since the class name
-    % is not available for a constructor in the mlds.
+    % is not available for a constructor in the MLDS.
+    %
  :- type ctor_data
-    --->    none                        % not a constructor
-    ;       cname(mlds_entity_name).   % constructor class name
+    --->    none                       % Not a constructor.
+    ;       cname(mlds_entity_name).   % Constructor class name.

  :- pred output_defns(indent::in, module_info::in, mlds_module_name::in,
      ctor_data::in, mlds_defns::in, io::di, io::uo) is det.
Index: compiler/mlds_to_managed.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_managed.m,v
retrieving revision 1.29
diff -u -r1.29 mlds_to_managed.m
--- compiler/mlds_to_managed.m	8 Jun 2006 08:19:23 -0000	1.29
+++ compiler/mlds_to_managed.m	11 Jul 2006 07:48:31 -0000
@@ -5,12 +5,13 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % Module: mlds_to_managed.m.
  % Main author: trd, petdr.
-
+%
  % Generate code for the foreign language interface to C# and managed C++.
-
+% 
+%-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

  :- module ml_backend.mlds_to_managed.
Index: compiler/module_qual.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/module_qual.m,v
retrieving revision 1.138
diff -u -r1.138 module_qual.m
--- compiler/module_qual.m	5 Jul 2006 08:45:33 -0000	1.138
+++ compiler/module_qual.m	10 Jul 2006 06:26:12 -0000
@@ -1089,8 +1089,8 @@
          import(Name, PredOrFunc, Modes, Attributes, CFunc),
          !Info, !IO) :-
      qualify_mode_list(Modes0, Modes, !Info, !IO).
-qualify_pragma(export(Name, PredOrFunc, Modes0, CFunc),
-        export(Name, PredOrFunc, Modes, CFunc), !Info, !IO) :-
+qualify_pragma(foreign_export(Lang, Name, PredOrFunc, Modes0, CFunc),
+        foreign_export(Lang, Name, PredOrFunc, Modes, CFunc), !Info, !IO) :-
      qualify_mode_list(Modes0, Modes, !Info, !IO).
  qualify_pragma(X at unused_args(_, _, _, _, _), X, !Info, !IO).
  qualify_pragma(X at exceptions(_, _, _, _, _), X, !Info, !IO).
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.395
diff -u -r1.395 modules.m
--- compiler/modules.m	28 Jun 2006 04:46:16 -0000	1.395
+++ compiler/modules.m	10 Jul 2006 07:05:56 -0000
@@ -2111,7 +2111,7 @@
  pragma_allowed_in_interface(inline(_, _), no).
  pragma_allowed_in_interface(no_inline(_, _), no).
  pragma_allowed_in_interface(obsolete(_, _), yes).
-pragma_allowed_in_interface(export(_, _, _, _), no).
+pragma_allowed_in_interface(foreign_export(_, _, _, _, _), no).
  pragma_allowed_in_interface(import(_, _, _, _, _), no).
  pragma_allowed_in_interface(source_file(_), yes).
      % yes, but the parser will strip out `source_file' pragmas anyway...
@@ -5857,11 +5857,11 @@
          % code for it, rather than assembler code.  So
          % we need to treat `pragma export' like the
          % other pragmas for foreign code.
-        Pragma = export(_, _, _, _),
-        list.member(lang_c, BackendLangs)
+        % XXX How is this going to be affected now we have moved
+        % to pragma foreign_export? - juliensf
+        Pragma = foreign_export(Lang, _, _, _, _),
+        list.member(Lang, BackendLangs)
      ->
-        % XXX we assume lang = c for exports
-        Lang = lang_c,
          Info1 = Info0 ^ used_foreign_languages :=
              set.insert(Info0 ^ used_foreign_languages, Lang),
          Info = Info1 ^ module_contains_foreign_export :=
@@ -7373,8 +7373,7 @@

  :- pred item_needs_foreign_imports(item::in, foreign_language::out) is nondet.

-item_needs_foreign_imports(pragma(_, export(_, _, _, _)), Lang) :-
-    foreign_language(Lang).
+item_needs_foreign_imports(pragma(_, foreign_export(Lang, _, _, _, _)), Lang).

      % `:- pragma import' is only supported for C.
  item_needs_foreign_imports(pragma(_, import(_, _, _, _, _)), lang_c).
@@ -7674,7 +7673,7 @@
      ; Pragma = exceptions(_, _, _, _, _), Reorderable = yes
      ; Pragma = trailing_info(_, _, _, _, _), Reorderable = yes
      ; Pragma = mm_tabling_info(_, _, _, _, _), Reorderable = yes
-    ; Pragma = export(_, _, _, _), Reorderable = yes
+    ; Pragma = foreign_export(_, _, _, _, _), Reorderable = yes
      ; Pragma = fact_table(_, _, _), Reorderable = no
      ; Pragma = foreign_code(_, _), Reorderable = no
      ; Pragma = foreign_decl(_, _, _), Reorderable = no
@@ -7755,7 +7754,7 @@
      ( Pragma = check_termination(_, _), Reorderable = yes
      ; Pragma = does_not_terminate(_, _), Reorderable = yes
      ; Pragma = exceptions(_, _, _, _, _), Reorderable = no
-    ; Pragma = export(_, _, _, _), Reorderable = yes
+    ; Pragma = foreign_export(_, _, _, _, _), Reorderable = yes
      ; Pragma = fact_table(_, _, _), Reorderable = no
      ; Pragma = foreign_code(_, _), Reorderable = no
      ; Pragma = foreign_decl(_, _, _), Reorderable = no
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.108
diff -u -r1.108 prog_io_pragma.m
--- compiler/prog_io_pragma.m	12 Jul 2006 06:15:33 -0000	1.108
+++ compiler/prog_io_pragma.m	12 Jul 2006 06:27:30 -0000
@@ -214,6 +214,40 @@
      parse_pragma_foreign_proc_pragma(ModuleName, "foreign_proc",
          PragmaTerms, ErrorTerm, VarSet, Result).

+parse_pragma_type(_ModuleName, "foreign_export", PragmaTerms, ErrorTerm,
+        _VarSet, Result) :-
+    ( PragmaTerms = [LangTerm, PredAndModesTerm, FunctionTerm] ->
+        ( FunctionTerm = term.functor(term.string(Function), [], _) ->
+            parse_pred_or_func_and_arg_modes(no, PredAndModesTerm,
+                ErrorTerm, "`:- pragma foreign_export' declaration",
+                PredAndModesResult),
+            (
+                PredAndModesResult = ok(PredName - PredOrFunc, Modes),
+                ( parse_foreign_language(LangTerm, ForeignLanguage) ->
+                    Result = ok(pragma(user,
+                        foreign_export(ForeignLanguage, PredName,
+                            PredOrFunc, Modes, Function)))
+                ;
+                    Result = error(
+                        "invalid foreign language in " ++
+                        "`:- pragma foreign_export declaration",
+                        LangTerm)
+                )
+            ;
+                PredAndModesResult = error(Msg, Term),
+                Result = error(Msg, Term)
+            )
+        ;
+            Result = error(
+                 "expected pragma " ++ 
+                    "foreign_export(Lang, PredName(ModeList), Function)",
+                 PredAndModesTerm)
+        )
+    ;
+        Result = error("wrong number of arguments in " ++
+            "`:- pragma foreign_export' declaration", ErrorTerm)
+    ).
+
      % pragma c_code is almost as if we have written foreign_code
      % or foreign_proc with the language set to "C".
      % There are a few differences (error messages, some deprecated
@@ -769,7 +803,6 @@

  parse_pragma_type(_ModuleName, "export", PragmaTerms, ErrorTerm, _VarSet,
          Result) :-
-    % XXX we implicitly assume exports are only for C
      ( PragmaTerms = [PredAndModesTerm, FunctionTerm] ->
          ( FunctionTerm = term.functor(term.string(Function), [], _) ->
              parse_pred_or_func_and_arg_modes(no, PredAndModesTerm,
@@ -777,8 +810,9 @@
                  PredAndModesResult),
              (
                  PredAndModesResult = ok(PredName - PredOrFunc, Modes),
-                Result = ok(pragma(user, export(PredName, PredOrFunc, Modes,
-                    Function)))
+                Result = ok(pragma(user,
+                    foreign_export(lang_c, PredName, PredOrFunc, Modes,
+                        Function)))
              ;
                  PredAndModesResult = error(Msg, Term),
                  Result = error(Msg, Term)
Index: compiler/prog_item.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_item.m,v
retrieving revision 1.17
diff -u -r1.17 prog_item.m
--- compiler/prog_item.m	15 Jun 2006 19:37:11 -0000	1.17
+++ compiler/prog_item.m	7 Jul 2006 08:21:01 -0000
@@ -397,7 +397,8 @@
                  % hard-coded, and mmake can use the dependency information.
              )

-    ;       export(
+    ;       foreign_export(
+                exp_language            :: foreign_language,
                  exp_predname            :: sym_name,
                  exp_p_or_f              :: pred_or_func,
                  exp_modes               :: list(mer_mode),
Index: compiler/recompilation.version.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/recompilation.version.m,v
retrieving revision 1.48
diff -u -r1.48 recompilation.version.m
--- compiler/recompilation.version.m	15 Jun 2006 19:37:11 -0000	1.48
+++ compiler/recompilation.version.m	10 Jul 2006 07:12:45 -0000
@@ -5,12 +5,12 @@
  % This file may only be copied under the terms of the GNU General
  % Public License - see the file COPYING in the Mercury distribution.
  %-----------------------------------------------------------------------------%
-
+%
  % File: recompilation_version.m.
  % Main author: stayl.
-
+%
  % Compute version numbers for program items in interface files.
-
+%
  %-----------------------------------------------------------------------------%

  :- module recompilation.version.
@@ -568,7 +568,7 @@
  is_pred_pragma(inline(Name, Arity), yes(no - Name / Arity)).
  is_pred_pragma(no_inline(Name, Arity), yes(no - Name / Arity)).
  is_pred_pragma(obsolete(Name, Arity), yes(no - Name / Arity)).
-is_pred_pragma(export(Name, PredOrFunc, Modes, _),
+is_pred_pragma(foreign_export(_, Name, PredOrFunc, Modes, _),
          yes(yes(PredOrFunc) - Name / Arity)) :-
      adjust_func_arity(PredOrFunc, Arity, list.length(Modes)).
      % Pragma import declarations are never used directly by Mercury code.
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.357
diff -u -r1.357 reference_manual.texi
--- doc/reference_manual.texi	5 Jul 2006 08:45:37 -0000	1.357
+++ doc/reference_manual.texi	12 Jul 2006 08:05:27 -0000
@@ -6071,6 +6071,9 @@
  				       or function as a call to code
  				       written in a different
  				       programming language.
+* Calling Mercury from foreign code::  How to call a Mercury predicate
+                                       or funciton from a different
+                                       programming language.
  * Using foreign types from Mercury::   How to use a type defined in
  				       a different programming language
  				       in Mercury code. 
@@ -6388,6 +6391,41 @@

  @c -----------------------------------------------------------------------

+ at node Calling Mercury from foreign code
+ at section Calling Mercury from foreign code
+
+Mercury procedures may be exported so that they can be called by code written
+in a foreign language.
+
+A declaration of the form:
+
+ at example
+:- pragma foreign_export("@var{Lang}",
+        @var{Pred}(@var{Mode1}, @var{Mode2}, @dots{}), "@var{ForeignName}").
+ at end example
+
+ at noindent
+or
+
+ at example
+:- pragma foreign_export("@var{Lang}",
+        @var{Func}(@var{Mode1}, @var{Mode2}, @dots{}) = @var{Mode},
+        "@var{ForeignName}").
+ at end example
+
+ at noindent
+exports a procedure for use by foreign language @var{Lang}.
+For each exported procedure the Mercury implementation will create an
+interface to the named Mercury procedure in the foreign language using
+the name @var{ForeignName}.  The form of this interface is depenendent
+upon the specified foreign language.  For further details see the language
+specific information below.
+
+It is an error to export a Mercury procedure that has a determinism of
+multi or nondet.
+
+ at c -----------------------------------------------------------------------
+
  @node Data passing conventions
  @section Data passing conventions

@@ -6765,6 +6803,7 @@
  @menu
  * Using pragma foreign_type for C 	:: Declaring C types in Mercury
  * Using pragma foreign_proc for C 	:: Calling C code from Mercury
+* Using pragma foreign_export for C     :: Calling Mercury code from C
  * Using pragma foreign_decl for C 	:: Including C declarations in Mercury
  * Using pragma foreign_code for C 	:: Including C code in Mercury
  @end menu
@@ -6862,6 +6901,59 @@
  If the procedure fails, the C code need only
  set @code{SUCCESS_INDICATOR} to false (zero).

+ at node Using pragma foreign_export for C
+ at subsubsection Using pragma foreign_export for C
+
+A @samp{pragma foreign_export} declaration for C has the form:
+
+ at example
+:- pragma foreign_export("C", @var{MercuryMode}, "@var{C_Name}").
+ at end example
+
+For example,
+
+ at example
+:- pragma foreign_export("C", foo(in, in, out), "FOO").
+ at end example
+
+For each Mercury module containing @samp{pragma foreign_export} declarations
+for C, the Mercury implementation will automatically create a header file for
+that module which declares a C function @var{C_Name}() for each of the
+ at samp{pragma foreign_export} declarations.  Each such C function is the C
+interface to the specified Mercury procedure.
+
+The type signature of the C interface to a Mercury procedure is determined as
+follows.  Mercury types are converted to C types according to the rules in
+ at ref{C data passing conventions}.  Input arguments are passed by value.
+For output arguments, the caller must pass the address in which to store the
+result.  If the Mercury procedure can fail, then its C interface function
+returns a truth value indicating success or failure.  If the Mercury procedure
+is a Mercury function that cannot fail, and the function result has an output
+mode, then the C interface function will return the Mercury function result
+value.  Otherwise the function result is appended as an extra argument.
+ at c XXX We need to update this for dummy unit types.
+Arguments of type @samp{io.state} or @samp{store.store(_)} are not passed
+at all.  (The reason for this is that these types represent mutable state,
+and in C modifications to mutable state are done via side effects, rather than
+argument passing.)
+
+Calling polymorphically typed Mercury procedures from C is a little bit more
+difficult than calling ordinary (monomorphically typed) Mercury procedures.
+The simplest method is to just create monomorphic forwarding procedures that
+call the polymorphic procedures, and export them, rather than exporting the
+polymorphic procedures.
+
+If you do export a polymorphically typed Mercury procedure, the compiler
+will prepend one @samp{type_info} argument to the parameter list of
+the C interface function for each polymorphic type variable in the
+Mercury procedure's type signature.  The caller must arrange to pass
+in appropriate @samp{type_info} values corresponding to the types
+of the other arguments passed.  These @samp{type_info} arguments can
+be obtained using the Mercury @samp{type_of} function in the Mercury
+standard library module @samp{type_desc}.
+
+To use the C declarations procduced see @ref{Using pragma foreign_decl for C}.
+
  @node Using pragma foreign_decl for C
  @subsubsection Using pragma foreign_decl for C

@@ -6947,6 +7039,7 @@
  @menu
  * Using pragma foreign_type for C#	:: Declaring C# types in Mercury
  * Using pragma foreign_proc for C# 	:: Calling C# code from Mercury
+* Using pragma foreign_export for C#    :: Calling Mercury code from C#
  * Using pragma foreign_decl for C# 	:: Including C# declarations in Mercury
  * Using pragma foreign_code for C# 	:: Including C# code in Mercury
  @end menu
@@ -7000,6 +7093,11 @@
  If the procedure fails, the C# code need only
  set @code{SUCCESS_INDICATOR} to false.

+ at node Using pragma foreign_export for C#
+ at subsubsection Using pragma foreign_export for C#
+
+ at samp{pramga foreign_export} is not currently supported for C#.
+
  @node Using pragma foreign_decl for C#
  @subsubsection Using pragma foreign_decl for C#

@@ -7060,6 +7158,7 @@
  @menu
  * Using pragma foreign_type for IL	:: Declaring IL types in Mercury
  * Using pragma foreign_proc for IL 	:: Calling IL code from Mercury
+* Using pragma foreign_export for IL    :: Calling Mercury code from IL
  * Using pragma foreign_decl for IL 	:: Including IL declarations in Mercury
  * Using pragma foreign_code for IL 	:: Including IL code in Mercury
  @end menu
@@ -7177,6 +7276,11 @@
  Each of the head variables will be represented by the Common Language
  Runtime types as specified in @ref{IL and C# data passing conventions}.

+ at node Using pragma foreign_export for IL
+ at subsubsection Using pragma foreign_export for IL
+
+ at samp{pragma foreign_export} is currently not supported for IL.
+
  @node Using pragma foreign_decl for IL
  @subsubsection Using pragma foreign_decl for IL

@@ -7197,10 +7301,12 @@
  @menu
  * Using pragma foreign_type for Java :: Declaring Java types in Mercury
  * Using pragma foreign_proc for Java :: Calling Java code from Mercury
+* Using pragma foreign_export for Java :: Calling Mercury from Java code
  * Using pragma foreign_decl for Java :: Including Java declarations in Mercury
  * Using pragma foreign_code for Java :: Including Java code in Mercury
  @end menu

+
  @node Using pragma foreign_type for Java
  @subsubsection Using pragma foreign_type for Java

@@ -7265,6 +7371,11 @@
  @c If the procedure fails, the Java code need only
  @c set the @code{succeeded} variable to false.

+ at node Using pragma foreign_export for Java
+ at subsubsection Using pragma foreign_export for Java
+
+ at samp{pragma foreign_export} is not currently supported for Java.
+
  @node Using pragma foreign_decl for Java
  @subsubsection Using pragma foreign_decl for Java

@@ -7334,6 +7445,7 @@
  @menu
  * Using pragma foreign_type for MC++::  Declaring MC++ types in Mercury
  * Using pragma foreign_proc for MC++::  Calling MC++ code from Mercury
+* Using pragma foreign_export for MC++:: Calling Mercury from MC++ code
  * Using pragma foreign_decl for MC++::  Including MC++ declarations in Mercury
  * Using pragma foreign_code for MC++::  Including MC++ code in Mercury
  @end menu
@@ -7387,6 +7499,11 @@
  If the procedure fails, the MC++ code need only
  set @code{SUCCESS_INDICATOR} to false.

+ at node Using pragma foreign_export for MC++
+ at subsubsection Using pragma foreign_export for MC++
+
+ at samp{pragma foreign_export} is not currently supported for MC++.
+
  @node Using pragma foreign_decl for MC++
  @subsubsection Using pragma foreign_decl for MC++

Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.288
diff -u -r1.288 Mmakefile
--- tests/hard_coded/Mmakefile	30 Jun 2006 12:51:55 -0000	1.288
+++ tests/hard_coded/Mmakefile	12 Jul 2006 08:13:21 -0000
@@ -146,6 +146,7 @@
  	pprint_test2 \
  	pragma_c_code \
  	pragma_export \
+	pragma_foreign_export \
  	pragma_import \
  	pragma_inline \
  	pretty_printing \
Index: tests/hard_coded/pragma_foreign_export.exp
===================================================================
RCS file: tests/hard_coded/pragma_foreign_export.exp
diff -N tests/hard_coded/pragma_foreign_export.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/pragma_foreign_export.exp	12 Jul 2006 08:13:02 -0000
@@ -0,0 +1 @@
+Hello World!
Index: tests/hard_coded/pragma_foreign_export.m
===================================================================
RCS file: tests/hard_coded/pragma_foreign_export.m
diff -N tests/hard_coded/pragma_foreign_export.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/pragma_foreign_export.m	12 Jul 2006 08:13:02 -0000
@@ -0,0 +1,29 @@
+% XXX Need to add IL and Java implementations.
+:- module pragma_foreign_export.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+main(!IO) :-
+	call_foreign(!IO).
+ 
+:- pred call_foreign(io::di, io::uo) is det.
+
+:- pred hello_world(io::di, io::uo) is det.
+:- pragma foreign_export("C", hello_world(di, uo),
+	"exported_hello_world").
+
+hello_world(!IO) :-
+	io.write_string("Hello World!\n", !IO).
+
+:- pragma foreign_proc("C",
+	call_foreign(IO0::di, IO::uo),
+	[promise_pure, may_call_mercury],
+"
+	exported_hello_world();
+	IO = IO0;
+").
Index: tests/invalid/invalid_export_detism.err_exp
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/invalid_export_detism.err_exp,v
retrieving revision 1.2
diff -u -r1.2 invalid_export_detism.err_exp
--- tests/invalid/invalid_export_detism.err_exp	14 Sep 2005 05:26:47 -0000	1.2
+++ tests/invalid/invalid_export_detism.err_exp	11 Jul 2006 12:26:35 -0000
@@ -1,3 +1,3 @@
-invalid_export_detism.m:009: Error: `:- pragma export' declaration for a
-invalid_export_detism.m:009:   procedure that has a declared determinism of
+invalid_export_detism.m:009: Error: `:- pragma foreign_export' declaration for
+invalid_export_detism.m:009:   a procedure that has a declared determinism of
  invalid_export_detism.m:009:   nondet.
Index: tests/invalid/invalid_export_detism.m
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/invalid_export_detism.m,v
retrieving revision 1.1
diff -u -r1.1 invalid_export_detism.m
--- tests/invalid/invalid_export_detism.m	6 Jan 2005 04:30:55 -0000	1.1
+++ tests/invalid/invalid_export_detism.m	11 Jul 2006 12:27:13 -0000
@@ -6,7 +6,7 @@

  :- implementation.

-:- pragma export(foo(in, out), "EXPORTED_FOO").
+:- pragma foreign_export("C", foo(in, out), "EXPORTED_FOO").

  foo(1, 2).
  foo(2, 3).

--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at csse.unimelb.edu.au
administrative address: owner-mercury-reviews at csse.unimelb.edu.au
unsubscribe: Address: mercury-reviews-request at csse.unimelb.edu.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at csse.unimelb.edu.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list