Handle case of a nested exception in a 'final'

This commit is contained in:
K. Lange 2023-11-25 12:14:05 +09:00
parent 01d377555a
commit d575bf7607
5 changed files with 48 additions and 10 deletions

View File

@ -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);
}

View File

@ -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: {

View File

@ -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;

View 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__

View File

@ -0,0 +1,4 @@
try
NameError("Undefined variable 'inner_error'.")
ZeroDivisionError('integer division by zero')
ValueError()