[pypy-commit] pypy rewrite-unrolling: merge default

fijal noreply at buildbot.pypy.org
Mon Jan 12 15:09:23 CET 2015


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: rewrite-unrolling
Changeset: r75305:101fa4a6ae54
Date: 2015-01-12 15:29 +0200
http://bitbucket.org/pypy/pypy/changeset/101fa4a6ae54/

Log:	merge default

diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -191,14 +191,16 @@
             cdecl = self._typeof(cdecl)
         return self._backend.alignof(cdecl)
 
-    def offsetof(self, cdecl, fieldname):
+    def offsetof(self, cdecl, *fields_or_indexes):
         """Return the offset of the named field inside the given
-        structure, which must be given as a C type name.  The field
-        may be 'x.y.z' in case of nested structures.
+        structure or array, which must be given as a C type name.  
+        You can give several field names in case of nested structures.
+        You can also give numeric values which correspond to array
+        items, in case of an array type.
         """
         if isinstance(cdecl, basestring):
             cdecl = self._typeof(cdecl)
-        return self._typeoffsetof(cdecl, fieldname)[1]
+        return self._typeoffsetof(cdecl, *fields_or_indexes)[1]
 
     def new(self, cdecl, init=None):
         """Allocate an instance according to the specified C type and
@@ -383,24 +385,28 @@
         with self._lock:
             return model.pointer_cache(self, ctype)
 
-    def addressof(self, cdata, field=None):
+    def addressof(self, cdata, *fields_or_indexes):
         """Return the address of a <cdata 'struct-or-union'>.
-        If 'field' is specified, return the address of this field.
-        The field may be 'x.y.z' in case of nested structures.
+        If 'fields_or_indexes' are given, returns the address of that
+        field or array item in the structure or array, recursively in
+        case of nested structures.
         """
         ctype = self._backend.typeof(cdata)
-        ctype, offset = self._typeoffsetof(ctype, field)
+        if fields_or_indexes:
+            ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes)
+        else:
+            if ctype.kind == "pointer":
+                raise TypeError("addressof(pointer)")
+            offset = 0
         ctypeptr = self._pointer_to(ctype)
         return self._backend.rawaddressof(ctypeptr, cdata, offset)
 
-    def _typeoffsetof(self, ctype, field):
-        if field is not None and '.' in field:
-            offset = 0
-            for field1 in field.split('.'):
-                ctype, offset1 = self._backend.typeoffsetof(ctype, field1)
-                offset += offset1
-            return ctype, offset
-        return self._backend.typeoffsetof(ctype, field)
+    def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes):
+        ctype, offset = self._backend.typeoffsetof(ctype, field_or_index)
+        for field1 in fields_or_indexes:
+            ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1)
+            offset += offset1
+        return ctype, offset
 
     def include(self, ffi_to_include):
         """Includes the typedefs, structs, unions and enums defined
diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py
--- a/lib_pypy/cffi/backend_ctypes.py
+++ b/lib_pypy/cffi/backend_ctypes.py
@@ -169,6 +169,7 @@
 class CTypesGenericPtr(CTypesData):
     __slots__ = ['_address', '_as_ctype_ptr']
     _automatic_casts = False
+    kind = "pointer"
 
     @classmethod
     def _newp(cls, init):
@@ -370,10 +371,12 @@
                                 (CTypesPrimitive, type(source).__name__))
             return source
         #
+        kind1 = kind
         class CTypesPrimitive(CTypesGenericPrimitive):
             __slots__ = ['_value']
             _ctype = ctype
             _reftypename = '%s &' % name
+            kind = kind1
 
             def __init__(self, value):
                 self._value = value
@@ -703,12 +706,13 @@
         class struct_or_union(base_ctypes_class):
             pass
         struct_or_union.__name__ = '%s_%s' % (kind, name)
+        kind1 = kind
         #
         class CTypesStructOrUnion(CTypesBaseStructOrUnion):
             __slots__ = ['_blob']
             _ctype = struct_or_union
             _reftypename = '%s &' % (name,)
-            _kind = kind
+            _kind = kind = kind1
         #
         CTypesStructOrUnion._fix_class()
         return CTypesStructOrUnion
@@ -994,27 +998,42 @@
     def getcname(self, BType, replace_with):
         return BType._get_c_name(replace_with)
 
