kopia lustrzana https://github.com/micropython/micropython
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>pull/13583/head
rodzic
39bd0b8a0a
commit
9b090603a0
|
@ -47,6 +47,7 @@ CFLAGS += $(INC)
|
||||||
|
|
||||||
EXPORTED_FUNCTIONS_EXTRA += ,\
|
EXPORTED_FUNCTIONS_EXTRA += ,\
|
||||||
_mp_js_do_exec,\
|
_mp_js_do_exec,\
|
||||||
|
_mp_js_do_exec_async,\
|
||||||
_mp_js_do_import,\
|
_mp_js_do_import,\
|
||||||
_mp_js_register_js_module,\
|
_mp_js_register_js_module,\
|
||||||
_proxy_c_init,\
|
_proxy_c_init,\
|
||||||
|
@ -58,6 +59,7 @@ EXPORTED_FUNCTIONS_EXTRA += ,\
|
||||||
_proxy_c_to_js_get_type,\
|
_proxy_c_to_js_get_type,\
|
||||||
_proxy_c_to_js_has_attr,\
|
_proxy_c_to_js_has_attr,\
|
||||||
_proxy_c_to_js_lookup_attr,\
|
_proxy_c_to_js_lookup_attr,\
|
||||||
|
_proxy_c_to_js_resume,\
|
||||||
_proxy_c_to_js_store_attr,\
|
_proxy_c_to_js_store_attr,\
|
||||||
_proxy_convert_mp_to_js_obj_cside
|
_proxy_convert_mp_to_js_obj_cside
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,16 @@ export async function loadMicroPython(options) {
|
||||||
);
|
);
|
||||||
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
|
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
|
||||||
},
|
},
|
||||||
|
runPythonAsync(code) {
|
||||||
|
const value = Module._malloc(3 * 4);
|
||||||
|
Module.ccall(
|
||||||
|
"mp_js_do_exec_async",
|
||||||
|
"number",
|
||||||
|
["string", "pointer"],
|
||||||
|
[code, value],
|
||||||
|
);
|
||||||
|
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,12 @@ void mp_js_do_exec(const char *src, uint32_t *out) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mp_js_do_exec_async(const char *src, uint32_t *out) {
|
||||||
|
mp_compile_allow_top_level_await = true;
|
||||||
|
mp_js_do_exec(src, out);
|
||||||
|
mp_compile_allow_top_level_await = false;
|
||||||
|
}
|
||||||
|
|
||||||
#if MICROPY_GC_SPLIT_HEAP_AUTO
|
#if MICROPY_GC_SPLIT_HEAP_AUTO
|
||||||
|
|
||||||
// The largest new region that is available to become Python heap.
|
// The largest new region that is available to become Python heap.
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MICROPY_ALLOC_PATH_MAX (256)
|
#define MICROPY_ALLOC_PATH_MAX (256)
|
||||||
|
#define MICROPY_COMP_ALLOW_TOP_LEVEL_AWAIT (1)
|
||||||
#define MICROPY_READER_VFS (MICROPY_VFS)
|
#define MICROPY_READER_VFS (MICROPY_VFS)
|
||||||
#define MICROPY_ENABLE_GC (1)
|
#define MICROPY_ENABLE_GC (1)
|
||||||
#define MICROPY_ENABLE_PYSTACK (1)
|
#define MICROPY_ENABLE_PYSTACK (1)
|
||||||
|
|
|
@ -32,6 +32,16 @@
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "proxy_c.h"
|
#include "proxy_c.h"
|
||||||
|
|
||||||
|
EM_JS(bool, has_attr, (int jsref, const char *str), {
|
||||||
|
const base = proxy_js_ref[jsref];
|
||||||
|
const attr = UTF8ToString(str);
|
||||||
|
if (attr in base) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// *FORMAT-OFF*
|
// *FORMAT-OFF*
|
||||||
EM_JS(bool, lookup_attr, (int jsref, const char *str, uint32_t * out), {
|
EM_JS(bool, lookup_attr, (int jsref, const char *str, uint32_t * out), {
|
||||||
const base = proxy_js_ref[jsref];
|
const base = proxy_js_ref[jsref];
|
||||||
|
@ -299,18 +309,165 @@ static mp_obj_t jsproxy_it_iternext(mp_obj_t self_in) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t jsproxy_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
|
static mp_obj_t jsproxy_new_it(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||||
assert(sizeof(jsproxy_it_t) <= sizeof(mp_obj_iter_buf_t));
|
assert(sizeof(jsproxy_it_t) <= sizeof(mp_obj_iter_buf_t));
|
||||||
|
mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
jsproxy_it_t *o = (jsproxy_it_t *)iter_buf;
|
jsproxy_it_t *o = (jsproxy_it_t *)iter_buf;
|
||||||
o->base.type = &mp_type_polymorph_iter;
|
o->base.type = &mp_type_polymorph_iter;
|
||||||
o->iternext = jsproxy_it_iternext;
|
o->iternext = jsproxy_it_iternext;
|
||||||
o->ref = mp_obj_jsproxy_get_ref(o_in);
|
o->ref = self->ref;
|
||||||
o->cur = 0;
|
o->cur = 0;
|
||||||
o->len = js_get_len(o->ref);
|
o->len = js_get_len(self->ref);
|
||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
// jsproxy generator
|
||||||
|
|
||||||
|
enum {
|
||||||
|
JSOBJ_GEN_STATE_WAITING,
|
||||||
|
JSOBJ_GEN_STATE_COMPLETED,
|
||||||
|
JSOBJ_GEN_STATE_EXHAUSTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _jsproxy_gen_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
mp_obj_t thenable;
|
||||||
|
int state;
|
||||||
|
} jsproxy_gen_t;
|
||||||
|
|
||||||
|
mp_vm_return_kind_t jsproxy_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
|
||||||
|
jsproxy_gen_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
switch (self->state) {
|
||||||
|
case JSOBJ_GEN_STATE_WAITING:
|
||||||
|
self->state = JSOBJ_GEN_STATE_COMPLETED;
|
||||||
|
*ret_val = self->thenable;
|
||||||
|
return MP_VM_RETURN_YIELD;
|
||||||
|
|
||||||
|
case JSOBJ_GEN_STATE_COMPLETED:
|
||||||
|
self->state = JSOBJ_GEN_STATE_EXHAUSTED;
|
||||||
|
*ret_val = send_value;
|
||||||
|
return MP_VM_RETURN_NORMAL;
|
||||||
|
|
||||||
|
case JSOBJ_GEN_STATE_EXHAUSTED:
|
||||||
|
default:
|
||||||
|
// Trying to resume an already stopped generator.
|
||||||
|
// This is an optimised "raise StopIteration(None)".
|
||||||
|
*ret_val = mp_const_none;
|
||||||
|
return MP_VM_RETURN_NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, bool raise_stop_iteration) {
|
||||||
|
mp_obj_t ret;
|
||||||
|
switch (jsproxy_gen_resume(self_in, send_value, throw_value, &ret)) {
|
||||||
|
case MP_VM_RETURN_NORMAL:
|
||||||
|
default:
|
||||||
|
// A normal return is a StopIteration, either raise it or return
|
||||||
|
// MP_OBJ_STOP_ITERATION as an optimisation.
|
||||||
|
if (ret == mp_const_none) {
|
||||||
|
ret = MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
if (raise_stop_iteration) {
|
||||||
|
mp_raise_StopIteration(ret);
|
||||||
|
} else {
|
||||||
|
return mp_make_stop_iteration(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
case MP_VM_RETURN_YIELD:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
case MP_VM_RETURN_EXCEPTION:
|
||||||
|
nlr_raise(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_gen_instance_iternext(mp_obj_t self_in) {
|
||||||
|
return jsproxy_gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
|
||||||
|
return jsproxy_gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL, true);
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_2(jsproxy_gen_instance_send_obj, jsproxy_gen_instance_send);
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_gen_instance_throw(size_t n_args, const mp_obj_t *args) {
|
||||||
|
// The signature of this function is: throw(type[, value[, traceback]])
|
||||||
|
// CPython will pass all given arguments through the call chain and process them
|
||||||
|
// at the point they are used (native generators will handle them differently to
|
||||||
|
// user-defined generators with a throw() method). To save passing multiple
|
||||||
|
// values, MicroPython instead does partial processing here to reduce it down to
|
||||||
|
// one argument and passes that through:
|
||||||
|
// - if only args[1] is given, or args[2] is given but is None, args[1] is
|
||||||
|
// passed through (in the standard case it is an exception class or instance)
|
||||||
|
// - if args[2] is given and not None it is passed through (in the standard
|
||||||
|
// case it would be an exception instance and args[1] its corresponding class)
|
||||||
|
// - args[3] is always ignored
|
||||||
|
|
||||||
|
mp_obj_t exc = args[1];
|
||||||
|
if (n_args > 2 && args[2] != mp_const_none) {
|
||||||
|
exc = args[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsproxy_gen_resume_and_raise(args[0], mp_const_none, exc, true);
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(jsproxy_gen_instance_throw_obj, 2, 4, jsproxy_gen_instance_throw);
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_gen_instance_close(mp_obj_t self_in) {
|
||||||
|
mp_obj_t ret;
|
||||||
|
switch (jsproxy_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) {
|
||||||
|
case MP_VM_RETURN_YIELD:
|
||||||
|
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("generator ignored GeneratorExit"));
|
||||||
|
|
||||||
|
// Swallow GeneratorExit (== successful close), and re-raise any other
|
||||||
|
case MP_VM_RETURN_EXCEPTION:
|
||||||
|
// ret should always be an instance of an exception class
|
||||||
|
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) {
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
nlr_raise(ret);
|
||||||
|
|
||||||
|
default:
|
||||||
|
// The only choice left is MP_VM_RETURN_NORMAL which is successful close
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_1(jsproxy_gen_instance_close_obj, jsproxy_gen_instance_close);
|
||||||
|
|
||||||
|
static const mp_rom_map_elem_t jsproxy_gen_instance_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&jsproxy_gen_instance_close_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&jsproxy_gen_instance_send_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&jsproxy_gen_instance_throw_obj) },
|
||||||
|
};
|
||||||
|
static MP_DEFINE_CONST_DICT(jsproxy_gen_instance_locals_dict, jsproxy_gen_instance_locals_dict_table);
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
|
mp_type_jsproxy_gen,
|
||||||
|
MP_QSTR_generator,
|
||||||
|
MP_TYPE_FLAG_ITER_IS_ITERNEXT,
|
||||||
|
iter, jsproxy_gen_instance_iternext,
|
||||||
|
locals_dict, &jsproxy_gen_instance_locals_dict
|
||||||
|
);
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_new_gen(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||||
|
assert(sizeof(jsproxy_gen_t) <= sizeof(mp_obj_iter_buf_t));
|
||||||
|
jsproxy_gen_t *o = (jsproxy_gen_t *)iter_buf;
|
||||||
|
o->base.type = &mp_type_jsproxy_gen;
|
||||||
|
o->thenable = self_in;
|
||||||
|
o->state = JSOBJ_GEN_STATE_WAITING;
|
||||||
|
return MP_OBJ_FROM_PTR(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static mp_obj_t jsproxy_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||||
|
mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
if (has_attr(self->ref, "then")) {
|
||||||
|
return jsproxy_new_gen(self_in, iter_buf);
|
||||||
|
} else {
|
||||||
|
return jsproxy_new_it(self_in, iter_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_OBJ_TYPE(
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
mp_type_jsproxy,
|
mp_type_jsproxy,
|
||||||
|
|
|
@ -159,6 +159,9 @@ const py_proxy_handler = {
|
||||||
if (prop === "_ref") {
|
if (prop === "_ref") {
|
||||||
return target._ref;
|
return target._ref;
|
||||||
}
|
}
|
||||||
|
if (prop === "then") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const value = Module._malloc(3 * 4);
|
const value = Module._malloc(3 * 4);
|
||||||
Module.ccall(
|
Module.ccall(
|
||||||
"proxy_c_to_js_lookup_attr",
|
"proxy_c_to_js_lookup_attr",
|
||||||
|
@ -189,3 +192,23 @@ const py_proxy_handler = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// PyProxy of a Python generator, that implements the thenable interface.
|
||||||
|
class PyProxyThenable {
|
||||||
|
constructor(ref) {
|
||||||
|
this._ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
then(resolve, reject) {
|
||||||
|
const values = Module._malloc(3 * 3 * 4);
|
||||||
|
proxy_convert_js_to_mp_obj_jsside(resolve, values + 3 * 4);
|
||||||
|
proxy_convert_js_to_mp_obj_jsside(reject, values + 2 * 3 * 4);
|
||||||
|
Module.ccall(
|
||||||
|
"proxy_c_to_js_resume",
|
||||||
|
"null",
|
||||||
|
["number", "pointer"],
|
||||||
|
[this._ref, values],
|
||||||
|
);
|
||||||
|
return proxy_convert_mp_to_js_obj_jsside_with_free(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "emscripten.h"
|
||||||
#include "py/builtin.h"
|
#include "py/builtin.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "proxy_c.h"
|
#include "proxy_c.h"
|
||||||
|
@ -42,8 +43,9 @@ enum {
|
||||||
PROXY_KIND_MP_FLOAT = 4,
|
PROXY_KIND_MP_FLOAT = 4,
|
||||||
PROXY_KIND_MP_STR = 5,
|
PROXY_KIND_MP_STR = 5,
|
||||||
PROXY_KIND_MP_CALLABLE = 6,
|
PROXY_KIND_MP_CALLABLE = 6,
|
||||||
PROXY_KIND_MP_OBJECT = 7,
|
PROXY_KIND_MP_GENERATOR = 7,
|
||||||
PROXY_KIND_MP_JSPROXY = 8,
|
PROXY_KIND_MP_OBJECT = 8,
|
||||||
|
PROXY_KIND_MP_JSPROXY = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -115,6 +117,8 @@ void proxy_convert_mp_to_js_obj_cside(mp_obj_t obj, uint32_t *out) {
|
||||||
} else {
|
} else {
|
||||||
if (mp_obj_is_callable(obj)) {
|
if (mp_obj_is_callable(obj)) {
|
||||||
kind = PROXY_KIND_MP_CALLABLE;
|
kind = PROXY_KIND_MP_CALLABLE;
|
||||||
|
} else if (mp_obj_is_type(obj, &mp_type_gen_instance)) {
|
||||||
|
kind = PROXY_KIND_MP_GENERATOR;
|
||||||
} else {
|
} else {
|
||||||
kind = PROXY_KIND_MP_OBJECT;
|
kind = PROXY_KIND_MP_OBJECT;
|
||||||
}
|
}
|
||||||
|
@ -279,3 +283,78 @@ void proxy_c_to_js_get_dict(uint32_t c_ref, uint32_t *out) {
|
||||||
out[0] = map->alloc;
|
out[0] = map->alloc;
|
||||||
out[1] = (uintptr_t)map->table;
|
out[1] = (uintptr_t)map->table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
// Bridge Python generator to JavaScript thenable.
|
||||||
|
|
||||||
|
static const mp_obj_fun_builtin_var_t resume_obj;
|
||||||
|
|
||||||
|
EM_JS(void, js_then_resolve, (uint32_t * resolve, uint32_t * reject), {
|
||||||
|
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
|
||||||
|
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
|
||||||
|
resolve_js(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
EM_JS(void, js_then_reject, (uint32_t * resolve, uint32_t * reject), {
|
||||||
|
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
|
||||||
|
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
|
||||||
|
reject_js(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
// *FORMAT-OFF*
|
||||||
|
EM_JS(void, js_then_continue, (int jsref, uint32_t * py_resume, uint32_t * resolve, uint32_t * reject, uint32_t * out), {
|
||||||
|
const py_resume_js = proxy_convert_mp_to_js_obj_jsside(py_resume);
|
||||||
|
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
|
||||||
|
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
|
||||||
|
const ret = proxy_js_ref[jsref].then((x) => {py_resume_js(x, resolve_js, reject_js);}, reject_js);
|
||||||
|
proxy_convert_js_to_mp_obj_jsside(ret, out);
|
||||||
|
});
|
||||||
|
// *FORMAT-ON*
|
||||||
|
|
||||||
|
static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t value, mp_obj_t resolve, mp_obj_t reject) {
|
||||||
|
mp_obj_t ret_value;
|
||||||
|
mp_vm_return_kind_t ret_kind = mp_resume(self_in, value, MP_OBJ_NULL, &ret_value);
|
||||||
|
|
||||||
|
uint32_t out_resolve[PVN];
|
||||||
|
uint32_t out_reject[PVN];
|
||||||
|
proxy_convert_mp_to_js_obj_cside(resolve, out_resolve);
|
||||||
|
proxy_convert_mp_to_js_obj_cside(reject, out_reject);
|
||||||
|
|
||||||
|
if (ret_kind == MP_VM_RETURN_NORMAL) {
|
||||||
|
js_then_resolve(out_resolve, out_reject);
|
||||||
|
return mp_const_none;
|
||||||
|
} else if (ret_kind == MP_VM_RETURN_YIELD) {
|
||||||
|
// ret_value should be a JS thenable
|
||||||
|
mp_obj_t py_resume = mp_obj_new_bound_meth(MP_OBJ_FROM_PTR(&resume_obj), self_in);
|
||||||
|
int ref = mp_obj_jsproxy_get_ref(ret_value);
|
||||||
|
uint32_t out_py_resume[PVN];
|
||||||
|
proxy_convert_mp_to_js_obj_cside(py_resume, out_py_resume);
|
||||||
|
uint32_t out[PVN];
|
||||||
|
js_then_continue(ref, out_py_resume, out_resolve, out_reject, out);
|
||||||
|
return proxy_convert_js_to_mp_obj_cside(out);
|
||||||
|
} else {
|
||||||
|
// MP_VM_RETURN_EXCEPTION;
|
||||||
|
js_then_reject(out_resolve, out_reject);
|
||||||
|
nlr_raise(ret_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t resume_fun(size_t n_args, const mp_obj_t *args) {
|
||||||
|
return proxy_resume_execute(args[0], args[1], args[2], args[3]);
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 4, 4, resume_fun);
|
||||||
|
|
||||||
|
void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) {
|
||||||
|
nlr_buf_t nlr;
|
||||||
|
if (nlr_push(&nlr) == 0) {
|
||||||
|
mp_obj_t obj = proxy_c_get_obj(c_ref);
|
||||||
|
mp_obj_t resolve = proxy_convert_js_to_mp_obj_cside(args + 1 * 3);
|
||||||
|
mp_obj_t reject = proxy_convert_js_to_mp_obj_cside(args + 2 * 3);
|
||||||
|
mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, resolve, reject);
|
||||||
|
nlr_pop();
|
||||||
|
return proxy_convert_mp_to_js_obj_cside(ret, args);
|
||||||
|
} else {
|
||||||
|
// uncaught exception
|
||||||
|
return proxy_convert_mp_to_js_exc_cside(nlr.ret_val, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ const PROXY_KIND_MP_INT = 3;
|
||||||
const PROXY_KIND_MP_FLOAT = 4;
|
const PROXY_KIND_MP_FLOAT = 4;
|
||||||
const PROXY_KIND_MP_STR = 5;
|
const PROXY_KIND_MP_STR = 5;
|
||||||
const PROXY_KIND_MP_CALLABLE = 6;
|
const PROXY_KIND_MP_CALLABLE = 6;
|
||||||
const PROXY_KIND_MP_OBJECT = 7;
|
const PROXY_KIND_MP_GENERATOR = 7;
|
||||||
const PROXY_KIND_MP_JSPROXY = 8;
|
const PROXY_KIND_MP_OBJECT = 8;
|
||||||
|
const PROXY_KIND_MP_JSPROXY = 9;
|
||||||
|
|
||||||
const PROXY_KIND_JS_NULL = 1;
|
const PROXY_KIND_JS_NULL = 1;
|
||||||
const PROXY_KIND_JS_BOOLEAN = 2;
|
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) {
|
} else if (js_obj instanceof PyProxy) {
|
||||||
kind = PROXY_KIND_JS_PYPROXY;
|
kind = PROXY_KIND_JS_PYPROXY;
|
||||||
Module.setValue(out + 4, js_obj._ref, "i32");
|
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 {
|
} else {
|
||||||
kind = PROXY_KIND_JS_OBJECT;
|
kind = PROXY_KIND_JS_OBJECT;
|
||||||
const id = proxy_js_ref.length;
|
const id = proxy_js_ref.length;
|
||||||
|
@ -193,6 +197,8 @@ function proxy_convert_mp_to_js_obj_jsside(value) {
|
||||||
obj = (...args) => {
|
obj = (...args) => {
|
||||||
return proxy_call_python(id, args);
|
return proxy_call_python(id, args);
|
||||||
};
|
};
|
||||||
|
} else if (kind === PROXY_KIND_MP_GENERATOR) {
|
||||||
|
obj = new PyProxyThenable(id);
|
||||||
} else {
|
} else {
|
||||||
// PROXY_KIND_MP_OBJECT
|
// PROXY_KIND_MP_OBJECT
|
||||||
const target = new PyProxy(id);
|
const target = new PyProxy(id);
|
||||||
|
|
Ładowanie…
Reference in New Issue