[m-rev.] diff: foreign export bool for java

Peter Wang novalazy at gmail.com
Tue Aug 11 17:31:44 AEST 2009


On 2009-08-11, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
> 
> On Tue, 11 Aug 2009, Peter Wang wrote:
> 
> >Branches: main
> >
> >library/bool.m:
> >       Export `bool' enumeration values for Java foreign code.
> >
> >diff --git a/library/bool.m b/library/bool.m
> >index a620e98..f997bfb 100644
> >--- a/library/bool.m
> >+++ b/library/bool.m
> >@@ -77,6 +77,12 @@
> >% The representation of bool values should correspond with the definitions of
> >% MR_TRUE and MR_FALSE in runtime/mercury_std.h.
> >
> >+:- pragma foreign_export_enum("Java", bool/0, [],
> >+    [
> >+        no  - "ML_NO",
> >+        yes - "ML_YES"
> >+    ]).
> >+
> 
> For consistency with the C version perhaps they should be called MR_NO
> and MR_YES?  (Or at least add a second foreign_export_enum pragma that
> uses those names.)

I've changed it in this patch (and builtin.comparison_result) but I'm
not really sure about it.

> You should also update the Java data passing conventions section of the
> reference manual.  (You may as well add the foreign export for
> builtin.comparison_result that the C grades have as well).

For review:

Branches: main

library/bool.m:
library/builtin.m:
        Rename exported enumeration values for Java to MR_* for consistency with
        the C version.

library/list.m:
        Add `MR_empty_list', `MR_cons', `MR_is_empty', `MR_det_head' and
        `MR_det_tail' for manipulating lists from Java foreign code.

        Add wrapper class `MR_ListIterator<E>' that allows iteration over
        Mercury lists using Java for-each syntax (undocumented for now).

doc/reference_manual.texi:
doc/user_guide.texi:
        Update documentation pertaining to Java foreign language interface.

library/bitmap.m:
library/rtti_implementation.m:
library/string.m:
        Conform to renamings.

        Use for-each syntax in some places.

diff --git a/doc/reference_manual.texi b/doc/reference_manual.texi
index 946c2e5..c55041d 100644
--- a/doc/reference_manual.texi
+++ b/doc/reference_manual.texi
@@ -6948,6 +6948,24 @@ and @code{string} are mapped to the Java types
 @code{int}, @code{double}, @code{char} and
 @code{java.lang.String} respectively.
 
+For the Mercury standard library type @samp{bool.bool}, there is a
+corresponding Java type, @code{bool.Bool_0}.  Java code can refer to the
+boolean data constructors @samp{yes} and @samp{no}, as @code{bool.MR_YES}
+and @code{bool.MR_NO} respectively.
+
+For the Mercury standard library type @samp{builtin.comparison_result}, there
+is a corresponding Java type, @code{builtin.Comparison_result_0}.  Java code
+can refer to the data constructors of this type, @samp{(<)}, @samp{(=)} and
+ at samp{(>)}, as @code{builtin.MR_COMPARE_LESS}, @code{builtin.MR_COMPARE_EQUAL}
+and @code{builtin.MR_COMPARE_GREATER} respectively.
+
+Mercury variables of a type for which there is a Java @samp{pragma
+foreign_type} declaration (@pxref{Using foreign types from Mercury}) will be
+passed as the corresponding Java type.
+
+Mercury tuple types are passed as @samp{java.lang.Object[]} where
+the length of the array is the number of elements in the tuple.
+
 Mercury variables whose type is a type variable will be passed as
 @code{java.lang.Object}.
 Mercury array types are mapped to Java array types.
@@ -6959,11 +6977,15 @@ 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.
+The first character of the type name will have its case inverted,
+and the name may be mangled to satisfy Java lexical rules.
+
+Java code generated by the Mercury compiler is placed in the @samp{jmercury}
+package.  Mercury module qualifiers are converted into a Java class name by
+concatenating the components with double underscore separators (@samp{__}).
 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.
+type @samp{jmercury.foo__bar.Baz_1}.
+
 Mercury variables whose type is a Mercury equivalence type
 will be passed as the representation of the right hand side of the
 equivalence type.
@@ -6999,6 +7021,17 @@ passed or returned at all.
 and in Java modifications to mutable state are done via side effects,
 rather than argument passing.)
 