-    def typeoffsetof(self, BType, fieldname):
-        if fieldname is not None and issubclass(BType, CTypesGenericPtr):
-            BType = BType._BItem
-        if not issubclass(BType, CTypesBaseStructOrUnion):
-            raise TypeError("expected a struct or union ctype")
-        if fieldname is None:
-            return (BType, 0)
-        else:
+    def typeoffsetof(self, BType, fieldname, num=0):
+        if isinstance(fieldname, str):
+            if num == 0 and issubclass(BType, CTypesGenericPtr):
+                BType = BType._BItem
+            if not issubclass(BType, CTypesBaseStructOrUnion):
+                raise TypeError("expected a struct or union ctype")
             BField = BType._bfield_types[fieldname]
             if BField is Ellipsis:
                 raise TypeError("not supported for bitfields")
             return (BField, BType._offsetof(fieldname))
+        elif isinstance(fieldname, (int, long)):
+            if issubclass(BType, CTypesGenericArray):
+                BType = BType._CTPtr
+            if not issubclass(BType, CTypesGenericPtr):
+                raise TypeError("expected an array or ptr ctype")
+            BItem = BType._BItem
+            offset = BItem._get_size() * fieldname
+            if offset > sys.maxsize:
+                raise OverflowError
+            return (BItem, offset)
+        else:
+            raise TypeError(type(fieldname))
 
-    def rawaddressof(self, BTypePtr, cdata, offset):
+    def rawaddressof(self, BTypePtr, cdata, offset=None):
         if isinstance(cdata, CTypesBaseStructOrUnion):
             ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata))
         elif isinstance(cdata, CTypesGenericPtr):
+            if offset is None or not issubclass(type(cdata)._BItem,
+                                                CTypesBaseStructOrUnion):
+                raise TypeError("unexpected cdata type")
+            ptr = type(cdata)._to_ctypes(cdata)
+        elif isinstance(cdata, CTypesGenericArray):
             ptr = type(cdata)._to_ctypes(cdata)
         else:
             raise TypeError("expected a <cdata 'struct-or-union'>")
-        if offset != 0:
+        if offset:
             ptr = ctypes.cast(
                 ctypes.c_void_p(
                     ctypes.cast(ptr, ctypes.c_void_p).value + offset),
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -229,12 +229,18 @@
 
                 pyvalue = int(int_str, 0)
                 self._add_constants(key, pyvalue)
+                self._declare('macro ' + key, pyvalue)
             elif value == '...':
                 self._declare('macro ' + key, value)
             else:
-                raise api.CDefError('only supports the syntax "#define '
-                                    '%s ..." (literally) or "#define '
-                                    '%s 0x1FF" for now' % (key, key))
+                raise api.CDefError(
+                    'only supports one of the following syntax:\n'
+                    '  #define %s ...     (literally dot-dot-dot)\n'
+                    '  #define %s NUMBER  (with NUMBER an integer'
+                                    ' constant, decimal/hex/octal)\n'
+                    'got:\n'
+                    '  #define %s %s'
+                    % (key, key, key, value))
 
     def _parse_decl(self, decl):
         node = decl.type
diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py
--- a/lib_pypy/cffi/vengine_cpy.py
+++ b/lib_pypy/cffi/vengine_cpy.py
@@ -592,7 +592,8 @@
     # constants, likely declared with '#define'
 
     def _generate_cpy_const(self, is_int, name, tp=None, category='const',
-                            vartp=None, delayed=True, size_too=False):
+                            vartp=None, delayed=True, size_too=False,
+                            check_value=None):
         prnt = self._prnt
         funcname = '_cffi_%s_%s' % (category, name)
         prnt('static int %s(PyObject *lib)' % funcname)
@@ -604,6 +605,9 @@
         else:
             assert category == 'const'
         #
+        if check_value is not None:
+            self._check_int_constant_value(name, check_value)
+        #
         if not is_int:
             if category == 'var':
                 realexpr = '&' + name
@@ -651,6 +655,27 @@
     # ----------
     # enums
 
