Add helper routines for Python callbacks. The generated C code for calling back into Python from Clownfish when a method is overridden will require these helper functions for running the Python callable, converting return values, etc.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/bb7e8807 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/bb7e8807 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/bb7e8807 Branch: refs/heads/master Commit: bb7e880799d6bb0e4743d24fcacb630e04b2e32f Parents: 8996f0f Author: Marvin Humphrey <[email protected]> Authored: Wed Jan 27 18:23:36 2016 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Tue Feb 23 18:22:04 2016 -0800 ---------------------------------------------------------------------- compiler/src/CFCPython.c | 203 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/bb7e8807/compiler/src/CFCPython.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCPython.c b/compiler/src/CFCPython.c index 10c9872..b39240d 100644 --- a/compiler/src/CFCPython.c +++ b/compiler/src/CFCPython.c @@ -137,7 +137,208 @@ S_gen_callbacks(CFCPython *self, CFCParcel *parcel, CFCClass **ordered) { } static const char helpers[] = - "" + "static PyObject*\n" + "S_pack_tuple(int num_args, ...) {\n" + " PyObject *tuple = PyTuple_New(num_args);\n" + " va_list args;\n" + " va_start(args, num_args);\n" + " for (int i = 0; i < num_args; i++) {\n" + " PyObject *arg = va_arg(args, PyObject*);\n" + " PyTuple_SET_ITEM(tuple, i, arg);\n" + " }\n" + " va_end(args);\n" + " return tuple;\n" + "}\n" + "\n" + "static PyObject*\n" + "S_call_pymeth(PyObject *self, const char *meth_name, PyObject *args,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *callable = PyObject_GetAttrString(self, meth_name);\n" + " if (!PyCallable_Check(callable)) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func, \"Attr '%s' not callable\",\n" + " meth_name);\n" + " cfish_Err_throw_mess(CFISH_ERR, mess);\n" + " }\n" + " PyObject *result = PyObject_CallObject(callable, args);\n" + " Py_DECREF(args);\n" + " if (result == NULL) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func,\n" + " \"Callback to '%s' failed\", meth_name);\n" + " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" + " }\n" + " return result;\n" + "}\n" + "\n" + "#define CALL_PYMETH_VOID(self, meth_name, args) \\\n" + " S_call_pymeth_void(self, meth_name, args, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "\n" + "static void\n" + "S_call_pymeth_void(PyObject *self, const char *meth_name, PyObject *args,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *py_result\n" + " = S_call_pymeth(self, meth_name, args, file, line, func);\n" + " if (py_result == NULL) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func, \"Call to %s failed\",\n" + " meth_name);\n" + " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" + " }\n" + " Py_DECREF(py_result);\n" + "}\n" + "\n" + "#define CALL_PYMETH_BOOL(self, meth_name, args) \\\n" + " S_call_pymeth_bool(self, meth_name, args, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "\n" + "static bool\n" + "S_call_pymeth_bool(PyObject *self, const char *meth_name, PyObject *args,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *py_result\n" + " = S_call_pymeth(self, meth_name, args, file, line, func);\n" + " int truthiness = py_result != NULL\n" + " ? PyObject_IsTrue(py_result)\n" + " : -1;\n" + " if (truthiness == -1) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func, \"Call to %s failed\",\n" + " meth_name);\n" + " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" + " }\n" + " Py_DECREF(py_result);\n" + " return !!truthiness;\n" + "}\n" + "\n" + "#define CALL_PYMETH_OBJ(self, meth_name, args, ret_class, nullable) \\\n" + " S_call_pymeth_obj(self, meth_name, args, ret_class, nullable, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "\n" + "static cfish_Obj*\n" + "S_call_pymeth_obj(PyObject *self, const char *meth_name,\n" + " PyObject *args, cfish_Class *ret_class, bool nullable,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *py_result\n" + " = S_call_pymeth(self, meth_name, args, file, line, func);\n" + " cfish_Obj *result = CFBind_py_to_cfish(py_result, ret_class);\n" + " Py_DECREF(py_result);\n" + " if (!nullable && result == NULL) {\n" + " CFISH_THROW(CFISH_ERR, \"%s cannot return NULL\", meth_name);\n" + " }\n" + " else if (!cfish_Obj_is_a(result, ret_class)) {\n" + " cfish_Class *result_class = cfish_Obj_get_class(result);\n" + " CFISH_DECREF(result);\n" + " CFISH_THROW(CFISH_ERR, \"%s returned %o instead of %o\", meth_name,\n" + " CFISH_Class_Get_Name(result_class),\n" + " CFISH_Class_Get_Name(ret_class));\n" + " }\n" + " return result;\n" + "}\n" + "\n" + "#define CALL_PYMETH_DOUBLE(self, meth_name, args) \\\n" + " S_call_pymeth_f64(self, meth_name, args, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "#define CALL_PYMETH_FLOAT(self, meth_name, args) \\\n" + " ((float)S_call_pymeth_f64(self, meth_name, args, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "\n" + "static double\n" + "S_call_pymeth_f64(PyObject *self, const char *meth_name, PyObject *args,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *py_result\n" + " = S_call_pymeth(self, meth_name, args, file, line, func);\n" + " PyErr_Clear();\n" + " double result = PyFloat_AsDouble(py_result);\n" + " if (PyErr_Occurred()) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func,\n" + " \"Converting result of '%s' to double failed\",\n" + " meth_name);\n" + " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" + " }\n" + " Py_DECREF(py_result);\n" + " return result;\n" + "}\n" + "\n" + "#define CALL_PYMETH_INT64_T(self, meth_name, args) \\\n" + " S_call_pymeth_i64(self, meth_name, args, INT64_MAX, INT64_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "#define CALL_PYMETH_INT32_T(self, meth_name, args) \\\n" + " ((int32_t)S_call_pymeth_i64(self, meth_name, args, INT32_MAX, INT32_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_INT16_T(self, meth_name, args) \\\n" + " ((int16_t)S_call_pymeth_i64(self, meth_name, args, INT16_MAX, INT16_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_INT8_T(self, meth_name, args) \\\n" + " ((int8_t)S_call_pymeth_i64(self, meth_name, args, INT8_MAX, INT8_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_CHAR(self, meth_name, args) \\\n" + " ((char)S_call_pymeth_i64(self, meth_name, args, CHAR_MAX, CHAR_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_SHORT(self, meth_name, args) \\\n" + " ((short)S_call_pymeth_i64(self, meth_name, args, SHRT_MAX, SHRT_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_INT(self, meth_name, args) \\\n" + " ((int16_t)S_call_pymeth_i64(self, meth_name, args, INT_MAX, INT_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_LONG(self, meth_name, args) \\\n" + " ((int16_t)S_call_pymeth_i64(self, meth_name, args, LONG_MAX, LONG_MIN, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "\n" + "static int64_t\n" + "S_call_pymeth_i64(PyObject *self, const char *meth_name, PyObject *args,\n" + " int64_t max, int64_t min,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *py_result\n" + " = S_call_pymeth(self, meth_name, args, file, line, func);\n" + " PyErr_Clear();\n" + " int64_t result = PyLong_AsLongLong(py_result);\n" + " if (PyErr_Occurred() || result > max || result < min) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func,\n" + " \"Converting result of '%s' to int64_t failed\",\n" + " meth_name);\n" + " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" + " }\n" + " Py_DECREF(py_result);\n" + " return result;\n" + "}\n" + "\n" + "#define CALL_PYMETH_UINT64_T(self, meth_name, args) \\\n" + " S_call_pymeth_u64(self, meth_name, args, UINT64_MAX, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "#define CALL_PYMETH_UINT32_T(self, meth_name, args) \\\n" + " ((uint32_t)S_call_pymeth_u64(self, meth_name, args, UINT32_MAX, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_UINT16_T(self, meth_name, args) \\\n" + " ((uint32_t)S_call_pymeth_u64(self, meth_name, args, UINT16_MAX, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_UINT8_T(self, meth_name, args) \\\n" + " ((uint32_t)S_call_pymeth_u64(self, meth_name, args, UINT8_MAX, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" + "#define CALL_PYMETH_SIZE_T(self, meth_name, args) \\\n" + " S_call_pymeth_u64(self, meth_name, args, SIZE_MAX, \\\n" + " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" + "\n" + "static uint64_t\n" + "S_call_pymeth_u64(PyObject *self, const char *meth_name, PyObject *args,\n" + " uint64_t max,\n" + " const char *file, int line, const char *func) {\n" + " PyObject *py_result\n" + " = S_call_pymeth(self, meth_name, args, file, line, func);\n" + " PyErr_Clear();\n" + " uint64_t result = PyLong_AsUnsignedLongLong(py_result);\n" + " if (PyErr_Occurred()) {\n" + " cfish_String *mess\n" + " = cfish_Err_make_mess(file, line, func,\n" + " \"Converting result of '%s' to uint64_t failed\",\n" + " meth_name);\n" + " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" + " }\n" + " Py_DECREF(py_result);\n" + " return result;\n" + "}\n" ; static const char pattern[] =
