Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r164:fca0f1dca466
Date: 2014-12-05 16:22 +0100
http://bitbucket.org/cffi/creflect/changeset/fca0f1dca466/

Log:    simple structs work

diff --git a/zeffir/builder.c b/zeffir/builder.c
--- a/zeffir/builder.c
+++ b/zeffir/builder.c
@@ -388,14 +388,42 @@
     return _zef_array_type(cb, ctitem, (size_t)-1, NULL);
 }
 
+static _crx_type_t *_zef_struct_or_union(_crx_builder_t *cb, const char *name,
+                                         int flag)
+{
+    if (PyErr_Occurred())
+        return NULL;
+
+    PyObject *name_obj;
+    CTypeDescrObject *ct;
+
+    name_obj = PyString_FromString(name);
+    if (name_obj == NULL)
+        return NULL;
+
+    ct = get_cached_type(cb, name_obj);
+    if (ct && (ct->ct_flags == flag))
+        goto done;
+
+    ct = ctypedescr_new(name_obj, PyString_GET_SIZE(name_obj));
+    if (ct == NULL)
+        goto done;
+
+    ct->ct_flags = flag;
+
+ done:
+    Py_DECREF(name_obj);
+    return ct;
+}
+
 static _crx_type_t *zef_get_struct_type(_crx_builder_t *cb, const char *name)
 {
-    abort();
+    return _zef_struct_or_union(cb, name, CT_STRUCT);
 }
 
 static _crx_type_t *zef_get_union_type(_crx_builder_t *cb, const char *name)
 {
-    abort();
+    return _zef_struct_or_union(cb, name, CT_UNION);
 }
 
 static _crx_type_t *zef_get_enum_type(_crx_builder_t *cb, const char *name)
@@ -426,11 +454,258 @@
     return _zef_primitive(cb, -1, name, CT_UNKNOWN);
 }
 
