Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1732:ed9bac3dead2 Date: 2015-04-16 15:18 +0200 http://bitbucket.org/cffi/cffi/changeset/ed9bac3dead2/
Log: Structs (opaque so far) diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -3629,7 +3629,7 @@ return new_void_type(); } -static PyObject *_b_struct_or_union_type(const char *name, int flag) +static PyObject *new_struct_or_union_type(const char *name, int flag) { int namelen = strlen(name); CTypeDescrObject *td = ctypedescr_new(namelen + 1); @@ -3654,7 +3654,7 @@ flag = CT_STRUCT; if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0) flag |= CT_IS_FILE; - return _b_struct_or_union_type(name, flag); + return new_struct_or_union_type(name, flag); } static PyObject *b_new_union_type(PyObject *self, PyObject *args) @@ -3662,7 +3662,7 @@ char *name; if (!PyArg_ParseTuple(args, "s:new_union_type", &name)) return NULL; - return _b_struct_or_union_type(name, CT_UNION); + return new_struct_or_union_type(name, CT_UNION); } static CFieldObject * diff --git a/cffi/cparser.py b/cffi/cparser.py --- a/cffi/cparser.py +++ b/cffi/cparser.py @@ -251,15 +251,11 @@ self._declare('function ' + decl.name, tp) else: 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_union_enum_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_union_enum_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_struct_union_enum_type('enum', node) + self._get_struct_union_enum_type('enum', node) elif not decl.name: raise api.CDefError("construct does not declare any variable", decl) diff --git a/new/manual.c b/new/manual.c --- a/new/manual.c +++ b/new/manual.c @@ -29,6 +29,7 @@ _CFFI_OP(_CFFI_OP_FUNCTION, 1), _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT), _CFFI_OP(_CFFI_OP_FUNCTION_END, 0), + _CFFI_OP(_CFFI_OP_STRUCT_UNION, 0), }; static PyObject * @@ -109,10 +110,9 @@ struct _cffi_align_foo_s { char x; struct foo_s y; }; static const struct _cffi_struct_union_s _cffi_struct_unions[] = { - { "foo_s", + { "foo_s", 7, 0, sizeof(struct foo_s), offsetof(struct _cffi_align_foo_s, y), - 0, 1, 0 }, }; diff --git a/new/parse_c_type.h b/new/parse_c_type.h --- a/new/parse_c_type.h +++ b/new/parse_c_type.h @@ -68,11 +68,12 @@ struct _cffi_struct_union_s { const char *name; + int type_index; // -> _cffi_types, on a OP_STRUCT_UNION + int flags; // CT_UNION? CT_IS_OPAQUE? size_t size; - int alignment; - int flags; // CT_UNION? CT_IS_OPAQUE? + size_t alignment; + int first_field_index; // -> _cffi_fields array int num_fields; - int first_field_index; // -> _cffi_fields array }; #define CT_UNION 128 #define CT_IS_OPAQUE 4096 diff --git a/new/realize_c_type.c b/new/realize_c_type.c --- a/new/realize_c_type.c +++ b/new/realize_c_type.c @@ -143,6 +143,25 @@ Py_DECREF(z); break; + case _CFFI_OP_STRUCT_UNION: + { + const struct _cffi_struct_union_s *s; + _cffi_opcode_t op2; + + s = &ctx->struct_unions[_CFFI_GETARG(op)]; + op2 = ctx->types[s->type_index]; + if ((((uintptr_t)op2) & 1) == 0) { + x = (PyObject *)op2; + Py_INCREF(x); + } + else { + opcodes = ctx->types; + index = s->type_index; + x = new_struct_or_union_type(s->name, CT_STRUCT); + } + break; + } + case _CFFI_OP_FUNCTION: { PyObject *fargs; @@ -207,6 +226,7 @@ if (x != NULL && opcodes == ctx->types) { assert((((uintptr_t)x) & 1) == 0); + assert((((uintptr_t)opcodes[index]) & 1) == 1); Py_INCREF(x); opcodes[index] = x; } diff --git a/new/recompiler.py b/new/recompiler.py --- a/new/recompiler.py +++ b/new/recompiler.py @@ -126,11 +126,13 @@ self._generate("decl") # # the declaration of '_cffi_globals' and '_cffi_typenames' + ALL_STEPS = ["global", "struct_union", "field", "enum", "typename"] nums = {} - self._lsts = {"global": [], "typename": [], - "struct_union": [], "enum": []} + self._lsts = {} + for step_name in ALL_STEPS: + self._lsts[step_name] = [] self._generate("ctx") - for step_name in ["global", "typename", "struct_union", "enum"]: + for step_name in ALL_STEPS: lst = self._lsts[step_name] nums[step_name] = len(lst) if nums[step_name] > 0: @@ -145,18 +147,14 @@ # the declaration of '_cffi_type_context' prnt('static const struct _cffi_type_context_s _cffi_type_context = {') prnt(' _cffi_types,') - ALL_STEPS = ["global", "struct_union", "enum", "typename"] for step_name in ALL_STEPS: if nums[step_name] > 0: prnt(' _cffi_%ss,' % step_name) - if step_name == 'struct_union': - prnt(' _cffi_fields,') else: prnt(' NULL, /* no %ss */' % step_name) - if step_name == 'struct_union': - prnt(' NULL, /* no fields */') for step_name in ALL_STEPS: - prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) + if step_name != "field": + prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) prnt('};') prnt() # @@ -366,15 +364,29 @@ # named structs or unions def _generate_cpy_struct_collecttype(self, tp, name): - for tp1 in tp.fldtypes: - self._do_collect_type(tp1) + self._do_collect_type(tp) + if tp.fldtypes is not None: + for tp1 in tp.fldtypes: + self._do_collect_type(tp1) def _generate_cpy_struct_decl(self, tp, name): - pass + if tp.fldtypes is not None: + prnt = self._prnt + prnt("struct _cffi_align_%s { char x; %s %s y; };" % ( + name, tp.kind, name)) + prnt() def _generate_cpy_struct_ctx(self, tp, name): + type_index = self._typesdict[tp] + if tp.fldtypes is not None: + size_align = ('\n' + + ' sizeof(%s %s),\n' % (tp.kind, name) + + ' offsetof(struct _cffi_align_%s, y),\n' % (name,) + + ' 0, 0 },') + else: + size_align = ' -1, -1, -1, 0 /* opaque */ },' self._lsts["struct_union"].append( - ' { "%s", ') + ' { "%s", %d, 0,' % (name, type_index) + size_align) _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype @@ -494,6 +506,8 @@ struct_index = self._struct_unions[tp] self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) + _emit_bytecode_UnionType = _emit_bytecode_StructType + def make_c_source(ffi, module_name, preamble, target_c_file): recompiler = Recompiler(ffi, module_name) recompiler.collect_type_table() diff --git a/new/test_recompiler.py b/new/test_recompiler.py --- a/new/test_recompiler.py +++ b/new/test_recompiler.py @@ -60,13 +60,17 @@ check_type_table("int32_t f(void);", "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 21)") +def test_struct_opaque(): + check_type_table("struct foo_s;", + "(STRUCT_UNION 0)") + def test_struct(): check_type_table("struct foo_s { int a; long b; };", - "(PRIMITIVE 7)(PRIMITIVE 9)") + "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)") def test_union(): check_type_table("union foo_u { int a; long b; };", - "(PRIMITIVE 7)(PRIMITIVE 9)") + "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)") def test_struct_used(): check_type_table("struct foo_s { int a; long b; }; int f(struct foo_s*);", @@ -153,7 +157,14 @@ lib.aa = 5 assert dir(lib) == ['aa', 'ff', 'my_constant'] +def test_verify_opaque_struct(): + ffi = FFI() + ffi.cdef("struct foo_s;") + lib = verify(ffi, 'test_verify_opaque_struct', "struct foo_s;") + ffi.new("struct foo_s **") + def test_verify_struct(): + py.test.skip("XXX in-progress:") ffi = FFI() ffi.cdef("struct foo_s { int b; short a; };") lib = verify(ffi, 'test_verify_struct', _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit