diff --git a/include/pocketpy/error.h b/include/pocketpy/error.h index 4fed1c1a..5e9e9e00 100644 --- a/include/pocketpy/error.h +++ b/include/pocketpy/error.h @@ -61,7 +61,9 @@ struct Exception { 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;} + bool match_type(StrName t) const { + return this->type==t || t.sv()=="Exception"; + } template void st_push(Args&&... args){ diff --git a/python/builtins.py b/python/builtins.py index 85e3f30d..7e371ab4 100644 --- a/python/builtins.py +++ b/python/builtins.py @@ -258,7 +258,6 @@ def help(obj): class Exception: pass - class classmethod: def __init__(self, f): self.f = f diff --git a/src/compiler.cpp b/src/compiler.cpp index 3b0a30b5..9cac9a65 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -677,14 +677,24 @@ __EAT_DOTS_END: }; ctx()->exit_block(); do { + StrName as_name; consume(TK("except")); if(match(TK("@id"))){ ctx()->emit_(OP_EXCEPTION_MATCH, StrName(prev().sv()).index, prev().line); + if(match(TK("as"))){ + consume(TK("@id")); + as_name = StrName(prev().sv()); + } }else{ ctx()->emit_(OP_LOAD_TRUE, BC_NOARG, BC_KEEPLINE); } int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE); - // pop the exception on match + // on match + if(!as_name.empty()){ + ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE); + ctx()->emit_store_name(name_scope(), as_name, BC_KEEPLINE); + } + // pop the exception ctx()->emit_(OP_POP_EXCEPTION, BC_NOARG, BC_KEEPLINE); compile_block_body(); patches.push_back(ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)); diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index fa7bdc4b..6014503e 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -1318,6 +1318,17 @@ void init_builtins(VM* _vm) { // return args[0]; // }); + // Exception + _vm->bind__repr__(_vm->tp_exception, [](VM* vm, PyObject* obj) { + Exception& self = _CAST(Exception&, obj); + return VAR(fmt(self.type.sv(), '(', self.msg.escape(), ')')); + }); + + _vm->bind__str__(_vm->tp_exception, [](VM* vm, PyObject* obj) { + Exception& self = _CAST(Exception&, obj); + return VAR(self.msg); + }); + RangeIter::register_class(_vm, _vm->builtins); ArrayIter::register_class(_vm, _vm->builtins); StringIter::register_class(_vm, _vm->builtins); diff --git a/src/vm.cpp b/src/vm.cpp index d0ae6ae2..9e9ce78f 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -724,7 +724,7 @@ void VM::init_builtin_types(){ tp_native_func = _new_type_object("native_func"); tp_bound_method = _new_type_object("bound_method"); tp_super = _new_type_object("super"); - tp_exception = _new_type_object("Exception"); + tp_exception = _new_type_object("_Exception"); tp_bytes = _new_type_object("bytes"); tp_mappingproxy = _new_type_object("mappingproxy"); tp_dict = _new_type_object("dict"); diff --git a/tests/41_exception.py b/tests/41_exception.py index a15aadbe..05bbdd19 100644 --- a/tests/41_exception.py +++ b/tests/41_exception.py @@ -81,4 +81,20 @@ def f(a: list): a[0] = 1 a = [0] f(a) -assert a == [1] \ No newline at end of file +assert a == [1] + +try: + a = [][3] +except IndexError as e: + assert str(e) == '3 not in [0, 0)' + assert repr(e).startswith('IndexError(') + +try: + a = {}[2] +except IndexError as e: + exit(1) +except Exception as e: + assert str(e) == '2' + assert repr(e).startswith('KeyError(') +except: + exit(1) \ No newline at end of file