-static void zef_complete(_crx_builder_t *cb, _crx_type_t *t,
+static CFieldObject *_add_field(PyObject *interned_fields,
+                                const char *fname, CTypeDescrObject *ftype,
+                                Py_ssize_t offset, int bitshift, int fbitsize)
+{
+    int err;
+    PyObject *fname_obj;
+    Py_ssize_t prev_size;
+    CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type);
+    if (cf == NULL)
+        return NULL;
+
+    Py_INCREF(ftype);
+    cf->cf_type = ftype;
+    cf->cf_offset = offset;
+    cf->cf_bitshift = bitshift;
+    cf->cf_bitsize = fbitsize;
+
+    fname_obj = PyString_InternFromString(fname);
+    prev_size = PyDict_Size(interned_fields);
+    err = PyDict_SetItem(interned_fields, fname_obj, (PyObject *)cf);
+    Py_DECREF(fname_obj);
+    Py_DECREF(cf);
+    if (err < 0)
+        return NULL;
+
+    if (PyDict_Size(interned_fields) != prev_size + 1) {
+        PyErr_Format(PyExc_KeyError, "duplicate field name '%s'",
+                     PyText_AS_UTF8(fname));
+        return NULL;
+    }
+    return cf;   /* borrowed reference */
+}
+
+static void zef_complete(_crx_builder_t *cb, _crx_type_t *ct,
                          size_t sz, size_t align,
                          _crx_field_t fields[], int nfields)
 {
-    abort();
+    PyObject *interned_fields;
+    CFieldObject **previous;
+    int i;
+
+    assert(ct->ct_flags & (CT_STRUCT | CT_UNION));
+    if (ct->ct_size >= 0) {
+        PyErr_Format(ZefError, "duplicate declaration of the fields of '%s'",
+                     ct->ct_name);
+        return;
+    }
+
+    interned_fields = PyDict_New();
+    if (interned_fields == NULL)
+        return;
+
+    previous = (CFieldObject **)&ct->ct_extra;
+
+    for (i = 0; i < nfields; i++) {
+        _crx_field_t *f = &fields[i];
+        CTypeDescrObject *ftype = f->type;
+
+        if (ftype->ct_size < 0) {
+            if ((ftype->ct_flags & CT_ARRAY) /* && fbitsize < 0
+                    && (i == nb_fields - 1 || foffset != -1) */ ) {
+                ct->ct_flags |= CT_WITH_VAR_ARRAY;
+            }
+            else {
+                PyErr_Format(PyExc_TypeError,
+                             "field '%s.%s' has ctype '%s' of unknown size",
+                             ct->ct_name, f->name, ftype->ct_name);
+                goto error;
+            }
+        }
+
+        if (f->numbits < 0) {
+            /* not a bitfield: common case */
+            int bs_flag;
+
+            if ((ftype->ct_flags & CT_ARRAY) && ftype->ct_length == 0)
+                bs_flag = BS_EMPTY_ARRAY;
+            else
+                bs_flag = BS_REGULAR;
+
+#if 0  /* XXX */
+            if (PyText_GetSize(fname) == 0 &&
+                    ftype->ct_flags & (CT_STRUCT|CT_UNION)) {
+                /* a nested anonymous struct or union */
+                CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra;
+                for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) {
+                    /* broken complexity in the call to get_field_name(),
+                       but we'll assume you never do that with nested
+                       anonymous structures with thousand of fields */
+                    *previous = _add_field(interned_fields,
+                                           get_field_name(ftype, cfsrc),
+                                           cfsrc->cf_type,
+                                           boffset / 8 + cfsrc->cf_offset,
+                                           cfsrc->cf_bitshift,
+                                           cfsrc->cf_bitsize);
+                    if (*previous == NULL)
+                        goto error;
+                    previous = &(*previous)->cf_next;
+                }
+                /* always forbid such structures from being passed by value */
+                ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+            }
+            else
+#endif
+            {
+                *previous = _add_field(interned_fields, f->name, ftype,
+                                       f->offset, bs_flag, -1);
+                if (*previous == NULL)
+                    goto error;
+                previous = &(*previous)->cf_next;
+            }
+        }
+        else {
+            abort();
+#if 0
+            /* this is the case of a bitfield */
+            Py_ssize_t field_offset_bytes;
+            int bits_already_occupied, bitshift;
+
+            if (foffset >= 0) {
+                PyErr_Format(PyExc_TypeError,
+                             "field '%s.%s' is a bitfield, "
+                             "but a fixed offset is specified",
+                             ct->ct_name, PyText_AS_UTF8(fname));
+                goto error;
+            }
+
+            if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED |
+                                     CT_PRIMITIVE_UNSIGNED |
+                                     CT_PRIMITIVE_CHAR))) {
+                PyErr_Format(PyExc_TypeError,
+                        "field '%s.%s' declared as '%s' cannot be a bit field",
+                             ct->ct_name, PyText_AS_UTF8(fname),
+                             ftype->ct_name);
+                goto error;
+            }
+            if (fbitsize > 8 * ftype->ct_size) {
+                PyErr_Format(PyExc_TypeError,
+                             "bit field '%s.%s' is declared '%s:%d', which "
+                             "exceeds the width of the type",
+                             ct->ct_name, PyText_AS_UTF8(fname),
+                             ftype->ct_name, fbitsize);
+                goto error;
+            }
+
+            /* compute the starting position of the theoretical field
+               that covers a complete 'ftype', inside of which we will
+               locate the real bitfield */
+            field_offset_bytes = boffset / 8;
+            field_offset_bytes &= ~(falign - 1);
+
+            if (fbitsize == 0) {
+                if (PyText_GetSize(fname) > 0) {
+                    PyErr_Format(PyExc_TypeError,
+                                 "field '%s.%s' is declared with :0",
+                                 ct->ct_name, PyText_AS_UTF8(fname));
+                    goto error;
+                }
+                if (!(sflags & SF_MSVC_BITFIELDS)) {
+                    /* GCC's notion of "ftype :0;" */
+
+                    /* pad boffset to a value aligned for "ftype" */
+                    if (boffset > field_offset_bytes * 8) {
+                        field_offset_bytes += falign;
+                        assert(boffset < field_offset_bytes * 8);
+                    }
+                    boffset = field_offset_bytes * 8;
+                }
+                else {
+                    /* MSVC's notion of "ftype :0;" */
+
+                    /* Mostly ignored.  It seems they only serve as
+                       separator between other bitfields, to force them
+                       into separate words. */
+                }
+                prev_bitfield_size = 0;
+            }
+            else {
+                if (!(sflags & SF_MSVC_BITFIELDS)) {
+                    /* GCC's algorithm */
+
+                    /* Can the field start at the offset given by 'boffset'?  
It
+                       can if it would entirely fit into an aligned ftype 
field. */
+                    bits_already_occupied = boffset - (field_offset_bytes * 8);
+
+                    if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) 
{
+                        /* it would not fit, we need to start at the next
+                           allowed position */
+                        if ((sflags & SF_PACKED) &&
+                            (bits_already_occupied & 7)) {
+                            PyErr_Format(PyExc_NotImplementedError,
+                                "with 'packed', gcc would compile field "
+                                "'%s.%s' to reuse some bits in the previous "
+                                "field", ct->ct_name, PyText_AS_UTF8(fname));
+                            goto error;
+                        }
+                        field_offset_bytes += falign;
+                        assert(boffset < field_offset_bytes * 8);
+                        boffset = field_offset_bytes * 8;
+                        bitshift = 0;
+                    }
+                    else {
+                        bitshift = bits_already_occupied;
+                        assert(bitshift >= 0);
+                    }
+                    boffset += fbitsize;
+                }
+                else {
+                    /* MSVC's algorithm */
+
+                    /* A bitfield is considered as taking the full width
+                       of their declared type.  It can share some bits
+                       with the previous field only if it was also a
+                       bitfield and used a type of the same size. */
+                    if (prev_bitfield_size == ftype->ct_size &&
+                        prev_bitfield_free >= fbitsize) {
+                        /* yes: reuse */
+                        bitshift = 8 * prev_bitfield_size - prev_bitfield_free;
+                    }
+                    else {
+                        /* no: start a new full field */
+                        boffset = (boffset + falign*8-1) & ~(falign*8-1); 
/*align*/
+                        boffset += ftype->ct_size * 8;
+                        bitshift = 0;
+                        prev_bitfield_size = ftype->ct_size;
+                        prev_bitfield_free = 8 * prev_bitfield_size;
+                    }
+                    prev_bitfield_free -= fbitsize;
+                    field_offset_bytes = boffset / 8 - ftype->ct_size;
+                }
+
+                if (sflags & SF_GCC_BIG_ENDIAN)
+                    bitshift = 8 * ftype->ct_size - fbitsize - bitshift;
+
+                *previous = _add_field(interned_fields, fname, ftype,
+                                       field_offset_bytes, bitshift, fbitsize);
+                if (*previous == NULL)
+                    goto error;
+                previous = &(*previous)->cf_next;
+            }
+#endif
+        }
+    }
+    *previous = NULL;
+
+    ct->ct_size = sz;
+    /* 'align' ignored for now */
+    ct->ct_stuff = interned_fields;
+    return;
+
+ error:
+    Py_DECREF(interned_fields);
 }
 
 static void zef_complete_enum(_crx_builder_t *cb, _crx_type_t *t,
diff --git a/zeffir/cdata.c b/zeffir/cdata.c
--- a/zeffir/cdata.c
+++ b/zeffir/cdata.c
@@ -6,17 +6,6 @@
     PyObject *c_weakreflist;
 } CDataObject;
 
