Skip to content

Commit 81ebba7

Browse files
pohmeliedpgeorge
authored andcommitted
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`.
1 parent 959ed93 commit 81ebba7

File tree

10 files changed

+265
-31
lines changed

10 files changed

+265
-31
lines changed

py/compile.c

Lines changed: 208 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -318,14 +318,14 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
318318
typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
319319
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
320320

321-
STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
321+
STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
322322
if (assign_kind != ASSIGN_AUG_STORE) {
323323
compile_node(comp, pns->nodes[0]);
324324
}
325325

326326
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
327327
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
328-
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) {
328+
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {
329329
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
330330
if (assign_kind != ASSIGN_AUG_STORE) {
331331
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
366366
goto cannot_assign;
367367
}
368368

369-
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
370-
goto cannot_assign;
371-
}
372-
373369
return;
374370

375371
cannot_assign:
@@ -440,9 +436,9 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
440436
// pn must be a struct
441437
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
442438
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
443-
case PN_power:
439+
case PN_atom_expr_normal:
444440
// lhs is an index or attribute
445-
c_assign_power(comp, pns, assign_kind);
441+
c_assign_atom_expr(comp, pns, assign_kind);
446442
break;
447443

448444
case PN_testlist_star_expr:
@@ -818,11 +814,19 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
818814
}
819815
}
820816

821-
// compile the body (funcdef or classdef) and get its name
817+
// compile the body (funcdef, async funcdef or classdef) and get its name
822818
mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1];
823819
qstr body_name = 0;
824820
if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
825821
body_name = compile_funcdef_helper(comp, pns_body, emit_options);
822+
#if MICROPY_PY_ASYNC_AWAIT
823+
} else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) {
824+
assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0]));
825+
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0];
826+
body_name = compile_funcdef_helper(comp, pns0, emit_options);
827+
scope_t *fscope = (scope_t*)pns0->nodes[4];
828+
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
829+
#endif
826830
} else {
827831
assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be
828832
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) {
846850
STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
847851
if (MP_PARSE_NODE_IS_ID(pn)) {
848852
compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn));
849-
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) {
853+
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) {
850854
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
851855

852-
compile_node(comp, pns->nodes[0]); // base of the power node
856+
compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node
853857

854858
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
855859
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
856-
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) {
860+
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {
857861
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
858862
for (int i = 0; i < n - 1; i++) {
859863
compile_node(comp, pns1->nodes[i]);
@@ -874,9 +878,6 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
874878
goto cannot_delete;
875879
}
876880

877-
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
878-
goto cannot_delete;
879-
}
880881
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {
881882
pn = ((mp_parse_node_struct_t*)pn)->nodes[0];
882883
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) {
13971398
// this bit optimises: for <x> in range(...), turning it into an explicitly incremented variable
13981399
// this is actually slower, but uses no heap memory
13991400
// for viper it will be much, much faster
1400-
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)) {
1401+
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)) {
14011402
mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1];
1402-
if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])
1403+
if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])
14031404
&& MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range
14041405
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren)
14051406
&& 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) {
16611662
compile_with_stmt_helper(comp, n, nodes, pns->nodes[1]);
16621663
}
16631664

1665+
STATIC void compile_yield_from(compiler_t *comp) {
1666+
EMIT(get_iter);
1667+
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
1668+
EMIT(yield_from);
1669+
}
1670+
1671+
#if MICROPY_PY_ASYNC_AWAIT
1672+
STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
1673+
EMIT_ARG(load_method, method);
1674+
EMIT_ARG(call_method, 0, 0, 0);
1675+
compile_yield_from(comp);
1676+
}
1677+
1678+
STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
1679+
// comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
1680+
1681+
qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
1682+
uint while_else_label = comp_next_label(comp);
1683+
uint try_exception_label = comp_next_label(comp);
1684+
uint try_else_label = comp_next_label(comp);
1685+
uint try_finally_label = comp_next_label(comp);
1686+
1687+
compile_node(comp, pns->nodes[1]); // iterator
1688+
compile_await_object_method(comp, MP_QSTR___aiter__);
1689+
compile_store_id(comp, context);
1690+
1691+
START_BREAK_CONTINUE_BLOCK
1692+
1693+
EMIT_ARG(label_assign, continue_label);
1694+
1695+
EMIT_ARG(setup_except, try_exception_label);
1696+
compile_increase_except_level(comp);
1697+
1698+
compile_load_id(comp, context);
1699+
compile_await_object_method(comp, MP_QSTR___anext__);
1700+
c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable
1701+
EMIT(pop_block);
1702+
EMIT_ARG(jump, try_else_label);
1703+
1704+
EMIT_ARG(label_assign, try_exception_label);
1705+
EMIT(start_except_handler);
1706+
EMIT(dup_top);
1707+
EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration);
1708+
EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);
1709+
EMIT_ARG(pop_jump_if, false, try_finally_label);
1710+
EMIT(pop_top);
1711+
EMIT(pop_top);
1712+
EMIT(pop_top);
1713+
EMIT(pop_except);
1714+
EMIT_ARG(jump, while_else_label);
1715+
1716+
EMIT_ARG(label_assign, try_finally_label);
1717+
EMIT_ARG(adjust_stack_size, 3);
1718+
compile_decrease_except_level(comp);
1719+
EMIT(end_finally);
1720+
EMIT(end_except_handler);
1721+
1722+
EMIT_ARG(label_assign, try_else_label);
1723+
compile_node(comp, pns->nodes[2]); // body
1724+
1725+
EMIT_ARG(jump, continue_label);
1726+
// break/continue apply to outer loop (if any) in the else block
1727+
END_BREAK_CONTINUE_BLOCK
1728+
1729+
EMIT_ARG(label_assign, while_else_label);
1730+
compile_node(comp, pns->nodes[3]); // else
1731+
1732+
EMIT_ARG(label_assign, break_label);
1733+
}
1734+
1735+
STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
1736+
if (n == 0) {
1737+
// no more pre-bits, compile the body of the with
1738+
compile_node(comp, body);
1739+
} else {
1740+
uint try_exception_label = comp_next_label(comp);
1741+
uint no_reraise_label = comp_next_label(comp);
1742+
uint try_else_label = comp_next_label(comp);
1743+
uint end_label = comp_next_label(comp);
1744+
qstr context;
1745+
1746+
if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) {
1747+
// this pre-bit is of the form "a as b"
1748+
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0];
1749+
compile_node(comp, pns->nodes[0]);
1750+
context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
1751+
compile_store_id(comp, context);
1752+
compile_load_id(comp, context);
1753+
compile_await_object_method(comp, MP_QSTR___aenter__);
1754+
c_assign(comp, pns->nodes[1], ASSIGN_STORE);
1755+
} else {
1756+
// this pre-bit is just an expression
1757+
compile_node(comp, nodes[0]);
1758+
context = MP_PARSE_NODE_LEAF_ARG(nodes[0]);
1759+
compile_store_id(comp, context);
1760+
compile_load_id(comp, context);
1761+
compile_await_object_method(comp, MP_QSTR___aenter__);
1762+
EMIT(pop_top);
1763+
}
1764+
1765+
compile_load_id(comp, context);
1766+
EMIT_ARG(load_method, MP_QSTR___aexit__);
1767+
1768+
EMIT_ARG(setup_except, try_exception_label);
1769+
compile_increase_except_level(comp);
1770+
// compile additional pre-bits and the body
1771+
compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body);
1772+
// finish this with block
1773+
EMIT(pop_block);
1774+
EMIT_ARG(jump, try_else_label); // jump over exception handler
1775+
1776+
EMIT_ARG(label_assign, try_exception_label); // start of exception handler
1777+
EMIT(start_except_handler);
1778+
EMIT(rot_three);
1779+
EMIT(rot_two);
1780+
EMIT_ARG(call_method, 3, 0, 0);
1781+
compile_yield_from(comp);
1782+
EMIT_ARG(pop_jump_if, true, no_reraise_label);
1783+
EMIT_ARG(raise_varargs, 0);
1784+
1785+
EMIT_ARG(label_assign, no_reraise_label);
1786+
EMIT(pop_except);
1787+
EMIT_ARG(jump, end_label);
1788+
1789+
EMIT_ARG(adjust_stack_size, 5);
1790+
compile_decrease_except_level(comp);
1791+
EMIT(end_finally);
1792+
EMIT(end_except_handler);
1793+
1794+
EMIT_ARG(label_assign, try_else_label); // start of try-else handler
1795+
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
1796+
EMIT(dup_top);
1797+
EMIT(dup_top);
1798+
EMIT_ARG(call_method, 3, 0, 0);
1799+
compile_yield_from(comp);
1800+
EMIT(pop_top);
1801+
1802+
EMIT_ARG(label_assign, end_label);
1803+
1804+
}
1805+
}
1806+
1807+
STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
1808+
// get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)
1809+
mp_parse_node_t *nodes;
1810+
int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);
1811+
assert(n > 0);
1812+
1813+
// compile in a nested fashion
1814+
compile_async_with_stmt_helper(comp, n, nodes, pns->nodes[1]);
1815+
}
1816+
1817+
STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
1818+
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[0]));
1819+
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0];
1820+
if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_funcdef) {
1821+
// async def
1822+
compile_funcdef(comp, pns0);
1823+
scope_t *fscope = (scope_t*)pns0->nodes[4];
1824+
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
1825+
} else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
1826+
// async for
1827+
compile_async_for_stmt(comp, pns0);
1828+
} else {
1829+
// async with
1830+
assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt);
1831+
compile_async_with_stmt(comp, pns0);
1832+
}
1833+
}
1834+
#endif
1835+
16641836
STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
16651837
if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
16661838
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) {
19672139
}
19682140
}
19692141

1970-
STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
2142+
STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) {
19712143
// this is to handle special super() call
19722144
comp->func_arg_is_super = MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super;
19732145

19742146
compile_generic_all_nodes(comp, pns);
2147+
}
19752148

1976-
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
1977-
EMIT_ARG(binary_op, MP_BINARY_OP_POWER);
1978-
}
2149+
STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
2150+
compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power
2151+
EMIT_ARG(binary_op, MP_BINARY_OP_POWER);
19792152
}
19802153

19812154
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
20762249
}
20772250
}
20782251

2079-
STATIC void compile_power_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) {
2252+
STATIC void compile_atom_expr_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) {
20802253
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
20812254
for (int i = 0; i < num_nodes; i++) {
20822255
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) {
24312604
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) {
24322605
pns = (mp_parse_node_struct_t*)pns->nodes[0];
24332606
compile_node(comp, pns->nodes[0]);
2434-
EMIT(get_iter);
2435-
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
2436-
EMIT(yield_from);
2607+
compile_yield_from(comp);
24372608
} else {
24382609
compile_node(comp, pns->nodes[0]);
24392610
EMIT(yield_value);
24402611
}
24412612
}
24422613

2614+
#if MICROPY_PY_ASYNC_AWAIT
2615+
STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pns) {
2616+
if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) {
2617+
compile_syntax_error(comp, (mp_parse_node_t)pns, "'await' outside function");
2618+
return;
2619+
}
2620+
compile_atom_expr_normal(comp, pns);
2621+
compile_yield_from(comp);
2622+
}
2623+
#endif
2624+
24432625
STATIC void compile_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
24442626
// only create and load the actual str object on the last pass
24452627
if (comp->pass != MP_PASS_EMIT) {
@@ -2995,7 +3177,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
29953177
goto not_an_instruction;
29963178
}
29973179
pns2 = (mp_parse_node_struct_t*)pns2->nodes[0];
2998-
if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_power) {
3180+
if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_atom_expr_normal) {
29993181
goto not_an_instruction;
30003182
}
30013183
if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) {

0 commit comments

Comments
 (0)