[pypy-commit] cffi default: Allow the syntax "a[...]; ", for now only on struct fields.
arigo
noreply at buildbot.pypy.org
Tue Jun 26 10:53:30 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r518:8e459b477b6b
Date: 2012-06-26 10:52 +0200
http://bitbucket.org/cffi/cffi/changeset/8e459b477b6b/
Log: Allow the syntax "a[...];", for now only on struct fields.
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -7,6 +7,7 @@
re.MULTILINE)
_r_partial_enum = re.compile(r"\.\.\.\s*\}")
_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
+_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
_parser_cache = None
def _get_parser():
@@ -25,6 +26,8 @@
macroname, macrovalue = match.groups()
macros[macroname] = macrovalue
csource = _r_define.sub('', csource)
+ # Replace "[...]" with "[__dotdotdotarray__]"
+ csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
# Replace "...}" with "__dotdotdotNUM__}". This construction should
# occur only at the end of enums; at the end of structs we have "...;}"
# and at the end of vararg functions "...);"
@@ -141,7 +144,7 @@
return model.PointerType(type)
def _get_type(self, typenode, convert_array_to_pointer=False,
- force_pointer=False, name=None):
+ force_pointer=False, name=None, partial_length_ok=False):
# first, dereference typedefs, if we have it already parsed, we're good
if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
@@ -163,7 +166,8 @@
if typenode.dim is None:
length = None
else:
- length = self._parse_constant(typenode.dim)
+ length = self._parse_constant(
+ typenode.dim, partial_length_ok=partial_length_ok)
return model.ArrayType(self._get_type(typenode.type), length)
#
if force_pointer:
@@ -317,23 +321,26 @@
# of strings, but is sometimes just one string. Use
# str.join() as a way to cope with both.
tp.partial = True
- if not tp.has_c_name():
- raise api.CDefError("%s is partial but has no C name"
- % (tp,))
continue
if decl.bitsize is None:
bitsize = -1
else:
bitsize = self._parse_constant(decl.bitsize)
+ self._partial_length = False
+ type = self._get_type(decl.type, partial_length_ok=True)
+ if self._partial_length:
+ tp.partial = True
fldnames.append(decl.name)
- fldtypes.append(self._get_type(decl.type))
+ fldtypes.append(type)
fldbitsize.append(bitsize)
+ if tp.partial and not tp.has_c_name():
+ raise api.CDefError("%s is partial but has no C name" % (tp,))
tp.fldnames = tuple(fldnames)
tp.fldtypes = tuple(fldtypes)
tp.fldbitsize = tuple(fldbitsize)
return tp
- def _parse_constant(self, exprnode):
+ def _parse_constant(self, exprnode, partial_length_ok=False):
# for now, limited to expressions that are an immediate number
# or negative number
if isinstance(exprnode, pycparser.c_ast.Constant):
@@ -343,6 +350,12 @@
exprnode.op == '-'):
return -self._parse_constant(exprnode.expr)
#
+ if partial_length_ok:
+ if (isinstance(exprnode, pycparser.c_ast.ID) and
+ exprnode.name == '__dotdotdotarray__'):
+ self._partial_length = True
+ return None
+ #
raise api.FFIError("unsupported non-constant or "
"not immediately constant expression")
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -267,6 +267,14 @@
s.a[14] = 4242
assert lib.bar(s) == 4242
+def test_struct_array_guess_length_3():
+ ffi = FFI()
+ ffi.cdef("struct foo_s { int a[...]; };")
+ ffi.verify("struct foo_s { int x; int a[17]; int y; };")
+ assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
+ s = ffi.new("struct foo_s")
+ assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
+
def test_global_constants():
ffi = FFI()
# use 'static const int', as generally documented, although in this
More information about the pypy-commit
mailing list