This commit is contained in:
blueloveTH 2024-08-11 13:05:56 +08:00
parent 145782b789
commit 66f7bbd18c
10 changed files with 46 additions and 12 deletions

View File

@ -47,6 +47,7 @@ typedef struct VM {
py_TValue last_retval; py_TValue last_retval;
py_TValue curr_exception; py_TValue curr_exception;
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
bool is_stopiteration; bool is_stopiteration;
py_TValue reg[8]; // users' registers py_TValue reg[8]; // users' registers

View File

@ -393,13 +393,16 @@ bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE;
/// Raise an expection object. Always return false. /// Raise an expection object. Always return false.
bool py_raise(py_Ref) PY_RAISE; bool py_raise(py_Ref) PY_RAISE;
/// Print the current exception. /// Print the current exception.
/// The exception will be set as handled.
void py_printexc(); void py_printexc();
/// Format the current exception and return a null-terminated string. /// Format the current exception and return a null-terminated string.
/// The result should be freed by the caller. /// The result should be freed by the caller.
/// The exception will be set as handled.
char* py_formatexc(); char* py_formatexc();
/// Check if an exception is raised. /// Check if an exception is raised.
bool py_checkexc(); bool py_checkexc(bool ignore_handled);
/// Check if the exception is an instance of the given type. /// Check if the exception is an instance of the given type.
/// If match, the exception will be set as handled.
bool py_matchexc(py_Type type); bool py_matchexc(py_Type type);
/// Clear the current exception. /// Clear the current exception.
/// @param p0 the unwinding point. Use `NULL` if not needed. /// @param p0 the unwinding point. Use `NULL` if not needed.

View File

@ -105,7 +105,8 @@ OPCODE(RAISE)
OPCODE(RAISE_ASSERT) OPCODE(RAISE_ASSERT)
OPCODE(RE_RAISE) OPCODE(RE_RAISE)
OPCODE(PUSH_EXCEPTION) OPCODE(PUSH_EXCEPTION)
OPCODE(POP_EXCEPTION) OPCODE(BEGIN_EXC_HANDLING)
OPCODE(END_EXC_HANDLING)
/**************************/ /**************************/
OPCODE(FSTRING_EVAL) OPCODE(FSTRING_EVAL)
OPCODE(FORMAT_STRING) OPCODE(FORMAT_STRING)

View File

@ -2519,13 +2519,13 @@ static Error* compile_try_except(Compiler* self) {
} }
int patch = Ctx__emit_(ctx(), OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE); int patch = Ctx__emit_(ctx(), OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
// on match // on match
Ctx__emit_(ctx(), OP_BEGIN_EXC_HANDLING, BC_NOARG, BC_KEEPLINE);
if(as_name) { if(as_name) {
Ctx__emit_(ctx(), OP_PUSH_EXCEPTION, BC_NOARG, BC_KEEPLINE); Ctx__emit_(ctx(), OP_PUSH_EXCEPTION, BC_NOARG, BC_KEEPLINE);
Ctx__emit_store_name(ctx(), name_scope(self), as_name, BC_KEEPLINE); Ctx__emit_store_name(ctx(), name_scope(self), as_name, BC_KEEPLINE);
} }
check(compile_block_body(self, compile_stmt)); check(compile_block_body(self, compile_stmt));
// pop the exception Ctx__emit_(ctx(), OP_END_EXC_HANDLING, BC_NOARG, BC_KEEPLINE);
Ctx__emit_(ctx(), OP_POP_EXCEPTION, BC_NOARG, BC_KEEPLINE);
patches[patches_length++] = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE); patches[patches_length++] = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
Ctx__patch_jump(ctx(), patch); Ctx__patch_jump(ctx(), patch);
} while(curr()->type == TK_EXCEPT); } while(curr()->type == TK_EXCEPT);

View File

@ -1013,7 +1013,11 @@ FrameResult VM__run_top_frame(VM* self) {
PUSH(&self->curr_exception); PUSH(&self->curr_exception);
DISPATCH(); DISPATCH();
} }
case OP_POP_EXCEPTION: { case OP_BEGIN_EXC_HANDLING: {
self->is_curr_exc_handled = true;
DISPATCH();
}
case OP_END_EXC_HANDLING: {
assert(self->curr_exception.type); assert(self->curr_exception.type);
py_clearexc(NULL); py_clearexc(NULL);
DISPATCH(); DISPATCH();

View File

@ -69,6 +69,7 @@ void VM__ctor(VM* self) {
self->last_retval = *py_NIL; self->last_retval = *py_NIL;
self->curr_exception = *py_NIL; self->curr_exception = *py_NIL;
self->is_curr_exc_handled = false;
self->is_stopiteration = false; self->is_stopiteration = false;
self->__curr_class = NULL; self->__curr_class = NULL;

View File

@ -104,7 +104,7 @@ bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
c11__abort( c11__abort(
"py_CFunction returns nothing! Did you forget to call `py_newnone(py_retval())`?"); "py_CFunction returns nothing! Did you forget to call `py_newnone(py_retval())`?");
} }
// if(py_checkexc()) { c11__abort("py_CFunction returns `true` but an exception is set!"); } if(py_checkexc(true)) { c11__abort("py_CFunction returns `true` but an exception is set!"); }
return true; return true;
} }
#endif #endif

