py: Implement break and continue byte codes, and add tests.
Also fixes a bug in the for-in-range optimiser. I hope to remove break and continue byte codes in the future and just use jump (if possible).
This commit is contained in:
parent
2c30256382
commit
600ae734cf
@ -1442,24 +1442,27 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
|
||||
comp->continue_label = continue_label;
|
||||
|
||||
int top_label = comp_next_label(comp);
|
||||
int entry_label = comp_next_label(comp);
|
||||
|
||||
// compile: var = start
|
||||
compile_node(comp, pn_start);
|
||||
c_assign(comp, pn_var, ASSIGN_STORE);
|
||||
|
||||
EMIT(jump, continue_label);
|
||||
EMIT(jump, entry_label);
|
||||
EMIT(label_assign, top_label);
|
||||
|
||||
// compile body
|
||||
compile_node(comp, pn_body);
|
||||
|
||||
EMIT(label_assign, continue_label);
|
||||
|
||||
// compile: var += step
|
||||
c_assign(comp, pn_var, ASSIGN_AUG_LOAD);
|
||||
compile_node(comp, pn_step);
|
||||
EMIT(binary_op, RT_BINARY_OP_INPLACE_ADD);
|
||||
c_assign(comp, pn_var, ASSIGN_AUG_STORE);
|
||||
|
||||
EMIT(label_assign, continue_label);
|
||||
EMIT(label_assign, entry_label);
|
||||
|
||||
// compile: if var <cond> end: goto top
|
||||
compile_node(comp, pn_var);
|
||||
|
14
py/vm.c
14
py/vm.c
@ -326,6 +326,18 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
||||
break;
|
||||
*/
|
||||
|
||||
// TODO this might need more sophisticated handling when breaking from within an except
|
||||
case MP_BC_BREAK_LOOP:
|
||||
DECODE_ULABEL;
|
||||
ip += unum;
|
||||
break;
|
||||
|
||||
// TODO this might need more sophisticated handling when breaking from within an except
|
||||
case MP_BC_CONTINUE_LOOP:
|
||||
DECODE_ULABEL;
|
||||
ip += unum;
|
||||
break;
|
||||
|
||||
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
|
||||
case MP_BC_SETUP_EXCEPT:
|
||||
DECODE_ULABEL; // except labels are always forward
|
||||
@ -366,7 +378,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
||||
exc_sp -= 2; // pop back to previous exception handler
|
||||
break;
|
||||
|
||||
// matched againts: SETUP_EXCEPT
|
||||
// matched against: SETUP_EXCEPT
|
||||
case MP_BC_POP_EXCEPT:
|
||||
// TODO need to work out how blocks work etc
|
||||
// pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
|
||||
|
13
tests/basics/break.py
Normal file
13
tests/basics/break.py
Normal file
@ -0,0 +1,13 @@
|
||||
while True:
|
||||
break
|
||||
|
||||
for i in range(4):
|
||||
print('one', i)
|
||||
if i > 2:
|
||||
break
|
||||
print('two', i)
|
||||
|
||||
for i in [1, 2, 3, 4]:
|
||||
if i == 3:
|
||||
break
|
||||
print(i)
|
16
tests/basics/continue.py
Normal file
16
tests/basics/continue.py
Normal file
@ -0,0 +1,16 @@
|
||||
for i in range(4):
|
||||
print('one', i)
|
||||
if i > 2:
|
||||
continue
|
||||
print('two', i)
|
||||
|
||||
for i in range(4):
|
||||
print('one', i)
|
||||
if i < 2:
|
||||
continue
|
||||
print('two', i)
|
||||
|
||||
for i in [1, 2, 3, 4]:
|
||||
if i == 3:
|
||||
continue
|
||||
print(i)
|
Loading…
Reference in New Issue
Block a user