+    def _check_int_constant_value(self, name, value, err_prefix=''):
+        prnt = self._prnt
+        if value <= 0:
+            prnt('  if ((%s) > 0 || (long)(%s) != %dL) {' % (
+                name, name, value))
+        else:
+            prnt('  if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
+                name, name, value))
+        prnt('    char buf[64];')
+        prnt('    if ((%s) <= 0)' % name)
+        prnt('        snprintf(buf, 63, "%%ld", (long)(%s));' % name)
+        prnt('    else')
+        prnt('        snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
+             name)
+        prnt('    PyErr_Format(_cffi_VerificationError,')
+        prnt('                 "%s%s has the real value %s, not %s",')
+        prnt('                 "%s", "%s", buf, "%d");' % (
+            err_prefix, name, value))
+        prnt('    return -1;')
+        prnt('  }')
+
     def _enum_funcname(self, prefix, name):
         # "$enum_$1" => "___D_enum____D_1"
         name = name.replace('$', '___D_')
@@ -667,25 +692,8 @@
         prnt('static int %s(PyObject *lib)' % funcname)
         prnt('{')
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
-            if enumvalue <= 0:
-                prnt('  if ((%s) > 0 || (long)(%s) != %dL) {' % (
-                    enumerator, enumerator, enumvalue))
-            else:
-                prnt('  if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
-                    enumerator, enumerator, enumvalue))
-            prnt('    char buf[64];')
-            prnt('    if ((%s) <= 0)' % enumerator)
-            prnt('        snprintf(buf, 63, "%%ld", (long)(%s));' % enumerator)
-            prnt('    else')
-            prnt('        snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
-                 enumerator)
-            prnt('    PyErr_Format(_cffi_VerificationError,')
-            prnt('                 "enum %s: %s has the real value %s, '
-                 'not %s",')
-            prnt('                 "%s", "%s", buf, "%d");' % (
-                name, enumerator, enumvalue))
-            prnt('    return -1;')
-            prnt('  }')
+            self._check_int_constant_value(enumerator, enumvalue,
+                                           "enum %s: " % name)
         prnt('  return %s;' % self._chained_list_constants[True])
         self._chained_list_constants[True] = funcname + '(lib)'
         prnt('}')
@@ -709,8 +717,11 @@
     # macros: for now only for integers
 
     def _generate_cpy_macro_decl(self, tp, name):
-        assert tp == '...'
-        self._generate_cpy_const(True, name)
+        if tp == '...':
+            check_value = None
+        else:
+            check_value = tp     # an integer
+        self._generate_cpy_const(True, name, check_value=check_value)
 
     _generate_cpy_macro_collecttype = _generate_nothing
     _generate_cpy_macro_method = _generate_nothing
diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py
--- a/lib_pypy/cffi/vengine_gen.py
+++ b/lib_pypy/cffi/vengine_gen.py
@@ -355,11 +355,20 @@
     # ----------
     # constants, likely declared with '#define'
 
-    def _generate_gen_const(self, is_int, name, tp=None, category='const'):
+    def _generate_gen_const(self, is_int, name, tp=None, category='const',
+                            check_value=None):
         prnt = self._prnt
         funcname = '_cffi_%s_%s' % (category, name)
         self.export_symbols.append(funcname)
-        if is_int:
+        if check_value is not None:
+            assert is_int
+            assert category == 'const'
+            prnt('int %s(char *out_error)' % funcname)
+            prnt('{')
+            self._check_int_constant_value(name, check_value)
+            prnt('  return 0;')
+            prnt('}')
+        elif is_int:
             assert category == 'const'
             prnt('int %s(long long *out_value)' % funcname)
             prnt('{')
@@ -368,6 +377,7 @@
             prnt('}')
         else:
             assert tp is not None
+            assert check_value is None
             prnt(tp.get_c_name(' %s(void)' % funcname, name),)
             prnt('{')
             if category == 'var':
@@ -384,9 +394,13 @@
 
     _loading_gen_constant = _loaded_noop
 
-    def _load_constant(self, is_int, tp, name, module):
+    def _load_constant(self, is_int, tp, name, module, check_value=None):
         funcname = '_cffi_const_%s' % name
-        if is_int:
+        if check_value is not None:
+            assert is_int
+            self._load_known_int_constant(module, funcname)
+            value = check_value
+        elif is_int:
             BType = self.ffi._typeof_locked("long long*")[0]
             BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0]
             function = module.load_function(BFunc, funcname)
@@ -397,6 +411,7 @@
                 BLongLong = self.ffi._typeof_locked("long long")[0]
                 value += (1 << (8*self.ffi.sizeof(BLongLong)))
         else:
+            assert check_value is None
             BFunc = self.ffi._typeof_locked(tp.get_c_name('(*)(void)', name))[0]
             function = module.load_function(BFunc, funcname)
             value = function()
