From 981fcbc8e5224d4e6aa8498e9f2a8d7c499b10e2 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 4 Feb 2023 04:07:48 +0800 Subject: [PATCH] up --- src/builtins.h | 4 ++-- src/codeobject.h | 17 +++++++++++++- src/compiler.h | 4 ++-- src/error.h | 26 +++++++-------------- src/pocketpy.h | 10 ++------ src/vm.h | 56 ++++++++++++++++++++++----------------------- tests/_exception.py | 14 ++++++++++++ 7 files changed, 71 insertions(+), 60 deletions(-) create mode 100644 tests/_exception.py diff --git a/src/builtins.h b/src/builtins.h index 2c66f666..97186680 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -201,7 +201,7 @@ class dict: def __getitem__(self, key): ok, i = self.__probe(key) if not ok: - raise KeyError(key) + raise KeyError(repr(key)) return self._a[i][1] def __contains__(self, key): @@ -222,7 +222,7 @@ class dict: def __delitem__(self, key): ok, i = self.__probe(key) if not ok: - raise KeyError(key) + raise KeyError(repr(key)) self._a[i] = None self._len -= 1 diff --git a/src/codeobject.h b/src/codeobject.h index 1da9ec49..24a666b4 100644 --- a/src/codeobject.h +++ b/src/codeobject.h @@ -204,6 +204,17 @@ public: } inline int stack_size() const{ return s_data.size(); } + _Str stack_info(){ + _StrStream ss; + ss << "["; + for(int i=0; ico_code.size(); } inline PyVar pop(){ @@ -247,7 +258,7 @@ public: inline void push(T&& obj){ s_data.push_back(std::forward(obj)); } inline void jump_abs(int i){ next_ip = i; } - inline void jump_rel(int i){ next_ip = ip + i; } + inline void jump_rel(int i){ next_ip += i; } std::stack>> s_try_block; @@ -259,10 +270,14 @@ public: s_try_block.pop(); } + inline int get_ip() const{ return ip; } + bool jump_to_exception_handler(){ if(s_try_block.empty()) return false; + PyVar obj = pop(); auto& p = s_try_block.top(); s_data = std::move(p.second); + s_data.push_back(obj); next_ip = code->co_blocks[p.first].end; on_try_block_exit(); return true; diff --git a/src/compiler.h b/src/compiler.h index f3f3291b..8c58841a 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -910,8 +910,8 @@ __LISTCOMP: // If last op is not an assignment, pop the result. uint8_t lastOp = co()->co_code.back().op; if( lastOp!=OP_STORE_NAME && lastOp!=OP_STORE_REF){ - if(mode()==SINGLE_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR); - emit(OP_POP_TOP); + if(mode()==SINGLE_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR, -1, true); + emit(OP_POP_TOP, -1, true); } } } diff --git a/src/error.h b/src/error.h index 23363231..5a4255ca 100644 --- a/src/error.h +++ b/src/error.h @@ -8,11 +8,7 @@ struct NeedMoreLines { }; struct HandledException {}; - -struct UnhandledException { - PyVar obj; - UnhandledException(PyVar obj) : obj(obj) {} -}; +struct UnhandledException {}; enum CompileMode { EXEC_MODE, @@ -73,32 +69,26 @@ struct SourceMetadata { typedef pkpy::shared_ptr _Source; -class _Exception : public std::exception { +class _Exception { _Str type; _Str msg; - bool is_runtime_error; + bool is_re; std::stack<_Str> stacktrace; - - mutable _Str _what_cached; public: - _Exception(_Str type, _Str msg, bool is_runtime_error): type(type), msg(msg), is_runtime_error(is_runtime_error) {} - - bool match_type(const _Str& type) const { - return this->type == type; - } + _Exception(_Str type, _Str msg, bool is_re): type(type), msg(msg), is_re(is_re) {} + bool match_type(const _Str& type) const { return this->type == type;} void st_push(_Str snapshot){ if(stacktrace.size() >= 8) return; stacktrace.push(snapshot); } - const char* what() const noexcept override { + _Str summary() const { std::stack<_Str> st(stacktrace); _StrStream ss; - if(is_runtime_error) ss << "Traceback (most recent call last):\n"; + if(is_re) ss << "Traceback (most recent call last):\n"; while(!st.empty()) { ss << st.top() << '\n'; st.pop(); } ss << type << ": " << msg; - _what_cached = ss.str(); - return _what_cached.c_str(); + return ss.str(); } }; \ No newline at end of file diff --git a/src/pocketpy.h b/src/pocketpy.h index 71a4b769..22082fdd 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -6,14 +6,7 @@ _Code VM::compile(_Str source, _Str filename, CompileMode mode) { Compiler compiler(this, source.c_str(), filename, mode); - try{ - return compiler.__fillCode(); - }catch(_Exception& e){ - throw e; - }catch(std::exception& e){ - compiler.__throw_e("UnexpectedError", e.what()); - return nullptr; - } + return compiler.__fillCode(); } #define BIND_NUM_ARITH_OPT(name, op) \ @@ -136,6 +129,7 @@ void __initializeBuiltinFunctions(VM* _vm) { _vm->bindMethod<1>("object", "__eq__", CPP_LAMBDA(vm->PyBool(args[0] == args[1]))); _vm->bindMethod<1>("object", "__ne__", CPP_LAMBDA(vm->PyBool(args[0] != args[1]))); + _vm->bindStaticMethod<1>("type", "__new__", CPP_LAMBDA(args[0]->_type)); _vm->bindStaticMethod<-1>("range", "__new__", [](VM* vm, const pkpy::Args& args) { diff --git a/src/vm.h b/src/vm.h index a30f8121..c3a76338 100644 --- a/src/vm.h +++ b/src/vm.h @@ -29,8 +29,9 @@ protected: PyVar run_frame(Frame* frame){ while(frame->has_next_bytecode()){ const Bytecode& byte = frame->next_bytecode(); - //printf("[%d] %s (%d)\n", frame->stack_size(), OP_NAMES[byte.op], byte.arg); - //printf("%s\n", frame->code->src->getLine(byte.line).c_str()); + // if(frame->_module != builtins){ + // printf("%d: %s (%d) %s\n", frame->get_ip(), OP_NAMES[byte.op], byte.arg, frame->stack_info().c_str()); + // } switch (byte.op) { case OP_NO_OP: break; // do nothing @@ -530,16 +531,13 @@ public: _Code code = compile(source, filename, mode); return _exec(code, _module, pkpy::make_shared()); }catch (const _Exception& e){ - *_stderr << e.what() << '\n'; - } - catch (const std::exception& e) { - auto re = _Exception("UnexpectedError", e.what(), false); - while (!callstack.empty()){ - re.st_push(callstack.back()->curr_snapshot()); - callstack.pop_back(); - } - *_stderr << re.what() << '\n'; + *_stderr << e.summary() << '\n'; } + // catch (const std::exception& e) { + // *_stderr << "A std::exception occurred! It may be a bug, please report it!!\n"; + // *_stderr << e.what() << '\n'; + // } + callstack.clear(); return nullptr; } @@ -564,34 +562,35 @@ public: try{ if(need_raise){ need_raise = false; _raise(); } ret = run_frame(frame); + + if(ret != __py2py_call_signal){ + if(frame->id() == base_id){ // [ frameBase<- ] + break; + }else{ + callstack.pop_back(); + frame = callstack.back().get(); + frame->push(ret); + } + }else{ + frame = callstack.back().get(); // [ frameBase, newFrame<- ] + } }catch(HandledException& e){ continue; }catch(UnhandledException& e){ - _Exception& _e = UNION_GET(_Exception, e.obj); + PyVar obj = frame->pop(); + _Exception& _e = PyException_AS_C(obj); _e.st_push(frame->curr_snapshot()); callstack.pop_back(); if(!callstack.empty()){ frame = callstack.back().get(); if(frame->id() < base_id) throw e; - frame->push(ret); + frame->push(obj); need_raise = true; continue; } throw _e; } - - if(ret != __py2py_call_signal){ - if(frame->id() == base_id){ // [ frameBase<- ] - break; - }else{ - callstack.pop_back(); - frame = callstack.back().get(); - frame->push(ret); - } - }else{ - frame = callstack.back().get(); // [ frameBase, newFrame<- ] - } } callstack.pop_back(); @@ -778,7 +777,7 @@ public: if(byte.op == OP_LOAD_CONST){ argStr += " (" + PyStr_AS_C(asRepr(code->co_consts[byte.arg])) + ")"; } - if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME){ + if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME || byte.op == OP_RAISE){ argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")"; } ss << pad(argStr, 20); // may overflow @@ -879,6 +878,7 @@ public: this->False = new_object(_tp_bool, false); this->builtins = new_module("builtins"); this->_main = new_module("__main__"); + this->__py2py_call_signal = new_object(new_type_object("_signal"), DUMMY_VAL); setattr(_tp_type, __base__, _tp_object); _tp_type->_type = _tp_type; @@ -889,8 +889,6 @@ public: setattr(type, __name__, PyStr(name)); } - this->__py2py_call_signal = new_object(_tp_object, DUMMY_VAL); - std::vector<_Str> publicTypes = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"}; for (auto& name : publicTypes) { setattr(builtins, name, _types[name]); @@ -929,7 +927,7 @@ private: void _raise(){ bool ok = top_frame()->jump_to_exception_handler(); if(ok) throw HandledException(); - throw UnhandledException(top_frame()->top()); + else throw UnhandledException(); } public: diff --git a/tests/_exception.py b/tests/_exception.py new file mode 100644 index 00000000..fac04d8a --- /dev/null +++ b/tests/_exception.py @@ -0,0 +1,14 @@ +try: + raise KeyError +except: + print("exception caught") +print(123) + +def f(): + try: + raise KeyError('foo') + except A: # will fail to catch + print("exception caught") + print(123) + +f() \ No newline at end of file