blueloveTH 3 سال پیش
والد
کامیت
ef36a1d3a0
3فایلهای تغییر یافته به همراه51 افزوده شده و 17 حذف شده
  1. 5 0
      src/codeobject.h
  2. 12 2
      src/error.h
  3. 34 15
      src/vm.h

+ 5 - 0
src/codeobject.h

@@ -175,6 +175,7 @@ private:
     std::vector<PyVar> 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<PyVarDict> _locals)
         : code(code), _module(_module), _locals(_locals) {
+        static thread_local i64 _id = 0;
+        m_id = _id++;
     }
 
     inline const Bytecode& next_bytecode() {

+ 12 - 2
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);

+ 34 - 15
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<typename ...Args>
     PyVar _exec(Args&&... args){
         Frame* frame = __push_new_frame(std::forward<Args>(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);