@@ -411,6 +426,36 @@
     # ----------
     # enums
 
+    def _check_int_constant_value(self, name, value):
+        prnt = self._prnt
+        if value <= 0:
+            prnt('  if ((%s) > 0 || (long)(%s) != %dL) {' % (
+                name, name, value))
+        else:
+            prnt('  if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
+                name, name, value))
+        prnt('    char buf[64];')
+        prnt('    if ((%s) <= 0)' % name)
+        prnt('        sprintf(buf, "%%ld", (long)(%s));' % name)
+        prnt('    else')
+        prnt('        sprintf(buf, "%%lu", (unsigned long)(%s));' %
+             name)
+        prnt('    sprintf(out_error, "%s has the real value %s, not %s",')
+        prnt('            "%s", buf, "%d");' % (name[:100], value))
+        prnt('    return -1;')
+        prnt('  }')
+
+    def _load_known_int_constant(self, module, funcname):
+        BType = self.ffi._typeof_locked("char[]")[0]
+        BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
+        function = module.load_function(BFunc, funcname)
+        p = self.ffi.new(BType, 256)
+        if function(p) < 0:
+            error = self.ffi.string(p)
+            if sys.version_info >= (3,):
+                error = str(error, 'utf-8')
+            raise ffiplatform.VerificationError(error)
+
     def _enum_funcname(self, prefix, name):
         # "$enum_$1" => "___D_enum____D_1"
         name = name.replace('$', '___D_')
@@ -428,24 +473,7 @@
         prnt('int %s(char *out_error)' % funcname)
         prnt('{')
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
-            if enumvalue <= 0:
-                prnt('  if ((%s) > 0 || (long)(%s) != %dL) {' % (
-                    enumerator, enumerator, enumvalue))
-            else:
-                prnt('  if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
-                    enumerator, enumerator, enumvalue))
-            prnt('    char buf[64];')
-            prnt('    if ((%s) <= 0)' % enumerator)
-            prnt('        sprintf(buf, "%%ld", (long)(%s));' % enumerator)
-            prnt('    else')
-            prnt('        sprintf(buf, "%%lu", (unsigned long)(%s));' %
-                 enumerator)
-            prnt('    sprintf(out_error,'
-                             ' "%s has the real value %s, not %s",')
-            prnt('            "%s", buf, "%d");' % (
-                enumerator[:100], enumvalue))
-            prnt('    return -1;')
-            prnt('  }')
+            self._check_int_constant_value(enumerator, enumvalue)
         prnt('  return 0;')
         prnt('}')
         prnt()
@@ -457,16 +485,8 @@
             tp.enumvalues = tuple(enumvalues)
             tp.partial_resolved = True
         else:
-            BType = self.ffi._typeof_locked("char[]")[0]
-            BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
             funcname = self._enum_funcname(prefix, name)
-            function = module.load_function(BFunc, funcname)
-            p = self.ffi.new(BType, 256)
-            if function(p) < 0:
-                error = self.ffi.string(p)
-                if sys.version_info >= (3,):
-                    error = str(error, 'utf-8')
-                raise ffiplatform.VerificationError(error)
+            self._load_known_int_constant(module, funcname)
 
     def _loaded_gen_enum(self, tp, name, module, library):
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
@@ -477,13 +497,21 @@
     # macros: for now only for integers
 
     def _generate_gen_macro_decl(self, tp, name):
-        assert tp == '...'
-        self._generate_gen_const(True, name)
+        if tp == '...':
+            check_value = None
+        else:
+            check_value = tp     # an integer
+        self._generate_gen_const(True, name, check_value=check_value)
 
     _loading_gen_macro = _loaded_noop
 
     def _loaded_gen_macro(self, tp, name, module, library):
-        value = self._load_constant(True, tp, name, module)
+        if tp == '...':
+            check_value = None
+        else:
+            check_value = tp     # an integer
+        value = self._load_constant(True, tp, name, module,
+                                    check_value=check_value)
         setattr(library, name, value)
         type(library)._cffi_dir.append(name)
 
diff --git a/pypy/module/__builtin__/app_io.py b/pypy/module/__builtin__/app_io.py
--- a/pypy/module/__builtin__/app_io.py
+++ b/pypy/module/__builtin__/app_io.py
@@ -86,9 +86,11 @@
 
 def print_(*args, **kwargs):
     """The new-style print function from py3k."""
