From 45de08dd39d1ab8530101a0b83b20056b45acb21 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 9 Jul 2024 01:32:14 +0800 Subject: [PATCH] ... --- include/pocketpy/interpreter/vm.h | 4 +- include/pocketpy/objects/error.h | 4 +- include/pocketpy/pocketpy.h | 1 + src/interpreter/ceval.c | 3 +- src/interpreter/vm.c | 6 ++- src/{ => objects}/error.c | 0 src/public/error.c | 33 ++++++++----- src/public/py_exception.c | 81 +++++++++++++++++++++++++++++++ tests/00_tmp.py | 4 -- 9 files changed, 112 insertions(+), 24 deletions(-) rename src/{ => objects}/error.c (100%) create mode 100644 src/public/py_exception.c delete mode 100644 tests/00_tmp.py diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 33e79713..0e2ecc72 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -51,7 +51,7 @@ typedef struct pk_VM { void (*_stderr)(const char*, ...); py_TValue last_retval; - bool has_error; + py_TValue last_exception; bool is_stopiteration; py_TValue reg[8]; // users' registers @@ -114,6 +114,8 @@ py_Type pk_function__register(); py_Type pk_nativefunc__register(); py_Type pk_range__register(); py_Type pk_range_iterator__register(); +py_Type pk_BaseException__register(); +py_Type pk_Exception__register(); py_TValue pk_builtins__register(); diff --git a/include/pocketpy/objects/error.h b/include/pocketpy/objects/error.h index 01de9745..cfbc44f2 100644 --- a/include/pocketpy/objects/error.h +++ b/include/pocketpy/objects/error.h @@ -13,12 +13,12 @@ extern "C" { // pk_SourceData_ src; // int lineno; // const char* cursor; -// py_Str name; +// c11_string* name; // } pkpy_ExceptionFrame; // typedef struct pkpy_Exception { // py_Name type; -// py_Str msg; +// c11_string* msg; // bool is_re; // int _ip_on_error; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index bebe6815..874a8a64 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -409,6 +409,7 @@ enum py_PredefinedTypes { tp_nativefunc, tp_bound_method, tp_super, // 1 slot + py_Type + tp_base_exception, tp_exception, tp_bytes, tp_mappingproxy, diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index ae9332a6..1f5951cc 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -83,7 +83,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { __NEXT_STEP: byte = *frame->ip; -#if 0 +#if 1 c11_sbuf buf; c11_sbuf__ctor(&buf); for(py_Ref p = self->stack.begin; p != SP(); p++) { @@ -777,7 +777,6 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { // 1. Exception can be handled inside the current frame // 2. Exception need to be propagated to the upper frame printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame)); - assert(false); return RES_ERROR; } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 1ac51238..31e4635b 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -71,7 +71,7 @@ void pk_VM__ctor(pk_VM* self) { self->_stderr = pk_default_stderr; self->last_retval = PY_NIL; - self->has_error = false; + self->last_exception = PY_NIL; self->is_stopiteration = false; self->__curr_class = PY_NIL; @@ -112,7 +112,8 @@ void pk_VM__ctor(pk_VM* self) { validate(tp_bound_method, pk_VM__new_type(self, "bound_method", tp_object, NULL, false)); validate(tp_super, pk_VM__new_type(self, "super", tp_object, NULL, false)); - validate(tp_exception, pk_VM__new_type(self, "Exception", tp_object, NULL, true)); + validate(tp_base_exception, pk_BaseException__register()); + validate(tp_exception, pk_Exception__register()); validate(tp_bytes, pk_bytes__register()); validate(tp_mappingproxy, pk_VM__new_type(self, "mappingproxy", tp_object, NULL, false)); @@ -148,6 +149,7 @@ void pk_VM__ctor(pk_VM* self) { tp_bytes, tp_dict, tp_property, + tp_base_exception, tp_exception, tp_stop_iteration, tp_syntax_error}; diff --git a/src/error.c b/src/objects/error.c similarity index 100% rename from src/error.c rename to src/objects/error.c diff --git a/src/public/error.c b/src/public/error.c index 494d4e0e..68c5e333 100644 --- a/src/public/error.c +++ b/src/public/error.c @@ -4,24 +4,25 @@ #include -void py_printexc(){ +void py_printexc() { pk_VM* vm = pk_current_vm; - if(vm->has_error){ - assert(vm->last_retval.type == tp_exception); - }else{ + if(py_isnil(&vm->last_exception)) { vm->_stdout("NoneType: None\n"); + } else { + const char* name = py_tpname(vm->last_exception.type); + bool ok = py_str(&vm->last_exception); + if(!ok) abort(); + const char* message = py_tostr(py_retval()); + vm->_stdout("%s: %s\n", name, message); } } +void py_formatexc(char* out) {} -void py_formatexc(char *out){ - -} - -bool py_exception(const char* name, const char* fmt, ...){ +bool py_exception(const char* name, const char* fmt, ...) { pk_VM* vm = pk_current_vm; - assert(!vm->has_error); // an error is already set - vm->has_error = true; + // an error is already set + assert(py_isnil(&vm->last_exception)); c11_sbuf buf; c11_sbuf__ctor(&buf); @@ -31,8 +32,14 @@ bool py_exception(const char* name, const char* fmt, ...){ va_end(args); c11_string* res = c11_sbuf__submit(&buf); - // vm->last_retval = py_newexception(name, res->data); - vm->_stderr("%s: %s\n", name, res->data); + py_Ref message = py_pushtmp(); + py_newstrn(message, res->data, res->size); c11_string__delete(res); + py_pop(); + + bool ok = py_tpcall(tp_exception, 1, message); + if(!ok) abort(); + vm->last_exception = *py_retval(); + return false; } \ No newline at end of file diff --git a/src/public/py_exception.c b/src/public/py_exception.c new file mode 100644 index 00000000..4b33453f --- /dev/null +++ b/src/public/py_exception.c @@ -0,0 +1,81 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" +#include "pocketpy/common/sstream.h" + +typedef struct BaseExceptionFrame { + pk_SourceData_ src; + int lineno; + c11_string* name; +} BaseExceptionFrame; + +typedef struct BaseException { + int ip_backup; + CodeObject* code_backup; + c11_vector /*T=BaseExceptionFrame*/ stacktrace; +} BaseException; + +static bool _py_BaseException__new__(int argc, py_Ref argv) { + py_Type cls = py_totype(argv); + BaseException* ud = py_newobject(py_retval(), cls, 1, sizeof(BaseException)); + ud->ip_backup = -1; + ud->code_backup = NULL; + return true; +} + +static bool _py_BaseException__init__(int argc, py_Ref argv) { + if(argc == 1 + 0) { return true; } + if(argc == 1 + 1) { + py_setslot(py_arg(0), 0, py_arg(1)); + return true; + } + return TypeError("__init__() takes at most 2 arguments but %d were given", argc); +} + +static bool _py_BaseException__repr__(int argc, py_Ref argv) { + c11_sbuf ss; + c11_sbuf__ctor(&ss); + pk_sprintf(&ss, "%t(", argv->type); + py_Ref arg = py_getslot(argv, 0); + if(!py_isnil(arg)) { + if(!py_repr(arg)) return false; + c11_sbuf__write_sv(&ss, py_tosv(py_retval())); + } + c11_sbuf__write_char(&ss, ')'); + c11_string* res = c11_sbuf__submit(&ss); + py_newstrn(py_retval(), res->data, res->size); + c11_string__delete(res); + return true; +} + +static bool _py_BaseException__str__(int argc, py_Ref argv) { + c11_sbuf ss; + c11_sbuf__ctor(&ss); + py_Ref arg = py_getslot(argv, 0); + if(!py_isnil(arg)) { + if(!py_str(arg)) return false; + c11_sbuf__write_sv(&ss, py_tosv(py_retval())); + } + c11_string* res = c11_sbuf__submit(&ss); + py_newstrn(py_retval(), res->data, res->size); + c11_string__delete(res); + return true; +} + +py_Type pk_BaseException__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "BaseException", tp_object, NULL, true); + py_bindmagic(type, __new__, _py_BaseException__new__); + py_bindmagic(type, __init__, _py_BaseException__init__); + py_bindmagic(type, __repr__, _py_BaseException__repr__); + py_bindmagic(type, __str__, _py_BaseException__str__); + return type; +} + +py_Type pk_Exception__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "Exception", tp_base_exception, NULL, true); + return type; +} \ No newline at end of file diff --git a/tests/00_tmp.py b/tests/00_tmp.py deleted file mode 100644 index ca5cf9be..00000000 --- a/tests/00_tmp.py +++ /dev/null @@ -1,4 +0,0 @@ -def f(a, b): - return a+b - -assert f(1, 2) == 3