+Mercury lists can be manipulated by Java code using the following methods,
+which are defined by the Mercury implementation.
+
+ at example
+list.MR_is_empty(list)      /* test if a list is empty */
+list.MR_det_head(list)      /* get the head of a list */
+list.MR_det_tail(list)      /* get the tail of a list */
+list.MR_empty_list()        /* create an empty list */
+list.MR_cons(head, tail)    /* construct a list with the given head and tail */
+ at end example
+
 @node Erlang data passing conventions
 @subsection Erlang data passing conventions
 
@@ -8088,16 +8121,15 @@ A Java @samp{pragma foreign_type} declaration has the form:
 :- pragma foreign_type("Java", @var{MercuryTypeName}, "@var{JavaType}").
 @end example
 
-The @var{JavaType} can be any accessible Java type.
+The @var{JavaType} can be any accessible non-primitive Java type.
 
 The effect of this declaration is that Mercury values of type
 @var{MercuryTypeName} will be passed to and from Java foreign_procs
 as having type @var{JavaType}.
 
- at c XXX `pragma foreign_export' not supported yet for Java
- at c Furthermore, any Mercury procedure exported with @samp{pragma foreign_export}
- at c will use @var{JavaType} as the type for any
- at c parameters whose Mercury type is @var{MercuryTypeName}.
+Furthermore, any Mercury procedure exported with @samp{pragma foreign_export}
+will use @var{JavaType} as the type for any
+parameters whose Mercury type is @var{MercuryTypeName}.
 
 @node Using pragma foreign_proc for Java
 @subsubsection Using pragma foreign_proc for Java
@@ -8146,7 +8178,38 @@ of all output variables, even if the procedure fails
 @node Using pragma foreign_export for Java
 @subsubsection Using pragma foreign_export for Java
 
- at samp{pragma foreign_export} is not currently supported for Java.
+A @samp{pragma foreign_export} declaration for Java has the form:
+
+ at example
+:- pragma foreign_export("Java", @var{MercuryMode}, "@var{Java_Name}").
+ at end example
+
+For example,
+
+ at example
+:- pragma foreign_export("Java", foo(in, in, out), "FOO").
+ at end example
+
+The type signature of the Java interface to a Mercury procedure is as
+described in @ref{Java data passing conventions}.
+
+Calling polymorphically typed Mercury procedures from Java 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 Java 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.
+ at c XXX the following won't work while type_descs and type_infos have
+ at c different representations in Java.
+ at c These @samp{type_info} arguments can
+ at c be obtained using the Mercury @samp{type_of} function in the Mercury
+ at c standard library module @samp{type_desc}.
 
 @node Using pragma foreign_decl for Java
 @subsubsection Using pragma foreign_decl for Java
diff --git a/doc/user_guide.texi b/doc/user_guide.texi
index a43a106..2a0ddf1 100644
--- a/doc/user_guide.texi
+++ b/doc/user_guide.texi
@@ -10134,6 +10134,9 @@ Runtime (sometimes also known as CIL or MSIL).
 Only available on backends that compile to IL.
 This is the preferred foreign language for IL code generation.
 
+ at item @samp{Java}
+This is the only foreign language for backends which compile to Java.
+
 @end table
 
 @c ----------------------------------------------------------------------------
diff --git a/library/bitmap.m b/library/bitmap.m
index c37a540..4bd2a0a 100644
--- a/library/bitmap.m
+++ b/library/bitmap.m
@@ -1631,21 +1631,21 @@ bytes_equal(Index, MaxIndex, BM1, BM2) :-
         may_not_duplicate],
 "
     if (BM1.num_bits < BM2.num_bits) {
-        Result = builtin.ML_COMPARE_LESS;
+        Result = builtin.MR_COMPARE_LESS;
     } else if (BM1.num_bits > BM2.num_bits) {
-        Result = builtin.ML_COMPARE_GREATER;
+        Result = builtin.MR_COMPARE_GREATER;
     } else {
-        Result = builtin.ML_COMPARE_EQUAL;
+        Result = builtin.MR_COMPARE_EQUAL;
         for (int i = 0; i < BM1.elements.length; i++) {
             // Mask off sign bits.
             int b1 = ((int) BM1.elements[i]) & 0xff;
             int b2 = ((int) BM2.elements[i]) & 0xff;
             if (b1 < b2) {
-                Result = builtin.ML_COMPARE_LESS;
+                Result = builtin.MR_COMPARE_LESS;
                 break;
             }
             if (b1 > b2) {
-                Result = builtin.ML_COMPARE_GREATER;
+                Result = builtin.MR_COMPARE_GREATER;
                 break;
             }
         }
diff --git a/library/bool.m b/library/bool.m
index 73b0ace..6322ab1 100644
--- a/library/bool.m
+++ b/library/bool.m
@@ -79,8 +79,8 @@
 
 :- pragma foreign_export_enum("Java", bool/0, [],
     [
-        no  - "ML_NO",
-        yes - "ML_YES"
+        no  - "MR_NO",
+        yes - "MR_YES"
     ]).
 
 :- instance enum(bool) where [
diff --git a/library/builtin.m b/library/builtin.m
index 5894503..9a6aedc 100644
--- a/library/builtin.m
+++ b/library/builtin.m
@@ -604,9 +604,9 @@ get_one_solution_io(Pred, X, !IO) :-
 
 :- pragma foreign_export_enum("Java", comparison_result/0, [],
     [
-        (=) - "ML_COMPARE_EQUAL",
-        (<) - "ML_COMPARE_LESS",
-        (>) - "ML_COMPARE_GREATER"
+        (=) - "MR_COMPARE_EQUAL",
+        (<) - "MR_COMPARE_LESS",
+        (>) - "MR_COMPARE_GREATER"
     ]).
 
 ordering(X, Y) = R :-
diff --git a/library/list.m b/library/list.m
index 63f6509..58aa296 100644
--- a/library/list.m
+++ b/library/list.m
@@ -2775,3 +2775,81 @@ list_to_doc_2([X | Xs]) = Doc :-
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
+
+:- pragma foreign_code("Java", "
+
+/*
+** We don't use `:- pragma foreign_export' to generate these methods because
+** the interfaces would expect type_info arguments.
+*/
+
+public static List_1 MR_empty_list()
+{
+    return new List_1.F_nil_0();
+}
+
+public static List_1 MR_cons(Object H, List_1 T)
+{
+    return new List_1.F_cons_2(H, T);
+}
+
+public static boolean MR_is_empty(List_1 lst)
+{
+    return (lst instanceof List_1.F_nil_0);
+}
+
+public static Object MR_det_head(List_1 lst)
+{
+    return ((List_1.F_cons_2) lst).F1;
+}
+
+public static List_1 MR_det_tail(List_1 lst)
+{
+    return ((List_1.F_cons_2) lst).F2;
+}
+
+/*
+** A wrapper class to allow for-each syntax.
+** You must use a new instance of this class for each loop!
+*/
+
+public static class MR_ListIterator<E>
+    implements java.lang.Iterable, java.util.Iterator<E>
+{
+    private List_1 lst;
+
+    public MR_ListIterator(List_1 lst)
+    {
+        this.lst = lst;
+    }
+
+    public java.util.Iterator<E> iterator()
+    {
+        return this;
+    }
+
+    public boolean hasNext()
+    {
+        return lst instanceof List_1.F_cons_2;
+    }
+
+    public E next()
+    {
+        if (lst instanceof List_1.F_cons_2) {
+            E head = (E) ((List_1.F_cons_2) lst).F1;
+            lst = ((List_1.F_cons_2) lst).F2;
+            return head;
+        } else {
+            throw new java.util.NoSuchElementException();
+        }
+    }
+
+    public void remove()
+    {
+        throw new java.lang.UnsupportedOperationException();
+    }
+}
+").
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
diff --git a/library/rtti_implementation.m b/library/rtti_implementation.m
index 1f0a872..bb36992 100644
--- a/library/rtti_implementation.m
+++ b/library/rtti_implementation.m
@@ -1342,17 +1342,17 @@ iterate(Start, Max, Func) = Results :-
     }
 
     private static Object[]
