changeset 152:80463c8c7930

Added a 'name' property to function obects. Fixed a TODO.
author Atul Varma <varmaa@toolness.com>
date Sat, 29 Aug 2009 22:46:48 -0700
parents 657afb7307eb
children 9ea6a9a566e2
files src/context.cpp src/function.cpp src/function.h src/object.cpp tests/test_pymonkey.py
diffstat 5 files changed, 82 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/context.cpp	Sat Aug 29 14:06:03 2009 -0700
+++ b/src/context.cpp	Sat Aug 29 22:46:48 2009 -0700
@@ -564,15 +564,11 @@
   }
 
   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);
+  result = JS_CallFunctionValue(self->cx, obj->obj,
+                                OBJECT_TO_JSVAL(fun->base.obj),
+                                argc, argv, &rval);
   Py_END_ALLOW_THREADS;
 
   PyMem_Free(argv);
--- a/src/function.cpp	Sat Aug 29 14:06:03 2009 -0700
+++ b/src/function.cpp	Sat Aug 29 22:46:48 2009 -0700
@@ -37,9 +37,18 @@
 #include "function.h"
 #include "utils.h"
 
+#include "structmember.h"
+
 static void
 PYM_JSFunctionDealloc(PYM_JSFunction *self)
 {
+  self->fun = NULL;
+
+  if (self->name) {
+    Py_DECREF(self->name);
+    self->name = NULL;
+  }
+
   PYM_JSObjectType.tp_dealloc((PyObject *) self);
 }
 
@@ -124,6 +133,12 @@
   return JS_TRUE;
 }
 
+static PyMemberDef PYM_members[] = {
+  {"name", T_OBJECT, offsetof(PYM_JSFunction, name), READONLY,
+   "Name of the function."},
+  {NULL, NULL, NULL, NULL, NULL}
+};
+
 PyTypeObject PYM_JSFunctionType = {
   PyObject_HEAD_INIT(NULL)
   0,                           /*ob_size*/
@@ -157,7 +172,7 @@
   0,                           /* tp_iter */
   0,                           /* tp_iternext */
   0,                           /* tp_methods */
-  0,                           /* tp_members */
+  PYM_members,                 /* tp_members */
   0,                           /* tp_getset */
   0,                           /* tp_base */
   0,                           /* tp_dict */
@@ -170,6 +185,33 @@
 };
 
 PYM_JSFunction *
+PYM_newJSFunction(PYM_JSContextObject *context,
+                  JSFunction *function)
+{
+  PYM_JSFunction *jsFunction = PyObject_New(PYM_JSFunction,
+                                            &PYM_JSFunctionType);
+  if (jsFunction == NULL)
+    return NULL;
+
+  jsFunction->fun = function;
+
+  JSString *name = JS_GetFunctionId(jsFunction->fun);
+  if (name == NULL) {
+    // It's an anonymous function.
+    jsFunction->name = NULL;
+  } else {
+    jsFunction->name = PYM_jsvalToPyObject(context,
+                                           STRING_TO_JSVAL(name));
+    if (jsFunction->name == NULL) {
+      Py_DECREF((PyObject *) jsFunction);
+      return NULL;
+    }
+  }
+
+  return jsFunction;
+}
+
+PYM_JSFunction *
 PYM_newJSFunctionFromCallable(PYM_JSContextObject *context,
                               PyObject *callable,
                               const char *name)
@@ -195,8 +237,7 @@
     return NULL;
   }
 
-  PYM_JSFunction *object = PyObject_New(PYM_JSFunction,
-                                        &PYM_JSFunctionType);
+  PYM_JSFunction *object = PYM_newJSFunction(context, func);
   if (object == NULL)
     return NULL;
 
--- a/src/function.h	Sat Aug 29 14:06:03 2009 -0700
+++ b/src/function.h	Sat Aug 29 22:46:48 2009 -0700
@@ -45,11 +45,17 @@
 
 typedef struct {
   PYM_JSObject base;
+  JSFunction *fun;
+  PyObject *name;
 } PYM_JSFunction;
 
 extern PyTypeObject PYM_JSFunctionType;
 
 extern PYM_JSFunction *
+PYM_newJSFunction(PYM_JSContextObject *context,
+                  JSFunction *function);
+
+extern PYM_JSFunction *
 PYM_newJSFunctionFromCallable(PYM_JSContextObject *context,
                               PyObject *callable,
                               const char *name);
--- a/src/object.cpp	Sat Aug 29 14:06:03 2009 -0700
+++ b/src/object.cpp	Sat Aug 29 22:46:48 2009 -0700
@@ -209,8 +209,10 @@
     object = subclass;
   else {
     if (JS_ObjectIsFunction(context->cx, obj)) {
-      PYM_JSFunction *func = PyObject_New(PYM_JSFunction,
-                                          &PYM_JSFunctionType);
+      PYM_JSFunction *func = PYM_newJSFunction(
+        context,
+        JS_ValueToFunction(context->cx, OBJECT_TO_JSVAL(obj))
+        );
       object = (PYM_JSObject *) func;
     } else
       object = PyObject_New(PYM_JSObject,
--- a/tests/test_pymonkey.py	Sat Aug 29 14:06:03 2009 -0700
+++ b/tests/test_pymonkey.py	Sat Aug 29 22:46:48 2009 -0700
@@ -125,6 +125,7 @@
                           stuff['rt'].new_context)
         self.assertEqual(self.last_exception.args[0],
                          'Function called from wrong thread')
+        del stuff['rt']
 
     def testClearObjectPrivateWorks(self):
         class Foo(object):
@@ -251,6 +252,30 @@
         del obj
         self.assertEqual(ref(), None)
 
+    def testAnonymousJsFunctionHasNullNameAttribute(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.evaluate_script(obj, "(function() {})",
+                                    "<string>", 1)
+        self.assertEqual(jsfunc.name, None)
+
+    def testJsFunctionHasNameAttribute(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.evaluate_script(obj, "(function blarg() {})",
+                                    "<string>", 1)
+        self.assertEqual(jsfunc.name, "blarg")
+
+    def testJsWrappedPythonFuncHasNameAttribute(self):
+        def func(cx, this, args):
+            return True
+
+        cx = pymonkey.Runtime().new_context()
+        jsfunc = cx.new_function(func, "foo")
+        self.assertEqual(jsfunc.name, "foo")
+
     def testJsWrappedPythonFuncIsGCdAtRuntimeDestruction(self):
         def define(cx, obj):
             def func(cx, this, args):