Implement 'finally'
This commit is contained in:
parent
baad0997fb
commit
8aed1368ea
@ -66,7 +66,9 @@ typedef enum {
|
||||
OP_BREAKPOINT, /* NEVER output this instruction in the compiler or bad things can happen */
|
||||
OP_YIELD,
|
||||
OP_ANNOTATE,
|
||||
/* current highest: 44 */
|
||||
OP_BEGIN_FINALLY,
|
||||
OP_END_FINALLY,
|
||||
/* current highest: 45 */
|
||||
|
||||
OP_CALL = 64,
|
||||
OP_CLASS,
|
||||
|
103
src/compiler.c
103
src/compiler.c
@ -257,6 +257,7 @@ static KrkToken classDeclaration();
|
||||
static void declareVariable();
|
||||
static void namedVariable(KrkToken name, int canAssign);
|
||||
static size_t addLocal(KrkToken name);
|
||||
static size_t renameLocal(size_t ind, KrkToken name);
|
||||
static void string(int canAssign);
|
||||
static KrkToken decorator(size_t level, FunctionType type);
|
||||
static void call(int canAssign);
|
||||
@ -907,7 +908,8 @@ static void endScope() {
|
||||
while (current->localCount > 0 &&
|
||||
current->locals[current->localCount - 1].depth > (ssize_t)current->scopeDepth) {
|
||||
for (size_t i = 0; i < current->codeobject->localNameCount; i++) {
|
||||
if (current->codeobject->localNames[i].id == current->localCount - 1) {
|
||||
if (current->codeobject->localNames[i].id == current->localCount - 1 &&
|
||||
current->codeobject->localNames[i].deathday == 0) {
|
||||
current->codeobject->localNames[i].deathday = (size_t)currentChunk()->count;
|
||||
}
|
||||
}
|
||||
@ -1730,18 +1732,27 @@ static void tryStatement() {
|
||||
/* Make sure we are in a local scope so this ends up on the stack */
|
||||
beginScope();
|
||||
int tryJump = emitJump(OP_PUSH_TRY);
|
||||
/* We'll rename this later, but it needs to be on the stack now as it represents the exception handler */
|
||||
size_t localNameCount = current->codeobject->localNameCount;
|
||||
|
||||
size_t exceptionObject = addLocal(syntheticToken(""));
|
||||
defineVariable(0);
|
||||
markInitialized();
|
||||
|
||||
addLocal(syntheticToken("")); /* Try */
|
||||
markInitialized();
|
||||
|
||||
beginScope();
|
||||
block(blockWidth,"try");
|
||||
endScope();
|
||||
|
||||
int successJump = emitJump(OP_JUMP);
|
||||
#define EXIT_JUMP_MAX 32
|
||||
int exitJumps = 1;
|
||||
int exitJumpOffsets[EXIT_JUMP_MAX] = {0};
|
||||
|
||||
exitJumpOffsets[0] = emitJump(OP_JUMP);
|
||||
patchJump(tryJump);
|
||||
|
||||
int nextJump = -1;
|
||||
|
||||
_anotherExcept:
|
||||
if (blockWidth == 0 || (check(TOKEN_INDENTATION) && (parser.current.length == blockWidth))) {
|
||||
KrkToken previous;
|
||||
if (blockWidth) {
|
||||
@ -1749,11 +1760,19 @@ static void tryStatement() {
|
||||
advance();
|
||||
}
|
||||
if (match(TOKEN_EXCEPT)) {
|
||||
if (nextJump != -1) {
|
||||
patchJump(nextJump);
|
||||
emitByte(OP_POP);
|
||||
}
|
||||
/* Match filter expression (should be class or tuple) */
|
||||
if (!check(TOKEN_COLON) && !check(TOKEN_AS)) {
|
||||
expression();
|
||||
emitByte(OP_FILTER_EXCEPT);
|
||||
} else {
|
||||
emitByte(OP_NONE);
|
||||
}
|
||||
emitByte(OP_FILTER_EXCEPT);
|
||||
nextJump = emitJump(OP_JUMP_IF_FALSE);
|
||||
emitByte(OP_POP);
|
||||
|
||||
/* Match 'as' to rename exception */
|
||||
if (match(TOKEN_AS)) {
|
||||
@ -1763,14 +1782,42 @@ static void tryStatement() {
|
||||
/* XXX Should we remove this now? */
|
||||
current->locals[exceptionObject].name = syntheticToken("exception");
|
||||
}
|
||||
/* Make sure we update the local name for debugging */
|
||||
current->codeobject->localNames[localNameCount].birthday = currentChunk()->count;
|
||||
current->codeobject->localNames[localNameCount].name = krk_copyString(current->locals[exceptionObject].name.start, current->locals[exceptionObject].name.length);
|
||||
|
||||
size_t nameInd = renameLocal(exceptionObject, current->locals[exceptionObject].name);
|
||||
|
||||
consume(TOKEN_COLON, "Expect ':' after except.");
|
||||
beginScope();
|
||||
block(blockWidth,"except");
|
||||
endScope();
|
||||
|
||||
current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
|
||||
|
||||
if (exitJumps < EXIT_JUMP_MAX) {
|
||||
exitJumpOffsets[exitJumps++] = emitJump(OP_JUMP);
|
||||
} else {
|
||||
error("too many except clauses");
|
||||
return;
|
||||
}
|
||||
|
||||
goto _anotherExcept;
|
||||
} else if (match(TOKEN_FINALLY)) {
|
||||
consume(TOKEN_COLON, "expected : after 'finally'");
|
||||
for (int i = 0; i < exitJumps; ++i) {
|
||||
patchJump(exitJumpOffsets[i]);
|
||||
}
|
||||
size_t nameInd = renameLocal(exceptionObject, syntheticToken("__tmp"));
|
||||
emitByte(OP_BEGIN_FINALLY);
|
||||
exitJumps = 0;
|
||||
if (nextJump != -1) {
|
||||
patchJump(nextJump);
|
||||
emitByte(OP_POP);
|
||||
}
|
||||
beginScope();
|
||||
block(blockWidth,"finally");
|
||||
endScope();
|
||||
nextJump = -2;
|
||||
current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
|
||||
emitByte(OP_END_FINALLY);
|
||||
} else if (!check(TOKEN_EOL) && !check(TOKEN_EOF)) {
|
||||
krk_ungetToken(parser.current);
|
||||
parser.current = parser.previous;
|
||||
@ -1782,7 +1829,18 @@ static void tryStatement() {
|
||||
}
|
||||
}
|
||||
|
||||
patchJump(successJump);
|
||||
for (int i = 0; i < exitJumps; ++i) {
|
||||
patchJump(exitJumpOffsets[i]);
|
||||
}
|
||||
|
||||
if (nextJump >= 0) {
|
||||
emitByte(OP_BEGIN_FINALLY);
|
||||
emitByte(OP_NONE);
|
||||
patchJump(nextJump);
|
||||
emitByte(OP_POP);
|
||||
emitByte(OP_END_FINALLY);
|
||||
}
|
||||
|
||||
endScope(); /* will pop the exception handler */
|
||||
}
|
||||
|
||||
@ -2818,6 +2876,19 @@ static ssize_t resolveLocal(Compiler * compiler, KrkToken * name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static size_t renameLocal(size_t ind, KrkToken name) {
|
||||
if (current->codeobject->localNameCount + 1 > current->localNameCapacity) {
|
||||
size_t old = current->localNameCapacity;
|
||||
current->localNameCapacity = GROW_CAPACITY(old);
|
||||
current->codeobject->localNames = GROW_ARRAY(KrkLocalEntry, current->codeobject->localNames, old, current->localNameCapacity);
|
||||
}
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].id = ind;
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].birthday = currentChunk()->count;
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].deathday = 0;
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].name = krk_copyString(name.start, name.length);
|
||||
return current->codeobject->localNameCount++;
|
||||
}
|
||||
|
||||
static size_t addLocal(KrkToken name) {
|
||||
if (current->localCount + 1 > current->localsSpace) {
|
||||
size_t old = current->localsSpace;
|
||||
@ -2830,16 +2901,10 @@ static size_t addLocal(KrkToken name) {
|
||||
local->depth = -1;
|
||||
local->isCaptured = 0;
|
||||
|
||||
if (current->codeobject->localNameCount + 1 > current->localNameCapacity) {
|
||||
size_t old = current->localNameCapacity;
|
||||
current->localNameCapacity = GROW_CAPACITY(old);
|
||||
current->codeobject->localNames = GROW_ARRAY(KrkLocalEntry, current->codeobject->localNames, old, current->localNameCapacity);
|
||||
if (name.length) {
|
||||
renameLocal(out, name);
|
||||
}
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].id = current->localCount-1;
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].birthday = currentChunk()->count;
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].deathday = 0;
|
||||
current->codeobject->localNames[current->codeobject->localNameCount].name = krk_copyString(name.start, name.length);
|
||||
current->codeobject->localNameCount++;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ void krk_debug_dumpStack(FILE * file, KrkCallFrame * frame) {
|
||||
if (relative == f->closure->function->localNames[j].id
|
||||
/* Only display this name if it's currently valid */
|
||||
&& f->closure->function->localNames[j].birthday <= (size_t)(f->ip - f->closure->function->chunk.code)
|
||||
&& f->closure->function->localNames[j].deathday >= (size_t)(f->ip - f->closure->function->chunk.code)
|
||||
) {
|
||||
fprintf(file, "%s=", f->closure->function->localNames[j].name->chars);
|
||||
found = 1;
|
||||
|
@ -40,6 +40,8 @@ SIMPLE(OP_FILTER_EXCEPT)
|
||||
SIMPLE(OP_BREAKPOINT)
|
||||
SIMPLE(OP_YIELD)
|
||||
SIMPLE(OP_ANNOTATE)
|
||||
SIMPLE(OP_BEGIN_FINALLY)
|
||||
SIMPLE(OP_END_FINALLY)
|
||||
CONSTANT(OP_DEFINE_GLOBAL,(void)0)
|
||||
CONSTANT(OP_CONSTANT,(void)0)
|
||||
CONSTANT(OP_GET_GLOBAL,(void)0)
|
||||
|
@ -553,7 +553,7 @@ char * syn_krk_keywords[] = {
|
||||
"and","class","def","else","for","if","in","import","del",
|
||||
"let","not","or","return","while","try","except","raise",
|
||||
"continue","break","as","from","elif","lambda","with","is",
|
||||
"pass","assert","yield",
|
||||
"pass","assert","yield","finally",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -224,6 +224,7 @@ static KrkTokenType identifierType() {
|
||||
case 'x': return checkKeyword(2, "cept", TOKEN_EXCEPT);
|
||||
} break;
|
||||
case 'f': if (MORE(1)) switch(scanner.start[1]) {
|
||||
case 'i': return checkKeyword(2, "nally", TOKEN_FINALLY);
|
||||
case 'o': return checkKeyword(2, "r", TOKEN_FOR);
|
||||
case 'r': return checkKeyword(2, "om", TOKEN_FROM);
|
||||
} else if (scanner.start[1] == '\'' || scanner.start[1] == '"') return TOKEN_PREFIX_F;
|
||||
|
@ -68,6 +68,7 @@ typedef enum {
|
||||
TOKEN_DEL,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_FINALLY,
|
||||
TOKEN_FOR,
|
||||
TOKEN_IF,
|
||||
TOKEN_IMPORT,
|
||||
|
11
src/value.c
11
src/value.c
@ -53,7 +53,16 @@ void krk_printValueSafe(FILE * f, KrkValue printable) {
|
||||
case KRK_VAL_BOOLEAN: fprintf(f, "%s", AS_BOOLEAN(printable) ? "True" : "False"); break;
|
||||
case KRK_VAL_FLOATING: fprintf(f, "%.16g", AS_FLOATING(printable)); break;
|
||||
case KRK_VAL_NONE: fprintf(f, "None"); break;
|
||||
case KRK_VAL_HANDLER: fprintf(f, "{%s->%d}", AS_HANDLER(printable).type == OP_PUSH_TRY ? "try" : "with", (int)AS_HANDLER(printable).target); break;
|
||||
case KRK_VAL_HANDLER:
|
||||
switch (AS_HANDLER(printable).type) {
|
||||
case OP_PUSH_TRY: fprintf(f, "{try->%d}", (int)AS_HANDLER(printable).target); break;
|
||||
case OP_PUSH_WITH: fprintf(f, "{with->%d}", (int)AS_HANDLER(printable).target); break;
|
||||
case OP_RAISE: fprintf(f, "{raise<-%d}", (int)AS_HANDLER(printable).target); break;
|
||||
case OP_FILTER_EXCEPT: fprintf(f, "{except<-%d}", (int)AS_HANDLER(printable).target); break;
|
||||
case OP_BEGIN_FINALLY: fprintf(f, "{finally<-%d}", (int)AS_HANDLER(printable).target); break;
|
||||
case OP_RETURN: fprintf(f, "{return<-%d}", (int)AS_HANDLER(printable).target); break;
|
||||
}
|
||||
break;
|
||||
case KRK_VAL_KWARGS: {
|
||||
if (AS_INTEGER(printable) == LONG_MAX) {
|
||||
fprintf(f, "{unpack single}");
|
||||
|
@ -207,4 +207,6 @@ extern int krk_valuesSame(KrkValue a, KrkValue b);
|
||||
|
||||
#define IS_TRY_HANDLER(value) (IS_HANDLER(value) && AS_HANDLER(value).type == OP_PUSH_TRY)
|
||||
#define IS_WITH_HANDLER(value) (IS_HANDLER(value) && AS_HANDLER(value).type == OP_PUSH_WITH)
|
||||
#define IS_RAISE_HANDLER(value) (IS_HANDLER(value) && AS_HANDLER(value).type == OP_RAISE)
|
||||
#define IS_EXCEPT_HANDLER(value) (IS_HANDLER(value) && AS_HANDLER(value).type == OP_FILTER_EXCEPT)
|
||||
|
||||
|
84
src/vm.c
84
src/vm.c
@ -1431,7 +1431,11 @@ MAKE_COMPARATOR(gt, >)
|
||||
static int handleException() {
|
||||
int stackOffset, frameOffset;
|
||||
int exitSlot = (krk_currentThread.exitOnFrame >= 0) ? krk_currentThread.frames[krk_currentThread.exitOnFrame].outSlots : 0;
|
||||
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1); stackOffset >= exitSlot && !IS_TRY_HANDLER(krk_currentThread.stack[stackOffset]); stackOffset--);
|
||||
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
|
||||
stackOffset >= exitSlot &&
|
||||
!IS_TRY_HANDLER(krk_currentThread.stack[stackOffset]) &&
|
||||
!IS_EXCEPT_HANDLER(krk_currentThread.stack[stackOffset])
|
||||
; stackOffset--);
|
||||
if (stackOffset < exitSlot) {
|
||||
if (exitSlot == 0) {
|
||||
/*
|
||||
@ -1982,21 +1986,32 @@ _resumeHook: (void)0;
|
||||
/* Top of stack is now either someone else's problem or a return value */
|
||||
if (AS_HANDLER(handler).type != OP_RETURN) break;
|
||||
krk_pop(); /* handler */
|
||||
krk_pop(); /* context manager */
|
||||
krk_pop(); /* contextManager */
|
||||
} /* fallthrough */
|
||||
case OP_RETURN: {
|
||||
_finishReturn: (void)0;
|
||||
KrkValue result = krk_pop();
|
||||
closeUpvalues(frame->slots);
|
||||
/* See if this frame had a thing */
|
||||
int stackOffset;
|
||||
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1); stackOffset >= (int)frame->slots && !IS_WITH_HANDLER(krk_currentThread.stack[stackOffset]); stackOffset--);
|
||||
for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
|
||||
stackOffset >= (int)frame->slots &&
|
||||
!IS_WITH_HANDLER(krk_currentThread.stack[stackOffset]) &&
|
||||
!IS_TRY_HANDLER(krk_currentThread.stack[stackOffset]) &&
|
||||
!IS_EXCEPT_HANDLER(krk_currentThread.stack[stackOffset])
|
||||
; stackOffset--);
|
||||
if (stackOffset >= (int)frame->slots) {
|
||||
krk_currentThread.stackTop = &krk_currentThread.stack[stackOffset + 1];
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER(krk_peek(0)).target;
|
||||
int wasWith = (IS_WITH_HANDLER(krk_peek(0)));
|
||||
AS_HANDLER(krk_currentThread.stackTop[-1]).type = OP_RETURN;
|
||||
krk_push(result);
|
||||
krk_swap(2);
|
||||
krk_swap(1);
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER(krk_peek(0)).target;
|
||||
AS_HANDLER(krk_currentThread.stackTop[-1]).type = OP_RETURN;
|
||||
if (wasWith) {
|
||||
krk_swap(1);
|
||||
} else {
|
||||
krk_pop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
krk_currentThread.frameCount--;
|
||||
@ -2185,24 +2200,52 @@ _resumeHook: (void)0;
|
||||
break;
|
||||
case OP_FILTER_EXCEPT: {
|
||||
int isMatch = 0;
|
||||
if (IS_CLASS(krk_peek(0)) && krk_isInstanceOf(krk_peek(1), AS_CLASS(krk_peek(0)))) {
|
||||
if (AS_HANDLER(krk_peek(1)).type == OP_RETURN) {
|
||||
isMatch = 0;
|
||||
} else if (AS_HANDLER(krk_peek(1)).type == OP_END_FINALLY) {
|
||||
isMatch = 0;
|
||||
} else if (IS_CLASS(krk_peek(0)) && krk_isInstanceOf(krk_peek(2), AS_CLASS(krk_peek(0)))) {
|
||||
isMatch = 1;
|
||||
} if (IS_TUPLE(krk_peek(0))) {
|
||||
} else if (IS_TUPLE(krk_peek(0))) {
|
||||
for (size_t i = 0; i < AS_TUPLE(krk_peek(0))->values.count; ++i) {
|
||||
if (IS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]) && krk_isInstanceOf(krk_peek(1), AS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]))) {
|
||||
if (IS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]) && krk_isInstanceOf(krk_peek(2), AS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]))) {
|
||||
isMatch = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (IS_NONE(krk_peek(0))) {
|
||||
isMatch = !IS_NONE(krk_peek(2));
|
||||
}
|
||||
if (!isMatch) {
|
||||
/* Restore and re-raise the exception if it didn't match. */
|
||||
krk_currentThread.currentException = krk_peek(1);
|
||||
krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
|
||||
goto _finishException;
|
||||
if (isMatch) {
|
||||
AS_HANDLER(krk_currentThread.stackTop[-2]).type = OP_FILTER_EXCEPT;
|
||||
}
|
||||
/* Else pop the filter value */
|
||||
krk_pop();
|
||||
krk_push(BOOLEAN_VAL(isMatch));
|
||||
break;
|
||||
}
|
||||
case OP_BEGIN_FINALLY: {
|
||||
if (IS_HANDLER(krk_peek(0))) {
|
||||
if (AS_HANDLER(krk_peek(0)).type == OP_PUSH_TRY) {
|
||||
AS_HANDLER(krk_currentThread.stackTop[-1]).type = OP_BEGIN_FINALLY;
|
||||
} else if (AS_HANDLER(krk_peek(0)).type == OP_FILTER_EXCEPT) {
|
||||
AS_HANDLER(krk_currentThread.stackTop[-1]).type = OP_BEGIN_FINALLY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_END_FINALLY: {
|
||||
KrkValue handler = krk_peek(0);
|
||||
if (IS_HANDLER(handler)) {
|
||||
if (AS_HANDLER(handler).type == OP_RAISE || AS_HANDLER(handler).type == OP_END_FINALLY) {
|
||||
krk_pop(); /* handler */
|
||||
krk_currentThread.currentException = krk_pop();
|
||||
krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
|
||||
goto _finishException;
|
||||
} else if (AS_HANDLER(handler).type == OP_RETURN) {
|
||||
krk_push(krk_peek(1));
|
||||
goto _finishReturn;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_BREAKPOINT: {
|
||||
@ -2258,6 +2301,7 @@ _resumeHook: (void)0;
|
||||
}
|
||||
case OP_PUSH_TRY: {
|
||||
uint16_t tryTarget = OPERAND + (frame->ip - frame->closure->function->chunk.code);
|
||||
krk_push(NONE_VAL());
|
||||
KrkValue handler = HANDLER_VAL(OP_PUSH_TRY, tryTarget);
|
||||
krk_push(handler);
|
||||
break;
|
||||
@ -2623,9 +2667,13 @@ _finishException:
|
||||
if (!handleException()) {
|
||||
frame = &krk_currentThread.frames[krk_currentThread.frameCount - 1];
|
||||
frame->ip = frame->closure->function->chunk.code + AS_HANDLER(krk_peek(0)).target;
|
||||
/* Replace the exception handler with the exception */
|
||||
krk_pop();
|
||||
krk_push(krk_currentThread.currentException);
|
||||
/* Stick the exception into the exception slot */
|
||||
if (AS_HANDLER(krk_currentThread.stackTop[-1]).type == OP_FILTER_EXCEPT) {
|
||||
AS_HANDLER(krk_currentThread.stackTop[-1]).type = OP_END_FINALLY;
|
||||
} else {
|
||||
AS_HANDLER(krk_currentThread.stackTop[-1]).type = OP_RAISE;
|
||||
}
|
||||
krk_currentThread.stackTop[-2] = krk_currentThread.currentException;
|
||||
krk_currentThread.currentException = NONE_VAL();
|
||||
} else {
|
||||
return NONE_VAL();
|
||||
|
73
test/testFinally.krk
Normal file
73
test/testFinally.krk
Normal file
@ -0,0 +1,73 @@
|
||||
def f():
|
||||
try:
|
||||
print("in try")
|
||||
return 'try'
|
||||
print("???")
|
||||
except:
|
||||
print("exception?")
|
||||
finally:
|
||||
print("in finally")
|
||||
return 'finally'
|
||||
|
||||
print(f())
|
||||
|
||||
def f():
|
||||
try:
|
||||
print("in try")
|
||||
raise Exception()
|
||||
except:
|
||||
print("exception?")
|
||||
return "exception"
|
||||
finally:
|
||||
print("in finally")
|
||||
return 'finally'
|
||||
|
||||
print(f())
|
||||
|
||||
def f():
|
||||
try:
|
||||
print("in try")
|
||||
raise Exception()
|
||||
except:
|
||||
print("exception?")
|
||||
return "exception"
|
||||
finally:
|
||||
print("in finally")
|
||||
|
||||
print(f())
|
||||
|
||||
def f():
|
||||
try:
|
||||
print("in try")
|
||||
raise Exception()
|
||||
finally:
|
||||
print("in finally")
|
||||
return 42
|
||||
|
||||
print(f())
|
||||
|
||||
def f():
|
||||
try:
|
||||
print("in try")
|
||||
raise Exception()
|
||||
finally:
|
||||
print("in finally")
|
||||
|
||||
try:
|
||||
print(f())
|
||||
except:
|
||||
print("Raised exception.")
|
||||
|
||||
def f():
|
||||
try:
|
||||
print("in try")
|
||||
raise Exception()
|
||||
except:
|
||||
raise ValueError()
|
||||
finally:
|
||||
print("in finally")
|
||||
|
||||
try:
|
||||
print(f())
|
||||
except Exception as e:
|
||||
print("Raised",type(e))
|
20
test/testFinally.krk.expect
Normal file
20
test/testFinally.krk.expect
Normal file
@ -0,0 +1,20 @@
|
||||
in try
|
||||
in finally
|
||||
finally
|
||||
in try
|
||||
exception?
|
||||
in finally
|
||||
finally
|
||||
in try
|
||||
exception?
|
||||
in finally
|
||||
exception
|
||||
in try
|
||||
in finally
|
||||
42
|
||||
in try
|
||||
in finally
|
||||
Raised exception.
|
||||
in try
|
||||
in finally
|
||||
Raised <class 'ValueError'>
|
27
test/testMultipleExcept.krk
Normal file
27
test/testMultipleExcept.krk
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
class SpecialException(ValueError):
|
||||
pass
|
||||
|
||||
def exceptionFilter(exc):
|
||||
print('with',repr(exc))
|
||||
try:
|
||||
if exc: raise exc()
|
||||
print("None")
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
finally:
|
||||
print("Running finally")
|
||||
print("Function exit")
|
||||
|
||||
exceptionFilter(None)
|
||||
exceptionFilter(TypeError)
|
||||
exceptionFilter(ValueError)
|
||||
exceptionFilter(SpecialException)
|
||||
|
||||
try:
|
||||
exceptionFilter(NameError)
|
||||
except Exception as e:
|
||||
print("NameError was not caught:", repr(e))
|
||||
|
19
test/testMultipleExcept.krk.expect
Normal file
19
test/testMultipleExcept.krk.expect
Normal file
@ -0,0 +1,19 @@
|
||||
with None
|
||||
None
|
||||
Running finally
|
||||
Function exit
|
||||
with <class 'TypeError'>
|
||||
TypeError
|
||||
Running finally
|
||||
Function exit
|
||||
with <class 'ValueError'>
|
||||
ValueError
|
||||
Running finally
|
||||
Function exit
|
||||
with <class '__main__.SpecialException'>
|
||||
ValueError
|
||||
Running finally
|
||||
Function exit
|
||||
with <class 'NameError'>
|
||||
Running finally
|
||||
NameError was not caught: NameError(None)
|
Loading…
Reference in New Issue
Block a user