py: add async/await/async for/async with syntax

They are sugar for marking function as generator, "yield from"
and pep492 python "semantically equivalents" respectively.

@dpgeorge was the original author of this patch, but @pohmelie made
changes to implement `async for` and `async with`.
This commit is contained in:
pohmelie 2016-01-27 23:23:11 +03:00 committed by Damien George
parent 959ed931a4
commit 81ebba7e02
10 changed files with 265 additions and 31 deletions

View File

@ -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; 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(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) { if (assign_kind != ASSIGN_AUG_STORE) {
compile_node(comp, pns->nodes[0]); compile_node(comp, pns->nodes[0]);
} }
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)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); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
if (assign_kind != ASSIGN_AUG_STORE) { if (assign_kind != ASSIGN_AUG_STORE) {
for (int i = 0; i < n - 1; i++) { 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; goto cannot_assign;
} }
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
goto cannot_assign;
}
return; return;
cannot_assign: 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 // pn must be a struct
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) { switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
case PN_power: case PN_atom_expr_normal:
// lhs is an index or attribute // lhs is an index or attribute
c_assign_power(comp, pns, assign_kind); c_assign_atom_expr(comp, pns, assign_kind);
break; break;
case PN_testlist_star_expr: 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]; mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1];
qstr body_name = 0; qstr body_name = 0;
if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) { if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
body_name = compile_funcdef_helper(comp, pns_body, emit_options); 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 { } else {
assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be
body_name = compile_classdef_helper(comp, pns_body, emit_options); 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) { STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_ID(pn)) { if (MP_PARSE_NODE_IS_ID(pn)) {
compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(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; 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])) { if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)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); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
for (int i = 0; i < n - 1; i++) { for (int i = 0; i < n - 1; i++) {
compile_node(comp, pns1->nodes[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; 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)) { } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {
pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; pn = ((mp_parse_node_struct_t*)pn)->nodes[0];
if (MP_PARSE_NODE_IS_NULL(pn)) { 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 <x> in range(...), turning it into an explicitly incremented variable // this bit optimises: for <x> in range(...), turning it into an explicitly incremented variable
// this is actually slower, but uses no heap memory // this is actually slower, but uses no heap memory
// for viper it will be much, much faster // 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]; 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_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_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren)
&& MP_PARSE_NODE_IS_NULL(pns_it->nodes[2])) { && 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]); 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) { STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) { 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 // 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; 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); compile_generic_all_nodes(comp, pns);
}
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(binary_op, MP_BINARY_OP_POWER); 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) { 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); int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (int i = 0; i < num_nodes; i++) { 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)) { 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)) { } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) {
pns = (mp_parse_node_struct_t*)pns->nodes[0]; pns = (mp_parse_node_struct_t*)pns->nodes[0];
compile_node(comp, pns->nodes[0]); compile_node(comp, pns->nodes[0]);
EMIT(get_iter); compile_yield_from(comp);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
EMIT(yield_from);
} else { } else {
compile_node(comp, pns->nodes[0]); compile_node(comp, pns->nodes[0]);
EMIT(yield_value); 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) { 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 // only create and load the actual str object on the last pass
if (comp->pass != MP_PASS_EMIT) { 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; goto not_an_instruction;
} }
pns2 = (mp_parse_node_struct_t*)pns2->nodes[0]; 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; goto not_an_instruction;
} }
if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) { if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) {

View File

@ -46,8 +46,9 @@ DEF_RULE(eval_input_2, nc, and(1), tok(NEWLINE))
// decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE // decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
// decorators: decorator+ // decorators: decorator+
// decorated: decorators (classdef | funcdef) // decorated: decorators (classdef | funcdef | async_funcdef)
// funcdef: 'def' NAME parameters ['->' test] ':' suite // funcdef: 'def' NAME parameters ['->' test] ':' suite
// async_funcdef: 'async' funcdef
// parameters: '(' [typedargslist] ')' // parameters: '(' [typedargslist] ')'
// typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef // typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef
// tfpdef: NAME [':' test] // 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(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(decorators, nc, one_or_more, rule(decorator))
DEF_RULE(decorated, c(decorated), and(2), rule(decorators), rule(decorated_body)) 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)) 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(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)) 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 // 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, 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)) 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] // if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
// while_stmt: 'while' test ':' suite ['else' ':' suite] // while_stmt: 'while' test ':' suite ['else' ':' suite]
// for_stmt: 'for' exprlist 'in' testlist ':' 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_stmt: 'with' with_item (',' with_item)* ':' suite
// with_item: test ['as' expr] // with_item: test ['as' expr]
// suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT // 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)) 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, 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_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)) 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)* // arith_expr: term (('+'|'-') term)*
// term: factor (('*'|'/'|'%'|'//') factor)* // term: factor (('*'|'/'|'%'|'//') factor)*
// factor: ('+'|'-'|'~') factor | power // 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(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)) 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, 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_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(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, c(power), and(2), rule(atom_expr), opt_rule(power_dbl_star))
DEF_RULE(power_trailers, c(power_trailers), one_or_more, rule(trailer)) #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)) 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' // atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'

