py: Fix break from within a for loop.
Needed to pop the iterator object when breaking out of a for loop. Need also to be careful to unwind exception handler before popping iterator. Addresses issue #635.
This commit is contained in:
parent
8827682b35
commit
25c84643b6
@ -73,8 +73,8 @@ typedef struct _compiler_t {
|
|||||||
|
|
||||||
uint next_label;
|
uint next_label;
|
||||||
|
|
||||||
uint break_label;
|
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||||
uint continue_label;
|
uint16_t continue_label;
|
||||||
int break_continue_except_level;
|
int break_continue_except_level;
|
||||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||||
|
|
||||||
@ -1745,6 +1745,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||||||
// And, if the loop never runs, the loop variable should never be assigned
|
// And, if the loop never runs, the loop variable should never be assigned
|
||||||
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
|
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
|
||||||
START_BREAK_CONTINUE_BLOCK
|
START_BREAK_CONTINUE_BLOCK
|
||||||
|
comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||||
|
|
||||||
uint top_label = comp_next_label(comp);
|
uint top_label = comp_next_label(comp);
|
||||||
uint entry_label = comp_next_label(comp);
|
uint entry_label = comp_next_label(comp);
|
||||||
@ -1843,6 +1844,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
START_BREAK_CONTINUE_BLOCK
|
START_BREAK_CONTINUE_BLOCK
|
||||||
|
comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||||
|
|
||||||
uint pop_label = comp_next_label(comp);
|
uint pop_label = comp_next_label(comp);
|
||||||
uint end_label = comp_next_label(comp);
|
uint end_label = comp_next_label(comp);
|
||||||
|
@ -44,6 +44,8 @@ typedef enum {
|
|||||||
#define MP_EMIT_STAR_FLAG_SINGLE (0x01)
|
#define MP_EMIT_STAR_FLAG_SINGLE (0x01)
|
||||||
#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)
|
#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)
|
||||||
|
|
||||||
|
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
|
||||||
|
|
||||||
typedef struct _emit_t emit_t;
|
typedef struct _emit_t emit_t;
|
||||||
|
|
||||||
typedef struct _emit_method_table_t {
|
typedef struct _emit_method_table_t {
|
||||||
|
12
py/emitbc.c
12
py/emitbc.c
@ -617,11 +617,15 @@ STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) {
|
|||||||
|
|
||||||
STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
|
STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
|
||||||
if (except_depth == 0) {
|
if (except_depth == 0) {
|
||||||
emit_bc_jump(emit, label);
|
|
||||||
} else {
|
|
||||||
emit_bc_pre(emit, 0);
|
emit_bc_pre(emit, 0);
|
||||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label);
|
if (label & MP_EMIT_BREAK_FROM_FOR) {
|
||||||
emit_write_bytecode_byte(emit, except_depth);
|
// need to pop the iterator if we are breaking out of a for loop
|
||||||
|
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
|
||||||
|
}
|
||||||
|
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
|
||||||
|
} else {
|
||||||
|
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
|
||||||
|
emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1043,7 +1043,7 @@ STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
|
STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
|
||||||
emit_native_jump(emit, label); // TODO properly
|
emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) {
|
STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) {
|
||||||
|
7
py/vm.c
7
py/vm.c
@ -618,10 +618,10 @@ dispatch_loop:
|
|||||||
ENTRY(MP_BC_UNWIND_JUMP):
|
ENTRY(MP_BC_UNWIND_JUMP):
|
||||||
DECODE_SLABEL;
|
DECODE_SLABEL;
|
||||||
PUSH((void*)(ip + unum)); // push destination ip for jump
|
PUSH((void*)(ip + unum)); // push destination ip for jump
|
||||||
PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind
|
PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind (0x80 bit set if we also need to pop stack)
|
||||||
unwind_jump:
|
unwind_jump:
|
||||||
unum = (machine_uint_t)POP(); // get number of exception handlers to unwind
|
unum = (machine_uint_t)POP(); // get number of exception handlers to unwind
|
||||||
while (unum > 0) {
|
while ((unum & 0x7f) > 0) {
|
||||||
unum -= 1;
|
unum -= 1;
|
||||||
assert(exc_sp >= exc_stack);
|
assert(exc_sp >= exc_stack);
|
||||||
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
|
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
|
||||||
@ -638,6 +638,9 @@ unwind_jump:
|
|||||||
exc_sp--;
|
exc_sp--;
|
||||||
}
|
}
|
||||||
ip = (const byte*)POP(); // pop destination ip for jump
|
ip = (const byte*)POP(); // pop destination ip for jump
|
||||||
|
if (unum != 0) {
|
||||||
|
sp--;
|
||||||
|
}
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
|
||||||
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
|
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user