[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