Mercurial > pymonkey
changeset 96:3570ab12747b
Renamed .c files to .cpp, since we use minor amounts of C++ code in pymonkey.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Sat, 15 Aug 2009 10:24:17 -0700 |
parents | 0701aee1b0cd |
children | 409cff0c7afb |
files | context.c context.cpp function.c function.cpp manage.py object.c object.cpp pymonkey.c pymonkey.cpp runtime.c runtime.cpp undefined.c undefined.cpp utils.c utils.cpp |
diffstat | 15 files changed, 1613 insertions(+), 1613 deletions(-) [+] |
line wrap: on
line diff
--- a/context.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,534 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "context.h" -#include "object.h" -#include "function.h" -#include "utils.h" - -// This is the default JSOperationCallback for pymonkey-owned JS contexts, -// when they've defined one in Python. -static JSBool -PYM_operationCallback(JSContext *cx) -{ - PYM_PyAutoEnsureGIL gil; - PYM_JSContextObject *context = (PYM_JSContextObject *) - JS_GetContextPrivate(cx); - - PyObject *callable = context->opCallback; - PyObject *args = PyTuple_Pack(1, (PyObject *) context); - if (args == NULL) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - PyObject *result = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - if (result == NULL) { - PYM_pythonExceptionToJs(context); - return JS_FALSE; - } - - Py_DECREF(result); - return JS_TRUE; -} - -// This is the default JSErrorReporter for pymonkey-owned JS contexts. -static void -PYM_reportError(JSContext *cx, const char *message, JSErrorReport *report) -{ - PYM_PyAutoEnsureGIL gil; - - // Convert JS warnings into Python warnings. - if (JSREPORT_IS_WARNING(report->flags)) { - if (report->filename) - PyErr_WarnExplicit(NULL, message, report->filename, report->lineno, - NULL, NULL); - else - PyErr_Warn(NULL, message); - } else - // TODO: Not sure if this will ever get called, but we should know - // if it is. - PyErr_Warn(NULL, "A JS error was reported."); -} - -static void -PYM_JSContextDealloc(PYM_JSContextObject *self) -{ - if (self->opCallback) { - Py_DECREF(self->opCallback); - self->opCallback = NULL; - } - - if (self->cx) { - JS_DestroyContext(self->cx); - self->cx = NULL; - } - - Py_DECREF(self->runtime); - self->runtime = NULL; - - self->ob_type->tp_free((PyObject *) self); -} - -static PyObject * -PYM_getRuntime(PYM_JSContextObject *self, PyObject *args) -{ - Py_INCREF(self->runtime); - return (PyObject *) self->runtime; -} - -static PyObject * -PYM_getObjectPrivate(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *object; - - if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) - return NULL; - - PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); - - JSObject *obj = object->obj; - - if (JS_ObjectIsFunction(self->cx, obj)) { - jsval functionHolder; - if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) { - JS_ClearPendingException(self->cx); - Py_RETURN_NONE; - } - if (!JSVAL_IS_OBJECT(functionHolder)) - Py_RETURN_NONE; - obj = JSVAL_TO_OBJECT(functionHolder); - } - - JSClass *klass = JS_GET_CLASS(self->cx, obj); - if (klass != &PYM_JS_ObjectClass) - Py_RETURN_NONE; - - PyObject *pyObject; - - if (!PYM_JS_getPrivatePyObject(self->cx, obj, &pyObject)) { - PYM_jsExceptionToPython(self); - return NULL; - } - - if (pyObject == NULL) - pyObject = Py_None; - - Py_INCREF(pyObject); - return pyObject; -} - -static PyObject * -PYM_clearObjectPrivate(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *object; - - if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) - return NULL; - - PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); - - JSObject *obj = object->obj; - - if (JS_ObjectIsFunction(self->cx, obj)) { - jsval functionHolder; - if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) { - JS_ClearPendingException(self->cx); - Py_RETURN_NONE; - } - if (!JSVAL_IS_OBJECT(functionHolder)) - Py_RETURN_NONE; - obj = JSVAL_TO_OBJECT(functionHolder); - } - - JSClass *klass = JS_GET_CLASS(self->cx, obj); - if (klass != &PYM_JS_ObjectClass) - Py_RETURN_NONE; - - if (!PYM_JS_setPrivatePyObject(self->cx, obj, Py_None)) { - PYM_jsExceptionToPython(self); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -PYM_newObject(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PyObject *privateObj = NULL; - - if (!PyArg_ParseTuple(args, "|O", &privateObj)) - return NULL; - - JSObject *obj = PYM_JS_newObject(self->cx, privateObj); - if (obj == NULL) { - PyErr_SetString(PYM_error, "PYM_JS_newObject() failed"); - return NULL; - } - - // If this fails, we don't need to worry about cleaning up - // obj because it'll get cleaned up at the next GC. - return (PyObject *) PYM_newJSObject(self, obj, NULL); -} - -static PyObject * -PYM_getProperty(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *object; - char *buffer = NULL; - int size; - - if (!PyArg_ParseTuple(args, "O!es#", &PYM_JSObjectType, &object, - "utf-16", &buffer, &size)) - return NULL; - - if (self->runtime != object->runtime) { - PyMem_Free(buffer); - PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); - } - - jsval val; - JSBool result; - Py_BEGIN_ALLOW_THREADS; - // Note that we're manipulating buffer and size here to get rid of - // the BOM. - result = JS_GetUCProperty(self->cx, object->obj, (jschar *) (buffer + 2), - (size / 2) - 1, &val); - Py_END_ALLOW_THREADS; - - PyMem_Free(buffer); - - if (!result) { - PYM_jsExceptionToPython(self); - return NULL; - } - - return PYM_jsvalToPyObject(self, val); -} - -static PyObject * -PYM_gc(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - JS_GC(self->cx); - Py_RETURN_NONE; -} - -static PyObject * -PYM_initStandardClasses(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *object; - - if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) - return NULL; - - PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); - - if (!JS_InitStandardClasses(self->cx, object->obj)) { - PyErr_SetString(PYM_error, "JS_InitStandardClasses() failed"); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -PYM_evaluateScript(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *object; - const char *source; - int sourceLen; - const char *filename; - int lineNo; - - if (!PyArg_ParseTuple(args, "O!s#si", &PYM_JSObjectType, &object, - &source, &sourceLen, &filename, &lineNo)) - return NULL; - - PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); - - jsval rval; - JSBool result; - Py_BEGIN_ALLOW_THREADS; - result = JS_EvaluateScript(self->cx, object->obj, source, sourceLen, - filename, lineNo, &rval); - Py_END_ALLOW_THREADS; - - if (!result) { - PYM_jsExceptionToPython(self); - return NULL; - } - - PyObject *pyRval = PYM_jsvalToPyObject(self, rval); - return pyRval; -} - -static PyObject * -PYM_defineProperty(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *object; - PyObject *value; - const char *name; - - if (!PyArg_ParseTuple(args, "O!sO", &PYM_JSObjectType, &object, - &name, &value)) - return NULL; - - PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); - jsval jsValue; - - if (PYM_pyObjectToJsval(self, value, &jsValue) == -1) - return NULL; - - // TODO: Support unicode naming. - if (!JS_DefineProperty(self->cx, object->obj, name, jsValue, - NULL, NULL, JSPROP_ENUMERATE)) { - // TODO: There's probably an exception pending on self->cx, - // what should we do about it? - PyErr_SetString(PYM_error, "JS_DefineProperty() failed"); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -PYM_callFunction(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PYM_JSObject *obj; - PYM_JSFunction *fun; - PyObject *funcArgs; - - if (!PyArg_ParseTuple(args, "O!O!O!", &PYM_JSObjectType, &obj, - &PYM_JSFunctionType, &fun, - &PyTuple_Type, &funcArgs)) - return NULL; - - PYM_ENSURE_RUNTIME_MATCH(self->runtime, obj->runtime); - PYM_ENSURE_RUNTIME_MATCH(self->runtime, fun->base.runtime); - - uintN argc = PyTuple_Size(funcArgs); - jsval argv[argc]; - jsval *currArg = argv; - - for (unsigned int i = 0; i < argc; i++) { - PyObject *item = PyTuple_GET_ITEM(funcArgs, i); - if (item == NULL || - PYM_pyObjectToJsval(self, item, currArg) == -1) - return NULL; - currArg++; - } - - jsval rval; - - // TODO: This assumes that a JSFunction * is actually a subclass of - // a JSObject *, which may or may not be regarded as an implementation - // detail. - JSBool result; - Py_BEGIN_ALLOW_THREADS; - result = JS_CallFunction(self->cx, obj->obj, - (JSFunction *) fun->base.obj, - argc, argv, &rval); - Py_END_ALLOW_THREADS; - - if (!result) { - PYM_jsExceptionToPython(self); - return NULL; - } - - return PYM_jsvalToPyObject(self, rval); -} - -static PyObject * -PYM_newFunction(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PyObject *callable; - const char *name; - - if (!PyArg_ParseTuple(args, "Os", &callable, &name)) - return NULL; - - return (PyObject *) PYM_newJSFunctionFromCallable(self, callable, name); -} - -static PyObject * -PYM_setOperationCallback(PYM_JSContextObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self->runtime); - PyObject *callable; - - if (!PyArg_ParseTuple(args, "O", &callable)) - return NULL; - - if (!PyCallable_Check(callable)) { - PyErr_SetString(PyExc_TypeError, "Callable must be callable"); - return NULL; - } - - JS_SetOperationCallback(self->cx, PYM_operationCallback); - - Py_INCREF(callable); - if (self->opCallback) - Py_DECREF(self->opCallback); - self->opCallback = callable; - - Py_RETURN_NONE; -} - -static PyObject * -PYM_triggerOperationCallback(PYM_JSContextObject *self, PyObject *args) -{ - JS_TriggerOperationCallback(self->cx); - Py_RETURN_NONE; -} - -static PyMethodDef PYM_JSContextMethods[] = { - {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS, - "Get the JavaScript runtime associated with this context."}, - {"new_object", (PyCFunction) PYM_newObject, METH_VARARGS, - "Create a new JavaScript object."}, - {"init_standard_classes", - (PyCFunction) PYM_initStandardClasses, METH_VARARGS, - "Add standard classes and functions to the given object."}, - {"evaluate_script", - (PyCFunction) PYM_evaluateScript, METH_VARARGS, - "Evaluate the given JavaScript code in the context of the given " - "global object, using the given filename" - "and line number information."}, - {"call_function", - (PyCFunction) PYM_callFunction, METH_VARARGS, - "Calls a JS function."}, - {"new_function", - (PyCFunction) PYM_newFunction, METH_VARARGS, - "Creates a new function callable from JS."}, - {"define_property", - (PyCFunction) PYM_defineProperty, METH_VARARGS, - "Defines a property on an object."}, - {"get_property", (PyCFunction) PYM_getProperty, METH_VARARGS, - "Gets the given property for the given JavaScript object."}, - {"gc", (PyCFunction) PYM_gc, METH_VARARGS, - "Performs garbage collection on the context's runtime."}, - {"set_operation_callback", (PyCFunction) PYM_setOperationCallback, - METH_VARARGS, - "Sets the operation callback for the context."}, - {"trigger_operation_callback", (PyCFunction) PYM_triggerOperationCallback, - METH_VARARGS, - "Triggers the operation callback for the context."}, - {"get_object_private", (PyCFunction) PYM_getObjectPrivate, METH_VARARGS, - "Returns the private Python object stored in the JavaScript object."}, - {"clear_object_private", (PyCFunction) PYM_clearObjectPrivate, METH_VARARGS, - "Clears any private Python object stored in the JavaScript object."}, - {NULL, NULL, 0, NULL} -}; - -PyTypeObject PYM_JSContextType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pymonkey.Context", /*tp_name*/ - sizeof(PYM_JSContextObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /*tp_dealloc*/ - (destructor) PYM_JSContextDealloc, - 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*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - /* tp_doc */ - "JavaScript Context.", - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PYM_JSContextMethods, /* 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 */ -}; - -extern PYM_JSContextObject * -PYM_newJSContextObject(PYM_JSRuntimeObject *runtime, JSContext *cx) -{ - PYM_JSContextObject *context = PyObject_New(PYM_JSContextObject, - &PYM_JSContextType); - if (context == NULL) - return NULL; - - context->opCallback = NULL; - context->runtime = runtime; - Py_INCREF(runtime); - - context->cx = cx; - JS_SetContextPrivate(cx, context); - JS_SetErrorReporter(cx, PYM_reportError); - -#ifdef JS_GC_ZEAL - // TODO: Consider exposing JS_SetGCZeal() to Python instead of - // hard-coding it here. - JS_SetGCZeal(cx, 2); -#endif - - return context; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/context.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,534 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "context.h" +#include "object.h" +#include "function.h" +#include "utils.h" + +// This is the default JSOperationCallback for pymonkey-owned JS contexts, +// when they've defined one in Python. +static JSBool +PYM_operationCallback(JSContext *cx) +{ + PYM_PyAutoEnsureGIL gil; + PYM_JSContextObject *context = (PYM_JSContextObject *) + JS_GetContextPrivate(cx); + + PyObject *callable = context->opCallback; + PyObject *args = PyTuple_Pack(1, (PyObject *) context); + if (args == NULL) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + PyObject *result = PyObject_Call(callable, args, NULL); + Py_DECREF(args); + if (result == NULL) { + PYM_pythonExceptionToJs(context); + return JS_FALSE; + } + + Py_DECREF(result); + return JS_TRUE; +} + +// This is the default JSErrorReporter for pymonkey-owned JS contexts. +static void +PYM_reportError(JSContext *cx, const char *message, JSErrorReport *report) +{ + PYM_PyAutoEnsureGIL gil; + + // Convert JS warnings into Python warnings. + if (JSREPORT_IS_WARNING(report->flags)) { + if (report->filename) + PyErr_WarnExplicit(NULL, message, report->filename, report->lineno, + NULL, NULL); + else + PyErr_Warn(NULL, message); + } else + // TODO: Not sure if this will ever get called, but we should know + // if it is. + PyErr_Warn(NULL, "A JS error was reported."); +} + +static void +PYM_JSContextDealloc(PYM_JSContextObject *self) +{ + if (self->opCallback) { + Py_DECREF(self->opCallback); + self->opCallback = NULL; + } + + if (self->cx) { + JS_DestroyContext(self->cx); + self->cx = NULL; + } + + Py_DECREF(self->runtime); + self->runtime = NULL; + + self->ob_type->tp_free((PyObject *) self); +} + +static PyObject * +PYM_getRuntime(PYM_JSContextObject *self, PyObject *args) +{ + Py_INCREF(self->runtime); + return (PyObject *) self->runtime; +} + +static PyObject * +PYM_getObjectPrivate(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *object; + + if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) + return NULL; + + PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); + + JSObject *obj = object->obj; + + if (JS_ObjectIsFunction(self->cx, obj)) { + jsval functionHolder; + if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) { + JS_ClearPendingException(self->cx); + Py_RETURN_NONE; + } + if (!JSVAL_IS_OBJECT(functionHolder)) + Py_RETURN_NONE; + obj = JSVAL_TO_OBJECT(functionHolder); + } + + JSClass *klass = JS_GET_CLASS(self->cx, obj); + if (klass != &PYM_JS_ObjectClass) + Py_RETURN_NONE; + + PyObject *pyObject; + + if (!PYM_JS_getPrivatePyObject(self->cx, obj, &pyObject)) { + PYM_jsExceptionToPython(self); + return NULL; + } + + if (pyObject == NULL) + pyObject = Py_None; + + Py_INCREF(pyObject); + return pyObject; +} + +static PyObject * +PYM_clearObjectPrivate(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *object; + + if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) + return NULL; + + PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); + + JSObject *obj = object->obj; + + if (JS_ObjectIsFunction(self->cx, obj)) { + jsval functionHolder; + if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) { + JS_ClearPendingException(self->cx); + Py_RETURN_NONE; + } + if (!JSVAL_IS_OBJECT(functionHolder)) + Py_RETURN_NONE; + obj = JSVAL_TO_OBJECT(functionHolder); + } + + JSClass *klass = JS_GET_CLASS(self->cx, obj); + if (klass != &PYM_JS_ObjectClass) + Py_RETURN_NONE; + + if (!PYM_JS_setPrivatePyObject(self->cx, obj, Py_None)) { + PYM_jsExceptionToPython(self); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +PYM_newObject(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PyObject *privateObj = NULL; + + if (!PyArg_ParseTuple(args, "|O", &privateObj)) + return NULL; + + JSObject *obj = PYM_JS_newObject(self->cx, privateObj); + if (obj == NULL) { + PyErr_SetString(PYM_error, "PYM_JS_newObject() failed"); + return NULL; + } + + // If this fails, we don't need to worry about cleaning up + // obj because it'll get cleaned up at the next GC. + return (PyObject *) PYM_newJSObject(self, obj, NULL); +} + +static PyObject * +PYM_getProperty(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *object; + char *buffer = NULL; + int size; + + if (!PyArg_ParseTuple(args, "O!es#", &PYM_JSObjectType, &object, + "utf-16", &buffer, &size)) + return NULL; + + if (self->runtime != object->runtime) { + PyMem_Free(buffer); + PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); + } + + jsval val; + JSBool result; + Py_BEGIN_ALLOW_THREADS; + // Note that we're manipulating buffer and size here to get rid of + // the BOM. + result = JS_GetUCProperty(self->cx, object->obj, (jschar *) (buffer + 2), + (size / 2) - 1, &val); + Py_END_ALLOW_THREADS; + + PyMem_Free(buffer); + + if (!result) { + PYM_jsExceptionToPython(self); + return NULL; + } + + return PYM_jsvalToPyObject(self, val); +} + +static PyObject * +PYM_gc(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + JS_GC(self->cx); + Py_RETURN_NONE; +} + +static PyObject * +PYM_initStandardClasses(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *object; + + if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) + return NULL; + + PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); + + if (!JS_InitStandardClasses(self->cx, object->obj)) { + PyErr_SetString(PYM_error, "JS_InitStandardClasses() failed"); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +PYM_evaluateScript(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *object; + const char *source; + int sourceLen; + const char *filename; + int lineNo; + + if (!PyArg_ParseTuple(args, "O!s#si", &PYM_JSObjectType, &object, + &source, &sourceLen, &filename, &lineNo)) + return NULL; + + PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); + + jsval rval; + JSBool result; + Py_BEGIN_ALLOW_THREADS; + result = JS_EvaluateScript(self->cx, object->obj, source, sourceLen, + filename, lineNo, &rval); + Py_END_ALLOW_THREADS; + + if (!result) { + PYM_jsExceptionToPython(self); + return NULL; + } + + PyObject *pyRval = PYM_jsvalToPyObject(self, rval); + return pyRval; +} + +static PyObject * +PYM_defineProperty(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *object; + PyObject *value; + const char *name; + + if (!PyArg_ParseTuple(args, "O!sO", &PYM_JSObjectType, &object, + &name, &value)) + return NULL; + + PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime); + jsval jsValue; + + if (PYM_pyObjectToJsval(self, value, &jsValue) == -1) + return NULL; + + // TODO: Support unicode naming. + if (!JS_DefineProperty(self->cx, object->obj, name, jsValue, + NULL, NULL, JSPROP_ENUMERATE)) { + // TODO: There's probably an exception pending on self->cx, + // what should we do about it? + PyErr_SetString(PYM_error, "JS_DefineProperty() failed"); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +PYM_callFunction(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PYM_JSObject *obj; + PYM_JSFunction *fun; + PyObject *funcArgs; + + if (!PyArg_ParseTuple(args, "O!O!O!", &PYM_JSObjectType, &obj, + &PYM_JSFunctionType, &fun, + &PyTuple_Type, &funcArgs)) + return NULL; + + PYM_ENSURE_RUNTIME_MATCH(self->runtime, obj->runtime); + PYM_ENSURE_RUNTIME_MATCH(self->runtime, fun->base.runtime); + + uintN argc = PyTuple_Size(funcArgs); + jsval argv[argc]; + jsval *currArg = argv; + + for (unsigned int i = 0; i < argc; i++) { + PyObject *item = PyTuple_GET_ITEM(funcArgs, i); + if (item == NULL || + PYM_pyObjectToJsval(self, item, currArg) == -1) + return NULL; + currArg++; + } + + jsval rval; + + // TODO: This assumes that a JSFunction * is actually a subclass of + // a JSObject *, which may or may not be regarded as an implementation + // detail. + JSBool result; + Py_BEGIN_ALLOW_THREADS; + result = JS_CallFunction(self->cx, obj->obj, + (JSFunction *) fun->base.obj, + argc, argv, &rval); + Py_END_ALLOW_THREADS; + + if (!result) { + PYM_jsExceptionToPython(self); + return NULL; + } + + return PYM_jsvalToPyObject(self, rval); +} + +static PyObject * +PYM_newFunction(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PyObject *callable; + const char *name; + + if (!PyArg_ParseTuple(args, "Os", &callable, &name)) + return NULL; + + return (PyObject *) PYM_newJSFunctionFromCallable(self, callable, name); +} + +static PyObject * +PYM_setOperationCallback(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PyObject *callable; + + if (!PyArg_ParseTuple(args, "O", &callable)) + return NULL; + + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "Callable must be callable"); + return NULL; + } + + JS_SetOperationCallback(self->cx, PYM_operationCallback); + + Py_INCREF(callable); + if (self->opCallback) + Py_DECREF(self->opCallback); + self->opCallback = callable; + + Py_RETURN_NONE; +} + +static PyObject * +PYM_triggerOperationCallback(PYM_JSContextObject *self, PyObject *args) +{ + JS_TriggerOperationCallback(self->cx); + Py_RETURN_NONE; +} + +static PyMethodDef PYM_JSContextMethods[] = { + {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS, + "Get the JavaScript runtime associated with this context."}, + {"new_object", (PyCFunction) PYM_newObject, METH_VARARGS, + "Create a new JavaScript object."}, + {"init_standard_classes", + (PyCFunction) PYM_initStandardClasses, METH_VARARGS, + "Add standard classes and functions to the given object."}, + {"evaluate_script", + (PyCFunction) PYM_evaluateScript, METH_VARARGS, + "Evaluate the given JavaScript code in the context of the given " + "global object, using the given filename" + "and line number information."}, + {"call_function", + (PyCFunction) PYM_callFunction, METH_VARARGS, + "Calls a JS function."}, + {"new_function", + (PyCFunction) PYM_newFunction, METH_VARARGS, + "Creates a new function callable from JS."}, + {"define_property", + (PyCFunction) PYM_defineProperty, METH_VARARGS, + "Defines a property on an object."}, + {"get_property", (PyCFunction) PYM_getProperty, METH_VARARGS, + "Gets the given property for the given JavaScript object."}, + {"gc", (PyCFunction) PYM_gc, METH_VARARGS, + "Performs garbage collection on the context's runtime."}, + {"set_operation_callback", (PyCFunction) PYM_setOperationCallback, + METH_VARARGS, + "Sets the operation callback for the context."}, + {"trigger_operation_callback", (PyCFunction) PYM_triggerOperationCallback, + METH_VARARGS, + "Triggers the operation callback for the context."}, + {"get_object_private", (PyCFunction) PYM_getObjectPrivate, METH_VARARGS, + "Returns the private Python object stored in the JavaScript object."}, + {"clear_object_private", (PyCFunction) PYM_clearObjectPrivate, METH_VARARGS, + "Clears any private Python object stored in the JavaScript object."}, + {NULL, NULL, 0, NULL} +}; + +PyTypeObject PYM_JSContextType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pymonkey.Context", /*tp_name*/ + sizeof(PYM_JSContextObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /*tp_dealloc*/ + (destructor) PYM_JSContextDealloc, + 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*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + /* tp_doc */ + "JavaScript Context.", + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PYM_JSContextMethods, /* 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 */ +}; + +extern PYM_JSContextObject * +PYM_newJSContextObject(PYM_JSRuntimeObject *runtime, JSContext *cx) +{ + PYM_JSContextObject *context = PyObject_New(PYM_JSContextObject, + &PYM_JSContextType); + if (context == NULL) + return NULL; + + context->opCallback = NULL; + context->runtime = runtime; + Py_INCREF(runtime); + + context->cx = cx; + JS_SetContextPrivate(cx, context); + JS_SetErrorReporter(cx, PYM_reportError); + +#ifdef JS_GC_ZEAL + // TODO: Consider exposing JS_SetGCZeal() to Python instead of + // hard-coding it here. + JS_SetGCZeal(cx, 2); +#endif + + return context; +}
--- a/function.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "function.h" -#include "utils.h" - -static void -PYM_JSFunctionDealloc(PYM_JSFunction *self) -{ - PYM_JSObjectType.tp_dealloc((PyObject *) self); -} - -static JSBool -PYM_dispatchJSFunctionToPython(JSContext *cx, - JSObject *obj, - uintN argc, - jsval *argv, - jsval *rval) -{ - PYM_PyAutoEnsureGIL gil; - jsval callee = JS_ARGV_CALLEE(argv); - jsval functionHolder; - if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder)) - return JS_FALSE; - - PyObject *callable; - if (!PYM_JS_getPrivatePyObject(cx, JSVAL_TO_OBJECT(functionHolder), - &callable)) - return JS_FALSE; - - if (callable == Py_None) { - JS_ReportError(cx, "Wrapped Python function no longer exists"); - return JS_FALSE; - } - - PYM_JSContextObject *context = (PYM_JSContextObject *) - JS_GetContextPrivate(cx); - - jsval thisArg = OBJECT_TO_JSVAL(obj); - PyObject *pyThisArg = PYM_jsvalToPyObject(context, thisArg); - if (pyThisArg == NULL) { - PYM_pythonExceptionToJs(context); - return JS_FALSE; - } - - PyObject *funcArgs = PyTuple_New(argc); - if (funcArgs == NULL) { - Py_DECREF(pyThisArg); - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - for (unsigned int i = 0; i < argc; i++) { - PyObject *arg = PYM_jsvalToPyObject(context, argv[i]); - if (arg == NULL || PyTuple_SetItem(funcArgs, i, arg)) { - if (arg) - Py_DECREF(arg); - Py_DECREF(funcArgs); - Py_DECREF(pyThisArg); - PYM_pythonExceptionToJs(context); - return JS_FALSE; - } - } - - PyObject *args = PyTuple_Pack(3, - (PyObject *) context, - pyThisArg, - funcArgs); - Py_DECREF(pyThisArg); - Py_DECREF(funcArgs); - if (args == NULL) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - PyObject *result = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - if (result == NULL) { - PYM_pythonExceptionToJs(context); - return JS_FALSE; - } - - int error = PYM_pyObjectToJsval(context, result, rval); - Py_DECREF(result); - - if (error) { - PYM_pythonExceptionToJs(context); - return JS_FALSE; - } - - return JS_TRUE; -} - -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 */ -}; - -PYM_JSFunction * -PYM_newJSFunctionFromCallable(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, - PYM_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; - } - - PYM_JSFunction *object = PyObject_New(PYM_JSFunction, - &PYM_JSFunctionType); - if (object == NULL) - return 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; - - JSObject *functionHolder = PYM_JS_newObject(context->cx, callable); - if (functionHolder == NULL) { - Py_DECREF((PyObject *) object); - PyErr_SetString(PYM_error, "PYM_JS_newObject() failed"); - return NULL; - } - - if (!JS_SetReservedSlot(context->cx, funcObj, 0, - OBJECT_TO_JSVAL(functionHolder))) { - Py_DECREF((PyObject *) object); - PyErr_SetString(PYM_error, "JS_SetReservedSlot() failed"); - return NULL; - } - - return object; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/function.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,224 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "function.h" +#include "utils.h" + +static void +PYM_JSFunctionDealloc(PYM_JSFunction *self) +{ + PYM_JSObjectType.tp_dealloc((PyObject *) self); +} + +static JSBool +PYM_dispatchJSFunctionToPython(JSContext *cx, + JSObject *obj, + uintN argc, + jsval *argv, + jsval *rval) +{ + PYM_PyAutoEnsureGIL gil; + jsval callee = JS_ARGV_CALLEE(argv); + jsval functionHolder; + if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder)) + return JS_FALSE; + + PyObject *callable; + if (!PYM_JS_getPrivatePyObject(cx, JSVAL_TO_OBJECT(functionHolder), + &callable)) + return JS_FALSE; + + if (callable == Py_None) { + JS_ReportError(cx, "Wrapped Python function no longer exists"); + return JS_FALSE; + } + + PYM_JSContextObject *context = (PYM_JSContextObject *) + JS_GetContextPrivate(cx); + + jsval thisArg = OBJECT_TO_JSVAL(obj); + PyObject *pyThisArg = PYM_jsvalToPyObject(context, thisArg); + if (pyThisArg == NULL) { + PYM_pythonExceptionToJs(context); + return JS_FALSE; + } + + PyObject *funcArgs = PyTuple_New(argc); + if (funcArgs == NULL) { + Py_DECREF(pyThisArg); + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + for (unsigned int i = 0; i < argc; i++) { + PyObject *arg = PYM_jsvalToPyObject(context, argv[i]); + if (arg == NULL || PyTuple_SetItem(funcArgs, i, arg)) { + if (arg) + Py_DECREF(arg); + Py_DECREF(funcArgs); + Py_DECREF(pyThisArg); + PYM_pythonExceptionToJs(context); + return JS_FALSE; + } + } + + PyObject *args = PyTuple_Pack(3, + (PyObject *) context, + pyThisArg, + funcArgs); + Py_DECREF(pyThisArg); + Py_DECREF(funcArgs); + if (args == NULL) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + PyObject *result = PyObject_Call(callable, args, NULL); + Py_DECREF(args); + if (result == NULL) { + PYM_pythonExceptionToJs(context); + return JS_FALSE; + } + + int error = PYM_pyObjectToJsval(context, result, rval); + Py_DECREF(result); + + if (error) { + PYM_pythonExceptionToJs(context); + return JS_FALSE; + } + + return JS_TRUE; +} + +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 */ +}; + +PYM_JSFunction * +PYM_newJSFunctionFromCallable(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, + PYM_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; + } + + PYM_JSFunction *object = PyObject_New(PYM_JSFunction, + &PYM_JSFunctionType); + if (object == NULL) + return 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; + + JSObject *functionHolder = PYM_JS_newObject(context->cx, callable); + if (functionHolder == NULL) { + Py_DECREF((PyObject *) object); + PyErr_SetString(PYM_error, "PYM_JS_newObject() failed"); + return NULL; + } + + if (!JS_SetReservedSlot(context->cx, funcObj, 0, + OBJECT_TO_JSVAL(functionHolder))) { + Py_DECREF((PyObject *) object); + PyErr_SetString(PYM_error, "JS_SetReservedSlot() failed"); + return NULL; + } + + return object; +}
--- a/manage.py Sat Aug 15 00:50:55 2009 -0700 +++ b/manage.py Sat Aug 15 10:24:17 2009 -0700 @@ -75,13 +75,13 @@ "-Wall", "-o", "pymonkey.so", "-dynamiclib", - "pymonkey.c", - "utils.c", - "object.c", - "function.c", - "undefined.c", - "context.c", - "runtime.c"] + "pymonkey.cpp", + "utils.cpp", + "object.cpp", + "function.cpp", + "undefined.cpp", + "context.cpp", + "runtime.cpp"] if options.get("static"): args.append(os.path.join(objdir, "libjs_static.a"))
--- a/object.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "object.h" -#include "function.h" -#include "runtime.h" -#include "utils.h" - -JSObject * -PYM_JS_newObject(JSContext *cx, PyObject *pyObject) -{ - JSObject *obj = JS_NewObject(cx, &PYM_JS_ObjectClass, NULL, NULL); - if (obj) { - if (!JS_SetPrivate(cx, obj, pyObject)) - return NULL; - Py_XINCREF(pyObject); - } - return obj; -} - -JSBool -PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject) -{ - PyObject *old; - if (!PYM_JS_getPrivatePyObject(cx, obj, &old)) - return JS_FALSE; - if (!JS_SetPrivate(cx, obj, pyObject)) - return JS_FALSE; - Py_INCREF(pyObject); - Py_XDECREF(old); - return JS_TRUE; -} - -JSBool -PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject) -{ - JSClass *klass = JS_GET_CLASS(cx, obj); - if (klass != &PYM_JS_ObjectClass) { - JS_ReportError(cx, "Object is not an instance of PymonkeyObject"); - return JS_FALSE; - } - - *pyObject = (PyObject *) JS_GetPrivate(cx, obj); - return JS_TRUE; -} - -static void -PYM_JS_finalizeObject(JSContext *cx, JSObject *obj) -{ - PYM_PyAutoEnsureGIL gil; - PyObject *pyObject; - // TODO: What if this fails? - if (PYM_JS_getPrivatePyObject(cx, obj, &pyObject)) - Py_XDECREF(pyObject); -} - -// This one-size-fits-all JSClass is used for any JS objects created -// in Python. It can hold a reference to a Python object for as long as -// its parent JS object is accessible from JS-land. As soon as it's -// garbage collected by the JS interpreter, it releases its reference on -// the Python object. -JSClass PYM_JS_ObjectClass = { - "PymonkeyObject", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PYM_JS_finalizeObject, - JSCLASS_NO_OPTIONAL_MEMBERS -}; - -static void -PYM_JSObjectDealloc(PYM_JSObject *self) -{ - if (self->obj) { - JS_DHashTableOperate(&self->runtime->objects, - (void *) self->obj, - JS_DHASH_REMOVE); - - // JS_RemoveRoot() always returns JS_TRUE, so don't - // bother checking its return value. - JS_RemoveRootRT(self->runtime->rt, &self->obj); - self->obj = NULL; - } - - if (self->runtime) { - Py_DECREF(self->runtime); - self->runtime = NULL; - } - - self->ob_type->tp_free((PyObject *) self); -} - -static PyObject * -PYM_getRuntime(PYM_JSObject *self, PyObject *args) -{ - Py_INCREF(self->runtime); - return (PyObject *) self->runtime; -} - -static PyMethodDef PYM_JSObjectMethods[] = { - {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS, - "Get the JavaScript runtime associated with this object."}, - {NULL, NULL, 0, NULL} -}; - -PyTypeObject PYM_JSObjectType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pymonkey.Object", /*tp_name*/ - sizeof(PYM_JSObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /*tp_dealloc*/ - (destructor) PYM_JSObjectDealloc, - 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 | Py_TPFLAGS_BASETYPE, - /* tp_doc */ - "JavaScript Object.", - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PYM_JSObjectMethods, /* 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 */ -}; - -PYM_JSObject *PYM_newJSObject(PYM_JSContextObject *context, - JSObject *obj, - PYM_JSObject *subclass) { - PYM_JSRuntimeObject *runtime = context->runtime; - PYM_HashEntry *cached = (PYM_HashEntry *) JS_DHashTableOperate( - &runtime->objects, - (void *) obj, - JS_DHASH_LOOKUP - ); - - if (JS_DHASH_ENTRY_IS_BUSY((JSDHashEntryHdr *) cached)) { - Py_INCREF((PyObject *) cached->value); - return (PYM_JSObject *) cached->value; - } - - PYM_JSObject *object; - - if (subclass) - object = subclass; - else { - if (JS_ObjectIsFunction(context->cx, obj)) { - PYM_JSFunction *func = PyObject_New(PYM_JSFunction, - &PYM_JSFunctionType); - object = (PYM_JSObject *) func; - } else - object = PyObject_New(PYM_JSObject, - &PYM_JSObjectType); - } - - if (object == NULL) - return NULL; - - object->runtime = NULL; - object->obj = NULL; - - cached = (PYM_HashEntry *) JS_DHashTableOperate(&runtime->objects, - (void *) obj, - JS_DHASH_ADD); - if (cached == NULL) { - Py_DECREF(object); - PyErr_SetString(PYM_error, "JS_DHashTableOperate() failed"); - return NULL; - } - - cached->base.key = (void *) obj; - cached->value = object; - - object->runtime = context->runtime; - Py_INCREF(object->runtime); - - object->obj = obj; - - JS_AddNamedRootRT(object->runtime->rt, &object->obj, - "Pymonkey-Generated Object"); - - return object; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/object.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,238 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "object.h" +#include "function.h" +#include "runtime.h" +#include "utils.h" + +JSObject * +PYM_JS_newObject(JSContext *cx, PyObject *pyObject) +{ + JSObject *obj = JS_NewObject(cx, &PYM_JS_ObjectClass, NULL, NULL); + if (obj) { + if (!JS_SetPrivate(cx, obj, pyObject)) + return NULL; + Py_XINCREF(pyObject); + } + return obj; +} + +JSBool +PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject) +{ + PyObject *old; + if (!PYM_JS_getPrivatePyObject(cx, obj, &old)) + return JS_FALSE; + if (!JS_SetPrivate(cx, obj, pyObject)) + return JS_FALSE; + Py_INCREF(pyObject); + Py_XDECREF(old); + return JS_TRUE; +} + +JSBool +PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject) +{ + JSClass *klass = JS_GET_CLASS(cx, obj); + if (klass != &PYM_JS_ObjectClass) { + JS_ReportError(cx, "Object is not an instance of PymonkeyObject"); + return JS_FALSE; + } + + *pyObject = (PyObject *) JS_GetPrivate(cx, obj); + return JS_TRUE; +} + +static void +PYM_JS_finalizeObject(JSContext *cx, JSObject *obj) +{ + PYM_PyAutoEnsureGIL gil; + PyObject *pyObject; + // TODO: What if this fails? + if (PYM_JS_getPrivatePyObject(cx, obj, &pyObject)) + Py_XDECREF(pyObject); +} + +// This one-size-fits-all JSClass is used for any JS objects created +// in Python. It can hold a reference to a Python object for as long as +// its parent JS object is accessible from JS-land. As soon as it's +// garbage collected by the JS interpreter, it releases its reference on +// the Python object. +JSClass PYM_JS_ObjectClass = { + "PymonkeyObject", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PYM_JS_finalizeObject, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static void +PYM_JSObjectDealloc(PYM_JSObject *self) +{ + if (self->obj) { + JS_DHashTableOperate(&self->runtime->objects, + (void *) self->obj, + JS_DHASH_REMOVE); + + // JS_RemoveRoot() always returns JS_TRUE, so don't + // bother checking its return value. + JS_RemoveRootRT(self->runtime->rt, &self->obj); + self->obj = NULL; + } + + if (self->runtime) { + Py_DECREF(self->runtime); + self->runtime = NULL; + } + + self->ob_type->tp_free((PyObject *) self); +} + +static PyObject * +PYM_getRuntime(PYM_JSObject *self, PyObject *args) +{ + Py_INCREF(self->runtime); + return (PyObject *) self->runtime; +} + +static PyMethodDef PYM_JSObjectMethods[] = { + {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS, + "Get the JavaScript runtime associated with this object."}, + {NULL, NULL, 0, NULL} +}; + +PyTypeObject PYM_JSObjectType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pymonkey.Object", /*tp_name*/ + sizeof(PYM_JSObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /*tp_dealloc*/ + (destructor) PYM_JSObjectDealloc, + 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 | Py_TPFLAGS_BASETYPE, + /* tp_doc */ + "JavaScript Object.", + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PYM_JSObjectMethods, /* 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 */ +}; + +PYM_JSObject *PYM_newJSObject(PYM_JSContextObject *context, + JSObject *obj, + PYM_JSObject *subclass) { + PYM_JSRuntimeObject *runtime = context->runtime; + PYM_HashEntry *cached = (PYM_HashEntry *) JS_DHashTableOperate( + &runtime->objects, + (void *) obj, + JS_DHASH_LOOKUP + ); + + if (JS_DHASH_ENTRY_IS_BUSY((JSDHashEntryHdr *) cached)) { + Py_INCREF((PyObject *) cached->value); + return (PYM_JSObject *) cached->value; + } + + PYM_JSObject *object; + + if (subclass) + object = subclass; + else { + if (JS_ObjectIsFunction(context->cx, obj)) { + PYM_JSFunction *func = PyObject_New(PYM_JSFunction, + &PYM_JSFunctionType); + object = (PYM_JSObject *) func; + } else + object = PyObject_New(PYM_JSObject, + &PYM_JSObjectType); + } + + if (object == NULL) + return NULL; + + object->runtime = NULL; + object->obj = NULL; + + cached = (PYM_HashEntry *) JS_DHashTableOperate(&runtime->objects, + (void *) obj, + JS_DHASH_ADD); + if (cached == NULL) { + Py_DECREF(object); + PyErr_SetString(PYM_error, "JS_DHashTableOperate() failed"); + return NULL; + } + + cached->base.key = (void *) obj; + cached->value = object; + + object->runtime = context->runtime; + Py_INCREF(object->runtime); + + object->obj = obj; + + JS_AddNamedRootRT(object->runtime->rt, &object->obj, + "Pymonkey-Generated Object"); + + return object; +}
--- a/pymonkey.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "undefined.h" -#include "runtime.h" -#include "context.h" -#include "object.h" -#include "function.h" -#include "utils.h" - -static PyMethodDef PYM_methods[] = { - {NULL, NULL, 0, NULL} -}; - -PyMODINIT_FUNC -initpymonkey(void) -{ - PyObject *module; - - module = Py_InitModule("pymonkey", PYM_methods); - if (module == NULL) - return; - - if (PyType_Ready(&PYM_undefinedType) < 0) - return; - - PYM_undefined = PyObject_New(PYM_undefinedObject, &PYM_undefinedType); - if (PYM_undefined == NULL) - return; - Py_INCREF(PYM_undefined); - PyModule_AddObject(module, "undefined", (PyObject *) PYM_undefined); - - PYM_error = PyErr_NewException("pymonkey.error", NULL, NULL); - Py_INCREF(PYM_error); - PyModule_AddObject(module, "error", PYM_error); - - if (!PyType_Ready(&PYM_JSRuntimeType) < 0) - return; - - Py_INCREF(&PYM_JSRuntimeType); - PyModule_AddObject(module, "Runtime", (PyObject *) &PYM_JSRuntimeType); - - if (!PyType_Ready(&PYM_JSContextType) < 0) - return; - - Py_INCREF(&PYM_JSContextType); - PyModule_AddObject(module, "Context", (PyObject *) &PYM_JSContextType); - - if (!PyType_Ready(&PYM_JSObjectType) < 0) - return; - - Py_INCREF(&PYM_JSObjectType); - PyModule_AddObject(module, "Object", (PyObject *) &PYM_JSObjectType); - - PYM_JSFunctionType.tp_base = &PYM_JSObjectType; - if (!PyType_Ready(&PYM_JSFunctionType) < 0) - return; - - Py_INCREF(&PYM_JSFunctionType); - PyModule_AddObject(module, "Function", (PyObject *) &PYM_JSFunctionType); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pymonkey.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,94 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "undefined.h" +#include "runtime.h" +#include "context.h" +#include "object.h" +#include "function.h" +#include "utils.h" + +static PyMethodDef PYM_methods[] = { + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC +initpymonkey(void) +{ + PyObject *module; + + module = Py_InitModule("pymonkey", PYM_methods); + if (module == NULL) + return; + + if (PyType_Ready(&PYM_undefinedType) < 0) + return; + + PYM_undefined = PyObject_New(PYM_undefinedObject, &PYM_undefinedType); + if (PYM_undefined == NULL) + return; + Py_INCREF(PYM_undefined); + PyModule_AddObject(module, "undefined", (PyObject *) PYM_undefined); + + PYM_error = PyErr_NewException("pymonkey.error", NULL, NULL); + Py_INCREF(PYM_error); + PyModule_AddObject(module, "error", PYM_error); + + if (!PyType_Ready(&PYM_JSRuntimeType) < 0) + return; + + Py_INCREF(&PYM_JSRuntimeType); + PyModule_AddObject(module, "Runtime", (PyObject *) &PYM_JSRuntimeType); + + if (!PyType_Ready(&PYM_JSContextType) < 0) + return; + + Py_INCREF(&PYM_JSContextType); + PyModule_AddObject(module, "Context", (PyObject *) &PYM_JSContextType); + + if (!PyType_Ready(&PYM_JSObjectType) < 0) + return; + + Py_INCREF(&PYM_JSObjectType); + PyModule_AddObject(module, "Object", (PyObject *) &PYM_JSObjectType); + + PYM_JSFunctionType.tp_base = &PYM_JSObjectType; + if (!PyType_Ready(&PYM_JSFunctionType) < 0) + return; + + Py_INCREF(&PYM_JSFunctionType); + PyModule_AddObject(module, "Function", (PyObject *) &PYM_JSFunctionType); +}
--- a/runtime.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "runtime.h" -#include "context.h" -#include "utils.h" - -static PyObject * -PYM_JSRuntimeNew(PyTypeObject *type, PyObject *args, - PyObject *kwds) -{ - PYM_JSRuntimeObject *self; - - self = (PYM_JSRuntimeObject *) type->tp_alloc(type, 0); - if (self != NULL) { - self->thread = PyThread_get_thread_ident(); - self->rt = NULL; - self->cx = NULL; - self->objects.ops = NULL; - - if (!JS_DHashTableInit(&self->objects, - JS_DHashGetStubOps(), - NULL, - sizeof(PYM_HashEntry), - JS_DHASH_DEFAULT_CAPACITY(100))) { - PyErr_SetString(PYM_error, "JS_DHashTableInit() failed"); - type->tp_dealloc((PyObject *) self); - self = NULL; - } - - if (self != NULL) { - self->rt = JS_NewRuntime(8L * 1024L * 1024L); - if (!self->rt) { - PyErr_SetString(PYM_error, "JS_NewRuntime() failed"); - type->tp_dealloc((PyObject *) self); - self = NULL; - } else { - self->cx = JS_NewContext(self->rt, 8192); - if (!self->cx) { - PyErr_SetString(PYM_error, "JS_NewContext() failed"); - type->tp_dealloc((PyObject *) self); - self = NULL; - } - } - } - } - - return (PyObject *) self; -} - -static void -PYM_JSRuntimeDealloc(PYM_JSRuntimeObject *self) -{ - if (self->objects.ops) { - JS_DHashTableFinish(&self->objects); - self->objects.ops = NULL; - } - - if (self->cx) { - // Note that this will also force GC of any remaining objects - // in the runtime. - JS_DestroyContext(self->cx); - self->cx = NULL; - } - - if (self->rt) { - JS_DestroyRuntime(self->rt); - self->rt = NULL; - } - - self->ob_type->tp_free((PyObject *) self); -} - -static PyObject * -PYM_newContext(PYM_JSRuntimeObject *self, PyObject *args) -{ - PYM_SANITY_CHECK(self); - JSContext *cx = JS_NewContext(self->rt, 8192); - if (cx == NULL) { - PyErr_SetString(PYM_error, "JS_NewContext() failed"); - return NULL; - } - - JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_DONT_REPORT_UNCAUGHT | - JSOPTION_ATLINE | JSOPTION_STRICT); - JS_SetVersion(cx, JSVERSION_LATEST); - - PyObject *retval = (PyObject *) PYM_newJSContextObject(self, cx); - - if (retval == NULL) - JS_DestroyContext(cx); - - return retval; -} - -static PyMethodDef PYM_JSRuntimeMethods[] = { - {"new_context", (PyCFunction) PYM_newContext, METH_VARARGS, - "Create a new JavaScript context."}, - {NULL, NULL, 0, NULL} -}; - -PyTypeObject PYM_JSRuntimeType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pymonkey.Runtime", /*tp_name*/ - sizeof(PYM_JSRuntimeObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /*tp_dealloc*/ - (destructor) PYM_JSRuntimeDealloc, - 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*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - /* tp_doc */ - "JavaScript Runtime.", - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PYM_JSRuntimeMethods, /* 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 */ - PYM_JSRuntimeNew, /* tp_new */ -};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runtime.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,177 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "runtime.h" +#include "context.h" +#include "utils.h" + +static PyObject * +PYM_JSRuntimeNew(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + PYM_JSRuntimeObject *self; + + self = (PYM_JSRuntimeObject *) type->tp_alloc(type, 0); + if (self != NULL) { + self->thread = PyThread_get_thread_ident(); + self->rt = NULL; + self->cx = NULL; + self->objects.ops = NULL; + + if (!JS_DHashTableInit(&self->objects, + JS_DHashGetStubOps(), + NULL, + sizeof(PYM_HashEntry), + JS_DHASH_DEFAULT_CAPACITY(100))) { + PyErr_SetString(PYM_error, "JS_DHashTableInit() failed"); + type->tp_dealloc((PyObject *) self); + self = NULL; + } + + if (self != NULL) { + self->rt = JS_NewRuntime(8L * 1024L * 1024L); + if (!self->rt) { + PyErr_SetString(PYM_error, "JS_NewRuntime() failed"); + type->tp_dealloc((PyObject *) self); + self = NULL; + } else { + self->cx = JS_NewContext(self->rt, 8192); + if (!self->cx) { + PyErr_SetString(PYM_error, "JS_NewContext() failed"); + type->tp_dealloc((PyObject *) self); + self = NULL; + } + } + } + } + + return (PyObject *) self; +} + +static void +PYM_JSRuntimeDealloc(PYM_JSRuntimeObject *self) +{ + if (self->objects.ops) { + JS_DHashTableFinish(&self->objects); + self->objects.ops = NULL; + } + + if (self->cx) { + // Note that this will also force GC of any remaining objects + // in the runtime. + JS_DestroyContext(self->cx); + self->cx = NULL; + } + + if (self->rt) { + JS_DestroyRuntime(self->rt); + self->rt = NULL; + } + + self->ob_type->tp_free((PyObject *) self); +} + +static PyObject * +PYM_newContext(PYM_JSRuntimeObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self); + JSContext *cx = JS_NewContext(self->rt, 8192); + if (cx == NULL) { + PyErr_SetString(PYM_error, "JS_NewContext() failed"); + return NULL; + } + + JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_DONT_REPORT_UNCAUGHT | + JSOPTION_ATLINE | JSOPTION_STRICT); + JS_SetVersion(cx, JSVERSION_LATEST); + + PyObject *retval = (PyObject *) PYM_newJSContextObject(self, cx); + + if (retval == NULL) + JS_DestroyContext(cx); + + return retval; +} + +static PyMethodDef PYM_JSRuntimeMethods[] = { + {"new_context", (PyCFunction) PYM_newContext, METH_VARARGS, + "Create a new JavaScript context."}, + {NULL, NULL, 0, NULL} +}; + +PyTypeObject PYM_JSRuntimeType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pymonkey.Runtime", /*tp_name*/ + sizeof(PYM_JSRuntimeObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /*tp_dealloc*/ + (destructor) PYM_JSRuntimeDealloc, + 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*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + /* tp_doc */ + "JavaScript Runtime.", + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PYM_JSRuntimeMethods, /* 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 */ + PYM_JSRuntimeNew, /* tp_new */ +};
--- a/undefined.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "undefined.h" - -static Py_ssize_t PYM_undefinedLength(PyObject *o) { - return 0; -}; - -static PyMappingMethods PYM_undefinedAsMapping = { - PYM_undefinedLength, /*mp_length*/ - 0, /*mp_subscript*/ - 0 /*mp_ass_subscript*/ -}; - -static PyObject *PYM_undefinedRepr(PyObject *o) { - return PyString_FromString("pymonkey.undefined"); -} - -// TODO: We should make this behave as much like JavaScript's -// "undefined" value as possible; e.g., its string value should -// be "undefined", the singleton should be falsy, etc. -PyTypeObject PYM_undefinedType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pymonkey.undefined", /*tp_name*/ - sizeof(PYM_undefinedObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - PYM_undefinedRepr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - &PYM_undefinedAsMapping, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - PYM_undefinedRepr, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - /* tp_doc */ - "Pythonic equivalent of JavaScript's 'undefined' value", -}; - -PYM_undefinedObject *PYM_undefined;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/undefined.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "undefined.h" + +static Py_ssize_t PYM_undefinedLength(PyObject *o) { + return 0; +}; + +static PyMappingMethods PYM_undefinedAsMapping = { + PYM_undefinedLength, /*mp_length*/ + 0, /*mp_subscript*/ + 0 /*mp_ass_subscript*/ +}; + +static PyObject *PYM_undefinedRepr(PyObject *o) { + return PyString_FromString("pymonkey.undefined"); +} + +// TODO: We should make this behave as much like JavaScript's +// "undefined" value as possible; e.g., its string value should +// be "undefined", the singleton should be falsy, etc. +PyTypeObject PYM_undefinedType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pymonkey.undefined", /*tp_name*/ + sizeof(PYM_undefinedObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + PYM_undefinedRepr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &PYM_undefinedAsMapping, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + PYM_undefinedRepr, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + /* tp_doc */ + "Pythonic equivalent of JavaScript's 'undefined' value", +}; + +PYM_undefinedObject *PYM_undefined;
--- a/utils.c Sat Aug 15 00:50:55 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Pymonkey. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Atul Varma <atul@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "utils.h" -#include "undefined.h" -#include "object.h" - -PyObject *PYM_error; - -static int -PYM_doubleToJsval(PYM_JSContextObject *context, - double number, - jsval *rval) -{ - jsdouble *numberAsJsdouble = JS_NewDouble(context->cx, number); - if (numberAsJsdouble == NULL) { - PyErr_SetString(PYM_error, "JS_NewDouble() failed"); - return -1; - } - *rval = DOUBLE_TO_JSVAL(numberAsJsdouble); - return 0; -} - -int -PYM_pyObjectToJsval(PYM_JSContextObject *context, - PyObject *object, - jsval *rval) -{ - if (PyString_Check(object) || PyUnicode_Check(object)) { - PyObject *unicode; - if (PyString_Check(object)) { - unicode = PyUnicode_FromObject(object); - if (unicode == NULL) - return -1; - } else { - unicode = object; - Py_INCREF(unicode); - } - - PyObject *string = PyUnicode_AsUTF16String(unicode); - Py_DECREF(unicode); - if (string == NULL) - return -1; - - char *buffer = PyString_AS_STRING(string); - Py_ssize_t size = PyString_GET_SIZE(string); - - // Note that we're manipulating buffer and size here to get rid of - // the BOM. - JSString *jsString = JS_NewUCStringCopyN(context->cx, - (const jschar *) (buffer + 2), - (size / 2) - 1); - Py_DECREF(string); - if (jsString == NULL) { - PyErr_SetString(PYM_error, "JS_NewUCStringCopyN() failed"); - return -1; - } - - *rval = STRING_TO_JSVAL(jsString); - return 0; - } - - if (PyInt_Check(object)) { - long number = PyInt_AS_LONG(object); - if (INT_FITS_IN_JSVAL(number)) { - *rval = INT_TO_JSVAL(number); - return 0; - } else - return PYM_doubleToJsval(context, number, rval); - } - - if (PyFloat_Check(object)) - return PYM_doubleToJsval(context, PyFloat_AS_DOUBLE(object), rval); - - if (PyObject_TypeCheck(object, &PYM_JSObjectType)) { - PYM_JSObject *jsObject = (PYM_JSObject *) object; - JSRuntime *rt = JS_GetRuntime(context->cx); - if (rt != jsObject->runtime->rt) { - PyErr_SetString(PyExc_ValueError, - "JS object and JS context are from different " - "JS runtimes"); - return -1; - } - *rval = OBJECT_TO_JSVAL(jsObject->obj); - return 0; - } - - if (object == Py_True) { - *rval = JSVAL_TRUE; - return 0; - } - - if (object == Py_False) { - *rval = JSVAL_FALSE; - return 0; - } - - if (object == Py_None) { - *rval = JSVAL_NULL; - return 0; - } - - // TODO: Support more types. - PyErr_SetString(PyExc_NotImplementedError, - "Data type conversion not implemented."); - return -1; -} - -PyObject * -PYM_jsvalToPyObject(PYM_JSContextObject *context, - jsval value) { - if (JSVAL_IS_INT(value)) - return PyInt_FromLong(JSVAL_TO_INT(value)); - - if (JSVAL_IS_DOUBLE(value)) { - jsdouble *doubleRef = JSVAL_TO_DOUBLE(value); - return PyFloat_FromDouble(*doubleRef); - } - - if (value == JSVAL_FALSE) - Py_RETURN_FALSE; - - if (value == JSVAL_TRUE) - Py_RETURN_TRUE; - - if (JSVAL_IS_NULL(value)) - Py_RETURN_NONE; - - if (JSVAL_IS_VOID(value)) - Py_RETURN_UNDEFINED; - - if (JSVAL_IS_STRING(value)) { - // Strings in JS are funky: think of them as 16-bit versions of - // Python 2.x's 'str' type. Whether or not they're valid UTF-16 - // is entirely up to the client code. - - // TODO: Instead of ignoring errors, consider actually treating - // the string as a raw character buffer. - JSString *str = JSVAL_TO_STRING(value); - const char *chars = (const char *) JS_GetStringChars(str); - size_t length = JS_GetStringLength(str); - - // We're multiplying length by two since Python wants the number - // of bytes, not the number of 16-bit characters. - return PyUnicode_DecodeUTF16(chars, length * 2, "ignore", NULL); - } - - if (JSVAL_IS_OBJECT(value)) - return (PyObject *) PYM_newJSObject(context, JSVAL_TO_OBJECT(value), - NULL); - - // TODO: Support more types. - PyErr_SetString(PyExc_NotImplementedError, - "Data type conversion not implemented."); - return NULL; -} - -void -PYM_pythonExceptionToJs(PYM_JSContextObject *context) -{ - PyObject *type; - PyObject *value; - PyObject *traceback; - - PyErr_Fetch(&type, &value, &traceback); - - if (type == PYM_error && value && - PyObject_HasAttrString(value, "message")) { - jsval val; - PyObject *message = PyObject_GetAttrString(value, "message"); - if (message && PYM_pyObjectToJsval(context, message, &val) == 0) { - JS_SetPendingException(context->cx, val); - } else - JS_ReportError(context->cx, - "Python exception occurred, but exception " - "couldn't be converted"); - Py_XDECREF(message); - } else { - if (value) { - JSObject *exception = PYM_JS_newObject(context->cx, value); - if (exception) - JS_SetPendingException(context->cx, OBJECT_TO_JSVAL(exception)); - else - JS_ReportOutOfMemory(context->cx); - } else - JS_ReportError(context->cx, "Python exception occurred"); - } - - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); -} - -void -PYM_jsExceptionToPython(PYM_JSContextObject *context) -{ - if (!JS_IsExceptionPending(context->cx) && - PyErr_Occurred()) - return; - - jsval val; - if (JS_GetPendingException(context->cx, &val)) { - PyObject *obj = PYM_jsvalToPyObject(context, val); - if (obj) { - PyErr_SetObject(PYM_error, obj); - Py_DECREF(obj); - } else { - PyErr_Clear(); - - JSString *str = NULL; - - Py_BEGIN_ALLOW_THREADS; - str = JS_ValueToString(context->cx, val); - Py_END_ALLOW_THREADS; - - if (str != NULL) { - const char *chars = JS_GetStringBytes(str); - PyErr_SetString(PYM_error, chars); - } else - PyErr_SetString(PYM_error, "JS exception occurred"); - } - } else - PyErr_SetString(PYM_error, "JS_GetPendingException() failed"); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils.cpp Sat Aug 15 10:24:17 2009 -0700 @@ -0,0 +1,257 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Pymonkey. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "utils.h" +#include "undefined.h" +#include "object.h" + +PyObject *PYM_error; + +static int +PYM_doubleToJsval(PYM_JSContextObject *context, + double number, + jsval *rval) +{ + jsdouble *numberAsJsdouble = JS_NewDouble(context->cx, number); + if (numberAsJsdouble == NULL) { + PyErr_SetString(PYM_error, "JS_NewDouble() failed"); + return -1; + } + *rval = DOUBLE_TO_JSVAL(numberAsJsdouble); + return 0; +} + +int +PYM_pyObjectToJsval(PYM_JSContextObject *context, + PyObject *object, + jsval *rval) +{ + if (PyString_Check(object) || PyUnicode_Check(object)) { + PyObject *unicode; + if (PyString_Check(object)) { + unicode = PyUnicode_FromObject(object); + if (unicode == NULL) + return -1; + } else { + unicode = object; + Py_INCREF(unicode); + } + + PyObject *string = PyUnicode_AsUTF16String(unicode); + Py_DECREF(unicode); + if (string == NULL) + return -1; + + char *buffer = PyString_AS_STRING(string); + Py_ssize_t size = PyString_GET_SIZE(string); + + // Note that we're manipulating buffer and size here to get rid of + // the BOM. + JSString *jsString = JS_NewUCStringCopyN(context->cx, + (const jschar *) (buffer + 2), + (size / 2) - 1); + Py_DECREF(string); + if (jsString == NULL) { + PyErr_SetString(PYM_error, "JS_NewUCStringCopyN() failed"); + return -1; + } + + *rval = STRING_TO_JSVAL(jsString); + return 0; + } + + if (PyInt_Check(object)) { + long number = PyInt_AS_LONG(object); + if (INT_FITS_IN_JSVAL(number)) { + *rval = INT_TO_JSVAL(number); + return 0; + } else + return PYM_doubleToJsval(context, number, rval); + } + + if (PyFloat_Check(object)) + return PYM_doubleToJsval(context, PyFloat_AS_DOUBLE(object), rval); + + if (PyObject_TypeCheck(object, &PYM_JSObjectType)) { + PYM_JSObject *jsObject = (PYM_JSObject *) object; + JSRuntime *rt = JS_GetRuntime(context->cx); + if (rt != jsObject->runtime->rt) { + PyErr_SetString(PyExc_ValueError, + "JS object and JS context are from different " + "JS runtimes"); + return -1; + } + *rval = OBJECT_TO_JSVAL(jsObject->obj); + return 0; + } + + if (object == Py_True) { + *rval = JSVAL_TRUE; + return 0; + } + + if (object == Py_False) { + *rval = JSVAL_FALSE; + return 0; + } + + if (object == Py_None) { + *rval = JSVAL_NULL; + return 0; + } + + // TODO: Support more types. + PyErr_SetString(PyExc_NotImplementedError, + "Data type conversion not implemented."); + return -1; +} + +PyObject * +PYM_jsvalToPyObject(PYM_JSContextObject *context, + jsval value) { + if (JSVAL_IS_INT(value)) + return PyInt_FromLong(JSVAL_TO_INT(value)); + + if (JSVAL_IS_DOUBLE(value)) { + jsdouble *doubleRef = JSVAL_TO_DOUBLE(value); + return PyFloat_FromDouble(*doubleRef); + } + + if (value == JSVAL_FALSE) + Py_RETURN_FALSE; + + if (value == JSVAL_TRUE) + Py_RETURN_TRUE; + + if (JSVAL_IS_NULL(value)) + Py_RETURN_NONE; + + if (JSVAL_IS_VOID(value)) + Py_RETURN_UNDEFINED; + + if (JSVAL_IS_STRING(value)) { + // Strings in JS are funky: think of them as 16-bit versions of + // Python 2.x's 'str' type. Whether or not they're valid UTF-16 + // is entirely up to the client code. + + // TODO: Instead of ignoring errors, consider actually treating + // the string as a raw character buffer. + JSString *str = JSVAL_TO_STRING(value); + const char *chars = (const char *) JS_GetStringChars(str); + size_t length = JS_GetStringLength(str); + + // We're multiplying length by two since Python wants the number + // of bytes, not the number of 16-bit characters. + return PyUnicode_DecodeUTF16(chars, length * 2, "ignore", NULL); + } + + if (JSVAL_IS_OBJECT(value)) + return (PyObject *) PYM_newJSObject(context, JSVAL_TO_OBJECT(value), + NULL); + + // TODO: Support more types. + PyErr_SetString(PyExc_NotImplementedError, + "Data type conversion not implemented."); + return NULL; +} + +void +PYM_pythonExceptionToJs(PYM_JSContextObject *context) +{ + PyObject *type; + PyObject *value; + PyObject *traceback; + + PyErr_Fetch(&type, &value, &traceback); + + if (type == PYM_error && value && + PyObject_HasAttrString(value, "message")) { + jsval val; + PyObject *message = PyObject_GetAttrString(value, "message"); + if (message && PYM_pyObjectToJsval(context, message, &val) == 0) { + JS_SetPendingException(context->cx, val); + } else + JS_ReportError(context->cx, + "Python exception occurred, but exception " + "couldn't be converted"); + Py_XDECREF(message); + } else { + if (value) { + JSObject *exception = PYM_JS_newObject(context->cx, value); + if (exception) + JS_SetPendingException(context->cx, OBJECT_TO_JSVAL(exception)); + else + JS_ReportOutOfMemory(context->cx); + } else + JS_ReportError(context->cx, "Python exception occurred"); + } + + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); +} + +void +PYM_jsExceptionToPython(PYM_JSContextObject *context) +{ + if (!JS_IsExceptionPending(context->cx) && + PyErr_Occurred()) + return; + + jsval val; + if (JS_GetPendingException(context->cx, &val)) { + PyObject *obj = PYM_jsvalToPyObject(context, val); + if (obj) { + PyErr_SetObject(PYM_error, obj); + Py_DECREF(obj); + } else { + PyErr_Clear(); + + JSString *str = NULL; + + Py_BEGIN_ALLOW_THREADS; + str = JS_ValueToString(context->cx, val); + Py_END_ALLOW_THREADS; + + if (str != NULL) { + const char *chars = JS_GetStringBytes(str); + PyErr_SetString(PYM_error, chars); + } else + PyErr_SetString(PYM_error, "JS exception occurred"); + } + } else + PyErr_SetString(PYM_error, "JS_GetPendingException() failed"); +}