Merge: Generalize instance creation service so FFI can use it
authorJean Privat <jean@pryen.org>
Fri, 6 Feb 2015 01:14:55 +0000 (08:14 +0700)
committerJean Privat <jean@pryen.org>
Fri, 6 Feb 2015 01:14:55 +0000 (08:14 +0700)
Move up instance creation from ANew to AbstractCompilerVisitor so they can be used from the FFI implementation. Allows to call extern constructors of extern classes from extern code, and fix #1145.

Pull-Request: #1150
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>

src/compiler/abstract_compiler.nit
src/compiler/compiler_ffi.nit
tests/sav/test_ffi_c_new_extern.res [new file with mode: 0644]
tests/test_ffi_c_new_extern.nit [new file with mode: 0644]

index b212fed..f286f02 100644 (file)
@@ -1387,6 +1387,24 @@ abstract class AbstractCompilerVisitor
        # Generate a alloc-instance + init-attributes
        fun init_instance(mtype: MClassType): RuntimeVariable is abstract
 
+       # Allocate and init attributes of an instance of a standard or extern class
+       #
+       # Does not support universals and the pseudo-internal `NativeArray` class.
+       fun init_instance_or_extern(mtype: MClassType): RuntimeVariable
+       do
+               var recv
+               var ctype = mtype.ctype
+               assert mtype.mclass.name != "NativeArray"
+               if ctype == "val*" then
+                       recv = init_instance(mtype)
+               else if ctype == "char*" then
+                       recv = new_expr("NULL/*special!*/", mtype)
+               else
+                       recv = new_expr("({ctype})0/*special!*/", mtype)
+               end
+               return recv
+       end
+
        # Set a GC finalizer on `recv`, only if `recv` isa Finalizable
        fun set_finalizer(recv: RuntimeVariable)
        do
@@ -2883,22 +2901,17 @@ redef class ANewExpr
        do
                var mtype = self.recvtype
                assert mtype != null
-               var recv
-               var ctype = mtype.ctype
+
                if mtype.mclass.name == "NativeArray" then
                        assert self.n_args.n_exprs.length == 1
                        var l = v.expr(self.n_args.n_exprs.first, null)
                        assert mtype isa MGenericType
                        var elttype = mtype.arguments.first
                        return v.native_array_instance(elttype, l)
-               else if ctype == "val*" then
-                       recv = v.init_instance(mtype)
-               else if ctype == "char*" then
-                       recv = v.new_expr("NULL/*special!*/", mtype)
-               else
-                       recv = v.new_expr("({ctype})0/*special!*/", mtype)
                end
 
+               var recv = v.init_instance_or_extern(mtype)
+
                var callsite = self.callsite.as(not null)
                var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
                var res2 = v.compile_callsite(callsite, args)
index dea917b..42423f9 100644 (file)
@@ -388,7 +388,7 @@ redef class MExplicitCall
                var recv_var = null
                if mproperty.is_init then
                        var recv_mtype = recv_mtype
-                       recv_var = nitni_visitor.init_instance(recv_mtype)
+                       recv_var = nitni_visitor.init_instance_or_extern(recv_mtype)
                        nitni_visitor.add("{mtype.ctype} recv /* var self: {mtype} */;")
                        nitni_visitor.add("recv = {recv_var};")
                else
diff --git a/tests/sav/test_ffi_c_new_extern.res b/tests/sav/test_ffi_c_new_extern.res
new file mode 100644 (file)
index 0000000..ae8c4c1
--- /dev/null
@@ -0,0 +1,2 @@
+1234
+5678
diff --git a/tests/test_ffi_c_new_extern.nit b/tests/test_ffi_c_new_extern.nit
new file mode 100644 (file)
index 0000000..e9b46d2
--- /dev/null
@@ -0,0 +1,45 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test callback to an extern constructor from extern code
+
+import standard::string
+
+extern class IntPtr `{ int* `}
+       new (v: Int) `{
+               int *r = malloc(sizeof(int));
+               *r = v;
+               return r;
+       `}
+
+       redef fun to_s import NativeString, NativeString.to_s `{
+               int len = snprintf(NULL, 0, "%d", *recv) + 1;
+               char *c = new_NativeString(len);
+               sprintf(c, "%d", *recv);
+               return NativeString_to_s(c);
+       `}
+end
+
+fun foo: IntPtr import IntPtr `{
+       int *c = new_IntPtr(5678);
+       return c;
+`}
+
+var a = new IntPtr(1234)
+a.to_s.output
+"\n".output
+
+var b = foo
+b.to_s.output
+"\n".output