diff --git a/src/codeobject.h b/src/codeobject.h index ebb2e229..1da9ec49 100644 --- a/src/codeobject.h +++ b/src/codeobject.h @@ -175,6 +175,7 @@ private: std::vector s_data; int ip = -1; int next_ip = 0; + int m_id; public: const _Code code; PyVar _module; @@ -183,8 +184,12 @@ public: inline PyVarDict& f_locals() noexcept { return *_locals; } inline PyVarDict& f_globals() noexcept { return _module->attribs; } + inline i64 id() const noexcept { return m_id; } + Frame(const _Code code, PyVar _module, pkpy::shared_ptr _locals) : code(code), _module(_module), _locals(_locals) { + static thread_local i64 _id = 0; + m_id = _id++; } inline const Bytecode& next_bytecode() { diff --git a/src/error.h b/src/error.h index 69516b79..23363231 100644 --- a/src/error.h +++ b/src/error.h @@ -2,12 +2,18 @@ #include "safestl.h" -class NeedMoreLines { -public: +struct NeedMoreLines { NeedMoreLines(bool isClassDef) : isClassDef(isClassDef) {} bool isClassDef; }; +struct HandledException {}; + +struct UnhandledException { + PyVar obj; + UnhandledException(PyVar obj) : obj(obj) {} +}; + enum CompileMode { EXEC_MODE, EVAL_MODE, @@ -77,6 +83,10 @@ class _Exception : public std::exception { 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; + } + void st_push(_Str snapshot){ if(stacktrace.size() >= 8) return; stacktrace.push(snapshot); diff --git a/src/vm.h b/src/vm.h index 4eb75ae0..a30f8121 100644 --- a/src/vm.h +++ b/src/vm.h @@ -187,10 +187,16 @@ protected: PyVar expr = frame->pop_value(this); if(asBool(expr) != True) _error("AssertionError", ""); } break; - case OP_EXCEPTION_MATCH: break; + case OP_EXCEPTION_MATCH: + { + const auto& _e = PyException_AS_C(frame->top()); + _Str name = frame->code->co_names[byte.arg].first; + frame->push(PyBool(_e.match_type(name))); + } break; case OP_RAISE: { - _Str msg = PyStr_AS_C(asStr(frame->pop_value(this))); + PyVar obj = frame->pop_value(this); + _Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj)); _Str type = frame->code->co_names[byte.arg].first; _error(type, msg); } break; @@ -549,13 +555,34 @@ public: template PyVar _exec(Args&&... args){ Frame* frame = __push_new_frame(std::forward(args)...); - Frame* frameBase = frame; + i64 base_id = frame->id(); PyVar ret = nullptr; + bool need_raise = false; while(true){ - ret = run_frame(frame); + if(frame->id() < base_id) UNREACHABLE(); + try{ + if(need_raise){ need_raise = false; _raise(); } + ret = run_frame(frame); + }catch(HandledException& e){ + continue; + }catch(UnhandledException& e){ + _Exception& _e = UNION_GET(_Exception, e.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); + need_raise = true; + continue; + } + throw _e; + } + if(ret != __py2py_call_signal){ - if(frame == frameBase){ // [ frameBase<- ] + if(frame->id() == base_id){ // [ frameBase<- ] break; }else{ callstack.pop_back(); @@ -893,10 +920,7 @@ public: /***** Error Reporter *****/ private: - bool _error_lock = false; - void _error(const _Str& name, const _Str& msg){ - if(_error_lock) UNREACHABLE(); auto e = _Exception(name, msg, true); top_frame()->push(PyException(e)); _raise(); @@ -904,12 +928,8 @@ private: void _raise(){ bool ok = top_frame()->jump_to_exception_handler(); - if(ok) return; - // 当前帧里面没有异常处理器了,应推到上一层 - _error_lock = true; - const auto& e = PyException_AS_C(top_frame()->top()); - _error_lock = false; - throw e; + if(ok) throw HandledException(); + throw UnhandledException(top_frame()->top()); } public: @@ -938,7 +958,6 @@ public: }; /***** Pointers' Impl *****/ - PyVar NameRef::get(VM* vm, Frame* frame) const{ PyVar* val; val = frame->f_locals().try_get(pair->first);