[pypy-commit] cffi default: Issue 75: implement multidimensional use of '[...]'.
arigo
noreply at buildbot.pypy.org
Sat May 30 11:17:29 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r2129:d2e7bb656d74
Date: 2015-05-30 11:17 +0200
http://bitbucket.org/cffi/cffi/changeset/d2e7bb656d74/
Log: Issue 75: implement multidimensional use of '[...]'.
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -338,7 +338,9 @@
else:
length = self._parse_constant(
typenode.dim, partial_length_ok=partial_length_ok)
- return model.ArrayType(self._get_type(typenode.type), length)
+ tp = self._get_type(typenode.type,
+ partial_length_ok=(length == '...'))
+ return model.ArrayType(tp, length)
#
if isinstance(typenode, pycparser.c_ast.PtrDecl):
# pointer type
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -753,7 +753,9 @@
ptr_struct_name = tp_struct.get_c_name('*')
actual_length = '_cffi_array_len(((%s)0)->%s)' % (
ptr_struct_name, field_name)
- tp_field = tp_field.resolve_length(actual_length)
+ tp_item = self._field_type(tp_struct, '%s[0]' % field_name,
+ tp_field.item)
+ tp_field = model.ArrayType(tp_item, actual_length)
return tp_field
def _struct_collecttype(self, tp):
@@ -775,16 +777,16 @@
and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double
prnt(' (void)((p->%s) << 1);' % fname)
- elif (isinstance(ftype, model.ArrayType)
- and (ftype.length is None or ftype.length == '...')):
- # for C++: "int(*)tmp[] = &p->a;" errors out if p->a is
- # declared as "int[5]". Instead, write "int *tmp = p->a;".
- prnt(' { %s = p->%s; (void)tmp; }' % (
- ftype.item.get_c_name('*tmp', 'field %r'%fname), fname))
- else:
- # only accept exactly the type declared.
- prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname), fname))
+ continue
+ # only accept exactly the type declared, except that '[]'
+ # is interpreted as a '*' and so will match any array length.
+ # (It would also match '*', but that's harder to detect...)
+ while (isinstance(ftype, model.ArrayType)
+ and (ftype.length is None or ftype.length == '...')):
+ ftype = ftype.item
+ fname = fname + '[0]'
+ prnt(' { %s = &p->%s; (void)tmp; }' % (
+ ftype.get_c_name('*tmp', 'field %r'%fname), fname))
except ffiplatform.VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
@@ -1056,7 +1058,8 @@
def _global_type(self, tp, global_name):
if isinstance(tp, model.ArrayType) and tp.length == '...':
actual_length = '_cffi_array_len(%s)' % (global_name,)
- tp = tp.resolve_length(actual_length)
+ tp_item = self._global_type(tp.item, '%s[0]' % global_name)
+ tp = model.ArrayType(tp_item, actual_length)
return tp
def _generate_cpy_variable_collecttype(self, tp, name):
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -387,11 +387,11 @@
* array lengths: when used as structure fields or in global variables,
arrays can have an unspecified length, as in "``int n[...];``". The
- length is completed by the C compiler. (Only the outermost array
- may have an unknown length, in case of array-of-array.)
+ length is completed by the C compiler.
This is slightly different from "``int n[];``", because the latter
means that the length is not known even to the C compiler, and thus
- no attempt is made to complete it.
+ no attempt is made to complete it. *New in version 1.0.4:* support
+ for multidimensional arrays: "``int n[...][...];``".
* enums: if you don't know the exact order (or values) of the declared
constants, then use this syntax: "``enum foo { A, B, C, ... };``"
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -6,6 +6,10 @@
1.0.4
=====
+* Out-of-line API mode: we can now declare multidimensional arrays
+ (as fields or as globals) with ``int n[...][...]``. Before, only the
+ outermost dimension would support the ``...`` syntax.
+
* Issue #175: in ABI mode: we now support any constant declaration,
instead of only integers whose value is given in the cdef. Such "new"
constants, i.e. either non-integers or without a value given in the
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -907,3 +907,28 @@
""")
assert lib.getx(lib.myglob) == 42.5
assert lib.getx(lib.increment(lib.myglob)) == 43.5
+
+def test_struct_array_guess_length_2():
+ ffi = FFI()
+ ffi.cdef("struct foo_s { int a[...][...]; };")
+ lib = verify(ffi, 'test_struct_array_guess_length_2',
+ "struct foo_s { int x; int a[5][8]; int y; };")
+ assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
+ s = ffi.new("struct foo_s *")
+ assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
+ assert s.a[4][7] == 0
+ py.test.raises(IndexError, 's.a[4][8]')
+ py.test.raises(IndexError, 's.a[5][0]')
+ assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
+ assert ffi.typeof(s.a[0]) == ffi.typeof("int[8]")
+
+def test_global_var_array_2():
+ ffi = FFI()
+ ffi.cdef("int a[...][...];")
+ lib = verify(ffi, 'test_global_var_array_2', 'int a[10][8];')
+ lib.a[9][7] = 123456
+ assert lib.a[9][7] == 123456
+ py.test.raises(IndexError, 'lib.a[0][8]')
+ py.test.raises(IndexError, 'lib.a[10][0]')
+ assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]")
+ assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")
More information about the pypy-commit
mailing list