nitc/ffi: allows to declare C type of extern classes from Nit
authorAlexis Laferrière <alexis.laf@xymus.net>
Wed, 6 Feb 2013 13:06:02 +0000 (08:06 -0500)
committerAlexis Laferrière <alexis.laf@xymus.net>
Wed, 6 Feb 2013 23:09:30 +0000 (18:09 -0500)
This feature uses the FFI grammar but acts at the level of the native
interface. It allows the user to specify the C equivalent of a Nit
extern class. Instances of extern classes are automatically converted
to this type when passed to C. The equivalent C type must be a pointer
or compatible with a pointer type.

Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

src/native_interface/frontier.nit
src/native_interface/ni_metamodel.nit
src/primitive_info.nit
src/syntax/extern_type_inheritance.nit [new file with mode: 0644]
src/syntax/syntax.nit

index 0e741b9..56e1bcf 100644 (file)
@@ -157,13 +157,6 @@ redef class MMSrcModule
                                        prop.compile_extern_to_frontier( v )
                                end
                        end
-
-                       ### extern classes
-                       # if class is extern and defined here first
-                       if local_class.global.intro == local_class and
-                          local_class.global.is_extern then
-                               local_class.compile_defaut_extern_type( v )
-                       end
                end
 
                v.header.add( "#endif\n" )
@@ -325,17 +318,6 @@ redef class MMSrcMethod
 
 end
 
-redef class MMLocalClass
-       # Defines a defaut type for special of pointers in frontier.
-       # Can be overriden in the custime .nit.h file, as seen with nits.
-       fun compile_defaut_extern_type( v : FrontierVisitor )
-       do
-               v.header.add( "#ifndef {get_type.friendly_extern_name}\n" )
-               v.header.add( "\ttypedef void* {get_type.friendly_extern_name};\n" )
-               v.header.add( "#endif\n\n" )
-       end
-end
-
 redef class MMSignature
        var recv_ni_variable : ReceiverVariable
        var return_ni_variable : nullable ReturnVariable
index 03c96fc..08df52b 100644 (file)
@@ -32,8 +32,6 @@ redef class MMType
                        return "nullable_{local_class.name.to_s}"
                else if pi == null then
                        return local_class.name.to_s
-               else if local_class.global.is_extern then
-                       return local_class.name.to_s
                else
                        return pi.cname
                end
index 44bf63a..039cc88 100644 (file)
@@ -22,6 +22,9 @@ package primitive_info
 import metamodel
 
 redef class MMLocalClass
+       # extern type of extern classes
+       fun extern_c_type : String is abstract
+
        # Cached primitive_info result
        var _primitive_info_cache: nullable PrimitiveInfo = null
 
@@ -40,6 +43,12 @@ redef class MMLocalClass
                        _primitive_info_b = true
                        return _primitive_info_cache
                end
+               if global.is_extern then
+                       var pi = new PrimitiveInfo( name, false, extern_c_type )
+                       _primitive_info_cache = pi
+                       _primitive_info_b = true
+                       return _primitive_info_cache
+               end
                var i = ctypes.iterator
                while i.is_ok do
                        var n = i.key
diff --git a/src/syntax/extern_type_inheritance.nit b/src/syntax/extern_type_inheritance.nit
new file mode 100644 (file)
index 0000000..e18782d
--- /dev/null
@@ -0,0 +1,93 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# This module manages the C type of extern classes
+module extern_type_inheritance
+
+import primitive_info
+intrude import extern_inline
+
+redef class MMLocalClass
+       redef fun extern_c_type : String
+       do
+               return extern_type.code
+       end
+
+       fun extern_type_origin : MMLocalClass
+       do
+               extern_type
+               return extern_type_origin_cache.as(not null)
+       end
+
+       # where was the extern type explicitly declared
+       private var extern_type_origin_cache : nullable MMLocalClass = null
+
+       # extern type of an extern class
+       private var extern_type_cache : nullable ExternCode = null
+
+       redef fun extern_type
+       do
+               assert global.is_extern
+
+               if extern_type_cache != null then return extern_type_cache
+
+               if global.intro != self then
+                       if global.intro.extern_type_cache != null then
+                               extern_type_cache = global.intro.extern_type_cache
+                               extern_type_origin_cache = self
+                               return extern_type_cache
+                       end
+               end
+
+               if name == once "Pointer".to_symbol then
+                       extern_type_cache = new ExternCode( "C", "void*", null )
+                       extern_type_origin_cache = self
+                       return extern_type_cache
+               end
+
+               # find all extern types in direct parents
+               var extern_types = new HashSet[MMLocalClass]
+               var local_class = self # global.class_refinement_hierarchy .first
+                       for c in local_class.cshe.direct_greaters do
+                               if c.global.is_extern then
+                                       extern_types.add( c.extern_type_origin )
+                               end
+                       end
+               #end
+
+               if extern_types.length > 1 then
+                       stderr.write("Error: Extern class {mmmodule}::{name} has ambiguous extern type, found in super classes: \n")
+                       for c in extern_types do stderr.write( "{c.extern_type.code} from {c}\n" )
+                       exit(1)
+               else if extern_types.length == 1 then
+                       var source = extern_types.first
+                       extern_type_cache = source.extern_type
+                       extern_type_origin_cache = source
+               else
+                       # Extern class has unknown extern type. This should never happen.
+                       abort
+               end
+
+               return extern_type_cache
+       end
+
+       redef fun extern_type=( v )
+       do
+               extern_type_cache = v
+               extern_type_origin_cache = self
+       end
+end
+
index 86f01c2..a17dc4a 100644 (file)
@@ -23,6 +23,7 @@ import mmbuilder
 import typing
 import icode_generation
 import extern_inline
+import extern_type_inheritance
 
 # Loader of nit source files
 class SrcModuleLoader