[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