[pypy-commit] cffi default: A non-passing test, a bit annoying: how are we supposed to fill in
arigo
noreply at buildbot.pypy.org
Sun Jun 17 10:17:35 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r396:874950ec032e
Date: 2012-06-16 18:42 +0200
http://bitbucket.org/cffi/cffi/changeset/874950ec032e/
Log: A non-passing test, a bit annoying: how are we supposed to fill in
the anonymous struct types declared in the middle of a typedef?
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -87,7 +87,7 @@
and decl.type.type.names == ['__dotdotdot__']):
realtype = model.OpaqueType(decl.name)
else:
- realtype = self._get_type(decl.type)
+ realtype = self._get_type(decl.type, name=decl.name)
self._declare('typedef ' + decl.name, realtype)
else:
raise api.CDefError("unrecognized construct", decl)
@@ -195,11 +195,11 @@
#
if isinstance(type, pycparser.c_ast.Struct):
# 'struct foobar'
- return self._get_struct_or_union_type('struct', type, typenode)
+ return self._get_struct_or_union_type('struct', type, name)
#
if isinstance(type, pycparser.c_ast.Union):
# 'union foobar'
- return self._get_struct_or_union_type('union', type, typenode)
+ return self._get_struct_or_union_type('union', type, name)
#
if isinstance(type, pycparser.c_ast.Enum):
# 'enum foobar'
@@ -242,7 +242,7 @@
return const or 'const' in typenode.quals
return False
- def _get_struct_or_union_type(self, kind, type, typenode=None):
+ def _get_struct_or_union_type(self, kind, type, name=None):
# First, a level of caching on the exact 'type' node of the AST.
# This is obscure, but needed because pycparser "unrolls" declarations
# such as "typedef struct { } foo_t, *foo_p" and we end up with
@@ -264,14 +264,15 @@
# with no caching; in this case, the fields are either specified
# right now or never.
#
+ force_name = name
name = type.name
#
# get the type or create it if needed
if name is None:
- # 'typenode' is only used to guess a more readable name for
+ # 'force_name' is used to guess a more readable name for
# anonymous structs, for the common case "typedef struct { } foo".
- if typenode is not None and isinstance(typenode.declname, str):
- explicit_name = '$%s' % typenode.declname
+ if force_name is not None:
+ explicit_name = '$%s' % force_name
else:
self._anonymous_counter += 1
explicit_name = '$%d' % self._anonymous_counter
@@ -290,6 +291,7 @@
raise AssertionError("kind = %r" % (kind,))
if name is not None:
self._declare(key, tp)
+ tp.forcename = tp.forcename or force_name
#
self._structnode2type[type] = tp
#
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -1,8 +1,17 @@
class BaseType(object):
+ def get_c_name(self, replace_with=''):
+ result = self._get_c_name(replace_with)
+ if '$' in result:
+ from .ffiplatform import VerificationError
+ raise VerificationError(
+ "cannot generate '%s' in a C file: unknown type name"
+ % (result,))
+ return result
+
def __repr__(self):
- return '<%s>' % (self.get_c_name(),)
+ return '<%s>' % (self._get_c_name(''),)
def __eq__(self, other):
return (self.__class__ == other.__class__ and
@@ -30,7 +39,7 @@
class VoidType(BaseType):
_attrs_ = ()
- def get_c_name(self, replace_with=''):
+ def _get_c_name(self, replace_with):
return 'void' + replace_with
def new_backend_type(self, ffi):
@@ -45,7 +54,7 @@
def __init__(self, name):
self.name = name
- def get_c_name(self, replace_with=''):
+ def _get_c_name(self, replace_with):
return self.name + replace_with
def is_char_type(self):
@@ -71,13 +80,13 @@
self.result = result
self.ellipsis = ellipsis
- def get_c_name(self, replace_with=''):
- reprargs = [arg.get_c_name() for arg in self.args]
+ def _get_c_name(self, replace_with):
+ reprargs = [arg._get_c_name('') for arg in self.args]
if self.ellipsis:
reprargs.append('...')
reprargs = reprargs or ['void']
replace_with = '(*%s)(%s)' % (replace_with, ', '.join(reprargs))
- return self.result.get_c_name(replace_with)
+ return self.result._get_c_name(replace_with)
def prepare_backend_type(self, ffi):
args = [ffi._get_cached_btype(self.result)]
@@ -95,8 +104,8 @@
def __init__(self, totype):
self.totype = totype
- def get_c_name(self, replace_with=''):
- return self.totype.get_c_name('* ' + replace_with)
+ def _get_c_name(self, replace_with):
+ return self.totype._get_c_name('* ' + replace_with)
def prepare_backend_type(self, ffi):
return (ffi._get_cached_btype(self.totype),)
@@ -107,8 +116,8 @@
class ConstPointerType(PointerType):
- def get_c_name(self, replace_with=''):
- return self.totype.get_c_name(' const * ' + replace_with)
+ def _get_c_name(self, replace_with):
+ return self.totype._get_c_name(' const * ' + replace_with)
def prepare_backend_type(self, ffi):
return (ffi._get_cached_btype(PointerType(self.totype)),)
@@ -127,12 +136,12 @@
def resolve_length(self, newlength):
return ArrayType(self.item, newlength)
- def get_c_name(self, replace_with=''):
+ def _get_c_name(self, replace_with):
if self.length is None:
brackets = '[]'
else:
brackets = '[%d]' % self.length
- return self.item.get_c_name(replace_with + brackets)
+ return self.item._get_c_name(replace_with + brackets)
def prepare_backend_type(self, ffi):
return (ffi._get_cached_btype(PointerType(self.item)),)
@@ -143,6 +152,7 @@
class StructOrUnion(BaseType):
_attrs_ = ('name',)
+ forcename = None
fixedlayout = None
def __init__(self, name, fldnames, fldtypes, fldbitsize):
@@ -151,8 +161,9 @@
self.fldtypes = fldtypes
self.fldbitsize = fldbitsize
- def get_c_name(self, replace_with=''):
- return '%s %s%s' % (self.kind, self.name, replace_with)
+ def _get_c_name(self, replace_with):
+ name = self.forcename or '%s %s' % (self.kind, self.name)
+ return name + replace_with
def prepare_backend_type(self, ffi):
BType = self.get_btype(ffi)
@@ -216,7 +227,7 @@
def check_not_partial(self):
if self.partial and self.fixedlayout is None:
from . import ffiplatform
- raise ffiplatform.VerificationMissing(self.get_c_name())
+ raise ffiplatform.VerificationMissing(self._get_c_name(''))
def get_btype(self, ffi):
self.check_not_partial()
@@ -239,13 +250,13 @@
self.enumerators = enumerators
self.enumvalues = enumvalues
- def get_c_name(self, replace_with=''):
+ def _get_c_name(self, replace_with):
return 'enum %s%s' % (self.name, replace_with)
def check_not_partial(self):
if self.partial:
from . import ffiplatform
- raise ffiplatform.VerificationMissing(self.get_c_name())
+ raise ffiplatform.VerificationMissing(self._get_c_name(''))
def new_backend_type(self, ffi):
self.check_not_partial()
@@ -259,7 +270,7 @@
def __init__(self, name):
self.name = name
- def get_c_name(self, replace_with=''):
+ def _get_c_name(self, replace_with):
return self.name + replace_with
def new_backend_type(self, ffi):
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -1,5 +1,5 @@
import py, sys
-from cffi import FFI, CDefError
+from cffi import FFI, CDefError, VerificationError
class FakeBackend(object):
@@ -149,3 +149,18 @@
e = py.test.raises(CDefError, ffi.cdef, "#define FOO 42")
assert str(e.value) == \
'only supports the syntax "#define FOO ..." for now (literally)'
+
+def test_unnamed_struct():
+ ffi = FFI(backend=FakeBackend())
+ ffi.cdef("typedef struct { int x; } foo_t;\n"
+ "typedef struct { int y; } *bar_p;\n")
+ assert 'typedef foo_t' in ffi._parser._declarations
+ assert 'typedef bar_p' in ffi._parser._declarations
+ #assert 'structdef foo_t' in ffi._parser._declarations ...
+ #assert 'structdef bar_p' in ffi._parser._declarations
+ type_foo = ffi._parser.parse_type("foo_t")
+ type_bar = ffi._parser.parse_type("bar_p").totype
+ assert repr(type_foo) == "<foo_t>"
+ assert repr(type_bar) == "<struct $1>"
+ py.test.raises(VerificationError, type_bar.get_c_name)
+ assert type_foo.get_c_name() == "foo_t"
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -452,3 +452,14 @@
ffi = FFI(backend=CTypesBackend())
ffi.cdef("int a;")
py.test.raises(NotImplementedError, ffi.verify, "int a;")
+
+def test_call_with_struct_ptr():
+ ffi = FFI()
+ ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);")
+ lib = ffi.verify("""
+ typedef struct { int y, x; } foo_t;
+ static int foo(foo_t *f) { return f->x * 7; }
+ """)
+ f = ffi.new("foo_t")
+ f.x = 6
+ assert lib.foo(f) == 42
More information about the pypy-commit
mailing list