-    fp = kwargs.pop("file", sys.stdout)
+    fp = kwargs.pop("file", None)
     if fp is None:
-        return
+        fp = sys.stdout
+        if fp is None:
+            return
     def write(data):
         if not isinstance(data, basestring):
             data = str(data)
diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -651,9 +651,12 @@
         out = sys.stdout = StringIO.StringIO()
         try:
             pr("Hello,", "person!")
+            pr("2nd line", file=None)
+            sys.stdout = None
+            pr("nowhere")
         finally:
             sys.stdout = save
-        assert out.getvalue() == "Hello, person!\n"
+        assert out.getvalue() == "Hello, person!\n2nd line\n"
         out = StringIO.StringIO()
         pr("Hello,", "person!", file=out)
         assert out.getvalue() == "Hello, person!\n"
@@ -668,7 +671,6 @@
         result = out.getvalue()
         assert isinstance(result, unicode)
         assert result == u"Hello, person!\n"
-        pr("Hello", file=None) # This works.
         out = StringIO.StringIO()
         pr(None, file=out)
         assert out.getvalue() == "None\n"
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -107,6 +107,9 @@
                 return self.space.w_None
         return W_CTypePtrOrArray._fget(self, attrchar)
 
+    def typeoffsetof_index(self, index):
+        return self.ctptr.typeoffsetof_index(index)
+
 
 class W_CDataIter(W_Root):
     _immutable_fields_ = ['ctitem', 'cdata', '_stop']    # but not '_next'
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -142,12 +142,14 @@
         raise oefmt(space.w_ValueError, "ctype '%s' is of unknown alignment",
                     self.name)
 
-    def typeoffsetof(self, fieldname):
+    def typeoffsetof_field(self, fieldname, following):
         space = self.space
-        if fieldname is None:
-            msg = "expected a struct or union ctype"
-        else:
-            msg = "expected a struct or union ctype, or a pointer to one"
+        msg = "with a field name argument, expected a struct or union ctype"
+        raise OperationError(space.w_TypeError, space.wrap(msg))
+
+    def typeoffsetof_index(self, index):
+        space = self.space
+        msg = "with an integer argument, expected an array or pointer ctype"
         raise OperationError(space.w_TypeError, space.wrap(msg))
 
     def rawaddressof(self, cdata, offset):
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -308,24 +308,36 @@
     def getcfield(self, attr):
         return self.ctitem.getcfield(attr)
 
-    def typeoffsetof(self, fieldname):
-        if fieldname is None:
-            return W_CTypePtrBase.typeoffsetof(self, fieldname)
-        else:
-            return self.ctitem.typeoffsetof(fieldname)
+    def typeoffsetof_field(self, fieldname, following):
+        if following == 0:
+            return self.ctitem.typeoffsetof_field(fieldname, -1)
+        return W_CTypePtrBase.typeoffsetof_field(self, fieldname, following)
+
+    def typeoffsetof_index(self, index):
+        space = self.space
+        ctitem = self.ctitem
+        if ctitem.size < 0:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("pointer to opaque"))
+        try:
+            offset = ovfcheck(index * ctitem.size)
+        except OverflowError:
+            raise OperationError(space.w_OverflowError,
+                    space.wrap("array offset would overflow a ssize_t"))
+        return ctitem, offset
 
     def rawaddressof(self, cdata, offset):
         from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
         space = self.space
         ctype2 = cdata.ctype
         if (isinstance(ctype2, W_CTypeStructOrUnion) or
-               (isinstance(ctype2, W_CTypePtrOrArray) and
-                isinstance(ctype2.ctitem, W_CTypeStructOrUnion))):
+                isinstance(ctype2, W_CTypePtrOrArray)):
             ptrdata = rffi.ptradd(cdata._cdata, offset)
             return cdataobj.W_CData(space, ptrdata, self)
         else:
             raise OperationError(space.w_TypeError,
-                     space.wrap("expected a 'cdata struct-or-union' object"))
+                    space.wrap("expected a cdata struct/union/array/pointer"
+                               " object"))
 
     def _fget(self, attrchar):
         if attrchar == 'i':     # item
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -65,9 +65,7 @@
         keepalive_until_here(ob)
         return ob
 
