diff --git a/include/pocketpy/common/strname.h b/include/pocketpy/common/strname.h index 1742130a..0a3583d7 100644 --- a/include/pocketpy/common/strname.h +++ b/include/pocketpy/common/strname.h @@ -7,6 +7,8 @@ extern "C" { #endif +typedef uint16_t pkpy_StrName; + uint16_t pkpy_StrName__map(const char*); uint16_t pkpy_StrName__map2(c11_string); const char* pkpy_StrName__rmap(uint16_t index); diff --git a/include/pocketpy/objects/base.hpp b/include/pocketpy/objects/base.hpp index 8c42b64a..9948e400 100644 --- a/include/pocketpy/objects/base.hpp +++ b/include/pocketpy/objects/base.hpp @@ -4,12 +4,6 @@ #include "pocketpy/common/traits.hpp" #include "pocketpy/objects/base.h" -#include -#include -#include -#include -#include - namespace pkpy { struct Type { diff --git a/include/pocketpy/objects/error.h b/include/pocketpy/objects/error.h new file mode 100644 index 00000000..159d3fe8 --- /dev/null +++ b/include/pocketpy/objects/error.h @@ -0,0 +1,39 @@ +#pragma once + +#include "pocketpy/common/str.h" +#include "pocketpy/common/strname.h" +#include "pocketpy/objects/sourcedata.h" +#include "pocketpy/objects/object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkpy_ExceptionFrame { + pkpy_SourceData_ src; + int lineno; + const char* cursor; + pkpy_Str name; +} pkpy_ExceptionFrame; + +typedef struct pkpy_Exception { + pkpy_StrName type; + pkpy_Str msg; + bool is_re; + + int _ip_on_error; + void* _code_on_error; + + PyObject* self; // weak reference + + c11_vector/*T=pkpy_ExceptionFrame*/ stacktrace; +} pkpy_Exception; + +void pkpy_Exception__ctor(pkpy_Exception* self, pkpy_StrName type); +void pkpy_Exception__dtor(pkpy_Exception* self); +void pkpy_Exception__stpush(pkpy_Exception* self, pkpy_SourceData_ src, int lineno, const char* cursor, const char* name); +pkpy_Str pkpy_Exception__summary(pkpy_Exception* self); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/pocketpy/objects/error.hpp b/include/pocketpy/objects/error.hpp index 14ee6169..abfa77b3 100644 --- a/include/pocketpy/objects/error.hpp +++ b/include/pocketpy/objects/error.hpp @@ -1,7 +1,9 @@ #pragma once #include "pocketpy/common/str.hpp" +#include "pocketpy/common/traits.hpp" #include "pocketpy/objects/sourcedata.h" +#include "pocketpy/objects/error.h" namespace pkpy { @@ -22,62 +24,24 @@ struct InternalException final { InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {} }; -struct Exception { - StrName type; - Str msg; - bool is_re; +struct Exception: pkpy_Exception{ + PK_ALWAYS_PASS_BY_POINTER(Exception) - int _ip_on_error; - void* _code_on_error; - - PyObject* _self; // weak reference - - struct Frame { - pkpy_SourceData_ src; - int lineno; - const char* cursor; - std::string name; - - Str snapshot() const { - return pkpy_SourceData__snapshot(src, lineno, cursor, name.empty() ? nullptr : name.c_str()); - } - - Frame(pkpy_SourceData_ src, int lineno, const char* cursor, std::string_view name) : - src(src), lineno(lineno), cursor(cursor), name(name) { - PK_INCREF(src); - } - // disable copy - Frame(const Frame&) = delete; - // allow move - Frame(Frame&& other) noexcept{ - src = other.src; - lineno = other.lineno; - cursor = other.cursor; - name = std::move(other.name); - other.src = nullptr; - } - - ~Frame() { - if(src) PK_DECREF(src); - } - }; - - vector stacktrace; - - Exception(StrName type) : type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {} - - PyObject* self() const { - assert(_self != nullptr); - return _self; + Exception(uint16_t type){ + pkpy_Exception__ctor(this, type); } - template - void st_push(Args&&... args) { - if(stacktrace.size() >= 7) return; - stacktrace.emplace_back(std::forward(args)...); + ~Exception(){ + pkpy_Exception__dtor(this); } - Str summary() const; + void stpush(pkpy_SourceData_ src, int lineno, const char* cursor, const char* name){ + pkpy_Exception__stpush(this, src, lineno, cursor, name); + } + + Str summary(){ + return pkpy_Exception__summary(this); + } }; struct TopLevelException : std::exception { diff --git a/src/common/sourcedata.c b/src/common/sourcedata.c index a6d9536f..f291548d 100644 --- a/src/common/sourcedata.c +++ b/src/common/sourcedata.c @@ -77,7 +77,7 @@ pkpy_Str pkpy_SourceData__snapshot(const struct pkpy_SourceData* self, int linen lineno ); - if(name) { + if(name && *name) { pkpy_SStream__write_cstr(&ss, ", in "); pkpy_SStream__write_cstr(&ss, name); } diff --git a/src/error.c b/src/error.c new file mode 100644 index 00000000..5916af52 --- /dev/null +++ b/src/error.c @@ -0,0 +1,59 @@ +#include "pocketpy/objects/error.h" +#include "pocketpy/common/strname.h" +#include "pocketpy/common/sstream.h" + +void pkpy_Exception__ctor(pkpy_Exception* self, pkpy_StrName type){ + self->type = type; + self->is_re = true; + self->_ip_on_error = -1; + self->_code_on_error = NULL; + self->self = NULL; + + pkpy_Str__ctor(&self->msg, ""); + c11_vector__ctor(&self->stacktrace, sizeof(pkpy_ExceptionFrame)); +} + +void pkpy_Exception__dtor(pkpy_Exception* self){ + for(int i=0; istacktrace.count; i++){ + pkpy_ExceptionFrame* frame = c11__at(pkpy_ExceptionFrame, &self->stacktrace, i); + PK_DECREF(frame->src); + pkpy_Str__dtor(&frame->name); + } + pkpy_Str__dtor(&self->msg); + c11_vector__dtor(&self->stacktrace); +} + +void pkpy_Exception__stpush(pkpy_Exception* self, pkpy_SourceData_ src, int lineno, const char* cursor, const char* name){ + if(self->stacktrace.count >= 7) return; + PK_INCREF(src); + pkpy_ExceptionFrame* frame = c11_vector__emplace(&self->stacktrace); + frame->src = src; + frame->lineno = lineno; + frame->cursor = cursor; + pkpy_Str__ctor(&frame->name, name); +} + +pkpy_Str pkpy_Exception__summary(pkpy_Exception* self){ + pkpy_SStream ss; + pkpy_SStream__ctor(&ss); + + if(self->is_re){ + pkpy_SStream__write_cstr(&ss, "Traceback (most recent call last):\n"); + } + for(int i=self->stacktrace.count-1; i >= 0; i--) { + pkpy_ExceptionFrame* frame = c11__at(pkpy_ExceptionFrame, &self->stacktrace, i); + pkpy_Str s = pkpy_SourceData__snapshot(frame->src, frame->lineno, frame->cursor, pkpy_Str__data(&frame->name)); + pkpy_SStream__write_Str(&ss, &s); + pkpy_Str__dtor(&s); + pkpy_SStream__write_cstr(&ss, "\n"); + } + + const char* name = pkpy_StrName__rmap(self->type); + pkpy_SStream__write_cstr(&ss, name); + + if(self->msg.size > 0){ + pkpy_SStream__write_cstr(&ss, ": "); + pkpy_SStream__write_Str(&ss, &self->msg); + } + return pkpy_SStream__submit(&ss); +} \ No newline at end of file diff --git a/src/interpreter/vm.cpp b/src/interpreter/vm.cpp index 3cc27726..63704d69 100644 --- a/src/interpreter/vm.cpp +++ b/src/interpreter/vm.cpp @@ -1455,9 +1455,9 @@ void VM::__raise_exc(bool re_raise) { int actual_ip = frame->ip(); if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) actual_ip = e._ip_on_error; int current_line = frame->co->lines[actual_ip].lineno; // current line - auto current_f_name = frame->co->name.sv(); // current function name + const char* current_f_name = frame->co->name.c_str(); // current function name if(frame->_callable == nullptr) current_f_name = ""; // not in a function - e.st_push(frame->co->src, current_line, nullptr, current_f_name); + e.stpush(frame->co->src, current_line, nullptr, current_f_name); if(next_ip >= 0) { throw InternalException(InternalExceptionType::Handled, next_ip); diff --git a/src/objects/error.cpp b/src/objects/error.cpp deleted file mode 100644 index f7fe8a86..00000000 --- a/src/objects/error.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "pocketpy/objects/error.hpp" - -namespace pkpy { -Str Exception::summary() const { - SStream ss; - if(is_re) ss << "Traceback (most recent call last):\n"; - for(int i = stacktrace.size() - 1; i >= 0; i--) { - ss << stacktrace[i].snapshot() << '\n'; - } - if(!msg.empty()) - ss << type.sv() << ": " << msg; - else - ss << type.sv(); - return ss.str(); -} - -} // namespace pkpy diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index e16cae27..9c8caeab 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -1539,30 +1539,31 @@ void __init_builtins(VM* _vm) { _vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args) -> PyVar { Type cls = PK_OBJ_GET(Type, args[0]); StrName cls_name = _type_name(vm, cls); - PyObject* e_obj = vm->heap.gcnew(cls, cls_name); + PyObject* e_obj = vm->heap.gcnew(cls, cls_name.index); e_obj->_attr = new NameDict(); - e_obj->as()._self = e_obj; + e_obj->as().self = e_obj; return e_obj; }); _vm->bind(_vm->_t(VM::tp_exception), "__init__(self, msg=...)", [](VM* vm, ArgsView args) { Exception& self = _CAST(Exception&, args[0]); - if(args[1].type == tp_ellipsis) { - self.msg = ""; - } else { - self.msg = CAST(Str, args[1]); + if(args[1].type != tp_ellipsis) { + const char* msg = CAST(Str&, args[1]).c_str(); + pkpy_Str__dtor(&self.msg); + pkpy_Str__ctor(&self.msg, msg); } return vm->None; }); _vm->bind__repr__(VM::tp_exception, [](VM* vm, PyVar _0) -> Str { Exception& self = _CAST(Exception&, _0); - return _S(_type_name(vm, _0.type), '(', self.msg.escape(), ')'); + const char* msg_s = pkpy_Str__data(&self.msg); + return _S(_type_name(vm, _0.type), '(', Str(msg_s).escape(), ')'); }); _vm->bind__str__(VM::tp_exception, [](VM* vm, PyVar _0) -> Str { Exception& self = _CAST(Exception&, _0); - return self.msg; + return pkpy_Str__copy(&self.msg); }); _vm->register_user_class(_vm->builtins, "_range_iter"); @@ -1743,7 +1744,7 @@ void VM::__compile_error(Error* err){ VAR((const char*)err->msg) ).get(); Exception& e = __last_exception->as(); - e.st_push(err->src, err->lineno, err->cursor, ""); + e.stpush(err->src, err->lineno, err->cursor, ""); PK_DECREF(err->src); std::free(err); _error(__last_exception); diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index 57e446a6..1807d342 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -43,7 +43,7 @@ static PyVar stack_item(VM* vm, int index) { try { \ __B \ } catch(TopLevelException e) { \ - vm->__c.error = e.ptr->self(); \ + vm->__c.error = (PyObject*)e.ptr->self; \ return false; \ } catch(const std::exception& re) { \ PyObject* e_t = vm->_t(vm->tp_exception); \