diff --git a/.gitignore b/.gitignore index 84f1c388..e6cae525 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ libpocketpy.dylib .xmake/ +libpocketpy.dylib.dSYM/ +main.dSYM/ \ No newline at end of file diff --git a/amalgamate.py b/amalgamate.py index 07659524..cf4b4112 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -6,9 +6,9 @@ with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f: OPCODES_TEXT = '\n' + f.read() + '\n' pipeline = [ - ["config.h", "export.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"], + ["config.h", "export.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h"], ["obj.h", "dict.h", "codeobject.h", "frame.h"], - ["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"], + ["gc.h", "vm.h", "ceval.h", "lexer.h", "expr.h", "compiler.h", "repl.h"], ["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"], ["pocketpy.h", "pocketpy_c.h"] ] diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index 7ccec844..bb612864 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -23,7 +23,7 @@ #include #include -#define PK_VERSION "1.3.5" +#define PK_VERSION "1.3.6" #include "config.h" #include "export.h" diff --git a/include/pocketpy/error.h b/include/pocketpy/error.h index 5e9e9e00..2f4ba542 100644 --- a/include/pocketpy/error.h +++ b/include/pocketpy/error.h @@ -56,14 +56,11 @@ struct Exception { int _ip_on_error; void* _code_on_error; + + PyObject* _self; // weak reference stack stacktrace; - - Exception(StrName type, Str msg): - type(type), msg(msg), is_re(true), _ip_on_error(-1), _code_on_error(nullptr) {} - bool match_type(StrName t) const { - return this->type==t || t.sv()=="Exception"; - } + Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {} template void st_push(Args&&... args){ diff --git a/include/pocketpy/lexer.h b/include/pocketpy/lexer.h index f96214eb..b00bec99 100644 --- a/include/pocketpy/lexer.h +++ b/include/pocketpy/lexer.h @@ -3,6 +3,7 @@ #include "common.h" #include "error.h" #include "str.h" +#include "obj.h" namespace pkpy{ @@ -100,6 +101,7 @@ enum Precedence { enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES }; struct Lexer { + VM* vm; std::shared_ptr src; const char* token_start; const char* curr_char; @@ -129,12 +131,12 @@ struct Lexer { bool lex_one_token(); /***** Error Reporter *****/ - void throw_err(Str type, Str msg); - void throw_err(Str type, Str msg, int lineno, const char* cursor); + void throw_err(StrName type, Str msg); + void throw_err(StrName type, Str msg, int lineno, const char* cursor); void SyntaxError(Str msg){ throw_err("SyntaxError", msg); } void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); } void IndentationError(Str msg){ throw_err("IndentationError", msg); } - Lexer(std::shared_ptr src); + Lexer(VM* vm, std::shared_ptr src); std::vector run(); }; diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index 8f3d2fa5..e81cc262 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -198,7 +198,7 @@ inline void gc_mark_namedict(NameDict& t){ }); } -Str obj_type_name(VM* vm, Type type); +StrName obj_type_name(VM* vm, Type type); #if PK_DEBUG_NO_BUILTINS #define OBJ_NAME(obj) Str("") diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index 9ffa640b..e19df1b6 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -140,6 +140,7 @@ struct SStream{ SStream& operator<<(const std::string& s); SStream& operator<<(std::string_view s); SStream& operator<<(char c); + SStream& operator<<(StrName sn); template SStream& operator<<(T val){ diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index f967f2d7..480648b9 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -52,7 +52,7 @@ struct PyTypeInfo{ PyObject* obj; // never be garbage collected Type base; PyObject* mod; // never be garbage collected - Str name; + StrName name; bool subclass_enabled; std::vector annotated_fields; @@ -219,7 +219,7 @@ public: } PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true); - Type _new_type_object(StrName name, Type base=0); + Type _new_type_object(StrName name, Type base=0, bool subclass_enabled=false); PyObject* _find_type_object(const Str& type); Type _type(const Str& type); @@ -362,37 +362,36 @@ public: PyObject* py_next(PyObject* obj); /***** Error Reporter *****/ - void _error(StrName name, const Str& msg){ - _error(Exception(name, msg)); - } - void _raise(bool re_raise=false); - void StackOverflowError() { _error("StackOverflowError", ""); } - void IOError(const Str& msg) { _error("IOError", msg); } - void NotImplementedError(){ _error("NotImplementedError", ""); } - void TypeError(const Str& msg){ _error("TypeError", msg); } - void IndexError(const Str& msg){ _error("IndexError", msg); } - void ValueError(const Str& msg){ _error("ValueError", msg); } - void RuntimeError(const Str& msg){ _error("RuntimeError", msg); } - void ZeroDivisionError(const Str& msg){ _error("ZeroDivisionError", msg); } - void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); } - void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } - void UnboundLocalError(StrName name){ _error("UnboundLocalError", fmt("local variable ", name.escape() + " referenced before assignment")); } - void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); } + void _builtin_error(StrName type); + void _builtin_error(StrName type, PyObject* arg); + void _builtin_error(StrName type, const Str& msg); + + void StackOverflowError() { _builtin_error("StackOverflowError"); } + void IOError(const Str& msg) { _builtin_error("IOError", msg); } + void NotImplementedError(){ _builtin_error("NotImplementedError"); } + void TypeError(const Str& msg){ _builtin_error("TypeError", msg); } + void IndexError(const Str& msg){ _builtin_error("IndexError", msg); } + void ValueError(const Str& msg){ _builtin_error("ValueError", msg); } + void RuntimeError(const Str& msg){ _builtin_error("RuntimeError", msg); } + void ZeroDivisionError(const Str& msg){ _builtin_error("ZeroDivisionError", msg); } + void ZeroDivisionError(){ _builtin_error("ZeroDivisionError", "division by zero"); } + void NameError(StrName name){ _builtin_error("NameError", fmt("name ", name.escape() + " is not defined")); } + void UnboundLocalError(StrName name){ _builtin_error("UnboundLocalError", fmt("local variable ", name.escape() + " referenced before assignment")); } + void KeyError(PyObject* obj){ _builtin_error("KeyError", obj); } void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); } - void ImportError(const Str& msg){ _error("ImportError", msg); } + void ImportError(const Str& msg){ _builtin_error("ImportError", msg); } void AttributeError(PyObject* obj, StrName name){ // OBJ_NAME calls getattr, which may lead to a infinite recursion if(isinstance(obj, vm->tp_type)){ - _error("AttributeError", fmt("type object ", OBJ_NAME(obj).escape(), " has no attribute ", name.escape())); + _builtin_error("AttributeError", fmt("type object ", OBJ_NAME(obj).escape(), " has no attribute ", name.escape())); }else{ - _error("AttributeError", fmt(OBJ_NAME(_t(obj)).escape(), " object has no attribute ", name.escape())); + _builtin_error("AttributeError", fmt(OBJ_NAME(_t(obj)).escape(), " object has no attribute ", name.escape())); } } - - void AttributeError(Str msg){ _error("AttributeError", msg); } + void AttributeError(const Str& msg){ _builtin_error("AttributeError", msg); } void check_type(PyObject* obj, Type type){ if(is_type(obj, type)) return; @@ -471,7 +470,7 @@ public: PyObject* bind_method(PyObject*, Str, NativeFuncC); template PyObject* bind_func(PyObject*, Str, NativeFuncC); - void _error(Exception); + void _error(PyObject*); PyObject* _run_top_frame(); void post_init(); PyObject* _py_generator(Frame&& frame, ArgsView buffer); diff --git a/python/builtins.py b/python/builtins.py index 85f7ef0e..303a5738 100644 --- a/python/builtins.py +++ b/python/builtins.py @@ -268,9 +268,6 @@ def help(obj): print(obj.__doc__) -class Exception: pass - - class classmethod: def __init__(self, f): self.f = f @@ -287,3 +284,40 @@ def complex(*args, **kwargs): def long(*args, **kwargs): import _long return _long.long(*args, **kwargs) + + +# builtin exceptions +class SyntaxError(Exception): pass +class IndentationError(SyntaxError): pass + +class StackOverflowError(Exception): pass +class IOError(Exception): pass +class NotImplementedError(Exception): pass +class TypeError(Exception): pass +class IndexError(Exception): pass +class ValueError(Exception): pass +class RuntimeError(Exception): pass +class ZeroDivisionError(Exception): pass +class NameError(Exception): pass +class UnboundLocalError(Exception): pass +class AttributeError(Exception): pass +class ImportError(Exception): pass +class AssertionError(Exception): pass + +class KeyError(Exception): + def __init__(self, key=...): + self.key = key + if key is ...: + super().__init__() + else: + super().__init__(repr(key)) + + def __str__(self): + if self.key is ...: + return '' + return str(self.key) + + def __repr__(self): + if self.key is ...: + return 'KeyError()' + return f'KeyError({self.key!r})' diff --git a/src/ceval.cpp b/src/ceval.cpp index 85c11af3..4c34cec9 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -568,7 +568,7 @@ __NEXT_STEP:; TARGET(GOTO) { StrName _name(byte.arg); int index = co->labels.try_get_likely_found(_name); - if(index < 0) _error("KeyError", fmt("label ", _name.escape(), " not found")); + if(index < 0) RuntimeError(fmt("label ", _name.escape(), " not found")); frame->jump_abs_break(index); } DISPATCH(); /*****************************************/ @@ -787,20 +787,28 @@ __NEXT_STEP:; DISPATCH(); /*****************************************/ TARGET(EXCEPTION_MATCH) { - const auto& e = CAST(Exception&, TOP()); - PUSH(VAR(e.match_type(StrName(byte.arg)))); + PyObject* assumed_type = POPX(); + check_non_tagged_type(assumed_type, tp_type); + PyObject* e_obj = TOP(); + bool ok = isinstance(e_obj, PK_OBJ_GET(Type, assumed_type)); + PUSH(VAR(ok)); } DISPATCH(); TARGET(RAISE) { - PyObject* _0 = POPX(); - Str msg = _0 == None ? "" : CAST(Str, py_str(_0)); - _error(StrName(byte.arg), msg); + if(is_non_tagged_type(TOP(), tp_type)){ + TOP() = call(TOP()); + } + if(!isinstance(TOP(), tp_exception)){ + _builtin_error("TypeError", "exceptions must derive from Exception"); + UNREACHABLE(); + } + _error(POPX()); } DISPATCH(); TARGET(RAISE_ASSERT) if(byte.arg){ PyObject* _0 = py_str(POPX()); - _error("AssertionError", CAST(Str, _0)); + _builtin_error("AssertionError", CAST(Str, _0)); }else{ - _error("AssertionError", ""); + _builtin_error("AssertionError"); } DISPATCH(); TARGET(RE_RAISE) _raise(true); DISPATCH(); @@ -853,8 +861,8 @@ __NEXT_STEP:; continue; }catch(UnhandledException& e){ PK_UNUSED(e); - PyObject* obj = POPX(); - Exception& _e = CAST(Exception&, obj); + PyObject* e_obj = POPX(); + Exception& _e = PK_OBJ_GET(Exception, e_obj); _pop_frame(); if(callstack.empty()){ #if PK_DEBUG_FULL_EXCEPTION @@ -863,7 +871,7 @@ __NEXT_STEP:; throw _e; } frame = top_frame(); - PUSH(obj); + PUSH(e_obj); if(frame.index < base_id) throw ToBeRaisedException(); need_raise = true; }catch(ToBeRaisedException& e){ diff --git a/src/compiler.cpp b/src/compiler.cpp index c7ee08a1..d28ed62b 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -38,14 +38,14 @@ namespace pkpy{ SyntaxError("maximum number of local variables exceeded"); } if(ctx()->co->consts.size() > 65535){ - std::map counts; - for(PyObject* c: ctx()->co->consts){ - std::string key = obj_type_name(vm, vm->_tp(c)).str(); - counts[key] += 1; - } - for(auto pair: counts){ - std::cout << pair.first << ": " << pair.second << std::endl; - } + // std::map counts; + // for(PyObject* c: ctx()->co->consts){ + // std::string_view key = obj_type_name(vm, vm->_tp(c)).sv(); + // counts[key] += 1; + // } + // for(auto pair: counts){ + // std::cout << pair.first << ": " << pair.second << std::endl; + // } SyntaxError("maximum number of constants exceeded"); } if(codes.size() > 65535 && ctx()->co->src->mode != JSON_MODE){ @@ -684,8 +684,9 @@ __EAT_DOTS_END: do { StrName as_name; consume(TK("except")); - if(match(TK("@id"))){ - ctx()->emit_(OP_EXCEPTION_MATCH, StrName(prev().sv()).index, prev().line); + if(is_expression()){ + EXPR(false); // push assumed type on to the stack + ctx()->emit_(OP_EXCEPTION_MATCH, BC_NOARG, prev().line); if(match(TK("as"))){ consume(TK("@id")); as_name = StrName(prev().sv()); @@ -880,14 +881,8 @@ __EAT_DOTS_END: consume_end_stmt(); break; case TK("raise"): { - consume(TK("@id")); - int dummy_t = StrName(prev().sv()).index; - if(match(TK("(")) && !match(TK(")"))){ - EXPR(false); consume(TK(")")); - }else{ - ctx()->emit_(OP_LOAD_NONE, BC_NOARG, kw_line); - } - ctx()->emit_(OP_RAISE, dummy_t, kw_line); + EXPR(false); + ctx()->emit_(OP_RAISE, BC_NOARG, kw_line); consume_end_stmt(); } break; case TK("del"): { @@ -1161,7 +1156,7 @@ __EAT_DOTS_END: this->used = false; this->unknown_global_scope = unknown_global_scope; this->lexer = std::make_unique( - std::make_shared(source, filename, mode) + vm, std::make_shared(source, filename, mode) ); init_pratt_rules(); } @@ -1202,4 +1197,12 @@ __EAT_DOTS_END: return code; } + // TODO: refactor this + void Lexer::throw_err(StrName type, Str msg, int lineno, const char* cursor){ + PyObject* e_obj = vm->call(vm->builtins->attr(type), VAR(msg)); + Exception& e = PK_OBJ_GET(Exception, e_obj); + e.st_push(src, lineno, cursor, ""); + e._self = e_obj; + throw e; + } } // namespace pkpy \ No newline at end of file diff --git a/src/gc.cpp b/src/gc.cpp index 4d86d1ed..9831c5a3 100644 --- a/src/gc.cpp +++ b/src/gc.cpp @@ -52,7 +52,7 @@ namespace pkpy{ for(PyObject* obj: gen) { obj->~PyObject(); pool64_dealloc(obj); } #if PK_DEBUG_GC_STATS for(auto& [type, count]: deleted){ - std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl; + std::cout << "GC: " << obj_type_name(vm, type).sv() << "=" << count << std::endl; } #endif } diff --git a/src/lexer.cpp b/src/lexer.cpp index b26435eb..2510669a 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -455,7 +455,7 @@ static bool is_unicode_Lo_char(uint32_t c) { return false; } - void Lexer::throw_err(Str type, Str msg){ + void Lexer::throw_err(StrName type, Str msg){ int lineno = current_line; const char* cursor = curr_char; if(peekchar() == '\n'){ @@ -465,14 +465,7 @@ static bool is_unicode_Lo_char(uint32_t c) { throw_err(type, msg, lineno, cursor); } - void Lexer::throw_err(Str type, Str msg, int lineno, const char* cursor){ - Exception e(type, msg); - e.st_push(src, lineno, cursor, ""); - throw e; - } - - Lexer::Lexer(std::shared_ptr src) { - this->src = src; + Lexer::Lexer(VM* vm, std::shared_ptr src) : vm(vm), src(src) { this->token_start = src->source.c_str(); this->curr_char = src->source.c_str(); this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level}); diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index acf26843..78bb8e78 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -73,8 +73,8 @@ void init_builtins(VM* _vm) { vm->check_non_tagged_type(class_arg, vm->tp_type); Type type = PK_OBJ_GET(Type, class_arg); if(!vm->isinstance(self_arg, type)){ - Str _0 = obj_type_name(vm, vm->_tp(self_arg)); - Str _1 = obj_type_name(vm, type); + StrName _0 = obj_type_name(vm, vm->_tp(self_arg)); + StrName _1 = obj_type_name(vm, type); vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape()); } return vm->heap.gcnew(vm->tp_super, self_arg, vm->_all_types[type].base); @@ -1296,9 +1296,27 @@ void init_builtins(VM* _vm) { // }); // Exception + _vm->bind_constructor<-1>("Exception", [](VM* vm, ArgsView args){ + Type cls = PK_OBJ_GET(Type, args[0]); + StrName cls_name = obj_type_name(vm, cls); + PyObject* e_obj = vm->heap.gcnew(cls, cls_name); + e_obj->_enable_instance_dict(); + 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] == vm->Ellipsis){ + self.msg = ""; + }else{ + self.msg = CAST(Str, args[1]); + } + return vm->None; + }); + _vm->bind__repr__(_vm->tp_exception, [](VM* vm, PyObject* obj) { Exception& self = _CAST(Exception&, obj); - return VAR(fmt(self.type.sv(), '(', self.msg.escape(), ')')); + return VAR(fmt(obj_type_name(vm, obj->type), '(', self.msg.escape(), ')')); }); _vm->bind__str__(_vm->tp_exception, [](VM* vm, PyObject* obj) { @@ -1616,7 +1634,7 @@ void VM::post_init(){ }); bind_property(_t(tp_type), "__name__", [](VM* vm, ArgsView args){ const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; - return VAR(info.name); + return VAR(info.name.sv()); }); bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args){ const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; @@ -1675,7 +1693,7 @@ void VM::post_init(){ this->_exec(code, this->builtins); code = compile(kPythonLibs["_set"], "", EXEC_MODE); this->_exec(code, this->builtins); - }catch(Exception& e){ + }catch(const Exception& e){ std::cerr << e.summary() << std::endl; std::cerr << "failed to load builtins module!!" << std::endl; exit(1); @@ -1705,11 +1723,11 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool unknown Compiler compiler(this, std::move(source), filename, mode, unknown_global_scope); try{ return compiler.compile(); - }catch(Exception& e){ + }catch(const Exception& e){ #if PK_DEBUG_FULL_EXCEPTION std::cerr << e.summary() << std::endl; #endif - _error(e); + _error(e._self); return nullptr; } } diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index 5e437d9c..a38c8784 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -44,12 +44,12 @@ static PyObject* stack_item(VM* vm, int index){ #define PK_PROTECTED(__B) \ try{ __B } \ - catch(Exception& e ) { \ - vm->_c.error = py_var(vm, e); \ + catch(const Exception& e ) { \ + vm->_c.error = e._self; \ return false; \ } catch(const std::exception& re){ \ - auto e = Exception("std::exception", re.what()); \ - vm->_c.error = py_var(vm, e); \ + PyObject* e_t = vm->_t(vm->tp_exception); \ + vm->_c.error = vm->call(e_t, VAR(re.what())); \ return false; \ } @@ -338,9 +338,9 @@ static PyObject* c_function_wrapper(VM* vm, ArgsView args) { // propagate_if_errored if (vm->_c.error != nullptr){ - Exception e = _py_cast(vm, vm->_c.error); + PyObject* e_obj = PK_OBJ_GET(Exception, vm->_c.error)._self; vm->_c.error = nullptr; - vm->_error(e); + vm->_error(e_obj); return nullptr; } PK_ASSERT(retc == vm->s_data._sp-curr_sp); @@ -495,7 +495,8 @@ bool pkpy_py_str(pkpy_vm* vm_handle) { bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) { VM* vm = (VM*) vm_handle; PK_ASSERT_NO_ERROR() - vm->_c.error = py_var(vm, Exception(name, Str(message.data, message.size))); + PyObject* e_t = vm->_t(vm->tp_exception); + vm->_c.error = vm->call(e_t, VAR(std::string_view(message.data, message.size))); return false; } @@ -508,7 +509,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { VM* vm = (VM*) vm_handle; // no error if (vm->_c.error == nullptr) return false; - Exception& e = _py_cast(vm, vm->_c.error); + Exception& e = PK_OBJ_GET(Exception, vm->_c.error); if (message != nullptr) *message = e.summary().c_str_dup(); else diff --git a/src/str.cpp b/src/str.cpp index a6a3f232..035f264d 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -465,6 +465,10 @@ int utf8len(unsigned char c, bool suppress){ return *this; } + SStream& SStream::operator<<(StrName sn){ + return *this << sn.sv(); + } + SStream& SStream::operator<<(i64 val){ // str(-2**64).__len__() == 21 buffer.reserve(buffer.size() + 24); diff --git a/src/vm.cpp b/src/vm.cpp index 3ad07860..89710410 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1,4 +1,5 @@ #include "pocketpy/vm.h" +#include "pocketpy/error.h" namespace pkpy{ @@ -172,11 +173,15 @@ namespace pkpy{ _stderr(sum.data, sum.size); } #if !PK_DEBUG_FULL_EXCEPTION - catch (const std::exception& e) { + catch(const std::exception& e) { Str msg = "An std::exception occurred! It could be a bug.\n"; msg = msg + e.what() + "\n"; _stderr(msg.data, msg.size); } + catch(...) { + Str msg = "An unknown exception occurred! It could be a bug. Please report it to @blueloveTH on GitHub.\n"; + _stderr(msg.data, msg.size); + } #endif callstack.clear(); s_data.clear(); @@ -201,15 +206,15 @@ namespace pkpy{ obj, base, mod, - name.sv(), + name, subclass_enabled, }; _all_types.push_back(info); return obj; } - Type VM::_new_type_object(StrName name, Type base) { - PyObject* obj = new_type_object(nullptr, name, base, false); + Type VM::_new_type_object(StrName name, Type base, bool subclass_enabled) { + PyObject* obj = new_type_object(nullptr, name, base, subclass_enabled); return PK_OBJ_GET(Type, obj); } @@ -725,7 +730,7 @@ void VM::init_builtin_types(){ PK_ASSERT(tp_bound_method == _new_type_object("bound_method")); PK_ASSERT(tp_super == _new_type_object("super")); - PK_ASSERT(tp_exception == _new_type_object("_Exception")); + PK_ASSERT(tp_exception == _new_type_object("Exception", 0, true)); PK_ASSERT(tp_bytes == _new_type_object("bytes")); PK_ASSERT(tp_mappingproxy == _new_type_object("mappingproxy")); PK_ASSERT(tp_dict == _new_type_object("dict")); @@ -757,6 +762,7 @@ void VM::init_builtin_types(){ builtins->attr().set("StopIteration", StopIteration); builtins->attr().set("NotImplemented", NotImplemented); builtins->attr().set("slice", _t(tp_slice)); + builtins->attr().set("Exception", _t(tp_exception)); post_init(); this->_main = new_module("__main__"); @@ -964,7 +970,7 @@ __FAST_CALL: if(new_f == cached_object__new__) { // fast path for object.__new__ Type t = PK_OBJ_GET(Type, callable); - obj= vm->heap.gcnew(t); + obj = vm->heap.gcnew(t); }else{ PUSH(new_f); PUSH(PY_NULL); @@ -1134,7 +1140,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native try{ // fn(a, b, *c, d=1) -> None co = compile("def " + Str(sig) + " : pass", "", EXEC_MODE); - }catch(Exception&){ + }catch(const Exception&){ throw std::runtime_error("invalid signature: " + std::string(sig)); } if(co->func_decls.size() != 1){ @@ -1163,12 +1169,19 @@ PyObject* VM::bind_property(PyObject* obj, Str name, NativeFuncC fget, NativeFun return prop; } -void VM::_error(Exception e){ +void VM::_builtin_error(StrName type){ _error(call(builtins->attr(type))); } +void VM::_builtin_error(StrName type, PyObject* arg){ _error(call(builtins->attr(type), arg)); } +void VM::_builtin_error(StrName type, const Str& msg){ _builtin_error(type, VAR(msg)); } + +void VM::_error(PyObject* e_obj){ + PK_ASSERT(isinstance(e_obj, tp_exception)) + Exception& e = PK_OBJ_GET(Exception, e_obj); + e._self = e_obj; if(callstack.empty()){ e.is_re = false; throw e; } - PUSH(VAR(std::move(e))); + PUSH(e_obj); _raise(); } @@ -1203,7 +1216,7 @@ void ManagedHeap::mark() { for(auto [_, co]: vm->_cached_codes) co->_gc_mark(); } -Str obj_type_name(VM *vm, Type type){ +StrName obj_type_name(VM *vm, Type type){ return vm->_all_types[type].name; } diff --git a/tests/99_builtin_func.py b/tests/99_builtin_func.py index 939473c9..a01d7657 100644 --- a/tests/99_builtin_func.py +++ b/tests/99_builtin_func.py @@ -1,25 +1,3 @@ -# 无法测试 ----------------------------------------------- -# #####: 41:static dylib_entry_t load_dylib(const char* path){ -# #####: 42: std::error_code ec; -# #####: 43: auto p = std::filesystem::absolute(path, ec); -# #####: 44: if(ec) return nullptr; -# #####: 45: void* handle = dlopen(p.c_str(), RTLD_LAZY); -# #####: 46: if(!handle) return nullptr; -# #####: 47: return (dylib_entry_t)dlsym(handle, "pkpy_module__init__"); -# #####: 48:} - -# ----------------------------------------------- -# 128: 107: _vm->bind_builtin_func<2>("super", [](VM* vm, ArgsView args) { -# 8: 108: vm->check_non_tagged_type(args[0], vm->tp_type); -# 8: 109: Type type = PK_OBJ_GET(Type, args[0]); -# 8: 110: if(!vm->isinstance(args[1], type)){ -# #####: 111: Str _0 = obj_type_name(vm, PK_OBJ_GET(Type, vm->_t(args[1]))); -# #####: 112: Str _1 = obj_type_name(vm, type); -# #####: 113: vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape()); -# #####: 114: } -# 8: 115: Type base = vm->_all_types[type].base; -# 16: 116: return vm->heap.gcnew(vm->tp_super, Super(args[1], base)); -# 8: 117: }); # test super: class TestSuperBase(): def __init__(self): @@ -29,7 +7,7 @@ class TestSuperBase(): return self.base_attr def error(self): - raise Expection('未能拦截错误') + raise Exception('未能拦截错误') class TestSuperChild1(TestSuperBase):