@@ -66,8 +66,48 @@ static bool iterable_next(JSContext *cx, unsigned argc, JS::Value *vp) {
6666 return iter_next (cx, args, it);
6767}
6868
69+ static bool toPrimitive (JSContext *cx, unsigned argc, JS::Value *vp) {
70+ JS::CallArgs args = JS::CallArgsFromVp (argc, vp);
71+
72+ JS::RootedObject proxy (cx, JS::ToObject (cx, args.thisv ()));
73+ if (!proxy) {
74+ return false ;
75+ }
76+
77+ PyObject *self = JS::GetMaybePtrFromReservedSlot<PyObject>(proxy, PyObjectSlot);
78+
79+ _PyUnicodeWriter writer;
80+
81+ _PyUnicodeWriter_Init (&writer);
82+
83+ PyObject *s = PyObject_Repr (self);
84+
85+ if (s == nullptr ) {
86+ args.rval ().setString (JS_NewStringCopyZ (cx, " <cannot repr type>" ));
87+ return true ;
88+ }
89+
90+ int res = _PyUnicodeWriter_WriteStr (&writer, s);
91+ Py_DECREF (s);
92+
93+ if (res < 0 ) {
94+ args.rval ().setString (JS_NewStringCopyZ (cx, " <cannot repr type>" ));
95+ return true ;
96+ }
97+
98+ PyObject* repr = _PyUnicodeWriter_Finish (&writer);
99+
100+ args.rval ().set (jsTypeFactory (cx, repr));
101+ return true ;
102+ }
103+
104+ static bool iterable_valueOf (JSContext *cx, unsigned argc, JS::Value *vp) {
105+ return toPrimitive (cx, argc, vp);
106+ }
107+
69108JSMethodDef PyIterableProxyHandler::iterable_methods[] = {
70109 {" next" , iterable_next, 0 },
110+ {" valueOf" , iterable_valueOf, 0 },
71111 {NULL , NULL , 0 }
72112};
73113
@@ -172,7 +212,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
172212 JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
173213 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc
174214) const {
175-
176215 // see if we're calling a function
177216 if (id.isString ()) {
178217 for (size_t index = 0 ;; index++) {
@@ -196,11 +235,38 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
196235 }
197236 }
198237
238+ // "constructor" property
239+ bool isConstructorProperty;
240+ if (id.isString () && JS_StringEqualsLiteral (cx, id.toString (), " constructor" , &isConstructorProperty) && isConstructorProperty) {
241+ JS::RootedObject global (cx, JS::GetNonCCWObjectGlobal (proxy));
242+
243+ JS::RootedObject rootedObjectPrototype (cx);
244+ if (!JS_GetClassPrototype (cx, JSProto_Object, &rootedObjectPrototype)) {
245+ return false ;
246+ }
247+
248+ JS::RootedValue Object_Prototype_Constructor (cx);
249+ if (!JS_GetProperty (cx, rootedObjectPrototype, " constructor" , &Object_Prototype_Constructor)) {
250+ return false ;
251+ }
252+
253+ JS::RootedObject rootedObjectPrototypeConstructor (cx, Object_Prototype_Constructor.toObjectOrNull ());
254+
255+ desc.set (mozilla::Some (
256+ JS::PropertyDescriptor::Data (
257+ JS::ObjectValue (*rootedObjectPrototypeConstructor),
258+ {JS::PropertyAttribute::Enumerable}
259+ )
260+ ));
261+ return true ;
262+ }
263+
199264 // symbol property
200265 if (id.isSymbol ()) {
201266 JS::RootedSymbol rootedSymbol (cx, id.toSymbol ());
267+ JS::SymbolCode symbolCode = JS::GetSymbolCode (rootedSymbol);
202268
203- if (JS::GetSymbolCode (rootedSymbol) == JS::SymbolCode::iterator) {
269+ if (symbolCode == JS::SymbolCode::iterator) {
204270 JSFunction *newFunction = JS_NewFunction (cx, iterable_values, 0 , 0 , NULL );
205271 if (!newFunction) return false ;
206272 JS::RootedObject funObj (cx, JS_GetFunctionObject (newFunction));
@@ -211,6 +277,18 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
211277 )
212278 ));
213279 return true ;
280+ }
281+ else if (symbolCode == JS::SymbolCode::toPrimitive) {
282+ JSFunction *newFunction = JS_NewFunction (cx, toPrimitive, 0 , 0 , nullptr );
283+ if (!newFunction) return false ;
284+ JS::RootedObject funObj (cx, JS_GetFunctionObject (newFunction));
285+ desc.set (mozilla::Some (
286+ JS::PropertyDescriptor::Data (
287+ JS::ObjectValue (*funObj),
288+ {JS::PropertyAttribute::Enumerable}
289+ )
290+ ));
291+ return true ;
214292 }
215293 }
216294
0 commit comments