@@ -66,8 +66,48 @@ static bool iterable_next(JSContext *cx, unsigned argc, JS::Value *vp) {
66
66
return iter_next (cx, args, it);
67
67
}
68
68
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
+
69
108
JSMethodDef PyIterableProxyHandler::iterable_methods[] = {
70
109
{" next" , iterable_next, 0 },
110
+ {" valueOf" , iterable_valueOf, 0 },
71
111
{NULL , NULL , 0 }
72
112
};
73
113
@@ -172,7 +212,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
172
212
JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
173
213
JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc
174
214
) const {
175
-
176
215
// see if we're calling a function
177
216
if (id.isString ()) {
178
217
for (size_t index = 0 ;; index++) {
@@ -196,11 +235,38 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
196
235
}
197
236
}
198
237
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
+
199
264
// symbol property
200
265
if (id.isSymbol ()) {
201
266
JS::RootedSymbol rootedSymbol (cx, id.toSymbol ());
267
+ JS::SymbolCode symbolCode = JS::GetSymbolCode (rootedSymbol);
202
268
203
- if (JS::GetSymbolCode (rootedSymbol) == JS::SymbolCode::iterator) {
269
+ if (symbolCode == JS::SymbolCode::iterator) {
204
270
JSFunction *newFunction = JS_NewFunction (cx, iterable_values, 0 , 0 , NULL );
205
271
if (!newFunction) return false ;
206
272
JS::RootedObject funObj (cx, JS_GetFunctionObject (newFunction));
@@ -211,6 +277,18 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
211
277
)
212
278
));
213
279
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 ;
214
292
}
215
293
}
216
294
0 commit comments