21
21
22
22
const char PyIterableProxyHandler::family = 0 ;
23
23
24
+ // TODO merge shared _next code
25
+
24
26
bool PyIterableProxyHandler::iterable_next (JSContext *cx, unsigned argc, JS::Value *vp) {
25
27
JS::CallArgs args = JS::CallArgsFromVp (argc, vp);
26
28
JS::RootedObject thisObj (cx);
@@ -41,7 +43,7 @@ bool PyIterableProxyHandler::iterable_next(JSContext *cx, unsigned argc, JS::Val
41
43
PyErr_Clear ();
42
44
}
43
45
else {
44
- return NULL ;
46
+ return false ;
45
47
}
46
48
}
47
49
@@ -66,10 +68,139 @@ JSMethodDef PyIterableProxyHandler::iterable_methods[] = {
66
68
{NULL , NULL , 0 }
67
69
};
68
70
71
+
72
+ // IterableIterator
73
+
74
+ enum {
75
+ IterableIteratorSlotIterableObject,
76
+ IterableIteratorSlotCount
77
+ };
78
+
79
+ static JSClass iterableIteratorClass = {" IterableIterator" , JSCLASS_HAS_RESERVED_SLOTS (IterableIteratorSlotCount)};
80
+
81
+ static bool iterator_next (JSContext *cx, unsigned argc, JS::Value *vp) {
82
+ JS::CallArgs args = JS::CallArgsFromVp (argc, vp);
83
+ JS::RootedObject thisObj (cx);
84
+ if (!args.computeThis (cx, &thisObj)) return false ;
85
+
86
+ PyObject *it = JS::GetMaybePtrFromReservedSlot<PyObject>(thisObj, IterableIteratorSlotIterableObject);
87
+
88
+ JS::RootedObject result (cx, JS_NewPlainObject (cx));
89
+
90
+ PyObject *(*iternext)(PyObject *) = *Py_TYPE (it)->tp_iternext ;
91
+
92
+ PyObject *item = iternext (it);
93
+
94
+ if (item == NULL ) {
95
+ if (PyErr_Occurred ()) {
96
+ if (PyErr_ExceptionMatches (PyExc_StopIteration) ||
97
+ PyErr_ExceptionMatches (PyExc_SystemError)) { // TODO this handles a result like SystemError: Objects/dictobject.c:1778: bad argument to internal function. Why are we getting that?
98
+ PyErr_Clear ();
99
+ }
100
+ else {
101
+ return false ;
102
+ }
103
+ }
104
+
105
+ JS::RootedValue done (cx, JS::BooleanValue (true ));
106
+ if (!JS_SetProperty (cx, result, " done" , done)) return false ;
107
+ args.rval ().setObject (*result);
108
+ return result;
109
+ }
110
+
111
+ JS::RootedValue done (cx, JS::BooleanValue (false ));
112
+ if (!JS_SetProperty (cx, result, " done" , done)) return false ;
113
+
114
+ JS::RootedValue value (cx, jsTypeFactory (cx, item));
115
+ if (!JS_SetProperty (cx, result, " value" , value)) return false ;
116
+
117
+ args.rval ().setObject (*result);
118
+ return true ;
119
+ }
120
+
121
+ static JSFunctionSpec iterable_iterator_methods[] = {
122
+ JS_FN (" next" , iterator_next, 0 , JSPROP_ENUMERATE),
123
+ JS_FS_END
124
+ };
125
+
126
+ static bool IterableIteratorConstructor (JSContext *cx, unsigned argc, JS::Value *vp) {
127
+ JS::CallArgs args = JS::CallArgsFromVp (argc, vp);
128
+
129
+ if (!args.isConstructing ()) {
130
+ JS_ReportErrorASCII (cx, " You must call this constructor with 'new'" );
131
+ return false ;
132
+ }
133
+
134
+ JS::RootedObject thisObj (cx, JS_NewObjectForConstructor (cx, &iterableIteratorClass, args));
135
+ if (!thisObj) {
136
+ return false ;
137
+ }
138
+
139
+ args.rval ().setObject (*thisObj);
140
+ return true ;
141
+ }
142
+
143
+ static bool DefineIterableIterator (JSContext *cx, JS::HandleObject global) {
144
+ JS::RootedObject iteratorPrototype (cx);
145
+ if (!JS_GetClassPrototype (cx, JSProto_Iterator, &iteratorPrototype)) {
146
+ return false ;
147
+ }
148
+
149
+ JS::RootedObject protoObj (cx,
150
+ JS_InitClass (cx, global,
151
+ nullptr , iteratorPrototype,
152
+ " IterableIterator" ,
153
+ IterableIteratorConstructor, 0 ,
154
+ nullptr , iterable_iterator_methods,
155
+ nullptr , nullptr )
156
+ );
157
+
158
+ return protoObj; // != nullptr
159
+ }
160
+
161
+ static bool iterable_values (JSContext *cx, unsigned argc, JS::Value *vp) {
162
+ JS::CallArgs args = JS::CallArgsFromVp (argc, vp);
163
+
164
+ JS::RootedObject proxy (cx, JS::ToObject (cx, args.thisv ()));
165
+ if (!proxy) {
166
+ return false ;
167
+ }
168
+
169
+ PyObject *self = JS::GetMaybePtrFromReservedSlot<PyObject>(proxy, PyObjectSlot);
170
+
171
+ JS::RootedObject global (cx, JS::GetNonCCWObjectGlobal (proxy));
172
+
173
+ JS::RootedValue constructor_val (cx);
174
+ if (!JS_GetProperty (cx, global, " IterableIterator" , &constructor_val)) return false ;
175
+ if (!constructor_val.isObject ()) {
176
+ if (!DefineIterableIterator (cx, global)) {
177
+ return false ;
178
+ }
179
+
180
+ if (!JS_GetProperty (cx, global, " IterableIterator" , &constructor_val)) return false ;
181
+ if (!constructor_val.isObject ()) {
182
+ JS_ReportErrorASCII (cx, " IterableIterator is not a constructor" );
183
+ return false ;
184
+ }
185
+ }
186
+ JS::RootedObject constructor (cx, &constructor_val.toObject ());
187
+
188
+ JS::RootedObject obj (cx);
189
+ if (!JS::Construct (cx, constructor_val, JS::HandleValueArray::empty (), &obj)) return false ;
190
+ if (!obj) return false ;
191
+
192
+ JS::SetReservedSlot (obj, IterableIteratorSlotIterableObject, JS::PrivateValue ((void *)self));
193
+
194
+ args.rval ().setObject (*obj);
195
+ return true ;
196
+ }
197
+
69
198
bool PyIterableProxyHandler::getOwnPropertyDescriptor (
70
199
JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
71
200
JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc
72
201
) const {
202
+
203
+ // see if we're calling a function
73
204
if (id.isString ()) {
74
205
for (size_t index = 0 ;; index ++) {
75
206
bool isThatFunction;
@@ -92,6 +223,24 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor(
92
223
}
93
224
}
94
225
226
+ // symbol property
227
+ if (id.isSymbol ()) {
228
+ JS::RootedSymbol rootedSymbol (cx, id.toSymbol ());
229
+
230
+ if (JS::GetSymbolCode (rootedSymbol) == JS::SymbolCode::iterator) {
231
+ JSFunction *newFunction = JS_NewFunction (cx, iterable_values, 0 , 0 , NULL );
232
+ if (!newFunction) return false ;
233
+ JS::RootedObject funObj (cx, JS_GetFunctionObject (newFunction));
234
+ desc.set (mozilla::Some (
235
+ JS::PropertyDescriptor::Data (
236
+ JS::ObjectValue (*funObj),
237
+ {JS::PropertyAttribute::Enumerable}
238
+ )
239
+ ));
240
+ return true ;
241
+ }
242
+ }
243
+
95
244
PyObject *attrName = idToKey (cx, id);
96
245
PyObject *self = JS::GetMaybePtrFromReservedSlot<PyObject>(proxy, PyObjectSlot);
97
246
PyObject *item = PyDict_GetItemWithError (self, attrName);
0 commit comments