[pypy-commit] cffi cffi-1.0: the '[...]' syntax

arigo noreply at buildbot.pypy.org
Sat Apr 18 12:10:26 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1748:28722032dd52
Date: 2015-04-18 12:11 +0200
http://bitbucket.org/cffi/cffi/changeset/28722032dd52/

Log:	the '[...]' syntax

diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -222,7 +222,7 @@
         elif length == '...':
             brackets = '&[/*...*/]'
         else:
-            brackets = '&[%d]' % length
+            brackets = '&[%s]' % length
         self.c_name_with_marker = (
             self.item.c_name_with_marker.replace('&', brackets))
 
diff --git a/new/_cffi_include.h b/new/_cffi_include.h
--- a/new/_cffi_include.h
+++ b/new/_cffi_include.h
@@ -159,6 +159,8 @@
     assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \
     (CTypeDescrObject *)_cffi_types[index])
 
+#define _cffi_array_len(array)   (sizeof(array) / sizeof((array)[0]))
+
 
 static int _cffi_init(void)
 {
diff --git a/new/recompiler.py b/new/recompiler.py
--- a/new/recompiler.py
+++ b/new/recompiler.py
@@ -369,11 +369,19 @@
     # ----------
     # named structs or unions
 
+    def _field_type(self, tp_struct, field_name, tp_field):
+        if isinstance(tp_field, model.ArrayType) and tp_field.length == '...':
+            ptr_struct_name = tp_struct.get_c_name('*')
+            actual_length = '_cffi_array_len(((%s)0)->%s)' % (
+                ptr_struct_name, field_name)
+            tp_field = model.ArrayType(tp_field.item, actual_length)
+        return tp_field
+
     def _generate_cpy_struct_collecttype(self, tp, name):
         self._do_collect_type(tp)
         if tp.fldtypes is not None:
-            for tp1 in tp.fldtypes:
-                self._do_collect_type(tp1)
+            for name1, tp1 in zip(tp.fldnames, tp.fldtypes):
+                self._do_collect_type(self._field_type(tp, name1, tp1))
 
     def _generate_cpy_struct_decl(self, tp, name):
         if tp.fldtypes is not None:
@@ -390,6 +398,7 @@
         if tp.fldtypes is not None:
             c_field = [name]
             for fldname, fldtype in zip(tp.fldnames, tp.fldtypes):
+                fldtype = self._field_type(tp, fldname, fldtype)
                 spaces = " " * len(fldname)
                 c_field.append(
                     '  { "%s", offsetof(%s, %s),\n' % (
@@ -483,13 +492,20 @@
     # ----------
     # global variables
 
+    def _global_type(self, tp, global_name):
+        if isinstance(tp, model.ArrayType) and tp.length == '...':
+            actual_length = '_cffi_array_len(%s)' % (global_name,)
+            tp = model.ArrayType(tp.item, actual_length)
+        return tp
+
     def _generate_cpy_variable_collecttype(self, tp, name):
-        self._do_collect_type(tp)
+        self._do_collect_type(self._global_type(tp, name))
 
     def _generate_cpy_variable_decl(self, tp, name):
         pass
 
     def _generate_cpy_variable_ctx(self, tp, name):
+        tp = self._global_type(tp, name)
         type_index = self._typesdict[tp]
         self._lsts["global"].append(
             '  { "%s", &%s, _CFFI_OP(_CFFI_OP_GLOBAL_VAR, %d)},'
@@ -528,10 +544,15 @@
         item_index = self._typesdict[tp.item]
         if tp.length is None:
             self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index)
+        elif tp.length == '...':
+            raise ffiplatform.VerificationError(
+                "type %s badly placed: the '...' array length can only be "
+                "used on global arrays or on fields of structures" % (
+                    str(tp).replace('/*...*/', '...'),))
         else:
             assert self.cffi_types[index + 1] == 'LEN'
             self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
-            self.cffi_types[index + 1] = CffiOp(None, '%d' % (tp.length,))
+            self.cffi_types[index + 1] = CffiOp(None, str(tp.length))
 
     def _emit_bytecode_StructType(self, tp, index):
         struct_index = self._struct_unions[tp]
diff --git a/new/test_recompiler.py b/new/test_recompiler.py
--- a/new/test_recompiler.py
+++ b/new/test_recompiler.py
@@ -219,3 +219,26 @@
         ffi2.typeof("struct foo_s*(*)()"))
     assert ffi1.typeof("void(*)(struct foo_s*)") is not (
         ffi2.typeof("void(*)(struct foo_s*)"))
+
+def test_dotdotdot_length_of_array_field():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int a[...]; int b[...]; };")
+    verify(ffi, 'test_dotdotdot_length_of_array_field',
+           "struct foo_s { int a[42]; int b[11]; };")
+    assert ffi.sizeof("struct foo_s") == (42 + 11) * 4
+    p = ffi.new("struct foo_s *")
+    assert p.a[41] == p.b[10] == 0
+    py.test.raises(IndexError, "p.a[42]")
+    py.test.raises(IndexError, "p.b[11]")
+
+def test_dotdotdot_global_array():
+    ffi = FFI()
+    ffi.cdef("int aa[...]; int bb[...];")
+    lib = verify(ffi, 'test_dotdotdot_global_array',
+                 "int aa[41]; int bb[12];")
+    assert ffi.sizeof(lib.aa) == 41 * 4
+    assert ffi.sizeof(lib.bb) == 12 * 4
+    assert lib.aa[40] == lib.bb[11] == 0
+    py.test.raises(IndexError, "lib.aa[41]")
+    py.test.raises(IndexError, "lib.bb[12]")
+


More information about the pypy-commit mailing list