Handle case of a nested exception in a 'final'
This commit is contained in:
parent
01d377555a
commit
d575bf7607
@ -2320,6 +2320,7 @@ _anotherExcept:
|
||||
patchJump(exitJumpOffsets[0]);
|
||||
firstJump = 1;
|
||||
emitByte(OP_TRY_ELSE);
|
||||
state->current->locals[exceptionObject].name = syntheticToken("");
|
||||
beginScope(state);
|
||||
block(state, blockWidth, "else");
|
||||
endScope(state);
|
||||
@ -2335,17 +2336,16 @@ _anotherExcept:
|
||||
for (int i = firstJump; i < exitJumps; ++i) {
|
||||
patchJump(exitJumpOffsets[i]);
|
||||
}
|
||||
size_t nameInd = renameLocal(state, exceptionObject, syntheticToken("__tmp"));
|
||||
emitByte(OP_BEGIN_FINALLY);
|
||||
exitJumps = 0;
|
||||
if (nextJump != -1) {
|
||||
patchJump(nextJump);
|
||||
}
|
||||
emitByte(OP_BEGIN_FINALLY);
|
||||
exitJumps = 0;
|
||||
state->current->locals[exceptionObject].name = syntheticToken("");
|
||||
beginScope(state);
|
||||
block(state,blockWidth,"finally");
|
||||
endScope(state);
|
||||
nextJump = -2;
|
||||
state->current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
|
||||
emitByte(OP_END_FINALLY);
|
||||
} else if (!check(TOKEN_EOL) && !check(TOKEN_EOF)) {
|
||||
krk_ungetToken(&state->scanner, state->parser.current);
|
||||
@ -2363,8 +2363,8 @@ _anotherExcept:
|
||||
}
|
||||
|
||||
if (nextJump >= 0) {
|
||||
emitByte(OP_BEGIN_FINALLY);
|
||||
patchJump(nextJump);
|
||||
emitByte(OP_BEGIN_FINALLY);
|
||||
emitByte(OP_END_FINALLY);
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@ void krk_printValueSafe(FILE * f, KrkValue printable) {
|
||||
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;
|
||||
case OP_RAISE_FROM: fprintf(f, "{reraise<-%d}", (int)AS_HANDLER_TARGET(printable)); break;
|
||||
}
|
||||
break;
|
||||
case KRK_VAL_KWARGS: {
|
||||
|
30
src/vm.c
30
src/vm.c
@ -1132,7 +1132,8 @@ static int handleException(void) {
|
||||
!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) &&
|
||||
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_RAISE)
|
||||
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_RAISE) &&
|
||||
!IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_END_FINALLY)
|
||||
; stackOffset--);
|
||||
if (stackOffset < exitSlot) {
|
||||
if (exitSlot == 0) {
|
||||
@ -2322,10 +2323,16 @@ _finishReturn: (void)0;
|
||||
}
|
||||
case OP_BEGIN_FINALLY: {
|
||||
if (IS_HANDLER(krk_peek(0))) {
|
||||
if (AS_HANDLER_TYPE(krk_peek(0)) == OP_PUSH_TRY) {
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_BEGIN_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
} else if (AS_HANDLER_TYPE(krk_peek(0)) == OP_FILTER_EXCEPT) {
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_BEGIN_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
switch (AS_HANDLER_TYPE(krk_peek(0))) {
|
||||
/* We either entered the @c finally without an exception, or the exception was handled by an @c except */
|
||||
case OP_PUSH_TRY:
|
||||
case OP_FILTER_EXCEPT:
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_BEGIN_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
break;
|
||||
/* We entered the @c finally without handling an exception. */
|
||||
case OP_RAISE:
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_END_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2583,6 +2590,12 @@ _finishReturn: (void)0;
|
||||
case OP_EXIT_LOOP:
|
||||
frame->ip += OPERAND;
|
||||
break;
|
||||
case OP_RAISE_FROM:
|
||||
/* Exception happened while in @c finally */
|
||||
krk_pop(); /* handler */
|
||||
krk_currentThread.currentException = krk_pop();
|
||||
krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
|
||||
goto _finishException;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3161,10 +3174,17 @@ _finishException:
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
|
||||
/* Stick the exception into the exception slot */
|
||||
switch (AS_HANDLER_TYPE(krk_currentThread.stackTop[-1])) {
|
||||
/* An exception happened while handling an exception */
|
||||
case OP_RAISE:
|
||||
case OP_FILTER_EXCEPT:
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_END_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
break;
|
||||
/* An exception happened while already in the @c finally block from handling
|
||||
* another exception. Bail. */
|
||||
case OP_END_FINALLY:
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RAISE_FROM,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
break;
|
||||
/* First exception in this chain. */
|
||||
default:
|
||||
krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RAISE,AS_HANDLER_TARGET(krk_peek(0)));
|
||||
break;
|
||||
|
13
test/testNestedExceptionInFinally.krk
Normal file
13
test/testNestedExceptionInFinally.krk
Normal file
@ -0,0 +1,13 @@
|
||||
try:
|
||||
try:
|
||||
print('try')
|
||||
raise ValueError()
|
||||
except 1/0:
|
||||
print('bad: except body')
|
||||
finally:
|
||||
print(inner_error)
|
||||
print('bad: after inner error')
|
||||
except BaseException as e:
|
||||
while e:
|
||||
print(repr(e))
|
||||
e = e.__context__
|
4
test/testNestedExceptionInFinally.krk.expect
Normal file
4
test/testNestedExceptionInFinally.krk.expect
Normal file
@ -0,0 +1,4 @@
|
||||
try
|
||||
NameError("Undefined variable 'inner_error'.")
|
||||
ZeroDivisionError('integer division by zero')
|
||||
ValueError()
|
Loading…
Reference in New Issue
Block a user