-    def typeoffsetof(self, fieldname):
-        if fieldname is None:
-            return (self, 0)
+    def typeoffsetof_field(self, fieldname, following):
         self.check_complete()
         space = self.space
         try:
diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -48,13 +48,28 @@
     align = w_ctype.alignof()
     return space.wrap(align)
 
- at unwrap_spec(w_ctype=ctypeobj.W_CType, fieldname="str_or_None")
-def typeoffsetof(space, w_ctype, fieldname):
-    ctype, offset = w_ctype.typeoffsetof(fieldname)
+ at unwrap_spec(w_ctype=ctypeobj.W_CType, following=int)
+def typeoffsetof(space, w_ctype, w_field_or_index, following=0):
+    try:
+        fieldname = space.str_w(w_field_or_index)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        try:
+            index = space.int_w(w_field_or_index)
+        except OperationError, e:
+            if not e.match(space, space.w_TypeError):
+                raise
+            raise OperationError(space.w_TypeError,
+                    space.wrap("field name or array index expected"))
+        ctype, offset = w_ctype.typeoffsetof_index(index)
+    else:
+        ctype, offset = w_ctype.typeoffsetof_field(fieldname, following)
+    #
     return space.newtuple([space.wrap(ctype), space.wrap(offset)])
 
 @unwrap_spec(w_ctype=ctypeobj.W_CType, w_cdata=cdataobj.W_CData, offset=int)
-def rawaddressof(space, w_ctype, w_cdata, offset=0):
+def rawaddressof(space, w_ctype, w_cdata, offset):
     return w_ctype.rawaddressof(w_cdata, offset)
 
 # ____________________________________________________________
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
@@ -2527,13 +2527,32 @@
                                        ('a2', BChar, -1),
                                        ('a3', BChar, -1)])
     py.test.raises(TypeError, typeoffsetof, BStructPtr, None)
-    assert typeoffsetof(BStruct, None) == (BStruct, 0)
+    py.test.raises(TypeError, typeoffsetof, BStruct, None)
     assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0)
     assert typeoffsetof(BStruct, 'a1') == (BChar, 0)
     assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1)
     assert typeoffsetof(BStruct, 'a3') == (BChar, 2)
+    assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1)
+    assert typeoffsetof(BStruct, u+'a3') == (BChar, 2)
+    py.test.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1)
     py.test.raises(KeyError, typeoffsetof, BStructPtr, 'a4')
     py.test.raises(KeyError, typeoffsetof, BStruct, 'a5')
+    py.test.raises(TypeError, typeoffsetof, BStruct, 42)
+    py.test.raises(TypeError, typeoffsetof, BChar, 'a1')
+
+def test_typeoffsetof_array():
+    BInt = new_primitive_type("int")
+    BIntP = new_pointer_type(BInt)
+    BArray = new_array_type(BIntP, None)
+    py.test.raises(TypeError, typeoffsetof, BArray, None)
+    py.test.raises(TypeError, typeoffsetof, BArray, 'a1')
+    assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int())
+    assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int())
+    assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int())
+    MAX = sys.maxsize // size_of_int()
+    assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int())
+    assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int())
+    py.test.raises(OverflowError, typeoffsetof, BArray, MAX + 1)
 
 def test_typeoffsetof_no_bitfield():
     BInt = new_primitive_type("int")
@@ -2553,17 +2572,26 @@
     assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>"
     s = p[0]
     assert repr(s) == "<cdata 'struct foo' owning 3 bytes>"
-    a = rawaddressof(BStructPtr, s)
+    a = rawaddressof(BStructPtr, s, 0)
     assert repr(a).startswith("<cdata 'struct foo *' 0x")
-    py.test.raises(TypeError, rawaddressof, BStruct, s)
-    b = rawaddressof(BCharP, s)
+    py.test.raises(TypeError, rawaddressof, BStruct, s, 0)
+    b = rawaddressof(BCharP, s, 0)
     assert b == cast(BCharP, p)
-    c = rawaddressof(BStructPtr, a)
+    c = rawaddressof(BStructPtr, a, 0)
     assert c == a
-    py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'))
+    py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0)
     #
     d = rawaddressof(BCharP, s, 1)
     assert d == cast(BCharP, p) + 1
