Properly run __exit__, finally on break or continue
This commit is contained in:
parent
d89b023752
commit
d6c9602abd
@ -1986,9 +1986,10 @@ static void breakStatement(struct GlobalState * state) {
|
||||
state->current->breaks = GROW_ARRAY(struct LoopExit,state->current->breaks,old,state->current->breakSpace);
|
||||
}
|
||||
|
||||
for (size_t i = state->current->loopLocalCount; i < state->current->localCount; ++i) {
|
||||
emitByte(OP_POP);
|
||||
if (state->current->loopLocalCount != state->current->localCount) {
|
||||
EMIT_OPERAND_OP(OP_EXIT_LOOP, state->current->loopLocalCount);
|
||||
}
|
||||
|
||||
state->current->breaks[state->current->breakCount++] = (struct LoopExit){emitJump(OP_JUMP),state->parser.previous};
|
||||
}
|
||||
|
||||
@ -1999,9 +2000,10 @@ static void continueStatement(struct GlobalState * state) {
|
||||
state->current->continues = GROW_ARRAY(struct LoopExit,state->current->continues,old,state->current->continueSpace);
|
||||
}
|
||||
|
||||
for (size_t i = state->current->loopLocalCount; i < state->current->localCount; ++i) {
|
||||
emitByte(OP_POP);
|
||||
if (state->current->loopLocalCount != state->current->localCount) {
|
||||
EMIT_OPERAND_OP(OP_EXIT_LOOP, state->current->loopLocalCount);
|
||||
}
|
||||
|
||||
state->current->continues[state->current->continueCount++] = (struct LoopExit){emitJump(OP_JUMP),state->parser.previous};
|
||||
}
|
||||
|
||||
|
@ -110,3 +110,4 @@ OPERAND(OP_EXPAND_ARGS,EXPAND_ARGS_MORE)
|
||||
SIMPLE(OP_INHERIT)
|
||||
JUMP(OP_CALL_ITER,+)
|
||||
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
|
||||
OPERAND(OP_EXIT_LOOP, (void)0)
|
||||
|
@ -64,6 +64,7 @@ void krk_printValueSafe(FILE * f, KrkValue printable) {
|
||||
case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_END_FINALLY: fprintf(f, "{end<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
case OP_EXIT_LOOP: fprintf(f, "{exit<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
}
|
||||
break;
|
||||
case KRK_VAL_KWARGS: {
|
||||
|
39
src/vm.c
39
src/vm.c
@ -2222,6 +2222,11 @@ _resumeHook: (void)0;
|
||||
krk_callDirect(type->_exit, 4);
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _finishException;
|
||||
}
|
||||
if (AS_HANDLER_TYPE(handler) == OP_EXIT_LOOP) {
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(handler);
|
||||
OPERAND = AS_INTEGER(krk_peek(1));
|
||||
goto _finishPopBlock;
|
||||
}
|
||||
if (AS_HANDLER_TYPE(handler) != OP_RETURN) break;
|
||||
krk_pop(); /* handler */
|
||||
} /* fallthrough */
|
||||
@ -2388,6 +2393,8 @@ _finishReturn: (void)0;
|
||||
isMatch = 0;
|
||||
} else if (AS_HANDLER_TYPE(krk_peek(1)) == OP_END_FINALLY) {
|
||||
isMatch = 0;
|
||||
} else if (AS_HANDLER_TYPE(krk_peek(1)) == OP_EXIT_LOOP) {
|
||||
isMatch = 0;
|
||||
} else if (IS_CLASS(krk_peek(0)) && krk_isInstanceOf(krk_peek(2), AS_CLASS(krk_peek(0)))) {
|
||||
isMatch = 1;
|
||||
} else if (IS_TUPLE(krk_peek(0))) {
|
||||
@ -2425,6 +2432,10 @@ _finishReturn: (void)0;
|
||||
krk_currentThread.currentException = krk_pop();
|
||||
krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
|
||||
goto _finishException;
|
||||
} else if (AS_HANDLER_TYPE(handler) == OP_EXIT_LOOP) {
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(handler);
|
||||
OPERAND = AS_INTEGER(krk_peek(1));
|
||||
goto _finishPopBlock;
|
||||
} else if (AS_HANDLER_TYPE(handler) == OP_RETURN) {
|
||||
krk_push(krk_peek(1));
|
||||
goto _finishReturn;
|
||||
@ -2887,6 +2898,34 @@ _finishReturn: (void)0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_EXIT_LOOP_LONG:
|
||||
THREE_BYTE_OPERAND;
|
||||
case OP_EXIT_LOOP: {
|
||||
ONE_BYTE_OPERAND;
|
||||
_finishPopBlock:
|
||||
closeUpvalues(frame->slots + OPERAND);
|
||||
int stackOffset;
|
||||
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
|
||||
stackOffset >= (int)(frame->slots + OPERAND) &&
|
||||
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_PUSH_TRY) &&
|
||||
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_PUSH_WITH) &&
|
||||
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_FILTER_EXCEPT)
|
||||
; stackOffset--) krk_pop();
|
||||
|
||||
/* Do the handler. */
|
||||
if (stackOffset >= (int)(frame->slots + OPERAND)) {
|
||||
uint16_t popTarget = (frame->ip - frame->closure->function->chunk.code);
|
||||
krk_currentThread.stackTop = &krk_currentThread.stack[stackOffset + 1];
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_EXIT_LOOP, popTarget);
|
||||
krk_currentThread.stackTop[-2] = INTEGER_VAL(OPERAND);
|
||||
}
|
||||
|
||||
/* Continue normally */
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_POP_MANY_LONG:
|
||||
THREE_BYTE_OPERAND;
|
||||
case OP_POP_MANY: {
|
||||
|
17
test/testBreakFinallys.krk
Normal file
17
test/testBreakFinallys.krk
Normal file
@ -0,0 +1,17 @@
|
||||
def foo():
|
||||
try:
|
||||
for i in range(5):
|
||||
try:
|
||||
try:
|
||||
print('in try')
|
||||
break
|
||||
finally:
|
||||
print('finally')
|
||||
finally:
|
||||
print('another finally')
|
||||
print('out of try/finally')
|
||||
print('out of loop')
|
||||
finally:
|
||||
print('in other finally')
|
||||
|
||||
foo()
|
5
test/testBreakFinallys.krk.expect
Normal file
5
test/testBreakFinallys.krk.expect
Normal file
@ -0,0 +1,5 @@
|
||||
in try
|
||||
finally
|
||||
another finally
|
||||
out of loop
|
||||
in other finally
|
25
test/testBreakWiths.krk
Normal file
25
test/testBreakWiths.krk
Normal file
@ -0,0 +1,25 @@
|
||||
class withable():
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
def __enter__(self):
|
||||
print("enter", self.name)
|
||||
def __exit__(self,*args):
|
||||
print("exit", self.name, args)
|
||||
|
||||
while True:
|
||||
with withable('outer'):
|
||||
while True:
|
||||
with withable('a'):
|
||||
print("into a")
|
||||
with withable('b'):
|
||||
print("into b")
|
||||
with withable('c'):
|
||||
print("into c")
|
||||
break
|
||||
print("nope b")
|
||||
print("nope a")
|
||||
print("nope loop")
|
||||
print("exit from loop")
|
||||
break
|
||||
print("nope outer")
|
||||
print("done")
|
13
test/testBreakWiths.krk.expect
Normal file
13
test/testBreakWiths.krk.expect
Normal file
@ -0,0 +1,13 @@
|
||||
enter outer
|
||||
enter a
|
||||
into a
|
||||
enter b
|
||||
into b
|
||||
enter c
|
||||
into c
|
||||
exit c [None, None, None]
|
||||
exit b [None, None, None]
|
||||
exit a [None, None, None]
|
||||
exit from loop
|
||||
exit outer [None, None, None]
|
||||
done
|
Loading…
Reference in New Issue
Block a user