Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r61168:3d9c73dd0f46 Date: 2013-02-13 11:26 +0100 http://bitbucket.org/pypy/pypy/changeset/3d9c73dd0f46/
Log: Support cffi's "enum-as-int" branch diff --git a/pypy/module/_cffi_backend/ctypeenum.py b/pypy/module/_cffi_backend/ctypeenum.py --- a/pypy/module/_cffi_backend/ctypeenum.py +++ b/pypy/module/_cffi_backend/ctypeenum.py @@ -6,23 +6,19 @@ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rarithmetic import intmask, r_ulonglong from rpython.rlib.objectmodel import keepalive_until_here +from rpython.rlib.objectmodel import specialize from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned +from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUnsigned from pypy.module._cffi_backend import misc -class W_CTypeEnum(W_CTypePrimitiveSigned): - _attrs_ = ['enumerators2values', 'enumvalues2erators'] - _immutable_fields_ = ['enumerators2values', 'enumvalues2erators'] - kind = "enum" +class _Mixin_Enum(object): + _mixin_ = True - def __init__(self, space, name, enumerators, enumvalues): - from pypy.module._cffi_backend.newtype import alignment + def __init__(self, space, name, size, align, enumerators, enumvalues): name = "enum " + name - size = rffi.sizeof(rffi.INT) - align = alignment(rffi.INT) - W_CTypePrimitiveSigned.__init__(self, space, size, - name, len(name), align) + self._super.__init__(self, space, size, name, len(name), align) self.enumerators2values = {} # str -> int self.enumvalues2erators = {} # int -> str for i in range(len(enumerators)-1, -1, -1): @@ -44,55 +40,46 @@ space.setitem(w_dct, space.wrap(enumerator), space.wrap(enumvalue)) return w_dct - return W_CTypePrimitiveSigned._fget(self, attrchar) + return self._super._fget(self, attrchar) + + def extra_repr(self, cdata): + value = self._get_value(cdata) + try: + s = self.enumvalues2erators[value] + except KeyError: + return str(value) + else: + return '%s: %s' % (value, s) def string(self, cdataobj, maxlen): - w_result = self.convert_to_object(cdataobj._cdata) + value = self._get_value(cdataobj._cdata) keepalive_until_here(cdataobj) - return w_result + try: + s = self.enumvalues2erators[value] + except KeyError: + s = str(value) + return self.space.wrap(s) - def convert_to_object(self, cdata): - value = misc.read_raw_long_data(cdata, self.size) - try: - enumerator = self.enumvalues2erators[value] - except KeyError: - enumerator = '#%d' % (value,) - return self.space.wrap(enumerator) - def convert_from_object(self, cdata, w_ob): - space = self.space - try: - return W_CTypePrimitiveSigned.convert_from_object(self, cdata, - w_ob) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - if space.isinstance_w(w_ob, space.w_basestring): - value = self.convert_enum_string_to_int(space.str_w(w_ob)) - value = r_ulonglong(value) - misc.write_raw_integer_data(cdata, value, self.size) - else: - raise self._convert_error("str or int", w_ob) +class W_CTypeEnumSigned(_Mixin_Enum, W_CTypePrimitiveSigned): + _attrs_ = ['enumerators2values', 'enumvalues2erators'] + _immutable_fields_ = ['enumerators2values', 'enumvalues2erators'] + kind = "enum" + _super = W_CTypePrimitiveSigned - def cast_str(self, w_ob): - space = self.space - return self.convert_enum_string_to_int(space.str_w(w_ob)) + def _get_value(self, cdata): + # returns a signed long + assert self.value_fits_long + return misc.read_raw_long_data(cdata, self.size) - def cast_unicode(self, w_ob): - return self.cast_str(w_ob) - def convert_enum_string_to_int(self, s): - space = self.space - if s.startswith('#'): - try: - return int(s[1:]) - except ValueError: - raise OperationError(space.w_ValueError, - space.wrap("invalid literal after '#'")) - else: - try: - return self.enumerators2values[s] - except KeyError: - raise operationerrfmt(space.w_ValueError, - "'%s' is not an enumerator for %s", - s, self.name) +class W_CTypeEnumUnsigned(_Mixin_Enum, W_CTypePrimitiveUnsigned): + _attrs_ = ['enumerators2values', 'enumvalues2erators'] + _immutable_fields_ = ['enumerators2values', 'enumvalues2erators'] + kind = "enum" + _super = W_CTypePrimitiveUnsigned + + def _get_value(self, cdata): + # returns an unsigned long + assert self.value_fits_ulong + return misc.read_raw_ulong_data(cdata, self.size) diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -171,9 +171,7 @@ self.vrangemax = (r_uint(1) << sh) - 1 def int(self, cdata): - # enums: really call convert_to_object() just below, - # and not the one overridden in W_CTypeEnum. - return W_CTypePrimitiveSigned.convert_to_object(self, cdata) + return self.convert_to_object(cdata) def convert_to_object(self, cdata): if self.value_fits_long: diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -1,7 +1,8 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec from rpython.rtyper.lltypesystem import lltype, rffi -from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.rarithmetic import ovfcheck, r_uint +from rpython.rlib.rarithmetic import most_neg_value_of, most_pos_value_of from rpython.rlib.objectmodel import specialize from pypy.module._cffi_backend import ctypeobj, ctypeprim, ctypeptr, ctypearray @@ -271,18 +272,57 @@ raise OperationError(space.w_ValueError, space.wrap("tuple args must have the same size")) enumerators = [space.str_w(w) for w in enumerators_w] - enumvalues = [] + # + smallest_value = 0 + largest_value = r_uint(0) + i = 0 try: for w in enumvalues_w: - enumvalues.append(space.c_int_w(w)) + try: + ulvalue = space.uint_w(w) + except OperationError, e: + if not e.match(space, space.w_ValueError): + raise + lvalue = space.int_w(w) + if lvalue < smallest_value: + smallest_value = lvalue + else: + if ulvalue > largest_value: + largest_value = ulvalue + i += 1 # 'i' is here for the exception case, see below except OperationError, e: if not e.match(space, space.w_OverflowError): raise - i = len(enumvalues) raise operationerrfmt(space.w_OverflowError, - "enum '%s' declaration for '%s' does not fit an int", + "enum '%s' declaration for '%s' does not fit " + "a long or unsigned long", name, enumerators[i]) - ctype = ctypeenum.W_CTypeEnum(space, name, enumerators, enumvalues) + # + if smallest_value < 0: + if (smallest_value >= most_neg_value_of(rffi.INT) and + largest_value <= r_uint(most_pos_value_of(rffi.INT))): + size = rffi.sizeof(rffi.INT) + align = alignment(rffi.INT) + elif largest_value <= r_uint(most_pos_value_of(rffi.LONG)): + size = rffi.sizeof(rffi.LONG) + align = alignment(rffi.LONG) + else: + raise operationerrfmt(space.w_OverflowError, + "enum '%s' values don't all fit into either 'long' " + "or 'unsigned long'", name) + enumvalues = [space.int_w(w) for w in enumvalues_w] + ctype = ctypeenum.W_CTypeEnumSigned(space, name, size, align, + enumerators, enumvalues) + else: + if largest_value <= r_uint(most_pos_value_of(rffi.UINT)): + size = rffi.sizeof(rffi.UINT) + align = alignment(rffi.UINT) + else: + size = rffi.sizeof(rffi.ULONG) + align = alignment(rffi.ULONG) + enumvalues = [space.uint_w(w) for w in enumvalues_w] + ctype = ctypeenum.W_CTypeEnumUnsigned(space, name, size, align, + enumerators, enumvalues) return ctype # ____________________________________________________________ diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1314,7 +1314,8 @@ p = newp(BStructPtr, [12]) assert p.a1 == 12 e = py.test.raises(TypeError, newp, BStructPtr, [None]) - assert "an integer is required" in str(e.value) + assert ("an integer is required" in str(e.value) or + "unsupported operand type for int(): 'NoneType'" in str(e.value)) #PyPy py.test.raises(TypeError, 'p.a1 = "def"') if sys.version_info < (3,): BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit