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:
parent
959ed931a4
commit
81ebba7e02
234
py/compile.c
234
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;
|
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])) {
|
||||||
|
31
py/grammar.h
31
py/grammar.h
@ -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'
|
||||||
|
@ -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",
|
||||||
|
@ -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,
|
||||||
|
@ -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) },
|
||||||
|
@ -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)
|
||||||
|
1
py/obj.h
1
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_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;
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user