+    #
+    e = cast(BCharP, 109238)
+    f = rawaddressof(BCharP, e, 42)
+    assert f == e + 42
+    #
+    BCharA = new_array_type(BCharP, None)
+    e = newp(BCharA, 50)
+    f = rawaddressof(BCharP, e, 42)
+    assert f == e + 42
 
 def test_newp_signed_unsigned_char():
     BCharArray = new_array_type(
diff --git a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py
@@ -965,9 +965,19 @@
         ffi.cdef("struct foo { int a, b, c; };"
                  "struct bar { struct foo d, e; };")
         assert ffi.offsetof("struct bar", "e") == 12
-        assert ffi.offsetof("struct bar", "e.a") == 12
-        assert ffi.offsetof("struct bar", "e.b") == 16
-        assert ffi.offsetof("struct bar", "e.c") == 20
+        py.test.raises(KeyError, ffi.offsetof, "struct bar", "e.a")
+        assert ffi.offsetof("struct bar", "e", "a") == 12
+        assert ffi.offsetof("struct bar", "e", "b") == 16
+        assert ffi.offsetof("struct bar", "e", "c") == 20
+
+    def test_offsetof_array(self):
+        ffi = FFI(backend=self.Backend())
+        assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int")
+        assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int")
+        ffi.cdef("struct bar { int a, b; int c[99]; };")
+        assert ffi.offsetof("struct bar", "c") == 2 * ffi.sizeof("int")
+        assert ffi.offsetof("struct bar", "c", 0) == 2 * ffi.sizeof("int")
+        assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int")
 
     def test_alignof(self):
         ffi = FFI(backend=self.Backend())
@@ -1501,8 +1511,10 @@
         p = ffi.new("struct foo_s *")
         a = ffi.addressof(p[0])
         assert repr(a).startswith("<cdata 'struct foo_s *' 0x")
+        assert a == p
         py.test.raises(TypeError, ffi.addressof, p)
         py.test.raises((AttributeError, TypeError), ffi.addressof, 5)
+        py.test.raises(TypeError, ffi.addressof, ffi.cast("int", 5))
 
     def test_addressof_field(self):
         ffi = FFI(backend=self.Backend())
@@ -1520,7 +1532,8 @@
         ffi.cdef("struct foo_s { int x, y; };"
                  "struct bar_s { struct foo_s a, b; };")
         p = ffi.new("struct bar_s *")
-        a = ffi.addressof(p[0], 'b.y')
+        py.test.raises(KeyError, ffi.addressof, p[0], 'b.y')
+        a = ffi.addressof(p[0], 'b', 'y')
         assert int(ffi.cast("uintptr_t", a)) == (
             int(ffi.cast("uintptr_t", p)) +
             ffi.sizeof("struct foo_s") + ffi.sizeof("int"))
@@ -1532,6 +1545,49 @@
         a = ffi.addressof(p[0])
         assert a == p
 
+    def test_addressof_array(self):
+        ffi = FFI()
+        p = ffi.new("int[52]")
+        p0 = ffi.addressof(p)
+        assert p0 == p
+        assert ffi.typeof(p0) is ffi.typeof("int(*)[52]")
+        py.test.raises(TypeError, ffi.addressof, p0)
+        #
+        p1 = ffi.addressof(p, 25)
+        assert ffi.typeof(p1) is ffi.typeof("int *")
+        assert (p1 - p) == 25
+        assert ffi.addressof(p, 0) == p
+
+    def test_addressof_pointer(self):
+        ffi = FFI()
+        array = ffi.new("int[50]")
+        p = ffi.cast("int *", array)
+        py.test.raises(TypeError, ffi.addressof, p)
+        assert ffi.addressof(p, 0) == p
+        assert ffi.addressof(p, 25) == p + 25
+        assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
+        #
+        ffi.cdef("struct foo { int a, b; };")
+        array = ffi.new("struct foo[50]")
+        p = ffi.cast("int *", array)
+        py.test.raises(TypeError, ffi.addressof, p)
+        assert ffi.addressof(p, 0) == p
+        assert ffi.addressof(p, 25) == p + 25
+        assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
+
+    def test_addressof_array_in_struct(self):
+        ffi = FFI()
+        ffi.cdef("struct foo { int a, b; int c[50]; };")
+        p = ffi.new("struct foo *")
+        p1 = ffi.addressof(p, "c", 25)
+        assert ffi.typeof(p1) is ffi.typeof("int *")
+        assert p1 == ffi.cast("int *", p) + 27
+        assert ffi.addressof(p, "c") == ffi.cast("int *", p) + 2
+        assert ffi.addressof(p, "c", 0) == ffi.cast("int *", p) + 2
+        p2 = ffi.addressof(p, 1)
+        assert ffi.typeof(p2) is ffi.typeof("struct foo *")
+        assert p2 == p + 1
+
     def test_multiple_independent_structs(self):
         ffi1 = FFI(); ffi1.cdef("struct foo { int x; };")
         ffi2 = FFI(); ffi2.cdef("struct foo { int y, z; };")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_parsing.py b/pypy/module/test_lib_pypy/cffi_tests/test_parsing.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_parsing.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_parsing.py
@@ -164,8 +164,12 @@
     ffi = FFI(backend=FakeBackend())
     e = py.test.raises(CDefError, ffi.cdef, '#define FOO "blah"')
     assert str(e.value) == (
-        'only supports the syntax "#define FOO ..." (literally)'
-        ' or "#define FOO 0x1FF" for now')
+        'only supports one of the following syntax:\n'
+        '  #define FOO ...     (literally dot-dot-dot)\n'
+        '  #define FOO NUMBER  (with NUMBER an integer'
+                                    ' constant, decimal/hex/octal)\n'
+        'got:\n'
+        '  #define FOO "blah"')
 
 def test_unnamed_struct():
     ffi = FFI(backend=FakeBackend())
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py
@@ -2140,3 +2140,15 @@
     this_dir = os.path.dirname(__file__)
     pycache_files = os.listdir(os.path.join(this_dir, '__pycache__'))
     assert any('test_use_local_dir' in s for s in pycache_files)
