diff options
| author | Scott Shawcroft <scott@adafruit.com> | 2020-10-12 15:31:43 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-12 15:31:43 -0700 |
| commit | bb046f9983d12b43481ddee7a67432ab6da8b144 (patch) | |
| tree | b0d57991e74e7ce3bdf15e4aa5f4676d107140e7 /py | |
| parent | 2e5bea26297180515dd5bb41e68bc3523eafcae8 (diff) | |
| parent | 10badd93c3ce4d2cdf074fe03bf23f9e481aa03e (diff) | |
Merge pull request #3540 from WarriorOfWire/async_syntax
__await__ magic method and async/await
Diffstat (limited to 'py')
| -rw-r--r-- | py/circuitpy_mpconfig.h | 1 | ||||
| -rw-r--r-- | py/circuitpy_mpconfig.mk | 3 | ||||
| -rw-r--r-- | py/compile.c | 17 | ||||
| -rw-r--r-- | py/objgenerator.c | 18 |
4 files changed, 36 insertions, 3 deletions
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 0583ae1c9..5ffdd4c8f 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -79,7 +79,6 @@ #define MICROPY_PY_ARRAY (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY_ASYNC_AWAIT (0) #define MICROPY_PY_ATTRTUPLE (1) #define MICROPY_PY_BUILTINS_BYTEARRAY (1) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 9b9bd83b4..91850448d 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -32,6 +32,9 @@ CIRCUITPY_FULL_BUILD ?= 1 CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD) +# async/await language keyword support +MICROPY_PY_ASYNC_AWAIT ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DMICROPY_PY_ASYNC_AWAIT=$(MICROPY_PY_ASYNC_AWAIT) CIRCUITPY_AESIO ?= 0 CFLAGS += -DCIRCUITPY_AESIO=$(CIRCUITPY_AESIO) diff --git a/py/compile.c b/py/compile.c index 653aae004..04bcf5bc1 100644 --- a/py/compile.c +++ b/py/compile.c @@ -853,7 +853,7 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0]; body_name = compile_funcdef_helper(comp, pns0, emit_options); scope_t *fscope = (scope_t*)pns0->nodes[4]; - fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; + fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC; #endif } else { assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be @@ -2632,6 +2632,12 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; +#if MICROPY_PY_ASYNC_AWAIT + if(comp->scope_cur->scope_flags & MP_SCOPE_FLAG_ASYNC) { + compile_syntax_error(comp, (mp_parse_node_t)pns, translate("'yield from' inside async function")); + return; + } +#endif compile_node(comp, pns->nodes[0]); compile_yield_from(comp); } else { @@ -2648,7 +2654,14 @@ STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pn } compile_require_async_context(comp, pns); compile_atom_expr_normal(comp, pns); - compile_yield_from(comp); + + // If it's an awaitable thing, need to reach for the __await__ method for the coroutine. + // async def functions' __await__ return themselves, which are able to receive a send(), + // while other types with custom __await__ implementations return async generators. + EMIT_ARG(load_method, MP_QSTR___await__, false); + EMIT_ARG(call_method, 0, 0, 0); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT_ARG(yield, MP_EMIT_YIELD_FROM); } #endif diff --git a/py/objgenerator.c b/py/objgenerator.c index df421b60c..5e651ac26 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -225,6 +225,21 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); +#if MICROPY_PY_ASYNC_AWAIT +STATIC mp_obj_t gen_instance_await(mp_obj_t self_in) { + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + if ( !self->coroutine_generator ) { + // Pretend like a generator does not have this coroutine behavior. + // Pay no attention to the dir() behind the curtain + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + translate("type object 'generator' has no attribute '__await__'"))); + } + // You can directly call send on a coroutine generator or you can __await__ then send on the return of that. + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_await_obj, gen_instance_await); +#endif + STATIC mp_obj_t gen_instance_close(mp_obj_t self_in); STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { mp_obj_t exc = (n_args == 2) ? args[1] : args[2]; @@ -280,6 +295,9 @@ STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { #if MICROPY_PY_GENERATOR_PEND_THROW { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) }, #endif + #if MICROPY_PY_ASYNC_AWAIT + { MP_ROM_QSTR(MP_QSTR___await__), MP_ROM_PTR(&gen_instance_await_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table); |
