[pypy-commit] cffi cffi-1.0: Structs (opaque so far)
arigo
noreply at buildbot.pypy.org
Thu Apr 16 15:17:39 CEST 2015
Author: Armin Rigo <arigo at 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',
More information about the pypy-commit
mailing list