[pypy-commit] pypy ffi-backend: in-progress

arigo noreply at buildbot.pypy.org
Tue Jun 26 19:02:57 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55835:06fce9e5c310
Date: 2012-06-26 18:55 +0200
http://bitbucket.org/pypy/pypy/changeset/06fce9e5c310/

Log:	in-progress

diff --git a/pypy/module/_ffi_backend/__init__.py b/pypy/module/_ffi_backend/__init__.py
--- a/pypy/module/_ffi_backend/__init__.py
+++ b/pypy/module/_ffi_backend/__init__.py
@@ -17,6 +17,7 @@
         'complete_struct_or_union': 'newtype.complete_struct_or_union',
         'new_void_type': 'newtype.new_void_type',
         'new_enum_type': 'newtype.new_enum_type',
+        'new_function_type': 'newtype.new_function_type',
 
         'newp': 'func.newp',
         'cast': 'func.cast',
diff --git a/pypy/module/_ffi_backend/ctypefunc.py b/pypy/module/_ffi_backend/ctypefunc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypefunc.py
@@ -0,0 +1,31 @@
+"""
+Function pointers.
+"""
+
+from pypy.module._ffi_backend.ctypeptr import W_CTypePtrOrArray
+
+
+class W_CTypeFunctionPtr(W_CTypePtrOrArray):
+
+    def __init__(self, space, fargs, fresult, ellipsis):
+        argnames = ['(*)(']
+        for i, farg in enumerate(fargs):
+            if i > 0:
+                argnames.append(', ')
+            argnames.append(farg.name)
+        if ellipsis:
+            if len(fargs) > 0:
+                argnames.append(', ')
+            argnames.append('...')
+        argnames.append(')')
+        extra = ''.join(argnames)
+        #
+        W_CTypePtrOrArray.__init__(self, space, extra, 2, 
+        self.ellipsis = ellipsis
+        
+        if not ellipsis:
+            # Functions with '...' varargs are stored without a cif_descr
+            # at all.  The cif is computed on every call from the actual
+            # types passed in.  For all other functions, the cif_descr
+            # is computed here.
+            pass
diff --git a/pypy/module/_ffi_backend/ctypeptr.py b/pypy/module/_ffi_backend/ctypeptr.py
--- a/pypy/module/_ffi_backend/ctypeptr.py
+++ b/pypy/module/_ffi_backend/ctypeptr.py
@@ -18,17 +18,61 @@
         W_CType.__init__(self, space, size, name, name_position)
         self.ctitem = ctitem
 
+    def cast_anything(self):
+        return self.ctitem is not None and self.ctitem.cast_anything
 
-class W_CTypePointer(W_CTypePtrOrArray):
+
+class W_CTypePtrBase(W_CTypePtrOrArray):
+    # base class for both pointers and pointers-to-functions
+
+    def __init__(self, space, extra, extra_position, ctitem):
+        size = rffi.sizeof(rffi.VOIDP)
+        W_CTypePtrOrArray.__init__(self, space, size,
+                                   extra, extra_position, ctitem)
+
+    def cast(self, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePtrOrArray)):
+            value = ob._cdata
+        else:
+            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
+            value = rffi.cast(rffi.CCHARP, value)
+        return cdataobj.W_CData(space, value, self)
+
+    def convert_to_object(self, cdata):
+        ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
+        return cdataobj.W_CData(self.space, ptrdata, self)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if not isinstance(ob, cdataobj.W_CData):
+            raise self._convert_error("compatible pointer", w_ob)
+        other = ob.ctype
+        if (isinstance(other, W_CTypePtrOrArray) and
+             (self is other or self.cast_anything() or other.cast_anything())):
+            pass    # compatible types
+        else:
+            raise self._convert_error("compatible pointer", w_ob)
+
+        rffi.cast(rffi.CCHARPP, cdata)[0] = ob._cdata
+
+    def _alignof(self):
+        from pypy.module._ffi_backend import newtype
+        return newtype.alignment_of_pointer
+
+
+class W_CTypePointer(W_CTypePtrBase):
 
     def __init__(self, space, ctitem):
-        size = rffi.sizeof(rffi.VOIDP)
         from pypy.module._ffi_backend import ctypearray
         if isinstance(ctitem, ctypearray.W_CTypeArray):
             extra = "(*)"    # obscure case: see test_array_add
         else:
             extra = " *"
-        W_CTypePtrOrArray.__init__(self, space, size, extra, 2, ctitem)
+        W_CTypePtrBase.__init__(self, space, extra, 2, ctitem)
 
     def str(self, cdataobj):
         if isinstance(self.ctitem, W_CTypePrimitiveChar):
@@ -42,17 +86,6 @@
             return self.space.wrap(s)
         return W_CTypePtrOrArray.str(self, cdataobj)
 
