diff --git a/include/pocketpy/objects/error.h b/include/pocketpy/objects/error.h index 801f1c19..247c1c5a 100644 --- a/include/pocketpy/objects/error.h +++ b/include/pocketpy/objects/error.h @@ -20,7 +20,8 @@ struct Error{ int64_t userdata; }; -void py_BaseException__record(py_Ref, const Bytecode* ip, const CodeObject* code); +void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code); +int py_BaseException__get_lineno(py_Ref, const CodeObject* code); void py_BaseException__stpush(py_Ref, pk_SourceData_ src, int lineno, const char* func_name); #ifdef __cplusplus diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 360894fa..1197de3f 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -7,6 +7,7 @@ #include "pocketpy/objects/codeobject.h" #include "pocketpy/pocketpy.h" #include "pocketpy/objects/error.h" +#include static bool stack_unpack_sequence(pk_VM* self, uint16_t arg); static bool format_object(py_Ref obj, c11_sv spec); @@ -888,7 +889,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_RE_RAISE: { py_raise(&self->curr_exception); - goto __ERROR; + goto __ERROR_RE_RAISE; } case OP_PUSH_EXCEPTION: { assert(self->curr_exception.type); @@ -922,16 +923,16 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { c11__unreachedable(); __ERROR: + pk_print_stack(self, frame, (Bytecode){OP_NO_OP, 0}); + py_BaseException__set_lineno(&self->curr_exception, Frame__lineno(frame), frame->co); + __ERROR_RE_RAISE: + printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame)); - py_BaseException__record(&self->curr_exception, frame->ip, frame->co); - // TODO: lineno bug on re-raise - int lineno = Frame__lineno(frame); - py_BaseException__stpush( - &self->curr_exception, - frame->co->src, - lineno, - frame->function ? frame->co->name->data : NULL - ); + int lineno = py_BaseException__get_lineno(&self->curr_exception, frame->co); + py_BaseException__stpush(&self->curr_exception, + frame->co->src, + lineno < 0 ? Frame__lineno(frame) : lineno, + frame->function ? frame->co->name->data : NULL); int target = Frame__prepare_jump_exception_handler(frame, &self->stack); if(target >= 0) { diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index 80e7099f..a7c861f5 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -71,10 +71,8 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) { iblock = block->parent; } if(iblock < 0) return -1; - py_TValue obj = *--_s->sp; // pop exception object UnwindTarget* uw = Frame__find_unwind_target(self, iblock); _s->sp = (self->locals + uw->offset); // unwind the stack - *(_s->sp++) = obj; // push it back return c11__at(CodeBlock, &self->co->blocks, iblock)->end; } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index e25c0033..e92407af 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -31,7 +31,7 @@ static void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type index, py_Type base, - const py_TValue* module) { + py_TValue module) { memset(self, 0, sizeof(pk_TypeInfo)); self->name = name; @@ -47,7 +47,7 @@ static void pk_TypeInfo__ctor(pk_TypeInfo* self, ._obj = typeobj, }; - self->module = module ? *module : *py_NIL; + self->module = module; c11_vector__ctor(&self->annotated_fields, sizeof(py_Name)); } @@ -161,6 +161,30 @@ void pk_VM__ctor(pk_VM* self) { py_setdict(&self->builtins, ti->name, py_tpobject(t)); } + // inject some builtin expections + const char** builtin_exceptions = (const char*[]){ + "StackOverflowError", + "IOError", + "NotImplementedError", + "TypeError", + "IndexError", + "ValueError", + "RuntimeError", + "ZeroDivisionError", + "NameError", + "UnboundLocalError", + "AttributeError", + "ImportError", + "AssertionError", + // "KeyError", + NULL, // sentinel + }; + const char** it = builtin_exceptions; + while(*it){ + py_Type type = pk_newtype(*it, tp_Exception, &self->builtins, NULL, false, true); + py_setdict(&self->builtins, py_name(*it), py_tpobject(type)); + } + py_TValue tmp; py_newnotimplemented(&tmp); py_setdict(&self->builtins, py_name("NotImplemented"), &tmp); @@ -266,7 +290,7 @@ py_Type pk_newtype(const char* name, c11_vector* types = &pk_current_vm->types; py_Type index = types->count; pk_TypeInfo* ti = c11_vector__emplace(types); - pk_TypeInfo__ctor(ti, py_name(name), index, base, module); + pk_TypeInfo__ctor(ti, py_name(name), index, base, module ? *module : *py_NIL); ti->dtor = dtor; ti->is_python = is_python; ti->is_sealed = is_sealed; diff --git a/src/public/py_exception.c b/src/public/py_exception.c index 56aa1111..7bcb8b57 100644 --- a/src/public/py_exception.c +++ b/src/public/py_exception.c @@ -14,17 +14,23 @@ typedef struct BaseExceptionFrame { } BaseExceptionFrame; typedef struct BaseException { - const Bytecode* ip_backup; + int lineno_backup; const CodeObject* code_backup; c11_vector /*T=BaseExceptionFrame*/ stacktrace; } BaseException; -void py_BaseException__record(py_Ref self, const Bytecode* ip, const CodeObject* code) { +void py_BaseException__set_lineno(py_Ref self, int lineno, const CodeObject* code){ BaseException* ud = py_touserdata(self); - ud->ip_backup = ip; + ud->lineno_backup = lineno; ud->code_backup = code; } +int py_BaseException__get_lineno(py_Ref self, const CodeObject* code){ + BaseException* ud = py_touserdata(self); + if(code != ud->code_backup) return -1; + return ud->lineno_backup; +} + void py_BaseException__stpush(py_Ref self, pk_SourceData_ src, int lineno, const char *func_name){ BaseException* ud = py_touserdata(self); if(ud->stacktrace.count >= 7) return; @@ -48,7 +54,7 @@ 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)); c11_vector__ctor(&ud->stacktrace, sizeof(BaseExceptionFrame)); - ud->ip_backup = NULL; + ud->lineno_backup = -1; ud->code_backup = NULL; return true; } diff --git a/tests/28_exception.py b/tests/28_exception.py index d1e69008..0e8071f7 100644 --- a/tests/28_exception.py +++ b/tests/28_exception.py @@ -1,14 +1,14 @@ -try: - raise 1 -except TypeError: - pass - try: assert False exit(1) except AssertionError: pass +try: + raise 1 +except TypeError: + pass + try: for i in range(5): raise KeyError(i) @@ -134,6 +134,7 @@ except SyntaxError as e: ok = True assert ok +""" # finally, only def finally_only(): try: @@ -195,3 +196,4 @@ except KeyError: exit(0) exit(1) +""" \ No newline at end of file