Attach and build upon partial tracebacks

If an exception is raised within a 'try', attach a traceback only up
until that 'try'. If a re-raised exception has a traceback already,
attach the new traceback "above" the existing one.
This commit is contained in:
K. Lange 2022-07-03 20:39:07 +09:00
parent 85ad910f23
commit f38a451f19
4 changed files with 78 additions and 9 deletions

View File

@ -263,16 +263,28 @@ void krk_dumpTraceback(void) {
static void attachTraceback(void) {
if (IS_INSTANCE(krk_currentThread.currentException)) {
KrkInstance * theException = AS_INSTANCE(krk_currentThread.currentException);
/* If there already is a traceback, don't add a new one; this exception was re-raised. */
KrkValue existing;
if (krk_tableGet(&theException->fields, OBJECT_VAL(S("traceback")), &existing)) return;
KrkValue tracebackList = krk_list_of(0,NULL,0);
KrkValue tracebackList;
if (krk_tableGet(&theException->fields, OBJECT_VAL(S("traceback")), &tracebackList)) {
krk_push(tracebackList);
} else {
krk_push(NONE_VAL());
}
tracebackList = krk_list_of(0,NULL,0);
krk_push(tracebackList);
/* Build the traceback object */
if (krk_currentThread.frameCount) {
for (size_t i = 0; i < krk_currentThread.frameCount; i++) {
/* Go up until we get to the exit frame */
size_t frameOffset = 0;
if (krk_currentThread.stackTop > krk_currentThread.stack) {
size_t stackOffset = krk_currentThread.stackTop - krk_currentThread.stack - 1;
while (stackOffset > 0 && !IS_TRY_HANDLER(krk_currentThread.stack[stackOffset])) stackOffset--;
frameOffset = krk_currentThread.frameCount - 1;
while (frameOffset > 0 && krk_currentThread.frames[frameOffset].slots > stackOffset) frameOffset--;
}
for (size_t i = frameOffset; i < krk_currentThread.frameCount; i++) {
KrkCallFrame * frame = &krk_currentThread.frames[i];
KrkTuple * tbEntry = krk_newTuple(2);
krk_push(OBJECT_VAL(tbEntry));
@ -282,8 +294,17 @@ static void attachTraceback(void) {
krk_pop();
}
}
if (IS_list(krk_peek(1))) {
KrkValueArray * existingTraceback = AS_LIST(krk_peek(1));
for (size_t i = 0; i < existingTraceback->count; ++i) {
krk_writeValueArray(AS_LIST(tracebackList), existingTraceback->values[i]);
}
}
krk_attachNamedValue(&theException->fields, "traceback", tracebackList);
krk_pop();
krk_pop();
} /* else: probably a legacy 'raise str', just don't bother. */
}

View File

@ -1,7 +1,5 @@
Caught a TypeError('A type error')
File 'test/testExceptionTracebacks.krk', line 14, in <module>
File 'test/testExceptionTracebacks.krk', line 4, in doTheThing
Caught a ValueError('A value error')
File 'test/testExceptionTracebacks.krk', line 15, in <module>
File 'test/testExceptionTracebacks.krk', line 4, in doTheThing
That's a name error!

View File

@ -0,0 +1,39 @@
def foo():
try:
raise ValueError("oh no")
except Exception as e:
raise e
if True:
try:
foo()
except Exception as e:
print("Traceback entries")
for i in e.traceback:
let func, instr = i
print(f" File '{func.__file__}', line {func._ip_to_line(instr)}, in {func.__name__}")
else:
foo()
def bar(n):
if n == 3:
raise ValueError(n)
else:
bar(n+1)
if True:
try:
try:
bar(0)
except Exception as e:
raise e
except Exception as e:
print("Traceback entries")
for i in e.traceback:
let func, instr = i
print(f" File '{func.__file__}', line {func._ip_to_line(instr)}, in {func.__name__}")
else:
try:
bar(0)
except Exception as e:
raise e

View File

@ -0,0 +1,11 @@
Traceback entries
File 'test/testReraisedExceptionTracebacks.krk', line 9, in <module>
File 'test/testReraisedExceptionTracebacks.krk', line 5, in foo
File 'test/testReraisedExceptionTracebacks.krk', line 3, in foo
Traceback entries
File 'test/testReraisedExceptionTracebacks.krk', line 29, in <module>
File 'test/testReraisedExceptionTracebacks.krk', line 27, in <module>
File 'test/testReraisedExceptionTracebacks.krk', line 22, in bar
File 'test/testReraisedExceptionTracebacks.krk', line 22, in bar
File 'test/testReraisedExceptionTracebacks.krk', line 22, in bar
File 'test/testReraisedExceptionTracebacks.krk', line 20, in bar