Author: Armin Rigo <ar...@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 + +# ____________________________________________________________ + +@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)]) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit