Content-Length: 569445 | pFad | http://github.com/micropython/micropython/commit/c056840ee8f7a154ff437a335eb4a83f14d47f0f

C8 webassembly/objpyproxy: Implement JS iterator protocol for Py iterables. · micropython/micropython@c056840 · GitHub
Skip to content

Commit c056840

Browse files
committed
webassembly/objpyproxy: Implement JS iterator protocol for Py iterables.
This allows using JavaScript for..of on Python iterables. Signed-off-by: Damien George <damien@micropython.org>
1 parent e860e32 commit c056840

File tree

5 files changed

+97
-4
lines changed

5 files changed

+97
-4
lines changed

Diff for: ports/webassembly/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ EXPORTED_FUNCTIONS_EXTRA += ,\
6060
_proxy_c_to_js_dir,\
6161
_proxy_c_to_js_get_array,\
6262
_proxy_c_to_js_get_dict,\
63+
_proxy_c_to_js_get_iter,\
6364
_proxy_c_to_js_get_type,\
6465
_proxy_c_to_js_has_attr,\
66+
_proxy_c_to_js_iternext,\
6567
_proxy_c_to_js_lookup_attr,\
6668
_proxy_c_to_js_resume,\
6769
_proxy_c_to_js_store_attr,\

Diff for: ports/webassembly/objpyproxy.js

+28-1
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,37 @@ const py_proxy_handler = {
162162
if (prop === "then") {
163163
return null;
164164
}
165+
166+
if (prop === Symbol.iterator) {
167+
// Get the Python object iterator, and return a JavaScript generator.
168+
const iter_ref = Module.ccall(
169+
"proxy_c_to_js_get_iter",
170+
"number",
171+
["number"],
172+
[target._ref],
173+
);
174+
return function* () {
175+
const value = Module._malloc(3 * 4);
176+
while (true) {
177+
const valid = Module.ccall(
178+
"proxy_c_to_js_iternext",
179+
"number",
180+
["number", "pointer"],
181+
[iter_ref, value],
182+
);
183+
if (!valid) {
184+
break;
185+
}
186+
yield proxy_convert_mp_to_js_obj_jsside(value);
187+
}
188+
Module._free(value);
189+
};
190+
}
191+
165192
const value = Module._malloc(3 * 4);
166193
Module.ccall(
167194
"proxy_c_to_js_lookup_attr",
168-
"number",
195+
"null",
169196
["number", "string", "pointer"],
170197
[target._ref, prop, value],
171198
);

Diff for: ports/webassembly/proxy_c.c

+39-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ void proxy_c_init(void) {
6565

6666
MP_REGISTER_ROOT_POINTER(mp_obj_t proxy_c_ref);
6767

68+
static inline size_t proxy_c_add_obj(mp_obj_t obj) {
69+
size_t id = ((mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)))->len;
70+
mp_obj_list_append(MP_STATE_PORT(proxy_c_ref), obj);
71+
return id;
72+
}
73+
6874
static inline mp_obj_t proxy_c_get_obj(uint32_t c_ref) {
6975
return ((mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)))->items[c_ref];
7076
}
@@ -122,9 +128,7 @@ void proxy_convert_mp_to_js_obj_cside(mp_obj_t obj, uint32_t *out) {
122128
} else {
123129
kind = PROXY_KIND_MP_OBJECT;
124130
}
125-
size_t id = ((mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)))->len;
126-
mp_obj_list_append(MP_STATE_PORT(proxy_c_ref), obj);
127-
out[1] = id;
131+
out[1] = proxy_c_add_obj(obj);
128132
}
129133
out[0] = kind;
130134
}
@@ -284,6 +288,38 @@ void proxy_c_to_js_get_dict(uint32_t c_ref, uint32_t *out) {
284288
out[1] = (uintptr_t)map->table;
285289
}
286290

291+
/******************************************************************************/
292+
// Bridge Python iterator to JavaScript iterator protocol.
293+
294+
uint32_t proxy_c_to_js_get_iter(uint32_t c_ref) {
295+
mp_obj_t obj = proxy_c_get_obj(c_ref);
296+
mp_obj_t iter = mp_getiter(obj, NULL);
297+
return proxy_c_add_obj(iter);
298+
}
299+
300+
bool proxy_c_to_js_iternext(uint32_t c_ref, uint32_t *out) {
301+
mp_obj_t obj = proxy_c_get_obj(c_ref);
302+
nlr_buf_t nlr;
303+
if (nlr_push(&nlr) == 0) {
304+
mp_obj_t iter = mp_iternext_allow_raise(obj);
305+
if (iter == MP_OBJ_STOP_ITERATION) {
306+
nlr_pop();
307+
return false;
308+
}
309+
nlr_pop();
310+
proxy_convert_mp_to_js_obj_cside(iter, out);
311+
return true;
312+
} else {
313+
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {
314+
return false;
315+
} else {
316+
// uncaught exception
317+
proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out);
318+
return true;
319+
}
320+
}
321+
}
322+
287323
/******************************************************************************/
288324
// Bridge Python generator to JavaScript thenable.
289325

Diff for: tests/ports/webassembly/iterator.mjs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Test accessing Python iterables from JavaScript via the JavaScript iterator protocol.
2+
3+
const mp = await (await import(process.argv[2])).loadMicroPython();
4+
5+
mp.runPython(`
6+
s = "abc"
7+
l = [1, 2, 3]
8+
`);
9+
10+
// Iterate a Python string.
11+
for (const value of mp.globals.get("s")) {
12+
console.log(value);
13+
}
14+
15+
// Iterate a Python list.
16+
for (const value of mp.globals.get("l")) {
17+
console.log(value);
18+
}
19+
20+
// Iterate a Python list from a built-in JavaScript constructor.
21+
mp.runPython("import js; print(js.Set.new([1, 2, 3]).has(3))");

Diff for: tests/ports/webassembly/iterator.mjs.exp

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
a
2+
b
3+
c
4+
1
5+
2
6+
3
7+
True

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/micropython/micropython/commit/c056840ee8f7a154ff437a335eb4a83f14d47f0f

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy