[m-rev.] document Java foreign language interface
Fergus Henderson
fjh at cs.mu.OZ.AU
Wed Dec 3 02:16:34 AEDT 2003
Estimated hours taken: 4
Branches: main
doc/reference_manual.texi:
Document the Java foreign language interface.
A few minor changes elsewhere in the foreign language interfacing
chapter. In particular, be consistent about how the language
name is specified in foreign language interfacing pragmas.
tests/hard_coded/Mmakefile:
tests/hard_coded/java_test.m:
tests/hard_coded/java_test.exp:
Add a test of the Java foreign language interface.
tests/hard_coded/Mmakefile:
tests/hard_coded/csharp_test.m:
tests/hard_coded/csharp_test.exp:
Enable the test of the C# foreign language interface.
Workspace: /home/jupiter/fjh/ws-jupiter/mercury
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.282
diff -u -d -r1.282 reference_manual.texi
--- doc/reference_manual.texi 12 Nov 2003 11:09:49 -0000 1.282
+++ doc/reference_manual.texi 2 Dec 2003 15:04:26 -0000
@@ -5572,6 +5572,7 @@
@menu
* C data passing conventions ::
* IL and C# data passing conventions ::
+* Java data passing conventions ::
@end menu
@node C data passing conventions
@@ -5632,7 +5633,66 @@
then the IL function should return the Mercury function result value.
Otherwise the function result is appended as an extra argument.
Arguments of type @samp{io__state} or @samp{store__store(_)} are not
-passed at all;
+passed or returned at all;
+that's because these types represent mutable state, and in IL
+modifications to mutable state are done via side effects,
+rather than argument passing.
+
+ at node Java data passing conventions
+ at subsection Java data passing conventions
+
+The Mercury types @code{int}, @code{float}, @code{char},
+and @code{string} are mapped to the Java types
+ at code{int}, @code{double}, @code{char} and
+ at code{java.lang.String} respectively.
+
+Mercury variables whose type is a type variable will be passed as
+ at code{java.lang.Object}.
+Mercury array types are mapped to Java array types.
+When compiling with @samp{--no-high-level-data}, all other Mercury variables
+are passed as @code{java.lang.Object[]}.
+When compiling with @samp{--high-level-data},
+Mercury variables whose type is a Mercury discriminated union type
+will be passed as a Java type whose type name is determined from
+the Mercury type name (ignoring any type parameters) followed by
+an underscore and then the type arity,
+expressed as a decimal integer.
+Mercury module qualifiers are converted to Java namespace qualifiers.
+For example the Mercury type @samp{foo__bar__baz/1} will be passed as the Java
+type @samp{foo.bar.baz_1}.
+Note an extra namespace qualifier, @samp{mercury}, will be prepended to the
+beginning of names residing in the Mercury standard library.
+Mercury variables whose type is a Mercury equivalence type
+will be passed as the representation of the right hand side of the
+equivalence type.
+
+This mapping is subject to change and you should try to avoid writing
+code that relies heavily upon a particular representation of Mercury
+terms.
+
+Mercury arguments declared with input modes are passed by value to the
+corresponding Java function. If the Mercury procedure is a function
+whose result has an input mode, then the Mercury function result is
+appended to the list of input parameters, so that the Mercury function
+result becomes the last parameter to the corresponding Java function.
+
+The return values from the Java function consist of the following:
+first, any arguments with output modes; next, if the Mercury procedure
+is a function whose result has an output mode, the function result;
+finally, if the Mercury procedure can fail, the success indicator.
+The success indicator is a truth value of type
+ at samp{boolean} indicating success or failure:
+ at code{true} indicates success, and @code{false} indicates failure.
+If there are no return values, then the return type of the Java
+function will be @samp{void}. If there is exactly one return
+value, then the Java return type will be the type of that value.
+If there is more than one return value, then the Java return type
+will be @samp{java.lang.Object[]}, and the Java function will return
+an array of type @samp{java.lang.Object[]} containing all the return
+values in the order described above.
+
+Arguments of type @samp{io__state} or @samp{store__store(_)} are not
+passed or returned at all;
that's because these types represent mutable state, and in IL
modifications to mutable state are done via side effects,
rather than argument passing.
@@ -5746,8 +5806,8 @@
before the object file for the module containing the
@samp{pragma foreign_import_module} declaration.
-A cycle of @samp{pragma foreign_import_module}, where the language is either
- at samp{"MC++"} or @samp{"C#"}, is not permitted.
+A cycle of @samp{pragma foreign_import_module}, where the language is
+ at samp{"MC++"}, @samp{"C#"}, or @samp{"Java"}, is not permitted.
@node Adding foreign definitions
@section Adding foreign definitions
@@ -5775,9 +5835,12 @@
@node Language specific bindings
@section Language specific bindings
+ at c Please keep this menu in alphabetical order
+
@menu
* Interfacing with C :: How to write code to interface with C
* Interfacing with C# :: How to write code to interface with C#
+* Interfacing with Java :: How to write code to interface with Java
* Interfacing with IL :: How to write code to interface with IL
* Interfacing with Managed C++ :: How to write code to interface with
Managed C++
@@ -5800,6 +5863,9 @@
@item @samp{C#}
Use the string @code{"C#"} to set the foreign language to C#.
+
+ at item @samp{Java}
+Use the string @code{"Java"} to set the foreign language to Java.
@item @samp{IL}
Use the string @code{"IL"} to set the foreign language to IL.
@@ -5867,8 +5933,8 @@
Arguments whose mode is input will have their values set by the
Mercury implementation on entry to the C code. If the procedure
-succeeds, the C code must set the values of all output arguments
-before returning. If the procedure fails, the C code need only
+succeeds, the C code must set the values of all output arguments.
+If the procedure fails, the C code need only
set @code{SUCCESS_INDICATOR} to false (zero).
@node Using pragma foreign_decl for C
@@ -5953,7 +6019,7 @@
The C @samp{pragma foreign_type} declaration is of the form:
@example
-:- pragma foreign_type(c, @var{MercuryTypeName}, @var{CForeignType}).
+:- pragma foreign_type("C", @var{MercuryTypeName}, @var{CForeignType}).
@end example
The @var{CForeignType} can be any C type name that obeys the following
@@ -5965,10 +6031,8 @@
@samp{void (*)(void)}. However, it would be OK to use a typedef name
which was defined as a function pointer type.)
- at c XXX No point documenting this until `--gc accurate'
- at c is officially supported.
- at c With @samp{--gc accurate}, foreign_types which are C pointer types
- at c must not point to the Mercury heap.
+With @samp{--gc accurate}, foreign_types which are C pointer types
+must not point to the Mercury heap.
If the @var{MercuryTypeName} is the type of a parameter of a procedure
defined using @samp{pragma foreign_proc},
@@ -6022,8 +6086,8 @@
C# code in a @code{pragma foreign_proc} declaration
for any procedure whose determinism indicates that it could fail
-must assign a value of type bool to the variable @samp{SUCCESS_INDICATOR}.
-For example:
+must assign a value of type @samp{bool} to the variable
+ at samp{SUCCESS_INDICATOR}. For example:
@example
:- pred string__contains_char(string, character).
@@ -6041,8 +6105,8 @@
Arguments whose mode is input will have their values set by the
Mercury implementation on entry to the C# code. If the procedure
-succeeds, the C# code must set the values of all output arguments
-before returning. If the procedure fails, the C# code need only
+succeeds, the C# code must set the values of all output arguments.
+If the procedure fails, the C# code need only
set @code{SUCCESS_INDICATOR} to false.
@node Using pragma foreign_decl for C#
@@ -6060,7 +6124,7 @@
using System;
").
:- pred hello(io__state::di, io__state::uo) is det.
-:- pragma foreign_decl("C#",
+:- pragma foreign_proc("C#",
hello(_IO0::di, _IO::uo),
[will_not_call_mercury],
"
@@ -6099,6 +6163,144 @@
@c ----------------------------------------------------------------------------
+ at node Interfacing with Java
+ at subsection Interfacing with Java
+
+ at 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_decl for Java :: Including Java declarations in Mercury
+* Using pragma foreign_code for Java :: Including Java code in Mercury
+ at end menu
+
+ at node Using pragma foreign_type for Java
+ at subsubsection Using pragma foreign_type for Java
+
+The Java @samp{pragma foreign_type} declaration is of the form:
+
+ at example
+:- pragma foreign_type("Java", @var{MercuryTypeName}, @var{JavaType}).
+ at end example
+
+The @var{JavaType} can be any accessible Java type.
+
+If the @var{MercuryTypeName} is the type of a parameter of a procedure
+defined using @samp{pragma foreign_proc},
+it will be passed to the foreign_proc's foreign language code
+as @var{JavaType}.
+
+ at c XXX `pragma export' not supported yet for Java
+ at c Furthermore, any Mercury procedure exported with @samp{pragma export}
+ at c will use @var{JavaType} as the type for any
+ at c parameters whose Mercury type is @var{MercuryTypeName}.
+
+ at node Using pragma foreign_proc for Java
+ at subsubsection Using pragma foreign_proc for Java
+
+The Java code from Java pragma foreign_proc declarations will be placed in
+the bodies of static member functions of an automatically-generated Java class.
+Since such Java code will become part of a static member function,
+it must not refer to the @samp{this} keyword.
+It may however refer to static member variables or static member
+functions declared with @samp{pragma foreign_code}.
+
+The input and output variables for a Java @samp{pragma foreign_proc} will
+have Java types corresponding to their Mercury types. The exact rules
+for mapping Mercury types to Java types are described in
+ at ref{Java data passing conventions}.
+
+Java code in a @code{pragma foreign_proc} declaration
+for any procedure whose determinism indicates that it could fail
+must assign a value of type @samp{boolean} to the variable @samp{succeeded}.
+For example:
+
+ at example
+:- pred string__contains_char(string, character).
+:- mode string__contains_char(in, in) is semidet.
+
+:- pragma foreign_proc("Java",
+ string__contains_char(Str::in, Ch::in),
+ [will_not_call_mercury, promise_pure],
+ "succeeded = (Str.IndexOf(Ch) != -1);").
+ at end example
+
+ at noindent
+Java code for procedures whose determinism indicates that they cannot fail
+should not access the @code{succeeded} variable.
+
+Arguments whose mode is input will have their values set by the
+Mercury implementation on entry to the Java code.
+With our current implementation, the Java code must set the values
+of all output variables, even if the procedure fails
+(i.e. the Java code sets the @samp{succeeded} variable to @code{false}).
+ at c If the procedure
+ at c succeeds, the Java code must set the values of all output arguments
+ at c If the procedure fails, the Java code need only
+ at c set the @code{succeeded} variable to false.
+
+ at node Using pragma foreign_decl for Java
+ at subsubsection Using pragma foreign_decl for Java
+
+ at samp{pragma foreign_decl} declarations for Java can be used to provide
+any top-level Java declarations (e.g.@: @samp{import} declarations
+or auxiliary class definitions) which are needed by Java code in
+ at samp{pragma foreign_proc} declarations in that module.
+
+For example:
+
+ at example
+:- pragma foreign_decl("Java", "
+import javax.swing.*;
+import java.awt.*;
+
+class MyApplet extends JApplet @{
+ public void init() @{
+ JLabel label = new JLabel(""Hello, world"");
+ label.setHorizontalAlignment(JLabel.CENTER);
+ getContentPane().add(label);
+ @}
+@}
+").
+:- pred hello(io__state::di, io__state::uo) is det.
+:- pragma foreign_proc("Java",
+ hello(_IO0::di, _IO::uo),
+ [will_not_call_mercury],
+"
+ MyApplet app = new MyApplet();
+ // ...
+").
+ at end example
+
+ at node Using pragma foreign_code for Java
+ at subsubsection Using pragma foreign_code for Java
+
+The Java code from @samp{pragma foreign_proc} declarations for Java will be
+placed in the bodies of static member functions of an
+automatically-generated Java class. @samp{pragma foreign_code}
+can be used to define additional members of this automatically-generated
+class, which can then be referenced by @samp{pragma foreign_proc}
+declarations for Java from that module.
+
+For example:
+
+ at example
+:- pragma foreign_code("Java", "
+ static int counter = 0;
+").
+
+:- impure pred incr_counter is det.
+:- pragma foreign_proc("Java", incr_counter,
+ [will_not_call_mercury], "counter++;").
+
+:- semipure func get_counter = int.
+:- pragma foreign_proc("Java",
+ get_counter = (Result::out),
+ [will_not_call_mercury, promise_semipure],
+ "Result = counter;").
+ at end example
+
+ at c ----------------------------------------------------------------------------
+
@node Interfacing with IL
@subsection Interfacing with IL
@@ -6115,7 +6317,7 @@
The IL @samp{pragma foreign_type} declaration is of the form:
@example
-:- pragma foreign_type(il, @var{MercuryTypeName}, @var{DotNetForeignType}).
+:- pragma foreign_type("IL", @var{MercuryTypeName}, @var{DotNetForeignType}).
@end example
If the @var{MercuryTypeName} is the type of a parameter of a procedure
@@ -6148,9 +6350,11 @@
@example
:- type xmldoc.
-:- pragma foreign_type(il, xmldoc, "class [System.Xml]System.Xml.XmlDocument").
+:- pragma foreign_type("IL", xmldoc,
+ "class [System.Xml]System.Xml.XmlDocument").
:- type int32.
-:- pragma foreign_type(il, int32, "valuetype [mscorlib]System.Int32").
+:- pragma foreign_type("IL", int32,
+ "valuetype [mscorlib]System.Int32").
@end example
ensures that on the .NET CLR backend the Mercury type @samp{xmldoc} is
@@ -6182,7 +6386,7 @@
@example
:- pred add(int::in, int::in, int::out) det.
-:- pragma foreign_proc("il", add(X::in, Y::in, Z::out), [max_stack_size(2)], "
+:- pragma foreign_proc("IL", add(X::in, Y::in, Z::out), [max_stack_size(2)], "
ldloc X
ldloc Y
add
@@ -6202,7 +6406,7 @@
@c
@c @example
@c :- pred same(int::in, int::in) is semidet.
- at c :- pragma foreign_proc("il", same(X::in, Y::in), [max_stack_size(2)], "
+ at c :- pragma foreign_proc("IL", same(X::in, Y::in), [max_stack_size(2)], "
@c ldloc X
@c ldloc Y
@c ceq
@@ -6212,8 +6416,7 @@
Arguments whose mode is input will have their values set by the
Mercury implementation on entry to the IL code. If the procedure
-succeeds, the IL code must set the values of all output arguments
-before returning.
+succeeds, the IL code must set the values of all output arguments.
@c If the procedure fails, the IL code need only
@c set @code{success} to false (zero).
@@ -6272,8 +6475,8 @@
MC++ code in a @code{pragma foreign_proc} declaration
for any procedure whose determinism indicates that it could fail
-must assign a value of type bool to the variable @samp{SUCCESS_INDICATOR}.
-For example:
+must assign a value of type @samp{bool} to the variable
+ at samp{SUCCESS_INDICATOR}. For example:
@example
:- pred string__contains_char(string, character).
@@ -6290,8 +6493,8 @@
Arguments whose mode is input will have their values set by the
Mercury implementation on entry to the MC++ code. If the procedure
-succeeds, the MC++ code must set the values of all output arguments
-before returning. If the procedure fails, the MC++ code need only
+succeeds, the MC++ code must set the values of all output arguments.
+If the procedure fails, the MC++ code need only
set @code{SUCCESS_INDICATOR} to false.
@node Using pragma foreign_decl for MC++
@@ -6537,8 +6740,8 @@
Arguments whose mode is input will have their values set by the
Mercury implementation on entry to the C code. If the procedure
-succeeds, the C code must set the values of all output arguments
-before returning. If the procedure fails, the C code need only
+succeeds, the C code must set the values of all output arguments.
+If the procedure fails, the C code need only
set @code{SUCCESS_INDICATOR} to false (zero).
@node Nondet pragma c_code
@@ -7984,6 +8187,8 @@
The University of Melbourne Mercury compiler performs user-requested type
specializations when invoked with @samp{--user-guided-type-specialization},
which is enabled at optimization level @samp{-O2} or higher.
+However, for the Java back-end, user-requested type specializations
+are ignored.
@node Obsolescence
@section Obsolescence
@@ -8056,35 +8261,6 @@
to reset the source file name and line number to point back to the
generated file for the automatically generated text, as in the above
example.
-
- at c * Interfacing:: Pragmas can be used to ease interfacing
- at c with other languages.
-
- at c @node Interfacing
- at c @section Interfacing
- at c
- at c A declaration of the form
- at c
- at c @example
- at c :- pragma foreign_type(xmldoc, 'System__Xml__XmlDocument', il("System.Xml")).
- at c @end example
- at c
- at c ensures that on the IL backend the mercury type @samp{xmldoc} is
- at c represented by the backend as a @samp{System.Xml.XmlDocument}. This
- at c avoids the need to marshall values when interfacing with libraries
- at c written in other languages. The following example shows how to do this
- at c interfacing.
- at c
- at c @example
- at c :- pred loadxml(string::in, xmldoc::di, xmldoc::uo) is det.
- at c
- at c :- pragma foreign_proc("C#", load(String::in, XML0::di, XML::uo),
- at c [will_not_call_mercury],
- at c "
- at c XML0.LoadXml(String);
- at c XML = XML0;
- at c ").
- at c @end example
@node Implementation-dependent extensions
@chapter Implementation-dependent extensions
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.207
diff -u -d -r1.207 Mmakefile
--- tests/hard_coded/Mmakefile 26 Oct 2003 12:43:33 -0000 1.207
+++ tests/hard_coded/Mmakefile 2 Dec 2003 14:15:45 -0000
@@ -173,6 +173,24 @@
write_reg1 \
write_reg2
+# Tests of the C#, MC++, and IL foreign language interfaces only
+# work in IL grades
+ifeq "$(filter il%,$(GRADE))" ""
+ DOTNET_PROGS =
+else
+ DOTNET_PROGS = \
+ csharp_test
+endif
+
+# Tests of the Java foreign language interface only
+# work in IL grades
+ifeq "$(filter java%,$(GRADE))" ""
+ JAVA_PROGS =
+else
+ JAVA_PROGS = \
+ java_test
+endif
+
# Fact tables current only work in the C grades.
ifeq "$(filter il% java%,$(GRADE))" ""
FACTT_PROGS= \
@@ -228,8 +246,6 @@
# predicate. This test uses partially instantiated modes,
# which are not yet fully supported.
#
-# XXX csharp_test doesn't work yet (not even in il* grades)
-#
# XXX needs_init doesn't work yet in profiling grades.
#
# XXX compare_rep_array doesn't work because MR_COMPARE_BY_RTTI is
@@ -326,16 +342,17 @@
endif
endif
-# We currently don't do any testing in grade java on this directory.
+# We currently don't do any testing in grade java on this directory,
+# except for java_test.m.
ifneq "$(findstring java,$(GRADE))" ""
- PROGS =
+ PROGS = $(JAVA_PROGS)
else
PROGS = $(ORDINARY_PROGS) $(BROKEN_FOR_LCC_PROGS) \
$(CLOSURE_LAYOUT_PROGS) $(EXCEPTION_PROGS) \
$(BACKEND_PROGS) $(NONDET_C_PROGS) \
$(C_AND_GC_ONLY_PROGS) $(STATIC_LINK_PROGS) \
$(CHAR_REP_PROGS) $(BROKEN_FOR_PROFDEEP) \
- $(FACTT_PROGS)
+ $(FACTT_PROGS) $(DOTNET_PROGS) $(JAVA_PROGS)
endif
# --split-c-files does not work in the hl* grades (e.g. hlc.gc),
Index: tests/hard_coded/csharp_test.exp
===================================================================
RCS file: tests/hard_coded/csharp_test.exp
diff -N tests/hard_coded/csharp_test.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/csharp_test.exp 2 Dec 2003 14:21:35 -0000
@@ -0,0 +1 @@
+Hello, world
Index: tests/hard_coded/csharp_test.m
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/csharp_test.m,v
retrieving revision 1.2
diff -u -d -r1.2 csharp_test.m
--- tests/hard_coded/csharp_test.m 15 May 2001 12:51:04 -0000 1.2
+++ tests/hard_coded/csharp_test.m 2 Dec 2003 14:21:08 -0000
@@ -23,7 +23,8 @@
:- pragma(foreign_proc, "C#",
csharp_write_string(Message::in, _IO0::di, _IO::uo),
- [will_not_call_mercury],
+ [will_not_call_mercury, promise_pure],
"
// a C sharp procedure
+ Console.WriteLine(Message);
").
Index: tests/hard_coded/java_test.exp
===================================================================
RCS file: tests/hard_coded/java_test.exp
diff -N tests/hard_coded/java_test.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/java_test.exp 2 Dec 2003 14:20:15 -0000
@@ -0,0 +1 @@
+Hello, world
Index: tests/hard_coded/java_test.m
===================================================================
RCS file: tests/hard_coded/java_test.m
diff -N tests/hard_coded/java_test.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/java_test.m 2 Dec 2003 14:38:10 -0000
@@ -0,0 +1,69 @@
+% A test of the Java interface.
+
+:- module java_test.
+:- interface.
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+:- import_module int.
+
+:- func foo(int) = int.
+/*
+XXX `pragma export' not yet supported for Java
+:- pragma export(foo(in) = out, "foo").
+*/
+foo(X) = X + 1.
+
+main -->
+ java_write_string("Hello, world\n"),
+ ( { java_semidet_succeed } ->
+ []
+ ;
+ java_write_string("java_semidet_succeed failed\n")
+ ),
+ ( { java_semidet_fail } ->
+ java_write_string("java_semidet_fail succeeded\n")
+ ;
+ []
+ ).
+
+:- pragma(foreign_decl, "Java", "
+ // some Java top-level declarations
+ class Foo {}
+").
+
+:- pragma(foreign_code, "Java", "
+ // some Java in-class declarations
+ static void bar() {
+/*
+XXX `pragma export' not yet supported for Java
+ // test `pragma export' functions
+ if (foo(42) != 43) {
+ throw new java.lang.Error(""bar: foo failed"");
+ }
+*/
+ }
+").
+
+:- pred java_write_string(string::in, io__state::di, io__state::uo) is det.
+
+:- pragma(foreign_proc, "Java",
+ java_write_string(Message::in, _IO0::di, _IO::uo),
+ [will_not_call_mercury, promise_pure],
+"
+ // a Java procedure
+ System.out.print(Message);
+ // test that foreign_decl declarations are visible
+ Foo f;
+ // test that foreign_code declarations are visible
+ bar();
+").
+
+:- pred java_semidet_succeed is semidet.
+:- pred java_semidet_fail is semidet.
+:- pragma(foreign_proc, "Java", java_semidet_succeed,
+ [will_not_call_mercury, promise_pure], "succeeded = true;").
+:- pragma(foreign_proc, "Java", java_semidet_fail,
+ [will_not_call_mercury, promise_pure], "succeeded = false;").
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list