View File

@ -234,6 +234,10 @@ STATIC const char *tok_kw[] = {
"and", "and",
"as", "as",
"assert", "assert",
#if MICROPY_PY_ASYNC_AWAIT
"async",
"await",
#endif
"break", "break",
"class", "class",
"continue", "continue",

View File

@ -63,6 +63,10 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_KW_AND, MP_TOKEN_KW_AND,
MP_TOKEN_KW_AS, MP_TOKEN_KW_AS,
MP_TOKEN_KW_ASSERT, 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_BREAK,
MP_TOKEN_KW_CLASS, MP_TOKEN_KW_CLASS,
MP_TOKEN_KW_CONTINUE, MP_TOKEN_KW_CONTINUE,

View File

@ -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_OSError), MP_ROM_PTR(&mp_type_OSError) },
{ MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) }, { MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) },
{ MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) }, { 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_StopIteration), MP_ROM_PTR(&mp_type_StopIteration) },
{ MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) }, { MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) },
{ MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) }, { MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) },

View File

@ -564,6 +564,11 @@ typedef double mp_float_t;
#define MICROPY_PY_DESCRIPTORS (0) #define MICROPY_PY_DESCRIPTORS (0)
#endif #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 // Whether str object is proper unicode
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE #ifndef MICROPY_PY_BUILTINS_STR_UNICODE
#define MICROPY_PY_BUILTINS_STR_UNICODE (0) #define MICROPY_PY_BUILTINS_STR_UNICODE (0)

View File

@ -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_TimeoutError;
extern const mp_obj_type_t mp_type_OverflowError; 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_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_StopIteration;
extern const mp_obj_type_t mp_type_SyntaxError; extern const mp_obj_type_t mp_type_SyntaxError;
extern const mp_obj_type_t mp_type_SystemExit; extern const mp_obj_type_t mp_type_SystemExit;

View File

@ -197,6 +197,9 @@ MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION_BASE(Exception) MP_DEFINE_EXCEPTION_BASE(Exception)
#if MICROPY_PY_ASYNC_AWAIT
MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception)
#endif
MP_DEFINE_EXCEPTION(StopIteration, Exception) MP_DEFINE_EXCEPTION(StopIteration, Exception)
MP_DEFINE_EXCEPTION(ArithmeticError, Exception) MP_DEFINE_EXCEPTION(ArithmeticError, Exception)
MP_DEFINE_EXCEPTION_BASE(ArithmeticError) MP_DEFINE_EXCEPTION_BASE(ArithmeticError)

View File

@ -94,6 +94,14 @@ Q(__neg__)
Q(__pos__) Q(__pos__)
#endif #endif
#if MICROPY_PY_ASYNC_AWAIT
Q(__aiter__)
Q(__anext__)
Q(__aenter__)
Q(__aexit__)
Q(StopAsyncIteration)
#endif
Q(micropython) Q(micropython)
Q(bytecode) Q(bytecode)
Q(const) Q(const)

View File

@ -57,6 +57,9 @@ bool mp_repl_continue_with_input(const char *input) {
|| str_startswith_word(input, "with") || str_startswith_word(input, "with")
|| str_startswith_word(input, "def") || str_startswith_word(input, "def")
|| str_startswith_word(input, "class") || 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 // check for unmatched open bracket, quote or escape quote