[pypy-commit] cffi default: Fix the tests about "typedef enum".
arigo
noreply at buildbot.pypy.org
Thu Aug 23 13:55:27 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r877:92e67ab3082d
Date: 2012-08-23 13:55 +0200
http://bitbucket.org/cffi/cffi/changeset/92e67ab3082d/
Log: Fix the tests about "typedef enum".
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -136,13 +136,13 @@
if isinstance(node, pycparser.c_ast.Struct):
# XXX do we need self._declare in any of those?
if node.decls is not None:
- self._get_struct_or_union_type('struct', node)
+ self._get_struct_union_enum_type('struct', node)
elif isinstance(node, pycparser.c_ast.Union):
if node.decls is not None:
- self._get_struct_or_union_type('union', node)
+ self._get_struct_union_enum_type('union', node)
elif isinstance(node, pycparser.c_ast.Enum):
if node.values is not None:
- self._get_enum_type(node)
+ self._get_struct_union_enum_type('enum', node)
elif not decl.name:
raise api.CDefError("construct does not declare any variable",
decl)
@@ -236,15 +236,15 @@
#
if isinstance(type, pycparser.c_ast.Struct):
# 'struct foobar'
- return self._get_struct_or_union_type('struct', type, name)
+ return self._get_struct_union_enum_type('struct', type, name)
#
if isinstance(type, pycparser.c_ast.Union):
# 'union foobar'
- return self._get_struct_or_union_type('union', type, name)
+ return self._get_struct_union_enum_type('union', type, name)
#
if isinstance(type, pycparser.c_ast.Enum):
# 'enum foobar'
- return self._get_enum_type(type)
+ return self._get_struct_union_enum_type('enum', type, name)
#
if isinstance(typenode, pycparser.c_ast.FuncDecl):
# a function type
@@ -291,7 +291,7 @@
return const or 'const' in typenode.quals
return False
- def _get_struct_or_union_type(self, kind, type, name=None):
+ def _get_struct_union_enum_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
@@ -336,16 +336,27 @@
tp = model.StructType(explicit_name, None, None, None)
elif kind == 'union':
tp = model.UnionType(explicit_name, None, None, None)
+ elif kind == 'enum':
+ tp = self._build_enum_type(explicit_name, type.values)
else:
raise AssertionError("kind = %r" % (kind,))
if name is not None:
self._declare(key, tp)
+ else:
+ if kind == 'enum' and type.values is not None:
+ raise NotImplementedError(
+ "enum %s: the '{}' declaration should appear on the first "
+ "time the enum is mentioned, not later" % explicit_name)
tp.forcename = tp.forcename or force_name
if tp.forcename and '$' in tp.name:
self._declare('anonymous %s' % tp.forcename, tp)
#
self._structnode2type[type] = tp
#
+ # enums: done here
+ if kind == 'enum':
+ return tp
+ #
# is there a 'type.decls'? If yes, then this is the place in the
# C sources that declare the fields. If no, then just return the
# existing type, possibly still incomplete.
@@ -407,28 +418,7 @@
raise api.FFIError("unsupported non-constant or "
"not immediately constant expression")
- def _get_enum_type(self, type):
- # See _get_struct_or_union_type() for the reason of the
- # complicated logic here. This is still a simplified version,
- # assuming that it's ok to assume the more complicated cases
- # don't occur...
- try:
- return self._structnode2type[type]
- except KeyError:
- pass
- name = type.name
- if name is None:
- self._anonymous_counter += 1
- explicit_name = '$%d' % self._anonymous_counter
- key = None
- else:
- explicit_name = name
- key = 'enum %s' % (name,)
- tp = self._declarations.get(key, None)
- if tp is not None:
- return tp
- #
- decls = type.values
+ def _build_enum_type(self, explicit_name, decls):
if decls is not None:
enumerators = [enum.name for enum in decls.enumerators]
partial = False
@@ -446,11 +436,6 @@
enumvalues = tuple(enumvalues)
tp = model.EnumType(explicit_name, enumerators, enumvalues)
tp.partial = partial
- if key is not None:
- self._declare(key, tp)
else: # opaque enum
- enumerators = ()
- enumvalues = ()
tp = model.EnumType(explicit_name, (), ())
- self._structnode2type[type] = tp
return tp
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -158,9 +158,16 @@
return global_cache(ffi, 'new_array_type', BPtrItem, self.length)
-class StructOrUnion(BaseType):
+class StructOrUnionOrEnum(BaseType):
_attrs_ = ('name',)
forcename = None
+
+ def _get_c_name(self, replace_with):
+ name = self.forcename or '%s %s' % (self.kind, self.name)
+ return name + replace_with
+
+
+class StructOrUnion(StructOrUnionOrEnum):
fixedlayout = None
def __init__(self, name, fldnames, fldtypes, fldbitsize):
@@ -169,10 +176,6 @@
self.fldtypes = fldtypes
self.fldbitsize = fldbitsize
- def _get_c_name(self, replace_with):
- name = self.forcename or '%s %s' % (self.kind, self.name)
- return name + replace_with
-
def finish_backend_type(self, ffi):
BType = self.new_btype(ffi)
ffi._cached_btypes[self] = BType
@@ -244,8 +247,8 @@
return ffi._backend.new_union_type(self.name)
-class EnumType(BaseType):
- _attrs_ = ('name',)
+class EnumType(StructOrUnionOrEnum):
+ kind = 'enum'
partial = False
def __init__(self, name, enumerators, enumvalues):
@@ -253,9 +256,6 @@
self.enumerators = enumerators
self.enumvalues = enumvalues
- 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
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -459,16 +459,26 @@
_generate_cpy_anonymous_collecttype = _generate_nothing
def _generate_cpy_anonymous_decl(self, tp, name):
- self._generate_struct_or_union_decl(tp, '', name)
+ if isinstance(tp, model.EnumType):
+ self._generate_cpy_enum_decl(tp, name, '')
+ else:
+ self._generate_struct_or_union_decl(tp, '', name)
def _generate_cpy_anonymous_method(self, tp, name):
- self._generate_struct_or_union_method(tp, '', name)
+ if not isinstance(tp, model.EnumType):
+ self._generate_struct_or_union_method(tp, '', name)
def _loading_cpy_anonymous(self, tp, name, module):
- self._loading_struct_or_union(tp, '', name, module)
+ if isinstance(tp, model.EnumType):
+ self._loading_cpy_enum(tp, name, module)
+ else:
+ self._loading_struct_or_union(tp, '', name, module)
def _loaded_cpy_anonymous(self, tp, name, module, **kwds):
- self._loaded_struct_or_union(tp)
+ if isinstance(tp, model.EnumType):
+ self._loaded_cpy_enum(tp, name, module, **kwds)
+ else:
+ self._loaded_struct_or_union(tp)
# ----------
# constants, likely declared with '#define'
@@ -529,13 +539,13 @@
# ----------
# enums
- def _generate_cpy_enum_decl(self, tp, name):
+ def _generate_cpy_enum_decl(self, tp, name, prefix='enum'):
if tp.partial:
for enumerator in tp.enumerators:
self._generate_cpy_const(True, enumerator, delayed=False)
return
#
- funcname = '_cffi_enum_%s' % name
+ funcname = '_cffi_e_%s_%s' % (prefix, name)
prnt = self._prnt
prnt('static int %s(PyObject *lib)' % funcname)
prnt('{')
@@ -555,7 +565,6 @@
_generate_cpy_enum_collecttype = _generate_nothing
_generate_cpy_enum_method = _generate_nothing
- _loading_cpy_enum = _loaded_noop
def _loading_cpy_enum(self, tp, name, module):
if tp.partial:
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -276,13 +276,22 @@
# or unions; the 'name' is obtained by a typedef.
def _generate_gen_anonymous_decl(self, tp, name):
- self._generate_struct_or_union_decl(tp, '', name)
+ if isinstance(tp, model.EnumType):
+ self._generate_gen_enum_decl(tp, name, '')
+ else:
+ self._generate_struct_or_union_decl(tp, '', name)
def _loading_gen_anonymous(self, tp, name, module):
- self._loading_struct_or_union(tp, '', name, module)
+ if isinstance(tp, model.EnumType):
+ self._loading_gen_enum(tp, name, module, '')
+ else:
+ self._loading_struct_or_union(tp, '', name, module)
def _loaded_gen_anonymous(self, tp, name, module, **kwds):
- self._loaded_struct_or_union(tp)
+ if isinstance(tp, model.EnumType):
+ self._loaded_gen_enum(tp, name, module, **kwds)
+ else:
+ self._loaded_struct_or_union(tp)
# ----------
# constants, likely declared with '#define'
@@ -340,13 +349,13 @@
# ----------
# enums
- def _generate_gen_enum_decl(self, tp, name):
+ def _generate_gen_enum_decl(self, tp, name, prefix='enum'):
if tp.partial:
for enumerator in tp.enumerators:
self._generate_gen_const(True, enumerator)
return
#
- funcname = '_cffi_enum_%s' % name
+ funcname = '_cffi_e_%s_%s' % (prefix, name)
self.export_symbols.append(funcname)
prnt = self._prnt
prnt('int %s(char *out_error)' % funcname)
@@ -365,7 +374,7 @@
_loading_gen_enum = _loaded_noop
- def _loading_gen_enum(self, tp, name, module):
+ def _loading_gen_enum(self, tp, name, module, prefix='enum'):
if tp.partial:
enumvalues = [self._load_constant(True, tp, enumerator, module)
for enumerator in tp.enumerators]
@@ -373,7 +382,7 @@
tp.partial = False
else:
BFunc = self.ffi.typeof("int(*)(char*)")
- funcname = '_cffi_enum_%s' % name
+ funcname = '_cffi_e_%s_%s' % (prefix, name)
function = module.load_function(BFunc, funcname)
p = self.ffi.new("char[]", 256)
if function(p) < 0:
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -1279,9 +1279,9 @@
ffi = FFI(backend=self.Backend())
ffi.cdef("typedef enum { Value0 = 0 } e, *pe;\n"
"typedef enum { Value1 = 1 } e1;")
- assert ffi.getctype("e*") == 'enum $1 *'
- assert ffi.getctype("pe") == 'enum $1 *'
- assert ffi.getctype("e1*") == 'enum $2 *'
+ assert ffi.getctype("e*") == 'enum $e *'
+ assert ffi.getctype("pe") == 'enum $e *'
+ assert ffi.getctype("e1*") == 'enum $e1 *'
def test_new_ctype(self):
ffi = FFI(backend=self.Backend())
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -189,3 +189,11 @@
ffi = FFI()
e = py.test.raises(CDefError, ffi.cdef, " x y z ")
assert re.match(r'cannot parse " x y z "\n:\d+:', str(e.value))
+
+def test_cannot_declare_enum_later():
+ ffi = FFI()
+ e = py.test.raises(NotImplementedError, ffi.cdef,
+ "typedef enum foo_e foo_t; enum foo_e { AA, BB };")
+ assert str(e.value) == (
+ "enum foo_e: the '{}' declaration should appear on the "
+ "first time the enum is mentioned, not later")
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -818,7 +818,7 @@
ffi = FFI()
ffi.cdef("typedef enum { AA, BB } enum1_t;")
lib = ffi.verify("typedef enum { AA, BB } enum1_t;")
- assert ffi.string(ffi.cast("enum enum1_e", 1)) == 'BB'
+ assert ffi.string(ffi.cast("enum1_t", 1)) == 'BB'
assert lib.AA == 0
assert lib.BB == 1
@@ -832,8 +832,8 @@
ffi = FFI()
ffi.cdef("typedef enum { AA, BB, ... } enum1_t;")
lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
- assert ffi.string(ffi.cast("enum enum1_e", 1)) == '#1'
- assert ffi.string(ffi.cast("enum enum1_e", 2)) == 'BB'
+ assert ffi.string(ffi.cast("enum1_t", 1)) == '#1'
+ assert ffi.string(ffi.cast("enum1_t", 2)) == 'BB'
assert lib.AA == 0
assert lib.BB == 2
More information about the pypy-commit
mailing list