webassembly: Implement runPythonAsync() for top-level async code.

With this commit, `interpreter.runPythonAsync(code)` can now be used to run
Python code that uses `await` at the top level.  That will yield up to
JavaScript and produce a thenable, which the JavaScript runtime can then
resume.  Also implemented is the ability for Python code to await on
JavaScript promises/thenables.  For example, outer JavaScript code can
await on `runPythonAsync(code)` which then runs Python code that does
`await js.fetch(url)`.  The entire chain of calls will be suspended until
the fetch completes.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George
2023-06-24 17:19:05 +10:00
parent 39bd0b8a0a
commit 9b090603a0
8 changed files with 291 additions and 7 deletions

View File

@@ -34,8 +34,9 @@ const PROXY_KIND_MP_INT = 3;
const PROXY_KIND_MP_FLOAT = 4;
const PROXY_KIND_MP_STR = 5;
const PROXY_KIND_MP_CALLABLE = 6;
const PROXY_KIND_MP_OBJECT = 7;
const PROXY_KIND_MP_JSPROXY = 8;
const PROXY_KIND_MP_GENERATOR = 7;
const PROXY_KIND_MP_OBJECT = 8;
const PROXY_KIND_MP_JSPROXY = 9;
const PROXY_KIND_JS_NULL = 1;
const PROXY_KIND_JS_BOOLEAN = 2;
@@ -122,6 +123,9 @@ function proxy_convert_js_to_mp_obj_jsside(js_obj, out) {
} else if (js_obj instanceof PyProxy) {
kind = PROXY_KIND_JS_PYPROXY;
Module.setValue(out + 4, js_obj._ref, "i32");
} else if (js_obj instanceof PyProxyThenable) {
kind = PROXY_KIND_JS_PYPROXY;
Module.setValue(out + 4, js_obj._ref, "i32");
} else {
kind = PROXY_KIND_JS_OBJECT;
const id = proxy_js_ref.length;
@@ -193,6 +197,8 @@ function proxy_convert_mp_to_js_obj_jsside(value) {
obj = (...args) => {
return proxy_call_python(id, args);
};
} else if (kind === PROXY_KIND_MP_GENERATOR) {
obj = new PyProxyThenable(id);
} else {
// PROXY_KIND_MP_OBJECT
const target = new PyProxy(id);