[m-rev.] for review: improve deconstruction (and printing) of foreign types in C# and Java grades
Julien Fischer
jfischer at opturion.com
Wed Mar 13 16:30:08 AEDT 2019
For review by anyone.
----------------------------
Improve deconstruction (and printing) of foreign types in C# and Java grades.
Currently, we return a placeholder string ("foreignxx") if we attempt to look
up the functor of a foreign type in the C# or Java grades. For C, we return a
string of the form:
<<foreign(Name, Rep)>>
where Name is the type's Mercury name and Rep is its "value" as results from
casting it to (void *) and then using sprintf's %p conversion specifier. Do
something similar for both the C# and Java grades, except that for Rep we
return the output of the calling the toString() (ToString()) method. If the
object in question is a null reference then we return "null" for Rep.
Document how the predicates in the deconstruct module handle foreign types.
library/rtti_implementation.m:
Return more information about foreign type functors.
library/deconstruct.m:
Make the above changes to the documentation.
tests/hard_coded/csharp_print_foreign.{m,exp}:
tests/hard_coded/java_print_foreign.{m,exp}:
Tests of the new functionality in the C# and Java grades.
tests/hard_coded/Mmakefile:
Add the new tests.
Add a new category of test programs that are only run in the C# grades.
Julien.
diff --git a/library/deconstruct.m b/library/deconstruct.m
index 3c8abec..a5446ce 100644
--- a/library/deconstruct.m
+++ b/library/deconstruct.m
@@ -92,6 +92,9 @@
% - for arrays, the string <<array>>.
% - for c_pointers, the string ptr(0xXXXX) where XXXX is the
% hexadecimal representation of the pointer.
+ % - for foreign types, a string of the form <<foreign(Name, Rep)>> where
+ % Name is the type's Mercury name and Rep is a target language specific
+ % representation of the term's value.
% - for bitmaps, the bitmap converted to a length and a
% hexadecimal string inside angle brackets and quotes of the
% form """<[0-9]:[0-9A-F]*>""".
@@ -113,6 +116,7 @@
% - for tuples, the number of elements in the tuple.
% - for arrays, the number of elements in the array.
% - for c_pointers, zero.
+ % - for foreign types, zero.
% - for bitmaps, zero.
%
% Note that in the current University of Melbourne implementation,
diff --git a/library/rtti_implementation.m b/library/rtti_implementation.m
index 85b9b42..42f582d 100644
--- a/library/rtti_implementation.m
+++ b/library/rtti_implementation.m
@@ -3142,7 +3142,10 @@ deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
;
(
TypeCtorRep = tcr_foreign,
- Functor = "<<foreignxx>>"
+ TypeCtorName = TypeCtorInfo ^ type_ctor_name,
+ TargetLangRep = get_target_lang_rep(Term),
+ string.format("<<foreign(%s, %s)>>",
+ [s(TypeCtorName), s(TargetLangRep)], Functor)
;
TypeCtorRep = tcr_stable_foreign,
Functor = "<<stable_foreign>>"
@@ -3956,6 +3959,43 @@ same_pointer_value_untyped(_, _) :-
% matching foreign_proc version.
private_builtin.sorry("same_pointer_value_untyped").
+:- func get_target_lang_rep(T) = string.
+
+:- pragma foreign_proc("C",
+ get_target_lang_rep(Term::in) = (S::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ // This should be kept in sync with the MR_TYEPCTOR_REP_FOREIGN
+ // case in runtime/mercury_ml_expand_body.h.
+ char buf[256];
+ MR_snprintf(buf, 256, ""%p"", (void *) Term);
+ MR_make_aligned_string_copy(S, buf);
+").
+
+:- pragma foreign_proc("C#",
+ get_target_lang_rep(Term::in) = (S::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if (Term == null) {
+ S = ""null"";
+ } else {
+ S = Term.ToString();
+ }
+").
+
+:- pragma foreign_proc("Java",
+ get_target_lang_rep(Term::in) = (S::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if (Term == null) {
+ S = ""null"";
+ } else {
+ S = Term.toString();
+ }
+").
+
+get_target_lang_rep(_) = "some_foreign_value".
+
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index d99efb8..1a51cc9 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -562,10 +562,20 @@ ifeq "$(filter java%,$(GRADE))" ""
JAVA_PROGS =
else
JAVA_PROGS = \
+ java_print_foreign \
java_test \
test_java_foreign_primitive
endif
+# Tests of the C# foreign language interface only work in the C# grades.
+
+ifeq "$(filter csharp%,$(GRADE))" ""
+ CSHARP_PROGS =
+else
+ CSHARP_PROGS = \
+ csharp_print_foreign
+endif
+
# Fact tables currently work only in the C grades.
# The foreign_type_assertion test is currently meaningful only in C grades.
# Tests of the C foreign language interface only work in C grades.
@@ -837,6 +847,7 @@ PROGS = \
$(STATIC_LINK_PROGS) \
$(C_ONLY_PROGS) \
$(JAVA_PROGS) \
+ $(CSHARP_PROGS) \
$(SOLVER_PROGS) \
$(FOREIGN_ENUM_PROGS) \
$(TRAILED_PROGS) \
diff --git a/tests/hard_coded/csharp_print_foreign.exp b/tests/hard_coded/csharp_print_foreign.exp
index e69de29..fea695b 100644
--- a/tests/hard_coded/csharp_print_foreign.exp
+++ b/tests/hard_coded/csharp_print_foreign.exp
@@ -0,0 +1,8 @@
+'<<foreign(foreign_bool, True)>>'
+'<<foreign(foreign_char, A)>>'
+'<<foreign(foreign_int, 561)>>'
+'<<foreign(foreign_long, 561)>>'
+'<<foreign(foreign_float, 3.402823E+38)>>'
+'<<foreign(foreign_double, 1.79769313486232E+308)>>'
+'<<foreign(uuid, 00000000-0000-0000-0000-000000000000)>>'
+'<<foreign(object, null)>>'
diff --git a/tests/hard_coded/csharp_print_foreign.m b/tests/hard_coded/csharp_print_foreign.m
index e69de29..5387006 100644
--- a/tests/hard_coded/csharp_print_foreign.m
+++ b/tests/hard_coded/csharp_print_foreign.m
@@ -0,0 +1,109 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test io.print etc with foreign types in the C# grades.
+%
+%---------------------------------------------------------------------------%
+
+:- module csharp_print_foreign.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+main(!IO) :-
+ io.print_line(get_foreign_bool, !IO),
+ io.print_line(get_foreign_char, !IO),
+ io.print_line(get_foreign_int, !IO),
+ io.print_line(get_foreign_long, !IO),
+ io.print_line(get_foreign_float, !IO),
+ io.print_line(get_foreign_double, !IO),
+ io.print_line(get_uuid, !IO),
+ io.print_line(null_object, !IO).
+
+:- type foreign_bool.
+:- pragma foreign_type("C#", foreign_bool, "bool").
+:- func get_foreign_bool = foreign_bool.
+:- pragma foreign_proc("C#",
+ get_foreign_bool = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = true;
+").
+
+:- type foreign_int.
+:- pragma foreign_type("C#", foreign_int, "int").
+:- func get_foreign_int = foreign_int.
+:- pragma foreign_proc("C#",
+ get_foreign_int = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = 561;
+").
+
+:- type foreign_char.
+:- pragma foreign_type("C#", foreign_char, "char").
+:- func get_foreign_char = foreign_char.
+:- pragma foreign_proc("C#",
+ get_foreign_char = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = 'A';
+").
+
+:- type foreign_long.
+:- pragma foreign_type("C#", foreign_long, "long").
+:- func get_foreign_long = foreign_long.
+:- pragma foreign_proc("C#",
+ get_foreign_long = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = 561L;
+").
+
+:- type foreign_float.
+:- pragma foreign_type("C#", foreign_float, "float").
+:- func get_foreign_float = foreign_float.
+:- pragma foreign_proc("C#",
+ get_foreign_float = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = System.Single.MaxValue;
+").
+
+:- type foreign_double.
+:- pragma foreign_type("C#", foreign_double, "double").
+:- func get_foreign_double = foreign_double.
+:- pragma foreign_proc("C#",
+ get_foreign_double = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = System.Double.MaxValue;
+").
+
+:- type uuid.
+:- pragma foreign_type("C#", uuid, "System.Guid").
+:- func get_uuid = uuid.
+:- pragma foreign_proc("C#",
+ get_uuid = (U::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U = System.Guid.Empty;
+").
+
+:- type object.
+:- pragma foreign_type("C#", object, "System.Object").
+:- func null_object = object.
+:- pragma foreign_proc("C#",
+ null_object = (U::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U = null;
+").
diff --git a/tests/hard_coded/java_print_foreign.exp b/tests/hard_coded/java_print_foreign.exp
index e69de29..e92084a 100644
--- a/tests/hard_coded/java_print_foreign.exp
+++ b/tests/hard_coded/java_print_foreign.exp
@@ -0,0 +1,10 @@
+'<<foreign(foreign_bool, true)>>'
+'<<foreign(foreign_char, A)>>'
+'<<foreign(foreign_int, 561)>>'
+'<<foreign(foreign_long, 561)>>'
+'<<foreign(foreign_float, 3.4028235E38)>>'
+'<<foreign(foreign_double, 1.7976931348623157E308)>>'
+'<<foreign(uuid, 5f4fe224-2d69-49f0-9c72-acb9ec8400ef)>>'
+'<<foreign(uuid, null)>>'
+'<<foreign(local_date, +999999999-12-31)>>'
+'<<foreign(local_date, null)>>'
diff --git a/tests/hard_coded/java_print_foreign.m b/tests/hard_coded/java_print_foreign.m
index e69de29..34f95bb 100644
--- a/tests/hard_coded/java_print_foreign.m
+++ b/tests/hard_coded/java_print_foreign.m
@@ -0,0 +1,129 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test io.print etc with foreign types in the Java grades.
+%
+%---------------------------------------------------------------------------%
+
+:- module java_print_foreign.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+main(!IO) :-
+ io.print_line(get_foreign_bool, !IO),
+ io.print_line(get_foreign_char, !IO),
+ io.print_line(get_foreign_int, !IO),
+ io.print_line(get_foreign_long, !IO),
+ io.print_line(get_foreign_float, !IO),
+ io.print_line(get_foreign_double, !IO),
+ io.print_line(get_uuid, !IO),
+ io.print_line(null_uuid, !IO),
+ io.print_line(get_local_date, !IO),
+ io.print_line(null_local_date, !IO).
+
+:- type foreign_bool.
+:- pragma foreign_type("Java", foreign_bool, "boolean").
+:- func get_foreign_bool = foreign_bool.
+:- pragma foreign_proc("Java",
+ get_foreign_bool = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = true;
+").
+
+:- type foreign_int.
+:- pragma foreign_type("Java", foreign_int, "int").
+:- func get_foreign_int = foreign_int.
+:- pragma foreign_proc("Java",
+ get_foreign_int = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = 561;
+").
+
+:- type foreign_char.
+:- pragma foreign_type("Java", foreign_char, "char").
+:- func get_foreign_char = foreign_char.
+:- pragma foreign_proc("Java",
+ get_foreign_char = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = 'A';
+").
+
+:- type foreign_long.
+:- pragma foreign_type("Java", foreign_long, "long").
+:- func get_foreign_long = foreign_long.
+:- pragma foreign_proc("Java",
+ get_foreign_long = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = 561L;
+").
+
+:- type foreign_float.
+:- pragma foreign_type("Java", foreign_float, "float").
+:- func get_foreign_float = foreign_float.
+:- pragma foreign_proc("Java",
+ get_foreign_float = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = java.lang.Float.MAX_VALUE;
+").
+
+:- type foreign_double.
+:- pragma foreign_type("Java", foreign_double, "double").
+:- func get_foreign_double = foreign_double.
+:- pragma foreign_proc("Java",
+ get_foreign_double = (V::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ V = java.lang.Double.MAX_VALUE;
+").
+
+:- type uuid.
+:- pragma foreign_type("Java", uuid, "java.util.UUID").
+:- func get_uuid = uuid.
+:- pragma foreign_proc("Java",
+ get_uuid = (U::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U = java.util.UUID.fromString(""5f4fe224-2d69-49f0-9c72-acb9ec8400ef"");
+").
+
+:- func null_uuid = uuid.
+:- pragma foreign_proc("Java",
+ null_uuid = (U::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U = null;
+").
+
+:- type local_date.
+:- pragma foreign_type("Java", local_date, "java.time.LocalDate").
+:- func get_local_date = local_date.
+:- pragma foreign_proc("Java",
+ get_local_date = (U::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U = java.time.LocalDate.MAX;
+").
+
+:- func null_local_date = local_date.
+:- pragma foreign_proc("Java",
+ null_local_date = (U::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U = null;
+").
+
+
More information about the reviews
mailing list