-struct cfieldobject_s {
-    PyObject_HEAD
-    CTypeDescrObject *cf_type;
-    Py_ssize_t cf_offset;
-    short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */
-    short cf_bitsize;
-    struct cfieldobject_s *cf_next;
-};
-#define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
-#define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
-
 typedef union {
     unsigned char m_char;
     unsigned short m_short;
@@ -52,6 +41,70 @@
 
 /************************************************************/
 
+struct cfieldobject_s {
+    PyObject_HEAD
+    CTypeDescrObject *cf_type;
+    Py_ssize_t cf_offset;
+    short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */
+    short cf_bitsize;
+    struct cfieldobject_s *cf_next;
+};
+#define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
+#define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
+
+static void
+cfield_dealloc(CFieldObject *cf)
+{
+    Py_DECREF(cf->cf_type);
+    PyObject_Del(cf);
+}
+
+#undef OFF
+#define OFF(x) offsetof(CFieldObject, x)
+
+static PyMemberDef cfield_members[] = {
+    {"type", T_OBJECT, OFF(cf_type), READONLY},
+    {"offset", T_PYSSIZET, OFF(cf_offset), READONLY},
+    {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY},
+    {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY},
+    {NULL}      /* Sentinel */
+};
+#undef OFF
+
+static PyTypeObject CField_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "zeffir.CField",
+    sizeof(CFieldObject),
+    0,
+    (destructor)cfield_dealloc,                 /* tp_dealloc */
+    0,                                          /* tp_print */
+    0,                                          /* tp_getattr */
+    0,                                          /* tp_setattr */
+    0,                                          /* tp_compare */
+    0,                                          /* tp_repr */
+    0,                                          /* tp_as_number */
+    0,                                          /* tp_as_sequence */
+    0,                                          /* tp_as_mapping */
+    0,                                          /* tp_hash */
+    0,                                          /* tp_call */
+    0,                                          /* tp_str */
+    PyObject_GenericGetAttr,                    /* tp_getattro */
+    0,                                          /* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
+    0,                                          /* tp_doc */
+    0,                                          /* tp_traverse */
+    0,                                          /* tp_clear */
+    0,                                          /* tp_richcompare */
+    0,                                          /* tp_weaklistoffset */
+    0,                                          /* tp_iter */
+    0,                                          /* tp_iternext */
+    0,                                          /* tp_methods */
+    cfield_members,                             /* tp_members */
+};
+
+/************************************************************/
+
 static int
 CDataObject_Or_PyFloat_Check(PyObject *ob)
 {
@@ -343,10 +396,10 @@
     return NULL;
 }
 
