I've some success with "async with":
Code: Select all
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 label_exception = comp_next_label(comp);
uint label_no_reraise = comp_next_label(comp);
uint label_success = comp_next_label(comp);
uint label_end = 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);
EMIT_ARG(load_method, MP_QSTR___aenter__);
EMIT_ARG(call_method, 0, 0, 0);
EMIT(get_iter);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
EMIT(yield_from);
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);
EMIT_ARG(load_method, MP_QSTR___aenter__);
EMIT_ARG(call_method, 0, 0, 0);
EMIT(get_iter);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
EMIT(yield_from);
EMIT(pop_top);
}
EMIT_ARG(setup_except, label_exception);
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, label_success); // jump over exception handler
EMIT_ARG(label_assign, label_exception); // start of exception handler
EMIT(start_except_handler);
EMIT(pop_top);
EMIT(pop_top);
EMIT(pop_top);
compile_load_id(comp, context);
EMIT_ARG(load_method, MP_QSTR___aexit__);
EMIT_ARG(call_method, 0, 0, 0); // TODO: add *sys.exc_info()
EMIT(get_iter);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
EMIT(yield_from);
EMIT_ARG(pop_jump_if, true, label_no_reraise);
EMIT_ARG(raise_varargs, 0);
EMIT_ARG(label_assign, label_no_reraise);
EMIT(pop_except);
compile_decrease_except_level(comp);
EMIT(end_except_handler);
EMIT_ARG(jump, label_end);
EMIT(end_finally);
EMIT_ARG(label_assign, label_success);
compile_load_id(comp, context);
EMIT_ARG(load_method, MP_QSTR___aexit__);
EMIT_ARG(call_method, 0, 0, 0); // TODO: add *sys.exc_info()
EMIT(get_iter);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
EMIT(yield_from);
EMIT(pop_top);
EMIT_ARG(label_assign, label_end);
}
}
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]);
}
#include <stdio.h>
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
// TODO implement me
printf("async for\n");
// compile_node(comp, pns->nodes[0]);
} else {
// async with
// TODO implement me
printf("async with\n");
assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt);
compile_async_with_stmt(comp, (mp_parse_node_struct_t *)pns->nodes[0]);
}
}
Above code compile
Code: Select all
async def yoba():
async with AWith() as foo:
print(foo)
into exactly same bytecode as
Code: Select all
async def yoba():
mgr = AWith()
foo = await mgr.__aenter__()
try:
print(foo)
except:
if not await mgr.__aexit__():
raise
else:
await mgr.__aexit__()
Except, that there is no «mgr» name in scope.
Code: Select all
----------------
[ 1] async_stmt(90) (n=1)
[ 1] funcdef(10) (n=5)
id(yoba)
NULL
NULL
[ 3] async_stmt(90) (n=1)
[ 3] with_stmt(86) (n=2)
[ 3] with_item(88) (n=2)
[ 3] power(123) (n=3)
id(AWith)
[ 3] trailer_paren(139) (n=1)
NULL
NULL
id(foo)
[ 5] expr_stmt(32) (n=2)
[ 5] power(123) (n=3)
id(print)
[ 5] trailer_paren(139) (n=1)
id(foo)
NULL
NULL
NULL
----------------
async with
File test-awith-short.py, code block '<module>' (descriptor: 0x7f921f59bf40, bytecode @0x7f921f59c420 37 bytes)
Raw bytecode (code_info_size=10, bytecode_size=27):
01 00 00 00 00 00 0a 82 33 83 7b 00 00 00 00 00
ff 60 00 00 00 00 00 00 80 c3 59 1f 92 7f 00 00
24 83 7c 11 5b
arg names:(N_STATE 1)
(N_EXC_STACK 0)
bc=-1 line=1
00 MAKE_FUNCTION 0x7f921f59c380
15 STORE_NAME yoba
18 LOAD_CONST_NONE
19 RETURN_VALUE
async with
ERROR: stack size not back to zero; got -3
async with
ERROR: stack size not back to zero; got -3
async with
ERROR: stack size not back to zero; got -3
File test-awith-short.py, code block 'yoba' (descriptor: 0x7f921f59c380, bytecode @0x7f921f59c460 80 bytes)
Raw bytecode (code_info_size=10, bytecode_size=70):
07 01 04 00 00 00 0a 83 7c 83 7b 41 53 00 00 00
ff 1d 83 7d 00 64 00 c0 b0 1f 18 66 00 42 11 5e
c1 3f 0c 00 1d 81 20 00 b1 64 01 32 44 35 15 80
32 32 32 b0 1f 19 66 00 42 11 5e 36 02 80 5c 00
45 35 0a 80 41 b0 1f 19 66 00 42 11 5e 32 11 5b
arg names:(N_STATE 7)
(N_EXC_STACK 1)
bc=-1 line=1
bc=0 line=3
bc=19 line=5
00 LOAD_GLOBAL AWith (cache=0)
04 CALL_FUNCTION n=0 nkw=0
06 STORE_FAST 0
07 LOAD_FAST 0
08 LOAD_METHOD __aenter__
10 CALL_METHOD n=0 nkw=0
12 GET_ITER
13 LOAD_CONST_NONE
14 YIELD_FROM
15 STORE_FAST 1
16 SETUP_EXCEPT 31
19 LOAD_GLOBAL print (cache=0)
23 LOAD_FAST 1
24 CALL_FUNCTION n=1 nkw=0
26 POP_TOP
27 POP_BLOCK
28 JUMP 52
31 POP_TOP
32 POP_TOP
33 POP_TOP
34 LOAD_FAST 0
35 LOAD_METHOD __aexit__
37 CALL_METHOD n=0 nkw=0
39 GET_ITER
40 LOAD_CONST_NONE
41 YIELD_FROM
42 POP_JUMP_IF_TRUE 47
45 RAISE_VARARGS 0
47 POP_EXCEPT
48 JUMP 61
51 END_FINALLY
52 LOAD_FAST 0
53 LOAD_METHOD __aexit__
55 CALL_METHOD n=0 nkw=0
57 GET_ITER
58 LOAD_CONST_NONE
59 YIELD_FROM
60 POP_TOP
61 LOAD_CONST_NONE
62 RETURN_VALUE
mem: total=3213, current=945, peak=2496
stack: 32 out of 80000
GC: total: 2072832, used: 1056, free: 2071776
No. of 1-blocks: 8, 2-blocks: 2, max blk sz: 6
But, I get "micropython: ../py/emitbc.c:486: emit_bc_pre: Assertion `(mp_int_t)emit->stack_size + stack_size_delta >= 0' failed." error.
What did I miss?