-    ML_univ_list_to_array(list.List_1 list, int arity)
+    ML_univ_list_to_array(list.List_1 lst, int arity)
     {
         final Object[] args = new Object[arity];
 
         for (int i = 0; i < arity; i++) {
-            univ.Univ_0 head = (univ.Univ_0) ((list.List_1.F_cons_2) list).F1;
-            args[i] = head.F2;
-            list = ((list.List_1.F_cons_2) list).F2;
+            univ.Univ_0 head = (univ.Univ_0) list.MR_det_head(lst);
+            args[i] = univ.ML_unravel_univ(head)[1];
+            lst = list.MR_det_tail(lst);
         }
 
-        if (list instanceof list.List_1.F_nil_0) {
+        if (list.MR_is_empty(lst)) {
             return args;
         } else {
             return null;
@@ -1429,13 +1429,13 @@ iterate(Start, Max, Func) = Results :-
     }
 
     private static Object[]
-    ML_list_to_array(list.List_1 list, int arity)
+    ML_list_to_array(list.List_1 lst, int arity)
     {
         final Object[] array = new Object[arity];
 
         for (int i = 0; i < arity; i++) {
-            array[i] = ((list.List_1.F_cons_2) list).F1;
-            list = ((list.List_1.F_cons_2) list).F2;
+            array[i] = list.MR_det_head(lst);
+            lst = list.MR_det_tail(lst);
         }
 
         return array;
@@ -1462,14 +1462,13 @@ construct(_, _, _) = _ :-
     [will_not_call_mercury, promise_pure, thread_safe,
         may_not_duplicate],
 "
+    list.List_1 args_list = (list.List_1) Args;
     Object[] args_array = new Object[Arity];
 
     for (int i = 0; i < Arity; i++) {
-        univ.Univ_0 head = (univ.Univ_0) ((list.List_1.F_cons_2) Args).F1;
-        Object[] rc = univ.ML_unravel_univ(head);
-        args_array[i] = rc[1];
-
-        Args = ((list.List_1.F_cons_2) Args).F2;
+        univ.Univ_0 head = (univ.Univ_0) list.MR_det_head(args_list);
+        args_array[i] = univ.ML_unravel_univ(head)[1];
+        args_list = list.MR_det_tail(args_list);
     }
 
     Object[] args = ML_list_to_array((list.List_1) ArgTypes, Arity);
diff --git a/library/string.m b/library/string.m
index 6d63b87..4ec4b36 100644
--- a/library/string.m
+++ b/library/string.m
@@ -1339,10 +1339,10 @@ string.to_char_list(Str::uo, CharList::in) :-
     [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
         does_not_affect_liveness, no_sharing],
 "
-    list.List_1 lst = new list.List_1.F_nil_0();
+    list.List_1 lst = list.MR_empty_list();
     for (int i = Str.length() - 1; i >= 0; i--) {
         char c = Str.charAt(i);
-        lst = new list.List_1.F_cons_2(c, lst);
+        lst = list.MR_cons(c, lst);
     }
     CharList = lst;
 ").
@@ -1438,11 +1438,9 @@ string.from_char_list(Chars::in, Str::uo) :-
         does_not_affect_liveness],
 "
     java.lang.StringBuilder sb = new StringBuilder();
-    while (CharList instanceof list.List_1.F_cons_2) {
-        list.List_1.F_cons_2 cons = (list.List_1.F_cons_2) CharList;
-        char c = ((java.lang.Character) cons.F1).charValue();
+    Iterable<Character> iterable = new list.MR_ListIterator((list.List_1) CharList);
+    for (char c : iterable) {
         sb.append(c);
-        CharList = cons.F2;
     }
     Str = sb.toString();
     succeeded = true;
@@ -1667,12 +1665,12 @@ string.append_list(Lists, string.append_list(Lists)).
         does_not_affect_liveness],
 "
     java.lang.StringBuilder sb = new java.lang.StringBuilder();
-    while (Strs instanceof list.List_1.F_cons_2) {
-        list.List_1.F_cons_2 cons = (list.List_1.F_cons_2) Strs;
-        java.lang.String s = (java.lang.String) cons.F1;
+
+    Iterable<String> iterable = new list.MR_ListIterator((list.List_1) Strs);
+    for (String s : iterable) {
         sb.append(s);
-        Strs = cons.F2;
     }
+
     Str = sb.toString();
 ").
 
@@ -1752,15 +1750,13 @@ string.append_list(Strs::in) = (Str::uo) :-
     java.lang.StringBuilder sb = new java.lang.StringBuilder();
     boolean add_sep = false;
 
-    while (Strs instanceof list.List_1.F_cons_2) {
-        list.List_1.F_cons_2 cons = (list.List_1.F_cons_2) Strs;
-        java.lang.String s = (java.lang.String) cons.F1;
+    Iterable<String> iterable = new list.MR_ListIterator((list.List_1) Strs);
+    for (String s : iterable) {
         if (add_sep) {
             sb.append(Sep);
         }
         sb.append(s);
         add_sep = true;
-        Strs = cons.F2;
     }
 
     Str = sb.toString();

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list