diff --git a/py/compile.c b/py/compile.c index ae91455e0..7366ee1fb 100644 --- a/py/compile.c +++ b/py/compile.c @@ -318,14 +318,14 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t; STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind); -STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) { +STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) { if (assign_kind != ASSIGN_AUG_STORE) { compile_node(comp, pns->nodes[0]); } if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; - if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) { + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) { int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); if (assign_kind != ASSIGN_AUG_STORE) { for (int i = 0; i < n - 1; i++) { @@ -366,10 +366,6 @@ STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign goto cannot_assign; } - if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { - goto cannot_assign; - } - return; cannot_assign: @@ -440,9 +436,9 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ // pn must be a struct mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; switch (MP_PARSE_NODE_STRUCT_KIND(pns)) { - case PN_power: + case PN_atom_expr_normal: // lhs is an index or attribute - c_assign_power(comp, pns, assign_kind); + c_assign_atom_expr(comp, pns, assign_kind); break; case PN_testlist_star_expr: @@ -818,11 +814,19 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { } } - // compile the body (funcdef or classdef) and get its name + // compile the body (funcdef, async funcdef or classdef) and get its name mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1]; qstr body_name = 0; if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) { body_name = compile_funcdef_helper(comp, pns_body, emit_options); + #if MICROPY_PY_ASYNC_AWAIT + } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) { + assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0])); + 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; + #endif } else { assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be body_name = compile_classdef_helper(comp, pns_body, emit_options); @@ -846,14 +850,14 @@ STATIC void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_ID(pn)) { compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn)); - } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) { + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; - compile_node(comp, pns->nodes[0]); // base of the power node + compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; - if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) { + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) { int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); for (int i = 0; i < n - 1; i++) { compile_node(comp, pns1->nodes[i]); @@ -874,9 +878,6 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { goto cannot_delete; } - if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { - goto cannot_delete; - } } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) { pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { @@ -1397,9 +1398,9 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // this bit optimises: for in range(...), turning it into an explicitly incremented variable // this is actually slower, but uses no heap memory // for viper it will be much, much faster - if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_power)) { + if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_atom_expr_normal)) { mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1]; - if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0]) + if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range && MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren) && MP_PARSE_NODE_IS_NULL(pns_it->nodes[2])) { @@ -1661,6 +1662,177 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_with_stmt_helper(comp, n, nodes, pns->nodes[1]); } +STATIC void compile_yield_from(compiler_t *comp) { + EMIT(get_iter); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT(yield_from); +} + +#if MICROPY_PY_ASYNC_AWAIT +STATIC void compile_await_object_method(compiler_t *comp, qstr method) { + EMIT_ARG(load_method, method); + EMIT_ARG(call_method, 0, 0, 0); + compile_yield_from(comp); +} + +STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // comp->break_label |= MP_EMIT_BREAK_FROM_FOR; + + qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); + uint while_else_label = comp_next_label(comp); + uint try_exception_label = comp_next_label(comp); + uint try_else_label = comp_next_label(comp); + uint try_finally_label = comp_next_label(comp); + + compile_node(comp, pns->nodes[1]); // iterator + compile_await_object_method(comp, MP_QSTR___aiter__); + compile_store_id(comp, context); + + START_BREAK_CONTINUE_BLOCK + + EMIT_ARG(label_assign, continue_label); + + EMIT_ARG(setup_except, try_exception_label); + compile_increase_except_level(comp); + + compile_load_id(comp, context); + compile_await_object_method(comp, MP_QSTR___anext__); + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable + EMIT(pop_block); + EMIT_ARG(jump, try_else_label); + + EMIT_ARG(label_assign, try_exception_label); + EMIT(start_except_handler); + EMIT(dup_top); + EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration); + EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); + EMIT_ARG(pop_jump_if, false, try_finally_label); + EMIT(pop_top); + EMIT(pop_top); + EMIT(pop_top); + EMIT(pop_except); + EMIT_ARG(jump, while_else_label); + + EMIT_ARG(label_assign, try_finally_label); + EMIT_ARG(adjust_stack_size, 3); + compile_decrease_except_level(comp); + EMIT(end_finally); + EMIT(end_except_handler); + + EMIT_ARG(label_assign, try_else_label); + compile_node(comp, pns->nodes[2]); // body + + EMIT_ARG(jump, continue_label); + // break/continue apply to outer loop (if any) in the else block + END_BREAK_CONTINUE_BLOCK + + EMIT_ARG(label_assign, while_else_label); + compile_node(comp, pns->nodes[3]); // else + + EMIT_ARG(label_assign, break_label); +} + +STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) { + if (n == 0) { + // no more pre-bits, compile the body of the with + compile_node(comp, body); + } else { + uint try_exception_label = comp_next_label(comp); + uint no_reraise_label = comp_next_label(comp); + uint try_else_label = comp_next_label(comp); + uint end_label = comp_next_label(comp); + qstr context; + + if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) { + // this pre-bit is of the form "a as b" + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; + compile_node(comp, pns->nodes[0]); + context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + compile_store_id(comp, context); + compile_load_id(comp, context); + compile_await_object_method(comp, MP_QSTR___aenter__); + c_assign(comp, pns->nodes[1], ASSIGN_STORE); + } else { + // this pre-bit is just an expression + compile_node(comp, nodes[0]); + context = MP_PARSE_NODE_LEAF_ARG(nodes[0]); + compile_store_id(comp, context); + compile_load_id(comp, context); + compile_await_object_method(comp, MP_QSTR___aenter__); + EMIT(pop_top); + } + + compile_load_id(comp, context); + EMIT_ARG(load_method, MP_QSTR___aexit__); + + EMIT_ARG(setup_except, try_exception_label); + compile_increase_except_level(comp); + // compile additional pre-bits and the body + compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); + // finish this with block + EMIT(pop_block); + EMIT_ARG(jump, try_else_label); // jump over exception handler + + EMIT_ARG(label_assign, try_exception_label); // start of exception handler + EMIT(start_except_handler); + EMIT(rot_three); + EMIT(rot_two); + EMIT_ARG(call_method, 3, 0, 0); + compile_yield_from(comp); + EMIT_ARG(pop_jump_if, true, no_reraise_label); + EMIT_ARG(raise_varargs, 0); + + EMIT_ARG(label_assign, no_reraise_label); + EMIT(pop_except); + EMIT_ARG(jump, end_label); + + EMIT_ARG(adjust_stack_size, 5); + compile_decrease_except_level(comp); + EMIT(end_finally); + EMIT(end_except_handler); + + EMIT_ARG(label_assign, try_else_label); // start of try-else handler + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT(dup_top); + EMIT(dup_top); + EMIT_ARG(call_method, 3, 0, 0); + compile_yield_from(comp); + EMIT(pop_top); + + EMIT_ARG(label_assign, end_label); + + } +} + +STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes); + assert(n > 0); + + // compile in a nested fashion + compile_async_with_stmt_helper(comp, n, nodes, pns->nodes[1]); +} + +STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[0])); + mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; + if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_funcdef) { + // async def + compile_funcdef(comp, pns0); + scope_t *fscope = (scope_t*)pns0->nodes[4]; + fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) { + // async for + compile_async_for_stmt(comp, pns0); + } else { + // async with + assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt); + compile_async_with_stmt(comp, pns0); + } +} +#endif + STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) { @@ -1967,15 +2139,16 @@ STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) { } } -STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) { // this is to handle special super() call comp->func_arg_is_super = MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super; compile_generic_all_nodes(comp, pns); +} - if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { - EMIT_ARG(binary_op, MP_BINARY_OP_POWER); - } +STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power + EMIT_ARG(binary_op, MP_BINARY_OP_POWER); } STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) { @@ -2076,7 +2249,7 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar } } -STATIC void compile_power_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_atom_expr_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) { int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < num_nodes; i++) { if (i + 1 < num_nodes && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[i], PN_trailer_period) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[i + 1], PN_trailer_paren)) { @@ -2431,15 +2604,24 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; compile_node(comp, pns->nodes[0]); - EMIT(get_iter); - EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_from); + compile_yield_from(comp); } else { compile_node(comp, pns->nodes[0]); EMIT(yield_value); } } +#if MICROPY_PY_ASYNC_AWAIT +STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "'await' outside function"); + return; + } + compile_atom_expr_normal(comp, pns); + compile_yield_from(comp); +} +#endif + STATIC void compile_string(compiler_t *comp, mp_parse_node_struct_t *pns) { // only create and load the actual str object on the last pass if (comp->pass != MP_PASS_EMIT) { @@ -2995,7 +3177,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind goto not_an_instruction; } pns2 = (mp_parse_node_struct_t*)pns2->nodes[0]; - if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_power) { + if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_atom_expr_normal) { goto not_an_instruction; } if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) { diff --git a/py/grammar.h b/py/grammar.h index a7d1b41e6..1091394f0 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -46,8 +46,9 @@ DEF_RULE(eval_input_2, nc, and(1), tok(NEWLINE)) // decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE // decorators: decorator+ -// decorated: decorators (classdef | funcdef) +// decorated: decorators (classdef | funcdef | async_funcdef) // funcdef: 'def' NAME parameters ['->' test] ':' suite +// async_funcdef: 'async' funcdef // parameters: '(' [typedargslist] ')' // typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef // tfpdef: NAME [':' test] @@ -57,7 +58,12 @@ DEF_RULE(eval_input_2, nc, and(1), tok(NEWLINE)) DEF_RULE(decorator, nc, and(4), tok(DEL_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE)) DEF_RULE(decorators, nc, one_or_more, rule(decorator)) DEF_RULE(decorated, c(decorated), and(2), rule(decorators), rule(decorated_body)) +#if MICROPY_PY_ASYNC_AWAIT +DEF_RULE(decorated_body, nc, or(3), rule(classdef), rule(funcdef), rule(async_funcdef)) +DEF_RULE(async_funcdef, nc, and(2), tok(KW_ASYNC), rule(funcdef)) +#else DEF_RULE(decorated_body, nc, or(2), rule(classdef), rule(funcdef)) +#endif DEF_RULE(funcdef, c(funcdef), blank | and(8), tok(KW_DEF), tok(NAME), tok(DEL_PAREN_OPEN), opt_rule(typedargslist), tok(DEL_PAREN_CLOSE), opt_rule(funcdefrettype), tok(DEL_COLON), rule(suite)) DEF_RULE(funcdefrettype, nc, ident | and(2), tok(DEL_MINUS_MORE), rule(test)) // note: typedargslist lets through more than is allowed, compiler does further checks @@ -157,7 +163,7 @@ DEF_RULE(name_list, nc, list, tok(NAME), tok(DEL_COMMA)) DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra)) DEF_RULE(assert_stmt_extra, nc, ident | and(2), tok(DEL_COMMA), rule(test)) -// compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated +// compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt // if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] // while_stmt: 'while' test ':' suite ['else' ':' suite] // for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] @@ -167,8 +173,15 @@ DEF_RULE(assert_stmt_extra, nc, ident | and(2), tok(DEL_COMMA), rule(test)) // with_stmt: 'with' with_item (',' with_item)* ':' suite // with_item: test ['as' expr] // suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT +// async_stmt: 'async' (funcdef | with_stmt | for_stmt) +#if MICROPY_PY_ASYNC_AWAIT +DEF_RULE(compound_stmt, nc, or(9), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated), rule(async_stmt)) +DEF_RULE(async_stmt, c(async_stmt), and(2), tok(KW_ASYNC), rule(async_stmt_2)) +DEF_RULE(async_stmt_2, nc, or(3), rule(funcdef), rule(with_stmt), rule(for_stmt)) +#else DEF_RULE(compound_stmt, nc, or(8), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated)) +#endif DEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt)) DEF_RULE(if_stmt_elif_list, nc, one_or_more, rule(if_stmt_elif)) DEF_RULE(if_stmt_elif, nc, and(4), tok(KW_ELIF), rule(test), tok(DEL_COLON), rule(suite)) @@ -215,7 +228,8 @@ DEF_RULE(lambdef_nocond, c(lambdef), blank | and(4), tok(KW_LAMBDA), opt_rule(va // arith_expr: term (('+'|'-') term)* // term: factor (('*'|'/'|'%'|'//') factor)* // factor: ('+'|'-'|'~') factor | power -// power: atom trailer* ['**' factor] +// power: atom_expr ['**' factor] +// atom_expr: 'await' atom trailer* | atom trailer* DEF_RULE(or_test, c(or_test), list, rule(and_test), tok(KW_OR)) DEF_RULE(and_test, c(and_test), list, rule(not_test), tok(KW_AND)) @@ -239,8 +253,15 @@ DEF_RULE(term_op, nc, or(4), tok(OP_STAR), tok(OP_SLASH), tok(OP_PERCENT), tok(O DEF_RULE(factor, nc, or(2), rule(factor_2), rule(power)) DEF_RULE(factor_2, c(factor_2), and(2), rule(factor_op), rule(factor)) DEF_RULE(factor_op, nc, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE)) -DEF_RULE(power, c(power), and(3), rule(atom), opt_rule(power_trailers), opt_rule(power_dbl_star)) -DEF_RULE(power_trailers, c(power_trailers), one_or_more, rule(trailer)) +DEF_RULE(power, c(power), and(2), rule(atom_expr), opt_rule(power_dbl_star)) +#if MICROPY_PY_ASYNC_AWAIT +DEF_RULE(atom_expr, nc, or(2), rule(atom_expr_await), rule(atom_expr_normal)) +DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom), opt_rule(atom_expr_trailers)) +#else +DEF_RULE(atom_expr, nc, or(1), rule(atom_expr_normal)) +#endif +DEF_RULE(atom_expr_normal, c(atom_expr_normal), and(2), rule(atom), opt_rule(atom_expr_trailers)) +DEF_RULE(atom_expr_trailers, c(atom_expr_trailers), one_or_more, rule(trailer)) DEF_RULE(power_dbl_star, nc, ident | and(2), tok(OP_DBL_STAR), rule(factor)) // atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' diff --git a/py/lexer.c b/py/lexer.c index 76abedd45..1639740d3 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -234,6 +234,10 @@ STATIC const char *tok_kw[] = { "and", "as", "assert", + #if MICROPY_PY_ASYNC_AWAIT + "async", + "await", + #endif "break", "class", "continue", diff --git a/py/lexer.h b/py/lexer.h index 36d1e99d2..463be5fff 100644 --- a/py/lexer.h +++ b/py/lexer.h @@ -63,6 +63,10 @@ typedef enum _mp_token_kind_t { MP_TOKEN_KW_AND, MP_TOKEN_KW_AS, MP_TOKEN_KW_ASSERT, + #if MICROPY_PY_ASYNC_AWAIT + MP_TOKEN_KW_ASYNC, + MP_TOKEN_KW_AWAIT, + #endif MP_TOKEN_KW_BREAK, MP_TOKEN_KW_CLASS, MP_TOKEN_KW_CONTINUE, diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 2b47c711a..87446f7fa 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -704,6 +704,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) }, { MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) }, { MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) }, + #if MICROPY_PY_ASYNC_AWAIT + { MP_ROM_QSTR(MP_QSTR_StopAsyncIteration), MP_ROM_PTR(&mp_type_StopAsyncIteration) }, + #endif { MP_ROM_QSTR(MP_QSTR_StopIteration), MP_ROM_PTR(&mp_type_StopIteration) }, { MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) }, { MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) }, diff --git a/py/mpconfig.h b/py/mpconfig.h index 017030b0f..77ac61493 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -564,6 +564,11 @@ typedef double mp_float_t; #define MICROPY_PY_DESCRIPTORS (0) #endif +// Support for async/await/async for/async with +#ifndef MICROPY_PY_ASYNC_AWAIT +#define MICROPY_PY_ASYNC_AWAIT (1) +#endif + // Whether str object is proper unicode #ifndef MICROPY_PY_BUILTINS_STR_UNICODE #define MICROPY_PY_BUILTINS_STR_UNICODE (0) diff --git a/py/obj.h b/py/obj.h index 25f31ea5a..809acb5a3 100644 --- a/py/obj.h +++ b/py/obj.h @@ -561,6 +561,7 @@ extern const mp_obj_type_t mp_type_OSError; extern const mp_obj_type_t mp_type_TimeoutError; extern const mp_obj_type_t mp_type_OverflowError; extern const mp_obj_type_t mp_type_RuntimeError; +extern const mp_obj_type_t mp_type_StopAsyncIteration; extern const mp_obj_type_t mp_type_StopIteration; extern const mp_obj_type_t mp_type_SyntaxError; extern const mp_obj_type_t mp_type_SystemExit; diff --git a/py/objexcept.c b/py/objexcept.c index d8aecb80f..adf17b08d 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -197,6 +197,9 @@ MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION_BASE(Exception) + #if MICROPY_PY_ASYNC_AWAIT + MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception) + #endif MP_DEFINE_EXCEPTION(StopIteration, Exception) MP_DEFINE_EXCEPTION(ArithmeticError, Exception) MP_DEFINE_EXCEPTION_BASE(ArithmeticError) diff --git a/py/qstrdefs.h b/py/qstrdefs.h index da22a40b5..a3b68832c 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -94,6 +94,14 @@ Q(__neg__) Q(__pos__) #endif +#if MICROPY_PY_ASYNC_AWAIT +Q(__aiter__) +Q(__anext__) +Q(__aenter__) +Q(__aexit__) +Q(StopAsyncIteration) +#endif + Q(micropython) Q(bytecode) Q(const) diff --git a/py/repl.c b/py/repl.c index de0e8a4e7..7bd875908 100644 --- a/py/repl.c +++ b/py/repl.c @@ -57,6 +57,9 @@ bool mp_repl_continue_with_input(const char *input) { || str_startswith_word(input, "with") || str_startswith_word(input, "def") || str_startswith_word(input, "class") + #if MICROPY_PY_ASYNC_AWAIT + || str_startswith_word(input, "async") + #endif ; // check for unmatched open bracket, quote or escape quote