Commits

Armin Rigo committed 44ff77d

Update to cffi/d63ceb231d7c.

Comments (0)

Files changed (11)

pypy/module/_cffi_backend/__init__.py

         'typeof': 'func.typeof',
         'typeoffsetof': 'func.typeoffsetof',
         'rawaddressof': 'func.rawaddressof',
-        '_getfields': 'func._getfields',
         'getcname': 'func.getcname',
         '_get_types': 'func._get_types',
 

pypy/module/_cffi_backend/ctypearray.py

 class W_CTypeArray(W_CTypePtrOrArray):
     _attrs_            = ['ctptr']
     _immutable_fields_ = ['ctptr']
+    kind = "array"
 
     def __init__(self, space, ctptr, length, arraysize, extra):
         W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
     def get_vararg_type(self):
         return self.ctptr
 
+    def _fget_item(self):
+        return self.space.wrap(self.ctitem)
+
+    def _fget_length(self):
+        if self.length >= 0:
+            return self.space.wrap(self.length)
+        else:
+            return self.space.w_None
+
 
 class W_CDataIter(Wrappable):
     _immutable_fields_ = ['ctitem', 'cdata', '_stop']    # but not '_next'

pypy/module/_cffi_backend/ctypeenum.py

 class W_CTypeEnum(W_CTypePrimitiveSigned):
     _attrs_            = ['enumerators2values', 'enumvalues2erators']
     _immutable_fields_ = ['enumerators2values', 'enumvalues2erators']
+    kind = "enum"
 
     def __init__(self, space, name, enumerators, enumvalues):
         from pypy.module._cffi_backend.newtype import alignment
             self.enumerators2values[enumerators[i]] = enumvalues[i]
             self.enumvalues2erators[enumvalues[i]] = enumerators[i]
 
-    def _getfields(self):
+    def _fget_elements(self):
         space = self.space
-        lst = []
-        for enumerator in self.enumerators2values:
-            enumvalue = self.enumerators2values[enumerator]
-            lst.append(space.newtuple([space.wrap(enumvalue),
-                                       space.wrap(enumerator)]))
-        w_lst = space.newlist(lst)
-        space.call_method(w_lst, 'sort')
-        return w_lst
+        w_dct = space.newdict()
+        for enumvalue, enumerator in self.enumvalues2erators.iteritems():
+            space.setitem(w_dct, space.wrap(enumvalue), space.wrap(enumerator))
+        return w_dct
 
     def string(self, cdataobj, maxlen):
         w_result = self.convert_to_object(cdataobj._cdata)

pypy/module/_cffi_backend/ctypefunc.py

 class W_CTypeFunc(W_CTypePtrBase):
     _attrs_            = ['fargs', 'ellipsis', 'cif_descr']
     _immutable_fields_ = ['fargs[*]', 'ellipsis', 'cif_descr']
+    kind = "function"
 
     def __init__(self, space, fargs, fresult, ellipsis):
         extra = self._compute_extra_text(fargs, fresult, ellipsis)
         argnames.append(')')
         return ''.join(argnames)
 
+    def _fget_args(self):
+        return self.space.newtuple(self.fargs)
+
+    def _fget_result(self):
+        return self.space.wrap(self.ctitem)
+
+    def _fget_ellipsis(self):
+        return self.space.wrap(self.ellipsis)
+
+    def _fget_abi(self):
+        return self.space.wrap(clibffi.FFI_DEFAULT_ABI)     # XXX
+
 
     def call(self, funcaddr, args_w):
         if self.cif_descr:

pypy/module/_cffi_backend/ctypeobj.py

 from pypy.interpreter.gateway import interp2app
 from pypy.interpreter.typedef import TypeDef
 from pypy.interpreter.typedef import make_weakref_descr
+from pypy.interpreter.typedef import GetSetProperty, interp_attrproperty
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rlib.objectmodel import we_are_translated
 
 
     cast_anything = False
     is_primitive_integer = False
+    kind = "?"
 
     def __init__(self, space, size, name, name_position):
         self.space = space
 
     def _alignof(self):
         space = self.space