+
+def test_define_known_value():
+    ffi = FFI()
+    ffi.cdef("#define FOO 0x123")
+    lib = ffi.verify("#define FOO 0x123")
+    assert lib.FOO == 0x123
+
+def test_define_wrong_value():
+    ffi = FFI()
+    ffi.cdef("#define FOO 123")
+    e = py.test.raises(VerificationError, ffi.verify, "#define FOO 124")
+    assert str(e.value).endswith("FOO has the real value 124, not 123")
diff --git a/rpython/jit/metainterp/optimizeopt/pure.py b/rpython/jit/metainterp/optimizeopt/pure.py
--- a/rpython/jit/metainterp/optimizeopt/pure.py
+++ b/rpython/jit/metainterp/optimizeopt/pure.py
@@ -7,6 +7,7 @@
     def __init__(self):
         self.postponed_op = None
         self.pure_operations = args_dict()
+        self.call_pure_positions = []
 
     def propagate_forward(self, op):
         dispatch_opt(self, op)
@@ -79,6 +80,7 @@
         args = op.getarglist()
         self.emit_operation(ResOperation(rop.CALL, args, op.result,
                                          op.getdescr()))
+        self.call_pure_positions.append(len(self.optimizer._newoperations) - 1)
 
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
@@ -107,5 +109,19 @@
     def get_pure_result(self, key):
         return self.pure_operations.get(key, None)
 
+    def produce_potential_short_preamble_ops(self, sb):
+        xxx
+        ops = sb.optimizer._newoperations
+        for i, op in enumerate(ops):
+            if op.is_always_pure():
+                sb.add_potential(op)
+            if op.is_ovf() and ops[i + 1].getopnum() == rop.GUARD_NO_OVERFLOW:
+                sb.add_potential(op)
+        for i in self.call_pure_positions:
+            op = ops[i]
+            assert op.getopnum() == rop.CALL
+            op = op.copy_and_change(rop.CALL_PURE)
+            sb.add_potential(op)
+
 dispatch_opt = make_dispatcher_method(OptPure, 'optimize_',
                                       default=OptPure.optimize_default)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5527,6 +5527,5 @@
         """
         self.optimize_loop(ops, ops)
 
-
 class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
     pass
diff --git a/rpython/translator/platform/windows.py b/rpython/translator/platform/windows.py
--- a/rpython/translator/platform/windows.py
+++ b/rpython/translator/platform/windows.py
@@ -293,7 +293,7 @@
 
         m.comment('automatically generated makefile')
         definitions = [
-            ('RPYDIR', rpydir),
+            ('RPYDIR', '"%s"' % rpydir),
             ('TARGET', target_name),
             ('DEFAULT_TARGET', exe_name.basename),
             ('SOURCES', rel_cfiles),


More information about the pypy-commit mailing list