Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r190:4f6dbe2e4bdc Date: 2014-12-06 20:11 +0100 http://bitbucket.org/cffi/creflect/changeset/4f6dbe2e4bdc/
Log: port more from _cffi_backend diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -224,15 +224,21 @@ ct->ct_size = -1; ct->ct_flags = CT_FUNCTION; + ct->ct_stuff = make_func_support(ret, args, nargs, dotdotdot, 0); + if (ct->ct_stuff == NULL) { + Py_DECREF(ct); + ct = NULL; + goto done; + } put_cached_type(get_types_dict(cb), name_obj, ct); done: Py_DECREF(name_obj); - if (ct->ct_stuff == NULL && trampl != NULL && !PyErr_Occurred()) { + if (!PyErr_Occurred() && trampl != NULL) { assert(!dotdotdot); /* should have 'trampl == NULL' in this case */ - ct->ct_stuff = make_func_support(ret, args, nargs, trampl, 0); + provide_trampoline(ct->ct_stuff, trampl); } return ct; } diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1903,3 +1903,40 @@ Py_TYPE(ob)->tp_name, ct->ct_name); return NULL; } + +static PyObject *get_field_name(CTypeDescrObject *ct, CFieldObject *cf) +{ + Py_ssize_t i = 0; + PyObject *d_key, *d_value; + while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) { + if (d_value == (PyObject *)cf) + return d_key; + } + Py_FatalError("_cffi_backend: get_field_name()"); + return NULL; +} + +static PyObject *cstructtype_getfields(CTypeDescrObject *ct) +{ + if (ct->ct_size >= 0) { + CFieldObject *cf; + PyObject *res = PyList_New(0); + if (res == NULL) + return NULL; + for (cf = ct->ct_fields; cf != NULL; cf = cf->cf_next) { + PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf), + (PyObject *)cf); + int err = (o != NULL) ? PyList_Append(res, o) : -1; + Py_XDECREF(o); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + return res; + } + else { + Py_INCREF(Py_None); + return Py_None; + } +} diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -2,7 +2,12 @@ typedef struct { PyObject_HEAD + /* note that 'zfs_trampl' is either a '_crx_trampoline0_fn' or a + '_crx_trampoline1_fn', depending on how the ZefFuncSupportObject + is going to be used. + */ int zfs_nargs; + int zfs_dotdotdot; void *zfs_trampl; PyMethodDef zfs_md; size_t zfs_size_args; @@ -199,7 +204,7 @@ } zfs = (ZefFuncSupportObject *)ct->ct_stuff; - if (zfs == NULL) { + if (zfs->zfs_trampl == NULL) { PyErr_SetString(ZefError, "cdata '%s' cannot be called, because no " "wrapper was generated for functions of this type "); return NULL; @@ -220,12 +225,8 @@ static PyObject *make_func_support(_crx_type_t *ret, _crx_qual_type args[], int nargs, - void *trampl, size_t extra_alloc) + int dotdotdot, size_t extra_alloc) { - /* note that 'trampl' is either a '_crx_trampoline0_fn' or a - '_crx_trampoline1_fn', depending on how the ZefFuncSupportObject - is going to be used. - */ int i; size_t size = (sizeof(ZefFuncSupportObject) + (nargs - 1) * sizeof(CTypeDescrObject *) @@ -236,8 +237,9 @@ PyObject_Init((PyObject *)zfs, &ZefFuncSupport_Type); memset(&zfs->zfs_md, 0, sizeof(PyMethodDef)); + zfs->zfs_trampl = NULL; zfs->zfs_nargs = nargs; - zfs->zfs_trampl = trampl; + zfs->zfs_dotdotdot = dotdotdot; zfs->zfs_ret = ret; Py_INCREF(ret); @@ -258,6 +260,13 @@ return (PyObject *)zfs; } +static void provide_trampoline(PyObject *zfs, void *trampl) +{ + if (((ZefFuncSupportObject *)zfs)->zfs_trampl == NULL) { + ((ZefFuncSupportObject *)zfs)->zfs_trampl = trampl; + } +} + static PyObject *make_builtin_func(PyObject *libname_obj, const char *funcname, _crx_type_t *ret, _crx_qual_type args[], int nargs, @@ -265,11 +274,13 @@ { char *p; ZefFuncSupportObject *zfs; - zfs = (ZefFuncSupportObject *)make_func_support(ret, args, nargs, trampl, + zfs = (ZefFuncSupportObject *)make_func_support(ret, args, nargs, 0, strlen(funcname) + 1); if (zfs == NULL) return NULL; + zfs->zfs_trampl = trampl; + p = (char *)(zfs->zfs_args + nargs); zfs->zfs_md.ml_name = strcpy(p, funcname); zfs->zfs_md.ml_meth = &zfs_call; @@ -281,3 +292,33 @@ Py_DECREF(zfs); return res; } + +static PyObject *cfunctype_getargs(CTypeDescrObject *ct) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)ct->ct_stuff; + int i; + PyObject *tup = PyTuple_New(zfs->zfs_nargs); + if (tup == NULL) + return NULL; + + for (i = 0; i < zfs->zfs_nargs; i++) { + PyObject *obj = (PyObject *)zfs->zfs_args[i]; + Py_INCREF(obj); + PyTuple_SET_ITEM(tup, i, obj); + } + return tup; +} + +static PyObject *cfunctype_getresult(CTypeDescrObject *ct) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)ct->ct_stuff; + PyObject *res = (PyObject *)zfs->zfs_ret; + Py_INCREF(res); + return res; +} + +static PyObject *cfunctype_getellipsis(CTypeDescrObject *ct) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)ct->ct_stuff; + return PyBool_FromLong(zfs->zfs_dotdotdot); +} diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -102,6 +102,176 @@ return 0; } + +static PyObject *nosuchattr(const char *attr) +{ + PyErr_SetString(PyExc_AttributeError, attr); + return NULL; +} + +static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context) +{ + char *result; + if (ct->ct_flags & CT_PRIMITIVE_ANY) { + if (ct->ct_flags & CT_IS_ENUM) + result = "enum"; + else + result = "primitive"; + } + else if (ct->ct_flags & CT_POINTER) { + result = "pointer"; + } + else if (ct->ct_flags & CT_ARRAY) { + result = "array"; + } + else if (ct->ct_flags & CT_VOID) { + result = "void"; + } + else if (ct->ct_flags & CT_STRUCT) { + result = "struct"; + } + else if (ct->ct_flags & CT_UNION) { + result = "union"; + } + else if (ct->ct_flags & CT_FUNCTION) { + result = "function"; + } + else if (ct->ct_flags & CT_UNKNOWN) { + result = "opaque"; + } + else + result = "?"; + + return PyText_FromString(result); +} + +static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context) +{ + return PyText_FromString(ct->ct_name); +} + +static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) { + Py_INCREF(ct->ct_itemdescr); + return (PyObject *)ct->ct_itemdescr; + } + return nosuchattr("item"); +} + +static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_ARRAY) { + if (ct->ct_length >= 0) { + return PyInt_FromSsize_t(ct->ct_length); + } + else { + Py_INCREF(Py_None); + return Py_None; + } + } + return nosuchattr("length"); +} + +static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & (CT_STRUCT | CT_UNION)) { + return cstructtype_getfields(ct); + } + return nosuchattr("fields"); +} + +static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTION) { + return cfunctype_getargs(ct); + } + return nosuchattr("args"); +} + +static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTION) { + return cfunctype_getresult(ct); + } + return nosuchattr("result"); +} + +static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTION) { + return cfunctype_getellipsis(ct); + } + return nosuchattr("ellipsis"); +} + +static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_IS_ENUM) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); + if (res) res = PyDict_Copy(res); + return res; + } + return nosuchattr("elements"); +} + +static PyObject *ctypeget_relements(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_IS_ENUM) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); + if (res) res = PyDict_Copy(res); + return res; + } + return nosuchattr("relements"); +} + +static PyGetSetDef ctypedescr_getsets[] = { + {"kind", (getter)ctypeget_kind, NULL, "kind"}, + {"cname", (getter)ctypeget_cname, NULL, "C name"}, + {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"}, + {"length", (getter)ctypeget_length, NULL, "array length or None"}, + {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"}, + {"args", (getter)ctypeget_args, NULL, "function argument types"}, + {"result", (getter)ctypeget_result, NULL, "function result type"}, + {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"}, + {"elements", (getter)ctypeget_elements, NULL, "enum elements"}, + {"relements", (getter)ctypeget_relements, NULL, "enum elements, reverse"}, + {NULL} /* sentinel */ +}; + +static PyObject * +ctypedescr_dir(PyObject *ct, PyObject *noarg) +{ + int err; + struct PyGetSetDef *gsdef; + PyObject *res = PyList_New(0); + if (res == NULL) + return NULL; + + for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) { + PyObject *x = PyObject_GetAttrString(ct, gsdef->name); + if (x == NULL) { + PyErr_Clear(); + } + else { + Py_DECREF(x); + x = PyText_FromString(gsdef->name); + err = (x != NULL) ? PyList_Append(res, x) : -1; + Py_XDECREF(x); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + } + return res; +} + +static PyMethodDef ctypedescr_methods[] = { + {"__dir__", ctypedescr_dir, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + static PyTypeObject CTypeDescr_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.CType", @@ -130,7 +300,7 @@ offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0,//ctypedescr_methods, /* tp_methods */ + ctypedescr_methods, /* tp_methods */ 0, /* tp_members */ - 0,//ctypedescr_getsets, /* tp_getset */ + ctypedescr_getsets, /* tp_getset */ }; diff --git a/zeffir/test/test_c.py b/zeffir/test/test_c.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_c.py @@ -0,0 +1,57 @@ +import py +import support + +import sys +if sys.version_info < (3,): + type_or_class = "type" + mandatory_b_prefix = '' + mandatory_u_prefix = 'u' + bytechr = chr + bitem2bchr = lambda x: x + class U(object): + def __add__(self, other): + return eval('u'+repr(other).replace(r'\\u', r'\u') + .replace(r'\\U', r'\U')) + u = U() + str2bytes = str +else: + type_or_class = "class" + long = int + unicode = str + unichr = chr + mandatory_b_prefix = 'b' + mandatory_u_prefix = '' + bytechr = lambda n: bytes([n]) + bitem2bchr = bytechr + u = "" + str2bytes = lambda s: bytes(s, "ascii") + +def size_of_int(): + ffi = support.new_ffi() + return ffi.sizeof("int") + +def size_of_long(): + ffi = support.new_ffi() + return ffi.sizeof("long") + +def size_of_ptr(): + ffi = support.new_ffi() + return ffi.sizeof("void*") + + +def test_new_primitive_type(): + ffi = support.new_ffi() + py.test.raises(ffi.error, ffi.typeof, "foo") + p = ffi.typeof("signed char") + assert repr(p) == "<ctype 'signed char'>" + +def check_dir(p, expected): + got = set(name for name in dir(p) if not name.startswith('_')) + assert got == set(expected) + +def test_inspect_primitive_type(): + ffi = support.new_ffi() + p = ffi.typeof("signed char") + assert p.kind == "primitive" + assert p.cname == "signed char" + check_dir(p, ['cname', 'kind']) diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -29,4 +29,8 @@ size_t extra_text_len); static PyObject *gc_weakrefs_build(ZefFFIObject *ffi, CDataObject *cd, PyObject *destructor); -static PyObject*cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds); +static PyObject *cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds); +static PyObject *cfunctype_getargs(CTypeDescrObject *ct); +static PyObject *cfunctype_getresult(CTypeDescrObject *ct); +static PyObject *cfunctype_getellipsis(CTypeDescrObject *ct); +static PyObject *cstructtype_getfields(CTypeDescrObject *ct); _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit