[pypy-commit] cffi cffi-1.0: start on ffi.include
arigo
noreply at buildbot.pypy.org
Mon Apr 27 23:48:52 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1861:fa462bbfa883
Date: 2015-04-27 18:27 +0200
http://bitbucket.org/cffi/cffi/changeset/fa462bbfa883/
Log: start on ffi.include
diff --git a/_cffi1/parse_c_type.h b/_cffi1/parse_c_type.h
--- a/_cffi1/parse_c_type.h
+++ b/_cffi1/parse_c_type.h
@@ -80,6 +80,7 @@
#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the
// "standard layout" or if some are missing
#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct
+#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include()
struct _cffi_field_s {
const char *name;
diff --git a/_cffi1/recompiler.py b/_cffi1/recompiler.py
--- a/_cffi1/recompiler.py
+++ b/_cffi1/recompiler.py
@@ -8,9 +8,6 @@
def __init__(self, ffi, module_name):
self.ffi = ffi
self.module_name = module_name
- #
- if ']' in self.ffi._cdefsources:
- raise NotImplementedError("ffi.include()")
def collect_type_table(self):
self._typesdict = {}
@@ -80,7 +77,8 @@
if isinstance(tp, model.FunctionPtrType):
self._do_collect_type(tp.as_raw_function())
elif isinstance(tp, model.StructOrUnion):
- if tp.fldtypes is not None:
+ if tp.fldtypes is not None and (
+ tp not in self.ffi._parser._included_declarations):
for name1, tp1, _ in tp.enumfields():
self._do_collect_type(self._field_type(tp, name1, tp1))
else:
@@ -464,19 +462,24 @@
def _struct_ctx(self, tp, cname, approxname):
type_index = self._typesdict[tp]
+ reason_for_not_expanding = None
flags = []
if isinstance(tp, model.UnionType):
flags.append("_CFFI_F_UNION")
- if tp.fldtypes is None:
- pass # opaque
- elif tp.partial or tp.has_anonymous_struct_fields():
- pass # the field layout is obtained silently from the C compiler
+ if tp not in self.ffi._parser._included_declarations:
+ if tp.fldtypes is None:
+ reason_for_not_expanding = "opaque"
+ elif tp.partial or tp.has_anonymous_struct_fields():
+ pass # field layout obtained silently from the C compiler
+ else:
+ flags.append("_CFFI_F_CHECK_FIELDS")
+ if tp.packed:
+ flags.append("_CFFI_F_PACKED")
else:
- flags.append("_CFFI_F_CHECK_FIELDS")
- if tp.packed:
- flags.append("_CFFI_F_PACKED")
+ flags.append("_CFFI_F_EXTERNAL")
+ reason_for_not_expanding = "external"
flags = '|'.join(flags) or '0'
- if tp.fldtypes is not None:
+ if reason_for_not_expanding is None:
c_field = [approxname]
enumfields = list(tp.enumfields())
for fldname, fldtype, fbitsize in enumfields:
@@ -515,7 +518,8 @@
' _cffi_FIELDS_FOR_%s, %d },' % (approxname,
len(enumfields),))
else:
- size_align = ' (size_t)-1, -1, -1, 0 /* opaque */ },'
+ size_align = ' (size_t)-1, -1, -1, 0 /* %s */ },' % (
+ reason_for_not_expanding,)
self._lsts["struct_union"].append(
' { "%s", %d, %s,' % (tp.name, type_index, flags) + size_align)
self._seen_struct_unions.add(tp)
diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py
--- a/_cffi1/test_recompiler.py
+++ b/_cffi1/test_recompiler.py
@@ -4,8 +4,12 @@
from _cffi1.udir import udir
-def check_type_table(input, expected_output):
+def check_type_table(input, expected_output, included=None):
ffi = FFI()
+ if included:
+ ffi1 = FFI()
+ ffi1.cdef(included)
+ ffi.include(ffi1)
ffi.cdef(input)
recomp = recompiler.Recompiler(ffi, 'testmod')
recomp.collect_type_table()
@@ -92,6 +96,16 @@
check_type_table("enum foo_e { AA, BB, ... };",
"(ENUM 0)")
+def test_type_table_include_1():
+ check_type_table("foo_t sin(foo_t);",
+ "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)",
+ included="typedef double foo_t;")
+
+def test_type_table_include_2():
+ check_type_table("struct foo_s *sin(struct foo_s *);",
+ "(FUNCTION 1)(POINTER 3)(FUNCTION_END 0)(STRUCT_UNION 0)",
+ included="struct foo_s { int x, y; };")
+
def test_math_sin():
import math
@@ -440,3 +454,25 @@
ffi.cdef("int glob[];")
lib = verify(ffi, "test_unspecified_size_of_global", "int glob[10];")
lib.glob # does not crash
+
+def test_include_1():
+ ffi1 = FFI(); ffi1.cdef("typedef double foo_t;")
+ ffi = FFI()
+ ffi.include(ffi1)
+ ffi.cdef("foo_t ff1(foo_t);")
+ lib = verify(ffi, "test_include_1", "double ff1(double x) { return 42.5; }")
+ assert lib.ff1(0) == 42.5
+
+def test_include_2():
+ ffi1 = FFI(); ffi1.cdef("struct foo_s { int x, y; };")
+ ffi = FFI()
+ ffi.include(ffi1)
+ ffi.cdef("struct foo_s *ff2(struct foo_s *);")
+ lib = verify(ffi, "test_include_2",
+ "struct foo_s { int x, y; };\n"
+ "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }")
+ p = ffi.new("struct foo_s *")
+ p.y = 41
+ q = lib.ff2(p)
+ assert q == p
+ assert p.y == 42
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -95,6 +95,7 @@
def __init__(self):
self._declarations = {}
+ self._included_declarations = set()
self._anonymous_counter = 0
self._structnode2type = weakref.WeakKeyDictionary()
self._override = False
@@ -278,7 +279,7 @@
raise api.CDefError("unknown identifier '%s'" % (exprnode.name,))
return self._get_type(exprnode.type)
- def _declare(self, name, obj):
+ def _declare(self, name, obj, included=False):
if name in self._declarations:
if self._declarations[name] is obj:
return
@@ -288,6 +289,8 @@
"try cdef(xx, override=True))" % (name,))
assert '__dotdotdot__' not in name.split()
self._declarations[name] = obj
+ if included:
+ self._included_declarations.add(obj)
def _get_type_pointer(self, type, const=False):
if isinstance(type, model.RawFunctionType):
@@ -601,7 +604,9 @@
def include(self, other):
for name, tp in other._declarations.items():
kind = name.split(' ', 1)[0]
- if kind in ('typedef', 'struct', 'union', 'enum'):
+ if kind in ('struct', 'union', 'enum'):
+ self._declare(name, tp, included=True)
+ elif kind == 'typedef':
self._declare(name, tp)
for k, v in other._int_constants.items():
self._add_constants(k, v)
More information about the pypy-commit
mailing list