diff --git a/docs/1_5_0.md b/docs/2_0_0.md similarity index 97% rename from docs/1_5_0.md rename to docs/2_0_0.md index e5f92a5b..dda2df02 100644 --- a/docs/1_5_0.md +++ b/docs/2_0_0.md @@ -1,6 +1,6 @@ --- icon: log -title: 'Upgrade to v1.5.0' +title: 'Upgrade to v2.0.0' order: 25 --- @@ -207,7 +207,7 @@ Enabling the profiler has a performance overhead. Only enable it when you need i + `vm->is_non_tagged_type` was removed. Use `vm->is_type` instead. + `vm->check_non_tagged_type` was removed. Use `vm->check_type` instead. -## Python Stringify functions +## Python stringify functions The following functions now return `Str` object instead of `PyVar`: @@ -216,3 +216,7 @@ The following functions now return `Str` object instead of `PyVar`: + `vm->py_json` Also, `vm->bind__str__` and `vm->bind__repr__` were changed to return `Str` object. + +## Catching exceptions + +Now you need to catch `TopLevelException` instead of `Exception`. \ No newline at end of file diff --git a/docs/cheatsheet.md b/docs/cheatsheet.md index 2847c864..d9896949 100644 --- a/docs/cheatsheet.md +++ b/docs/cheatsheet.md @@ -49,7 +49,7 @@ Execute a compiled code object ```cpp try{ vm->_exec(co); // may throw -}catch(Exception& e){ +}catch(TopLevelException e){ std::cerr << e.summary() << std::endl; } ``` diff --git a/docs/quick-start/exec.md b/docs/quick-start/exec.md index f0e74abd..cbc88b20 100644 --- a/docs/quick-start/exec.md +++ b/docs/quick-start/exec.md @@ -52,7 +52,7 @@ These two methods are provided for this purpose: try{ CodeObject_ code = vm->compile("a[0]", "main.py", EXEC_MODE, false); vm->_exec(code, vm->_main); -}catch(Exception& e){ +}catch(TopLevelException e){ // use e.summary() to get a summary of the exception std::cerr << e.summary() << std::endl; } diff --git a/include/pocketpy/error.h b/include/pocketpy/error.h index b3b7d817..e31bcddb 100644 --- a/include/pocketpy/error.h +++ b/include/pocketpy/error.h @@ -88,4 +88,17 @@ struct Exception { Str summary() const; }; +struct TopLevelException: std::exception{ + Exception* ptr; + TopLevelException(Exception* ptr): ptr(ptr) {} + + PyObject* self() const { return ptr->self(); } + Str summary() const { return ptr->summary(); } + + const char* what() const noexcept override { + static Str cached_summary(summary()); + return cached_summary.c_str(); + } +}; + } // namespace pkpy \ No newline at end of file diff --git a/src/ceval.cpp b/src/ceval.cpp index 1e8b1234..60fd5d84 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -1,5 +1,4 @@ #include "pocketpy/ceval.h" -#include "pocketpy/codeobject.h" namespace pkpy{ @@ -1052,15 +1051,16 @@ __NEXT_STEP: }catch(InternalException internal){ __internal_exception = internal; if(internal.type == InternalExceptionType::Unhandled){ - PyVar e_obj = POPX(); - Exception& _e = PK_OBJ_GET(Exception, e_obj); + __last_exception = POPX().get(); + Exception& _e = __last_exception->as(); bool is_base_frame_to_be_popped = frame == base_frame; __pop_frame(); if(callstack.empty()){ - throw std::move(_e); // propagate to the top level + // propagate to the top level + throw TopLevelException(&_e); } frame = &callstack.top(); - PUSH(e_obj); + PUSH(__last_exception); if(is_base_frame_to_be_popped){ throw InternalException(InternalExceptionType::ToBeRaised); } diff --git a/src/compiler.cpp b/src/compiler.cpp index 9b8263e1..0aa22247 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1376,10 +1376,10 @@ __EAT_DOTS_END: // TODO: refactor this void Lexer::throw_err(StrName type, Str msg, int lineno, const char* cursor){ - PyVar e_obj = vm->call(vm->builtins->attr(type), VAR(msg)); - Exception& e = PK_OBJ_GET(Exception, e_obj); + vm->__last_exception = vm->call(vm->builtins->attr(type), VAR(msg)).get(); + Exception& e = vm->__last_exception->as(); e.st_push(src, lineno, cursor, ""); - throw std::move(e); + throw TopLevelException(&e); } std::string_view TokenDeserializer::read_string(char c){ diff --git a/src/modules.cpp b/src/modules.cpp index 55822fc3..7e899f62 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -198,15 +198,15 @@ void add_module_math(VM* vm){ void add_module_traceback(VM* vm){ PyObject* mod = vm->new_module("traceback"); vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) { - if(vm->__last_exception==nullptr) vm->ValueError("no exception"); - Exception& e = _CAST(Exception&, vm->__last_exception); + if(vm->__last_exception == nullptr) vm->ValueError("no exception"); + Exception& e = vm->__last_exception->as(); vm->stdout_write(e.summary()); return vm->None; }); vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) { - if(vm->__last_exception==nullptr) vm->ValueError("no exception"); - Exception& e = _CAST(Exception&, vm->__last_exception); + if(vm->__last_exception == nullptr) vm->ValueError("no exception"); + Exception& e = vm->__last_exception->as(); return VAR(e.summary()); }); } diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 1c347371..6f736d18 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -1649,7 +1649,7 @@ void VM::__post_init_builtin_types(){ this->_exec(code, this->builtins); code = compile(kPythonLibs__set, "", EXEC_MODE); this->_exec(code, this->builtins); - }catch(const Exception& e){ + }catch(TopLevelException e){ std::cerr << e.summary() << std::endl; std::cerr << "failed to load builtins module!!" << std::endl; exit(1); @@ -1679,7 +1679,7 @@ CodeObject_ VM::compile(std::string_view source, const Str& filename, CompileMod Compiler compiler(this, source, filename, mode, unknown_global_scope); try{ return compiler.compile(); - }catch(const Exception& e){ + }catch(TopLevelException e){ _error(e.self()); return nullptr; } @@ -1689,7 +1689,7 @@ Str VM::precompile(std::string_view source, const Str& filename, CompileMode mod Compiler compiler(this, source, filename, mode, false); try{ return compiler.precompile(); - }catch(const Exception& e){ + }catch(TopLevelException e){ _error(e.self()); return nullptr; } diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index f44c5adb..7904e742 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -44,7 +44,7 @@ static PyVar stack_item(VM* vm, int index){ #define PK_PROTECTED(__B) \ try{ __B } \ - catch(const Exception& e ) { \ + catch(TopLevelException e) { \ vm->__c.error = e.self(); \ return false; \ } catch(const std::exception& re){ \ diff --git a/src/vm.cpp b/src/vm.cpp index b81ee0de..fcc62378 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1383,7 +1383,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native try{ // fn(a, b, *c, d=1) -> None co = compile(_S("def ", sig, " : pass"), "", EXEC_MODE); - }catch(const Exception&){ + }catch(TopLevelException){ throw std::runtime_error("invalid signature: " + std::string(sig)); } if(co->func_decls.size() != 1){ @@ -1442,7 +1442,8 @@ void VM::_error(PyVar e_obj){ Exception& e = PK_OBJ_GET(Exception, e_obj); if(callstack.empty()){ e.is_re = false; - throw std::move(e); + __last_exception = e_obj.get(); + throw TopLevelException(&e); } PUSH(e_obj); __raise_exc();