-    def cast(self, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if (isinstance(ob, cdataobj.W_CData) and
-                isinstance(ob.ctype, W_CTypePtrOrArray)):
-            value = ob._cdata
-        else:
-            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
-            value = rffi.cast(rffi.CCHARP, value)
-        return cdataobj.W_CData(space, value, self)
-
     def newp(self, w_init):
         from pypy.module._ffi_backend import ctypeprim
         space = self.space
@@ -86,27 +119,3 @@
                                   self.name)
         p = rffi.ptradd(cdata, i * self.ctitem.size)
         return cdataobj.W_CData(space, p, self)
-
-    def _alignof(self):
-        from pypy.module._ffi_backend import newtype
-        return newtype.alignment_of_pointer
-
-    def convert_to_object(self, cdata):
-        ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
-        return cdataobj.W_CData(self.space, ptrdata, self)
-
-    def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        ob = space.interpclass_w(w_ob)
-        if not isinstance(ob, cdataobj.W_CData):
-            raise self._convert_error("compatible pointer", w_ob)
-        otherctype = ob.ctype
-        if (isinstance(otherctype, W_CTypePtrOrArray) and
-            (self.ctitem.cast_anything or
-             otherctype.ctitem.cast_anything or
-             self.ctitem is otherctype.ctitem)):
-            pass    # compatible types
-        else:
-            raise self._convert_error("compatible pointer", w_ob)
-
-        rffi.cast(rffi.CCHARPP, cdata)[0] = ob._cdata
diff --git a/pypy/module/_ffi_backend/newtype.py b/pypy/module/_ffi_backend/newtype.py
--- a/pypy/module/_ffi_backend/newtype.py
+++ b/pypy/module/_ffi_backend/newtype.py
@@ -200,3 +200,26 @@
     enumvalues  = [space.int_w(w) for w in enumvalues_w]
     ctype = ctypeenum.W_CTypeEnum(space, name, enumerators, enumvalues)
     return ctype
+
+# ____________________________________________________________
+
+ at unwrap_spec(fresult=ctypeobj.W_CType, ellipsis=int)
+def new_function_type(space, w_fargs, fresult, ellipsis=0):
+    fargs = []
+    for w_farg in space.fixedview(w_fargs):
+        farg = space.interpclass_w(w_farg)
+        if not isinstance(farg, ctypeobj.W_CType):
+            raise OperationError(space.w_TypeError,
+                space.wrap("first arg must be a tuple of ctype objects"))
+        fargs.append(farg)
+    #
+    if isinstance(fresult, ctypestruct.W_CTypeStructOrUnion):
+        raise OperationError(space.w_NotImplementedError,
+                         space.wrap("functions returning a struct or a union"))
+    if ((fresult.size < 0 and not isinstance(fresult, ctypevoid.W_CTypeVoid))
+            or isinstance(fresult, ctypearray.W_CTypeArray)):
+        raise operationerrfmt(space.w_TypeError,
+                              "invalid result type: '%s'", fresult.name)
+    #
+    fct = ctypefunc.W_CTypeFunc(fargs, fresult, ellipsis)
+    return fct
diff --git a/pypy/module/_ffi_backend/test/_backend_test_c.py b/pypy/module/_ffi_backend/test/_backend_test_c.py
--- a/pypy/module/_ffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_ffi_backend/test/_backend_test_c.py
@@ -593,12 +593,13 @@
 def test_struct_init_list():
     BVoidP = new_pointer_type(new_void_type())
     BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
     BStruct = new_struct_type("foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                        ('a2', BInt, -1),
                                        ('a3', BInt, -1),
-                                       ('p4', new_pointer_type(BInt), -1)])
+                                       ('p4', BIntPtr, -1)])
     s = newp(BStructPtr, [123, 456])
     assert s.a1 == 123
     assert s.a2 == 456
@@ -613,7 +614,7 @@
     #
     py.test.raises(KeyError, newp, BStructPtr, {'foobar': 0})
     #
-    p = newp(new_pointer_type(BInt), 14141)
+    p = newp(BIntPtr, 14141)
     s = newp(BStructPtr, [12, 34, 56, p])
     assert s.p4 == p
     #
@@ -1108,3 +1109,28 @@
     assert list(p.a1) == ['f', 'o', 'o'] + ['\x00'] * 7
     p.a1 = ['x', 'y']
     assert str(p.a1) == 'xyo'
+
+def test_no_struct_return_in_func():
+    BFunc = new_function_type((), new_void_type())
+    BArray = new_array_type(new_pointer_type(BFunc), 5)        # works
+    new_function_type((), BFunc)    # works
+    new_function_type((), new_primitive_type("int"))
+    new_function_type((), new_pointer_type(BFunc))
+    py.test.raises(NotImplementedError, new_function_type, (),
+                   new_struct_type("foo_s"))
+    py.test.raises(NotImplementedError, new_function_type, (),
+                   new_union_type("foo_u"))
+    py.test.raises(TypeError, new_function_type, (), BArray)
+
+def test_cast_with_functionptr():
+    BFunc = new_function_type((), new_void_type())
+    BFunc2 = new_function_type((), new_primitive_type("short"))
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BFunc, -1)])
+    newp(BStructPtr, [cast(BFunc, 0)])
+    newp(BStructPtr, [cast(BCharP, 0)])
+    py.test.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)])
+    py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)])


More information about the pypy-commit mailing list