From 9bd257e6255d554db9104128698e9384848d8167 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Fri, 29 Jul 2022 20:05:21 +0900 Subject: [PATCH] Exceptions raised in 'else' should run 'finally' before raising, not run 'except' --- src/compiler.c | 7 +++++++ src/opcodes.h | 1 + src/vm.c | 6 ++++++ test/testTryElseRaise.krk | 12 ++++++++++++ test/testTryElseRaise.krk.expect | 4 ++++ 5 files changed, 30 insertions(+) create mode 100644 test/testTryElseRaise.krk create mode 100644 test/testTryElseRaise.krk.expect diff --git a/src/compiler.c b/src/compiler.c index cfa3e94..80eb0ef 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -2260,9 +2260,16 @@ _anotherExcept: consume(TOKEN_COLON, "Expected ':' after 'else'."); patchJump(exitJumpOffsets[0]); firstJump = 1; + emitByte(OP_TRY_ELSE); beginScope(state); block(state, blockWidth, "else"); endScope(state); + if (nextJump == -1) { + /* If there were no except: blocks, we need to make sure that the + * 'try' handler goes directly to the finally, so that 'break'/'continue' + * within the 'try' does not run this 'else' step. */ + patchJump(tryJump); + } goto _anotherExcept; } else if (match(TOKEN_FINALLY)) { consume(TOKEN_COLON, "Expected ':' after 'finally'."); diff --git a/src/opcodes.h b/src/opcodes.h index 9fae36d..93d1e49 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -111,3 +111,4 @@ SIMPLE(OP_INHERIT) JUMP(OP_CALL_ITER,+) JUMP(OP_JUMP_IF_TRUE_OR_POP,+) OPERAND(OP_EXIT_LOOP, (void)0) +SIMPLE(OP_TRY_ELSE) diff --git a/src/vm.c b/src/vm.c index 45137c4..9bf98f4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2414,6 +2414,12 @@ _finishReturn: (void)0; krk_push(BOOLEAN_VAL(isMatch)); break; } + case OP_TRY_ELSE: { + if (IS_HANDLER(krk_peek(0))) { + krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_FILTER_EXCEPT,AS_HANDLER_TARGET(krk_peek(0))); + } + break; + } case OP_BEGIN_FINALLY: { if (IS_HANDLER(krk_peek(0))) { if (AS_HANDLER_TYPE(krk_peek(0)) == OP_PUSH_TRY) { diff --git a/test/testTryElseRaise.krk b/test/testTryElseRaise.krk new file mode 100644 index 0000000..032f5f4 --- /dev/null +++ b/test/testTryElseRaise.krk @@ -0,0 +1,12 @@ +try: + try: + print("good") + except: + print("bad") + else: + print('else') + raise ValueError + finally: + print('finally') +except ValueError: + print("raised ValueError as expected") diff --git a/test/testTryElseRaise.krk.expect b/test/testTryElseRaise.krk.expect new file mode 100644 index 0000000..5bf427d --- /dev/null +++ b/test/testTryElseRaise.krk.expect @@ -0,0 +1,4 @@ +good +else +finally +raised ValueError as expected