View File

@ -88,7 +88,11 @@ static bool _py_BaseException__str__(int argc, py_Ref argv) {
c11_sbuf__ctor(&ss); c11_sbuf__ctor(&ss);
py_Ref arg = py_getslot(argv, 0); py_Ref arg = py_getslot(argv, 0);
if(!py_isnil(arg)) { if(!py_isnil(arg)) {
if(argv->type == tp_KeyError) {
if(!py_repr(arg)) return false;
} else {
if(!py_str(arg)) return false; if(!py_str(arg)) return false;
}
c11_sbuf__write_sv(&ss, py_tosv(py_retval())); c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
} }
c11_sbuf__py_submit(&ss, py_retval()); c11_sbuf__py_submit(&ss, py_retval());
@ -111,21 +115,29 @@ py_Type pk_Exception__register() {
} }
////////////////////////////////////////////////// //////////////////////////////////////////////////
bool py_checkexc() { bool py_checkexc(bool ignore_handled) {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(ignore_handled && vm->is_curr_exc_handled) return false;
return !py_isnil(&vm->curr_exception); return !py_isnil(&vm->curr_exception);
} }
bool py_matchexc(py_Type type) { bool py_matchexc(py_Type type) {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(vm->is_curr_exc_handled) return false;
if(py_isnil(&vm->curr_exception)) return false; if(py_isnil(&vm->curr_exception)) return false;
return py_issubclass(vm->curr_exception.type, type); bool ok = py_issubclass(vm->curr_exception.type, type);
if(ok) {
// if match, then the exception is handled
vm->is_curr_exc_handled = true;
}
return ok;
} }
void py_clearexc(py_StackRef p0) { void py_clearexc(py_StackRef p0) {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
vm->last_retval = *py_NIL; vm->last_retval = *py_NIL;
vm->curr_exception = *py_NIL; vm->curr_exception = *py_NIL;
vm->is_curr_exc_handled = false;
vm->is_stopiteration = false; vm->is_stopiteration = false;
vm->__curr_class = NULL; vm->__curr_class = NULL;
if(p0) vm->stack.sp = p0; if(p0) vm->stack.sp = p0;
@ -155,9 +167,13 @@ static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
} }
const char* name = py_tpname(exc->type); const char* name = py_tpname(exc->type);
const char* message;
bool ok = py_str(exc); bool ok = py_str(exc);
if(!ok) c11__abort("py_printexc(): failed to convert exception to string"); if(!ok || !py_isstr(py_retval())) {
const char* message = py_tostr(py_retval()); message = "<exception str() failed>";
} else {
message = py_tostr(py_retval());
}
c11_sbuf__write_cstr(self, name); c11_sbuf__write_cstr(self, name);
c11_sbuf__write_cstr(self, ": "); c11_sbuf__write_cstr(self, ": ");
@ -167,6 +183,10 @@ static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
char* py_formatexc() { char* py_formatexc() {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(py_isnil(&vm->curr_exception)) return NULL; if(py_isnil(&vm->curr_exception)) return NULL;
// when you call `py_formatexc()`, you are handling the exception
vm->is_curr_exc_handled = true;
c11_sbuf ss; c11_sbuf ss;
c11_sbuf__ctor(&ss); c11_sbuf__ctor(&ss);
@ -215,6 +235,7 @@ bool py_raise(py_Ref exc) {
py_setslot(exc, 1, &vm->curr_exception); py_setslot(exc, 1, &vm->curr_exception);
} }
vm->curr_exception = *exc; vm->curr_exception = *exc;
vm->is_curr_exc_handled = false;
return false; return false;
} }

View File

@ -68,7 +68,7 @@ int main(int argc, char** argv) {
} }
} }
int code = py_checkexc() ? 1 : 0; int code = py_checkexc(false) ? 1 : 0;
py_finalize(); py_finalize();
return code; return code;
} }

View File

@ -7,6 +7,9 @@ try:
except IndexError: except IndexError:
pass pass
k = KeyError('foo')
assert str(k) == "'foo'"
try: try:
assert False assert False
exit(1) exit(1)