+static PyObject *convert_to_object_bitfield(char *data, CFieldObject *cf)
+{
+    abort();
 #if 0
-static PyObject *
-convert_to_object_bitfield(char *data, CFieldObject *cf)
-{
     CTypeDescrObject *ct = cf->cf_type;
     /*READ(data, ct->ct_size)*/
 
@@ -377,8 +430,8 @@
         else
             return PyLong_FromUnsignedLongLong(value);
     }
+#endif
 }
-#endif
 
 static int _convert_overflow(PyObject *init, const char *ct_name)
 {
@@ -1237,6 +1290,58 @@
     return convert_from_object(c, ctitem, v);
 }
 
+//2172
+static PyObject *cdata_getattro(CDataObject *cd, PyObject *attr)
+{
+    CFieldObject *cf;
+    CTypeDescrObject *ct = cd->c_type;
+
+    if (ct->ct_flags & CT_POINTER)
+        ct = ct->ct_itemdescr;
+
+    if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) {
+        cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
+        if (cf != NULL) {
+            /* read the field 'cf' */
+            char *data = cd->c_data + cf->cf_offset;
+            if (cf->cf_bitshift == BS_REGULAR)
+                return convert_to_object(data, cf->cf_type);
+            else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
+                return new_simple_cdata(data,
+                    (CTypeDescrObject *)cf->cf_type->ct_stuff);
+            else
+                return convert_to_object_bitfield(data, cf);
+        }
+    }
+    return PyObject_GenericGetAttr((PyObject *)cd, attr);
+}
+
+//2198
+static int cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value)
+{
+    CFieldObject *cf;
+    CTypeDescrObject *ct = cd->c_type;
+
+    if (ct->ct_flags & CT_POINTER)
+        ct = ct->ct_itemdescr;
+
+    if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) {
+        cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
+        if (cf != NULL) {
+            /* write the field 'cf' */
+            if (value != NULL) {
+                return convert_field_from_object(cd->c_data, cf, value);
+            }
+            else {
+                PyErr_SetString(PyExc_AttributeError,
+                                "cannot delete struct field");
+                return -1;
+            }
+        }
+    }
+    return PyObject_GenericSetAttr((PyObject *)cd, attr, value);
+}
+
 
 static PyMappingMethods CData_as_mapping = {
     (lenfunc)cdata_length, /*mp_length*/
@@ -1261,8 +1366,8 @@
     0,//(hashfunc)cdata_hash,                       /* tp_hash */
     0,//(ternaryfunc)cdata_call,                    /* tp_call */
     0,                                          /* tp_str */
-    0,//(getattrofunc)cdata_getattro,               /* tp_getattro */
-    0,//(setattrofunc)cdata_setattro,               /* tp_setattro */
+    (getattrofunc)cdata_getattro,               /* tp_getattro */
+    (setattrofunc)cdata_setattro,               /* tp_setattro */
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
     0,                                          /* tp_doc */
diff --git a/zeffir/test/struct.crx b/zeffir/test/struct.crx
new file mode 100644
--- /dev/null
+++ b/zeffir/test/struct.crx
@@ -0,0 +1,13 @@
+typedef struct {
+    int a;
+    long b;
+} mystruct_t;
+
+
+// CREFLECT: start
+
+typedef struct {
+    int a, b;
+} mystruct_t;
+
+// CREFLECT: end
diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py
new file mode 100644
--- /dev/null
+++ b/zeffir/test/test_struct.py
@@ -0,0 +1,10 @@
+import support
+
+
+def test_simple_struct():
+    ffi, lib = support.compile_and_open('struct')
+    p = ffi.new('mystruct_t *', [-5, 0x600112233])
+    assert p.a == -5
+    assert p.b == 0x600112233
+    p.b += 1
+    assert p.b == 0x600112234
diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c
--- a/zeffir/zeffir.c
+++ b/zeffir/zeffir.c
@@ -41,6 +41,8 @@
         return;
     if (PyType_Ready(&CTypeDescr_Type) < 0)
         return;
+    if (PyType_Ready(&CField_Type) < 0)
+        return;
     if (PyType_Ready(&CData_Type) < 0)
         return;
     if (PyType_Ready(&CDataOwning_Type) < 0)
diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h
--- a/zeffir/zeffir.h
+++ b/zeffir/zeffir.h
@@ -6,7 +6,7 @@
 
 static PyTypeObject ZefFFI_Type;
 static PyTypeObject CTypeDescr_Type;
-//static PyTypeObject CField_Type;
+static PyTypeObject CField_Type;
 static PyTypeObject CData_Type;
 static PyTypeObject CDataOwning_Type;
 static PyTypeObject CDataOwningGC_Type;
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to