[pypy-commit] creflect default: Trying out the overloaded function declarations. Right now only
arigo
noreply at buildbot.pypy.org
Fri Dec 12 22:37:22 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r199:a34448506d46
Date: 2014-12-12 20:50 +0000
http://bitbucket.org/cffi/creflect/changeset/a34448506d46/
Log: Trying out the overloaded function declarations. Right now only
supports overloaded by number of arguments.
diff --git a/zeffir/builder.c b/zeffir/builder.c
--- a/zeffir/builder.c
+++ b/zeffir/builder.c
@@ -828,10 +828,10 @@
PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict;
PyObject *l_libname_obj = ((zeffir_builder_t *)cb)->lib->l_libname_obj;
+ PyObject *x = PyDict_GetItemString(l_dict, name);
assert(trampl != NULL);
- PyObject *x = make_builtin_func(l_libname_obj, name, ret,
- args, nargs, trampl);
+ x = make_builtin_func(l_libname_obj, name, ret, args, nargs, trampl, x);
if (x == NULL)
return;
diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c
--- a/zeffir/cfunc.c
+++ b/zeffir/cfunc.c
@@ -1,5 +1,5 @@
-typedef struct {
+typedef struct ZefFuncSupportObject_s {
PyObject_HEAD
/* note that 'zfs_trampl' is either a '_crx_trampoline0_fn' or a
@@ -9,6 +9,7 @@
int zfs_nargs;
int zfs_dotdotdot;
void *zfs_trampl;
+ struct ZefFuncSupportObject_s *zfs_overloaded_next;
PyMethodDef zfs_md;
size_t zfs_size_args;
CTypeDescrObject *zfs_ret;
@@ -25,6 +26,14 @@
Py_DECREF(zfs->zfs_args[i]);
Py_DECREF(zfs->zfs_ret);
+ /* avoid long chain of recursive calls to zef_func_support_dealloc */
+ while (zfs->zfs_overloaded_next != NULL) {
+ ZefFuncSupportObject *zfs2 = zfs->zfs_overloaded_next;
+ zfs->zfs_overloaded_next = zfs2->zfs_overloaded_next;
+ zfs2->zfs_overloaded_next = NULL;
+ Py_DECREF(zfs2);
+ }
+
PyObject_Del(zfs);
}
@@ -117,21 +126,41 @@
static PyObject *common_call(ZefFuncSupportObject *zfs, PyObject *args,
void *func, const char *funcname)
{
- int i, nargs = zfs->zfs_nargs;
- Py_ssize_t actualnargs;
+ int nargs;
+ Py_ssize_t actualnargs = PyTuple_Size(args);
+
+ nargs = zfs->zfs_nargs;
+ if (actualnargs != nargs) {
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (zfs->zfs_overloaded_next == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "'%s' expected %d arguments, but got %zd",
+ funcname, nargs, actualnargs);
+ return NULL;
+ }
+
+ /* XXX right now, pick the first overloaded function with the
+ correct number of arguments. Later we'll need to pick the
+ right one based on the provided argument types. */
+ zfs = zfs->zfs_overloaded_next;
+ while (zfs->zfs_nargs != actualnargs) {
+ zfs = zfs->zfs_overloaded_next;
+ if (zfs == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "'%s': no version with %zd arguments found",
+ funcname, actualnargs);
+ return NULL;
+ }
+ }
+ nargs = zfs->zfs_nargs;
+ }
+
void *llargs[nargs];
char *llbuffer;
size_t lloffset;
- int returns_void;
-
- actualnargs = PyTuple_Size(args);
- if (actualnargs != nargs) {
- if (!PyErr_Occurred())
- PyErr_Format(PyExc_TypeError,
- "'%s' expected %d arguments, but got %zd",
- funcname, nargs, actualnargs);
- return NULL;
- }
+ int i, returns_void;
llbuffer = alloca(zfs->zfs_size_args);
returns_void = (zfs->zfs_ret->ct_flags & CT_VOID);
@@ -241,6 +270,7 @@
memset(&zfs->zfs_md, 0, sizeof(PyMethodDef));
zfs->zfs_trampl = NULL;
+ zfs->zfs_overloaded_next = NULL;
zfs->zfs_nargs = nargs;
zfs->zfs_dotdotdot = dotdotdot;
zfs->zfs_ret = ret;
@@ -273,7 +303,8 @@
static PyObject *make_builtin_func(PyObject *libname_obj,
const char *funcname, _crx_type_t *ret,
_crx_qual_type args[], int nargs,
- _crx_trampoline0_fn trampl)
+ _crx_trampoline0_fn trampl,
+ PyObject *overloaded)
{
char *p;
ZefFuncSupportObject *zfs;
@@ -290,10 +321,27 @@
zfs->zfs_md.ml_flags = METH_VARARGS;
/*zfs->zfs_md.ml_doc = ... */
- PyObject *res = PyCFunction_NewEx(&zfs->zfs_md, (PyObject *)zfs,
- libname_obj);
- Py_DECREF(zfs);
- return res;
+ if (overloaded != NULL && PyCFunction_Check(overloaded) &&
+ PyCFunction_GET_FUNCTION(overloaded) == &zfs_call) {
+
+ /* attach 'zfs' to the end of the chain of zfs_overloaded_next */
+ PyObject *oself = PyCFunction_GET_SELF(overloaded);
+ ZefFuncSupportObject *zfs1 = (ZefFuncSupportObject *)oself;
+
+ while (zfs1->zfs_overloaded_next != NULL) {
+ zfs1 = zfs1->zfs_overloaded_next;
+ }
+ zfs1->zfs_overloaded_next = zfs;
+ Py_INCREF(overloaded);
+ return overloaded;
+ }
+ else {
+ /* make a new PyCFunction */
+ PyObject *res = PyCFunction_NewEx(&zfs->zfs_md, (PyObject *)zfs,
+ libname_obj);
+ Py_DECREF(zfs);
+ return res;
+ }
}
static PyObject *cfunctype_getargs(CTypeDescrObject *ct)
diff --git a/zeffir/test/function.crx b/zeffir/test/function.crx
--- a/zeffir/test/function.crx
+++ b/zeffir/test/function.crx
@@ -1,3 +1,5 @@
+#include <stdarg.h>
+
int simple_function(int x)
{
return x + 1;
@@ -22,6 +24,18 @@
{
}
+int sum_ints(int count, ...)
+{
+ int i, result = 0;
+ va_list ap;
+ va_start(ap, count);
+ for (i = 0; i < count; i++) {
+ result += va_arg(ap, int);
+ }
+ va_end(ap);
+ return result;
+}
+
// CREFLECT: start
@@ -29,5 +43,10 @@
int add_from_array(int array[], int count);
void returning_nothing(char *);
void cant_call_dotdotdot(int x, ...);
+int sum_ints(int);
+int sum_ints(int, int);
+int sum_ints(int, int, int);
+int sum_ints(int, int, int, int);
+int sum_ints(int, int, int, int, int);
// CREFLECT: end
diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py
--- a/zeffir/test/test_function.py
+++ b/zeffir/test/test_function.py
@@ -49,3 +49,11 @@
assert str(e.value) == ("cdata 'void(int, ...)' cannot be called, because "
"no wrapper was generated for functions of this "
"type (because signature ends in '...')")
+
+def test_overloaded_function():
+ ffi, lib = support.compile_and_open('function')
+ assert lib.sum_ints(0) == 0
+ assert lib.sum_ints(1, 10) == 10
+ assert lib.sum_ints(2, 20, 30) == 50
+ assert lib.sum_ints(3, 40, 50, 60) == 150
+ assert lib.sum_ints(4, 70, 80, 90, 100) == 340
More information about the pypy-commit
mailing list