[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