-        raise operationerrfmt(space.w_TypeError,
+        raise operationerrfmt(space.w_ValueError,
                               "ctype '%s' is of unknown alignment",
                               self.name)
 
             msg = "expected a struct or union ctype, or a pointer to one"
         raise OperationError(space.w_TypeError, space.wrap(msg))
 
-    def _getfields(self):
-        return None
-
     def rawaddressof(self, cdata, offset):
         space = self.space
         raise OperationError(space.w_TypeError,
     def copy_and_convert_to_object(self, cdata):
         return self.convert_to_object(cdata)
 
+    # __________ app-level attributes __________
+    def dir(self):
+        space = self.space
+        w_self = space.wrap(self)
+        lst = [space.wrap(name)
+                  for name in _name_of_attributes
+                  if space.findattr(w_self, space.wrap(name)) is not None]
+        return space.newlist(lst)
+
+    def fget_kind(self, space):
+        return space.wrap(self.kind)      # class attribute
+
+    def _no_such_attribute(self):
+        space = self.space
+        raise operationerrfmt(space.w_AttributeError,
+                              "cdata '%s' has no such attribute",
+                              self.name)
+
+    _fget_item = _no_such_attribute
+    def fget_item(self, space):
+        return self._fget_item()
+
+    _fget_length = _no_such_attribute
+    def fget_length(self, space):
+        return self._fget_length()
+
+    _fget_fields = _no_such_attribute
+    def fget_fields(self, space):
+        return self._fget_fields()
+
+    _fget_args = _no_such_attribute
+    def fget_args(self, space):
+        return self._fget_args()
+
+    _fget_result = _no_such_attribute
+    def fget_result(self, space):
+        return self._fget_result()
+
+    _fget_ellipsis = _no_such_attribute
+    def fget_ellipsis(self, space):
+        return self._fget_ellipsis()
+
+    _fget_abi = _no_such_attribute
+    def fget_abi(self, space):
+        return self._fget_abi()
+
+    _fget_elements = _no_such_attribute
+    def fget_elements(self, space):
+        return self._fget_elements()
+
 
 W_CType.typedef = TypeDef(
     'CTypeDescr',
     __module__ = '_cffi_backend',
     __repr__ = interp2app(W_CType.repr),
     __weakref__ = make_weakref_descr(W_CType),
+    kind = GetSetProperty(W_CType.fget_kind, doc="kind"),
+    cname = interp_attrproperty('name', W_CType, doc="C name"),
+    item = GetSetProperty(W_CType.fget_item, doc="pointer to, or array of"),
+    length = GetSetProperty(W_CType.fget_length, doc="array length or None"),
+    fields = GetSetProperty(W_CType.fget_fields, doc="struct or union fields"),
+    args = GetSetProperty(W_CType.fget_args, doc="function argument types"),
+    result = GetSetProperty(W_CType.fget_result, doc="function result type"),
+    ellipsis = GetSetProperty(W_CType.fget_ellipsis, doc="function has '...'"),
+    abi = GetSetProperty(W_CType.fget_abi, doc="function ABI"),
+    elements = GetSetProperty(W_CType.fget_elements, doc="enum elements"),
+    __dir__ = interp2app(W_CType.dir),
     )
 W_CType.typedef.acceptable_as_base_class = False
+
+_name_of_attributes = [name for name in W_CType.typedef.rawdict
+                            if not name.startswith('_')]
+_name_of_attributes.sort()

pypy/module/_cffi_backend/ctypeprim.py

 class W_CTypePrimitive(W_CType):
     _attrs_            = ['align']
     _immutable_fields_ = ['align']
+    kind = "primitive"
 
     def __init__(self, space, size, name, name_position, align):
         W_CType.__init__(self, space, size, name, name_position)

pypy/module/_cffi_backend/ctypeptr.py

 class W_CTypePointer(W_CTypePtrBase):
     _attrs_ = ['is_file']
     _immutable_fields_ = ['is_file']
+    kind = "pointer"
 
     def __init__(self, space, ctitem):
         from pypy.module._cffi_backend import ctypearray
             raise OperationError(space.w_TypeError,
                      space.wrap("expected a 'cdata struct-or-union' object"))
 
+    def _fget_item(self):
+        return self.space.wrap(self.ctitem)
+
 # ____________________________________________________________
 
 

pypy/module/_cffi_backend/ctypestruct.py

         name = '%s %s' % (self.kind, name)
         W_CType.__init__(self, space, -1, name, len(name))
 
-    def check_complete(self):
+    def check_complete(self, w_errorcls=None):
         if self.fields_dict is None:
             space = self.space
-            raise operationerrfmt(space.w_TypeError,
+            raise operationerrfmt(w_errorcls or space.w_TypeError,
                                   "'%s' is not completed yet", self.name)
 
     def _alignof(self):
-        self.check_complete()
+        self.check_complete(w_errorcls=self.space.w_ValueError)
         return self.alignment
 
-    def _getfields(self):
+    def _fget_fields(self):
+        space = self.space
         if self.size < 0:
-            return None
-        space = self.space
+            return space.w_None
         result = [None] * len(self.fields_list)
         for fname, field in self.fields_dict.iteritems():
             i = self.fields_list.index(field)

pypy/module/_cffi_backend/ctypevoid.py

 class W_CTypeVoid(W_CType):
     _attrs_ = []
     cast_anything = True
+    kind = "void"
 
     def __init__(self, space):
         W_CType.__init__(self, space, -1, "void", len("void"))

pypy/module/_cffi_backend/func.py

     ctype, offset = ctype.typeoffsetof(fieldname)
     return space.newtuple([space.wrap(ctype), space.wrap(offset)])
 
-@unwrap_spec(ctype=ctypeobj.W_CType)
-def _getfields(space, ctype):
-    return ctype._getfields()
-
 @unwrap_spec(ctype=ctypeobj.W_CType, cdata=cdataobj.W_CData, offset=int)
 def rawaddressof(space, ctype, cdata, offset=0):
     return ctype.rawaddressof(cdata, offset)

pypy/module/_cffi_backend/test/_backend_test_c.py

     p = new_primitive_type("signed char")
     assert repr(p) == "<ctype 'signed char'>"
 
+def check_dir(p, expected):
+    got = set(name for name in dir(p) if not name.startswith('_'))
+    assert got == set(expected)
+
+def test_inspect_primitive_type():
+    p = new_primitive_type("signed char")
+    assert p.kind == "primitive"
+    assert p.cname == "signed char"
+    check_dir(p, ['cname', 'kind'])
+
 def test_cast_to_signed_char():
     p = new_primitive_type("signed char")
     x = cast(p, -65 + 17*256)
     p = new_pointer_type(p)
     assert repr(p) == "<ctype 'int * * *'>"
 
+def test_inspect_pointer_type():
+    p1 = new_primitive_type("int")
+    p2 = new_pointer_type(p1)
+    assert p2.kind == "pointer"
+    assert p2.cname == "int *"
+    assert p2.item is p1
+    check_dir(p2, ['cname', 'kind', 'item'])
+    p3 = new_pointer_type(p2)
+    assert p3.item is p2
+
 def test_pointer_to_int():
     BInt = new_primitive_type("int")
     py.test.raises(TypeError, newp, BInt)
     z = cast(BInt, y)
     assert int(z) == 42
 
+def test_void_type():
+    p = new_void_type()
+    assert p.kind == "void"
+    assert p.cname == "void"
+    check_dir(p, ['kind', 'cname'])
+
 def test_array_type():
     p = new_primitive_type("int")
     assert repr(p) == "<ctype 'int'>"
     py.test.raises(OverflowError,
                    new_array_type, new_pointer_type(p), sys.maxsize // 3)
 
+def test_inspect_array_type():
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), None)
+    assert p1.kind == "array"
+    assert p1.cname == "int[]"
+    assert p1.item is p
+    assert p1.length is None
+    check_dir(p1, ['cname', 'kind', 'item', 'length'])
+    p1 = new_array_type(new_pointer_type(p), 42)
+    assert p1.kind == "array"
+    assert p1.cname == "int[42]"
+    assert p1.item is p
+    assert p1.length == 42
+    check_dir(p1, ['cname', 'kind', 'item', 'length'])
+
 def test_array_instance():
     LENGTH = 1423
     p = new_primitive_type("int")
     assert repr(BStruct) == "<ctype 'struct foo'>"
     BPtr = new_pointer_type(BStruct)
     assert repr(BPtr) == "<ctype 'struct foo *'>"
-    py.test.raises(TypeError, alignof, BStruct)
+    py.test.raises(ValueError, sizeof, BStruct)
+    py.test.raises(ValueError, alignof, BStruct)
 
 def test_new_union_type():
     BUnion = new_union_type("foo")
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
     BStruct = new_struct_type("foo")
-    assert _getfields(BStruct) is None
+    assert BStruct.kind == "struct"
+    assert BStruct.cname == "struct foo"
+    assert BStruct.fields is None
+    check_dir(BStruct, ['cname', 'kind', 'fields'])
+    #
     complete_struct_or_union(BStruct, [('a1', BLong, -1),
                                        ('a2', BChar, -1),
                                        ('a3', BShort, -1)])
-    d = _getfields(BStruct)
+    d = BStruct.fields
     assert len(d) == 3
     assert d[0][0] == 'a1'
     assert d[0][1].type is BLong
     BLong = new_primitive_type("long")
     BChar = new_primitive_type("char")
     BUnion = new_union_type("foo")
-    assert _getfields(BUnion) is None
+    assert BUnion.kind == "union"
+    assert BUnion.cname == "union foo"
+    assert BUnion.fields is None
     complete_struct_or_union(BUnion, [('a1', BLong, -1),
                                       ('a2', BChar, -1)])
-    d = _getfields(BUnion)
+    d = BUnion.fields
     assert len(d) == 2
     assert d[0][0] == 'a1'
     assert d[0][1].type is BLong
     BFunc2 = new_function_type((), BFunc, False)
     assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>"
 
+def test_inspect_function_type():
+    BInt = new_primitive_type("int")
+    BFunc = new_function_type((BInt, BInt), BInt, False)
+    assert BFunc.kind == "function"
+    assert BFunc.cname == "int(*)(int, int)"
+    assert BFunc.args == (BInt, BInt)
+    assert BFunc.result is BInt
+    assert BFunc.ellipsis is False
+    assert BFunc.abi == FFI_DEFAULT_ABI
+
 def test_function_type_taking_struct():
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
 def test_enum_type():
     BEnum = new_enum_type("foo", (), ())
     assert repr(BEnum) == "<ctype 'enum foo'>"
-    assert _getfields(BEnum) == []
+    assert BEnum.kind == "enum"
+    assert BEnum.cname == "enum foo"
+    assert BEnum.elements == {}
     #
     BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
-    assert _getfields(BEnum) == [(-20, 'ab'), (0, 'def'), (1, 'c')]
+    assert BEnum.kind == "enum"
+    assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
 
 def test_cast_to_enum():
     BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
                                        ('a2', BLong, 2),
                                        ('a3', BLong, 3),
                                        ('a4', BLong, LONGBITS - 5)])
-    d = _getfields(BStruct)
+    d = BStruct.fields
     assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
     assert d[3][1].offset == sizeof(BLong)
     assert d[0][1].bitshift == 0
     py.test.raises(TypeError, "x - 1")
 
 def test_void_errors():
-    py.test.raises(TypeError, alignof, new_void_type())
+    py.test.raises(ValueError, alignof, new_void_type())
     py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None)
     x = cast(new_pointer_type(new_void_type()), 42)
     py.test.raises(TypeError, "x + 1")
                                        ('a3', BChar, -1)])
     assert sizeof(BInnerStruct) == sizeof(BInt) * 2   # with alignment
     assert sizeof(BStruct) == sizeof(BInt) * 3        # 'a3' is placed after
-    d = _getfields(BStruct)
+    d = BStruct.fields
     assert len(d) == 3
     assert d[0][0] == 'a1'
     assert d[0][1].type is BInt