Mercurial > pymonkey
diff function.c @ 37:d4efcbb06964
Added a new PYM_JSFunction type, PYM_JSContext.define_property(), and PYM_JSContext.new_function(). Also fixed a memory leak.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Thu, 02 Jul 2009 22:42:31 -0700 |
parents | |
children | 9103afca7386 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/function.c Thu Jul 02 22:42:31 2009 -0700 @@ -0,0 +1,149 @@ +#include "function.h" +#include "utils.h" + +static void +PYM_JSFunctionDealloc(PYM_JSFunction *self) +{ + // TODO: What if there's still a reference to the callable in + // JS-land? + if (self->callable) { + Py_DECREF(self->callable); + self->callable = NULL; + } + PYM_JSObjectType.tp_dealloc((PyObject *) self); +} + +static JSBool +dispatchJSFunctionToPython(JSContext *cx, + JSObject *obj, + uintN argc, + jsval *argv, + jsval *rval) +{ + jsval callee = JS_ARGV_CALLEE(argv); + jsval jsCallable; + if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &jsCallable)) { + JS_ReportError(cx, "JS_GetReservedSlot() failed."); + return JS_FALSE; + } + PyObject *callable = (PyObject *) JSVAL_TO_PRIVATE(jsCallable); + + // TODO: Convert args and 'this' parameter. + PyObject *args = PyTuple_New(0); + if (args == NULL) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + PyObject *result = PyObject_Call(callable, args, NULL); + if (result == NULL) { + // TODO: Get the actual exception. + JS_ReportError(cx, "Python function failed."); + return JS_FALSE; + } + + int error = PYM_pyObjectToJsval(cx, result, rval); + Py_DECREF(result); + + if (error) { + // TODO: Get the actual exception. + JS_ReportError(cx, "Python function failed."); + return JS_FALSE; + } + return JS_TRUE; +} + +PYM_JSFunction * +PYM_newJSFunction(PYM_JSContextObject *context, + PyObject *callable, + const char *name) +{ + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "Callable must be callable"); + return NULL; + } + + JSFunction *func = JS_NewFunction(context->cx, + dispatchJSFunctionToPython, 0, + 0, NULL, name); + + if (func == NULL) { + PyErr_SetString(PYM_error, "JS_DefineFunction() failed"); + return NULL; + } + + JSObject *funcObj = JS_GetFunctionObject(func); + + if (funcObj == NULL) { + PyErr_SetString(PYM_error, "JS_GetFunctionObject() failed"); + return NULL; + } + + if (!JS_SetReservedSlot(context->cx, funcObj, 0, + PRIVATE_TO_JSVAL(callable))) { + PyErr_SetString(PYM_error, "JS_SetReservedSlot() failed"); + return NULL; + } + + PYM_JSFunction *object = PyObject_New(PYM_JSFunction, + &PYM_JSFunctionType); + if (object == NULL) + return NULL; + + object->callable = NULL; + if (PYM_newJSObject(context, funcObj, + (PYM_JSObject *) object) == NULL) + // Note that our object's reference count will have already + // been decremented by PYM_newJSObject(). + return NULL; + + object->callable = callable; + Py_INCREF(callable); + + return object; +} + +PyTypeObject PYM_JSFunctionType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pymonkey.Function", /*tp_name*/ + sizeof(PYM_JSFunction), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /*tp_dealloc*/ + (destructor) PYM_JSFunctionDealloc, + 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*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + /*tp_flags*/ + Py_TPFLAGS_DEFAULT, + /* tp_doc */ + "JavaScript Function.", + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +};