Subj : Re: Binding a global object (again) To : netscape.public.mozilla.jseng From : John J Lee Date : Sun Aug 31 2003 04:16 am On Sat, 30 Aug 2003, Brendan Eich wrote: > John J. Lee wrote: > > > Brendan Eich writes: [...] > You mentioned lookupProperty, that's only in JSObjectOps. There is no > struct named JSPropertyOps, so I'm not sure what you mean here. Sorry -- I did mean JSObjectOps. [...] > Can you show some code and say how it fails to work the way you > expect? It's written in Pyrex, so here is the relevant part of the code translated to C (Pyrex is -- roughly -- Python + C types, and compiles to C code, containing the JS API calls, which pass through essentially undigested, and piles of dull-as-ditchwater Python C API calls and associated refcounting / error handling). What I expecting was that, when new_context was called with a non-NULL obj argument, the JS global object created there would have its JSClass's getProperty function (get_property) called when I evaluate a script like "name;". This would allow me, in get_property, to look up on the corresponding Python object (the obj argument to new_context) the value of the Python attribute named "name". What actually happens is that get_property never gets called, and instead I get this error from the JS engine: ReferenceError: name is not defined OTOH, evaluating "window.name;" causes get_property to be called first for "window", then for "name", as I expected. Any clues are much appreciated! // Snipped Python code is indicated by comments like so: // (description of what Python code does goes here) // trivial global object JSClass for use in the case where no Python // object is bound to the JS global object static JSClass global_class = { "GlobalClass", 0, JS_PropertyStub, // JSPropertyOp addProperty; JS_PropertyStub, // JSPropertyOp delProperty; JS_PropertyStub, // JSPropertyOp getProperty; JS_PropertyStub, // JSPropertyOp setProperty; JS_EnumerateStub, // JSEnumerateOp enumerate; JS_ResolveStub, // JSResolveOp resolve; JS_ConvertStub, // JSConvertOp convert; JS_FinalizeStub // JSFinalizeOp finalize; }; // The following structs also represent Python classes. struct Runtime { PyObject_HEAD struct JSRuntime (*rt); //... }; struct Context { PyObject_HEAD struct JSContext (*cx); struct JSObject (*globj); struct Runtime *rt; //... }; struct Class { PyObject_HEAD struct JSClass (*jsclass); PyObject *klass; }; // the object pointed to by self arg is created by Pyrex static int new_context(struct Context *self, struct Runtime *rt, PyObject *globj, char *globj_name) { struct Class *c; self->cx = JS_NewContext(rt->rt, STACK_CHUNK_SIZE); if (self->cx == NULL) // raise Python exception if (globj) { // We're binding a Python object to JS proxy that is to be the JS // global object. c = new_class(globj, is_global); // (keep references to Python class (extracted from obj with // Python C API function) and proxy (c->jsclass)) self->jsglobj = JS_NewObject(self->cx, c->jsclass, NULL, NULL); if (self->jsglobj == NULL) // (raise Python exception) // (keep references to Python object (obj) and proxy (self->jsobj)) if (globj_name != NULL) // we want to create an alias to the global object -- eg. "window" // JS_DefineProperty(self->cx, self->jsglobj, globj_name, // OBJECT_TO_JSVAL(self->jsglobj), NULL, NULL, 0); } else { // We're binding a Python object to any other JS proxy. self->jsglobj = JS_NewObject(self->cx, &global_class, 0, 0); if (self->jsglobj == NULL) // (raise Python exception) } if (! JS_InitStandardClasses(self->cx, self->jsglobj)) // (raise Python exception) JS_SetErrorReporter(self->cx, report_error); // functions just contains a print function ATM if (! JS_DefineFunctions(self->cx, self->jsglobj, functions)) // (raise Python exception) // (Pyrex returns) } // the object pointed to by self arg is created by Pyrex static int new_class(struct Class *self, PyObject *obj, bool bind_constructor) { JSObject *base_obj; char *name; self->jsclass = (JSClass *) xmalloc(sizeof(JSClass)); // (ask Python object for name under which to bind to JS) self->jsc->name = (char *) xmalloc(strlen(name)+1); strcpy(self->jsc->name, name); self->jsclass->flags = 0; self->jsclass->addProperty = JS_PropertyStub; self->jsclass->delProperty = JS_PropertyStub; self->jsclass->getProperty = get_property; self->jsclass->setProperty = set_property; self->jsclass->enumerate = JS_EnumerateStub; self->jsclass->resolve = JS_ResolveStub; self->jsclass->convert = JS_ConvertStub; self->jsclass->finalize = JS_FinalizeStub; self->jsclass->getObjectOps = NULL; self->jsclass->checkAccess = NULL; self->jsclass->call = NULL; self->jsclass->construct = NULL; self->jsclass->xdrObject = NULL; self->jsclass->hasInstance = NULL; self->jsclass->mark = NULL; self->jsclass->spare = 0; if (bind_constructor) if (JS_InitClass(context.cx, context->jsglobj, NULL, self->jsclass, constructor_cb, 0, NULL, NULL, NULL, NULL) == NULL) // (raise Python exception) } John .