# HG changeset patch # User Atul Varma # Date 1251655980 25200 # Node ID 5ec81091cb890aa4451abd66d5ff8c50e9846e9f # Parent 9ea6a9a566e2a311528ec94a0bf85b7eb329dadd Added filename/line-number metadata to functions. Wanted to just add a 'script' property but this proved problematic--see the TODO in the code for more information. diff -r 9ea6a9a566e2 -r 5ec81091cb89 src/function.cpp --- a/src/function.cpp Sun Aug 30 10:54:56 2009 -0700 +++ b/src/function.cpp Sun Aug 30 11:13:00 2009 -0700 @@ -37,12 +37,14 @@ #include "function.h" #include "utils.h" +#include "jsdbgapi.h" #include "structmember.h" static void PYM_JSFunctionDealloc(PYM_JSFunction *self) { self->fun = NULL; + self->filename = NULL; if (self->name) { Py_DECREF(self->name); @@ -136,6 +138,12 @@ static PyMemberDef PYM_members[] = { {"name", T_OBJECT, offsetof(PYM_JSFunction, name), READONLY, "Name of the function."}, + {"filename", T_STRING, offsetof(PYM_JSFunction, filename), READONLY, + "Filename of function's source code."}, + {"base_lineno", T_UINT, offsetof(PYM_JSFunction, baseLineno), READONLY, + "Base line number of function's source code."}, + {"line_extent", T_UINT, offsetof(PYM_JSFunction, lineExtent), READONLY, + "Line extent of function's source code."}, {NULL, NULL, NULL, NULL, NULL} }; @@ -194,12 +202,14 @@ return NULL; jsFunction->fun = function; + jsFunction->name = NULL; + jsFunction->filename = NULL; + jsFunction->baseLineno = 0; + jsFunction->lineExtent = 0; JSString *name = JS_GetFunctionId(jsFunction->fun); - if (name == NULL) { - // It's an anonymous function. - jsFunction->name = NULL; - } else { + if (name != NULL) { + // It's not an anonymous function. jsFunction->name = PYM_jsvalToPyObject(context, STRING_TO_JSVAL(name)); if (jsFunction->name == NULL) { @@ -208,6 +218,19 @@ } } + JSScript *script = JS_GetFunctionScript(context->cx, jsFunction->fun); + + // TODO: Ideally, we'd convert the script to an object and set it as + // an attribute of the function, but this results in strange segfaults, + // perhaps because JS functions destroy their scripts on finalization + // while creating an object from a script makes it subject to GC. + if (script) { + // It's an interpreted function. + jsFunction->filename = JS_GetScriptFilename(context->cx, script); + jsFunction->baseLineno = JS_GetScriptBaseLineNumber(context->cx, script); + jsFunction->lineExtent = JS_GetScriptLineExtent(context->cx, script); + } + return jsFunction; } diff -r 9ea6a9a566e2 -r 5ec81091cb89 src/function.h --- a/src/function.h Sun Aug 30 10:54:56 2009 -0700 +++ b/src/function.h Sun Aug 30 11:13:00 2009 -0700 @@ -47,6 +47,9 @@ PYM_JSObject base; JSFunction *fun; PyObject *name; + const char *filename; + unsigned int baseLineno; + unsigned int lineExtent; } PYM_JSFunction; extern PyTypeObject PYM_JSFunctionType; diff -r 9ea6a9a566e2 -r 5ec81091cb89 tests/test_pymonkey.py --- a/tests/test_pymonkey.py Sun Aug 30 10:54:56 2009 -0700 +++ b/tests/test_pymonkey.py Sun Aug 30 11:13:00 2009 -0700 @@ -660,6 +660,17 @@ self.assertTrue(isinstance(obj, pymonkey.Object)) self.assertEqual(cx.get_property(obj, u"boop"), 1) + def testScriptedFunctionsHaveFilenameInfo(self): + cx = pymonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.evaluate_script(obj, + '(function boop() { \nreturn 1; })', + 'somefile', 5) + self.assertEqual(jsfunc.filename, 'somefile') + self.assertEqual(jsfunc.base_lineno, 5) + self.assertEqual(jsfunc.line_extent, 2) + def testEvaluateReturnsFunction(self): cx = pymonkey.Runtime().new_context() obj = cx.new_object()