blueloveTH 3 лет назад
Родитель
Сommit
d4e299bce0
6 измененных файлов с 62 добавлено и 34 удалено
  1. 19 0
      src/codeobject.h
  2. 3 1
      src/compiler.h
  3. 7 3
      src/error.h
  4. 3 0
      src/opcodes.h
  5. 1 1
      src/pocketpy.h
  6. 29 29
      src/vm.h

+ 19 - 0
src/codeobject.h

@@ -244,6 +244,25 @@ public:
     inline void jump_abs(int i){ next_ip = i; }
     inline void jump_rel(int i){ next_ip = ip + i; }
 
+    std::stack<std::pair<int, std::vector<PyVar>>> s_try_block;
+
+    inline void on_try_block_enter(){
+        s_try_block.push(std::make_pair(code->co_code[ip].block, s_data));
+    }
+
+    inline void on_try_block_exit(){
+        s_try_block.pop();
+    }
+
+    bool jump_to_exception_handler(){
+        if(s_try_block.empty()) return false;
+        auto& p = s_try_block.top();
+        s_data = std::move(p.second);
+        next_ip = code->co_blocks[p.first].end;
+        on_try_block_exit();
+        return true;
+    }
+
     void jump_abs_safe(int target){
         const Bytecode& prev = code->co_code[ip];
         int i = prev.block;

+ 3 - 1
src/compiler.h

@@ -805,7 +805,9 @@ __LISTCOMP:
 
     void compileTryExcept() {
         co()->__enter_block(TRY_EXCEPT);
+        emit(OP_TRY_BLOCK_ENTER);
         compileBlockBody();
+        emit(OP_TRY_BLOCK_EXIT);
         int patch = emit(OP_JUMP_ABSOLUTE);
         co()->__exit_block();
         consume(TK("except"));
@@ -1077,7 +1079,7 @@ __LISTCOMP:
     }
 
     void __throw_e(_Str type, _Str msg){
-        auto e = _Error0("SyntaxError", msg, false);
+        auto e = _Exception("SyntaxError", msg, false);
         e.st_push(getLineSnapshot());
         throw e;
     }

+ 7 - 3
src/error.h

@@ -67,7 +67,7 @@ struct SourceMetadata {
 
 typedef pkpy::shared_ptr<SourceMetadata> _Source;
 
-class _Error0 : public std::exception {
+class _Exception : public std::exception {
     _Str type;
     _Str msg;
     bool is_runtime_error;
@@ -75,8 +75,12 @@ class _Error0 : public std::exception {
 
     mutable _Str _what_cached;
 public:
-    _Error0(_Str type, _Str msg, bool is_runtime_error): type(type), msg(msg), is_runtime_error(is_runtime_error) {}
-    void st_push(_Str snapshot){ stacktrace.push(snapshot); }
+    _Exception(_Str type, _Str msg, bool is_runtime_error): type(type), msg(msg), is_runtime_error(is_runtime_error) {}
+
+    void st_push(_Str snapshot){
+        if(stacktrace.size() >= 8) return;
+        stacktrace.push(snapshot);
+    }
 
     const char* what() const noexcept override {
         std::stack<_Str> st(stacktrace);

+ 3 - 0
src/opcodes.h

@@ -66,4 +66,7 @@ OPCODE(STORE_FUNCTION)
 OPCODE(STORE_REF)
 OPCODE(DELETE_REF)
 
+OPCODE(TRY_BLOCK_ENTER)
+OPCODE(TRY_BLOCK_EXIT)
+
 #endif

+ 1 - 1
src/pocketpy.h

@@ -8,7 +8,7 @@ _Code VM::compile(_Str source, _Str filename, CompileMode mode) {
     Compiler compiler(this, source.c_str(), filename, mode);
     try{
         return compiler.__fillCode();
-    }catch(_Error0& e){
+    }catch(_Exception& e){
         throw e;
     }catch(std::exception& e){
         compiler.__throw_e("UnexpectedError", e.what());

+ 29 - 29
src/vm.h

@@ -194,7 +194,7 @@ protected:
                     _Str type = frame->code->co_names[byte.arg].first;
                     _error(type, msg);
                 } break;
-            case OP_RE_RAISE: break;
+            case OP_RE_RAISE: _raise(); break;
             case OP_BUILD_LIST:
                 frame->push(PyList(
                     frame->pop_n_values_reversed(this, byte.arg).toList()));
@@ -317,6 +317,8 @@ protected:
             // TODO: using "goto" inside with block may cause __exit__ not called
             case OP_WITH_ENTER: call(frame->pop_value(this), __enter__); break;
             case OP_WITH_EXIT: call(frame->pop_value(this), __exit__); break;
+            case OP_TRY_BLOCK_ENTER: frame->on_try_block_enter(); break;
+            case OP_TRY_BLOCK_EXIT: frame->on_try_block_exit(); break;
             default:
                 throw std::runtime_error(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
                 break;
@@ -521,15 +523,14 @@ public:
         try {
             _Code code = compile(source, filename, mode);
             return _exec(code, _module, pkpy::make_shared<PyVarDict>());
-        }catch (const _Error0& e){
+        }catch (const _Exception& e){
             *_stderr << e.what() << '\n';
         }
         catch (const std::exception& e) {
-            auto re = _Error0("UnexpectedError", e.what(), false);
-            auto snapshots = _cleanErrorAndGetSnapshots();
-            while(!snapshots.empty()){
-                re.st_push(snapshots.top());
-                snapshots.pop();
+            auto re = _Exception("UnexpectedError", e.what(), false);
+            while (!callstack.empty()){
+                re.st_push(callstack.back()->curr_snapshot());
+                callstack.pop_back();
             }
             *_stderr << re.what() << '\n';
         }
@@ -571,7 +572,7 @@ public:
     }
 
     PyVar new_user_type_object(PyVar mod, _Str name, PyVar base){
-        PyVar obj = pkpy::make_shared<PyObject, Py_<i64>>((i64)1, _tp_type);
+        PyVar obj = pkpy::make_shared<PyObject, Py_<i64>>(DUMMY_VAL, _tp_type);
         setattr(obj, __base__, base);
         _Str fullName = name;
         if(mod != builtins) fullName = UNION_NAME(mod) + "." + name;
@@ -582,7 +583,7 @@ public:
 
     PyVar new_type_object(_Str name, PyVar base=nullptr) {
         if(base == nullptr) base = _tp_object;
-        PyVar obj = pkpy::make_shared<PyObject, Py_<i64>>((i64)0, _tp_type);
+        PyVar obj = pkpy::make_shared<PyObject, Py_<i64>>(DUMMY_VAL, _tp_type);
         setattr(obj, __base__, base);
         _types[name] = obj;
         return obj;
@@ -785,7 +786,7 @@ public:
     PyVar _tp_list, _tp_tuple;
     PyVar _tp_function, _tp_native_function, _tp_native_iterator, _tp_bounded_method;
     PyVar _tp_slice, _tp_range, _tp_module, _tp_ref;
-    PyVar _tp_super;
+    PyVar _tp_super, _tp_exception;
 
     template<typename P>
     inline PyVarRef PyRef(P&& value) {
@@ -815,15 +816,15 @@ public:
     DEF_NATIVE(BoundedMethod, _BoundedMethod, _tp_bounded_method)
     DEF_NATIVE(Range, _Range, _tp_range)
     DEF_NATIVE(Slice, _Slice, _tp_slice)
+    DEF_NATIVE(Exception, _Exception, _tp_exception)
     
     // there is only one True/False, so no need to copy them!
     inline bool PyBool_AS_C(const PyVar& obj){return obj == True;}
     inline const PyVar& PyBool(bool value){return value ? True : False;}
 
     void initializeBuiltinClasses(){
-        _tp_object = pkpy::make_shared<PyObject, Py_<i64>>((i64)0, nullptr);
-        _tp_type = pkpy::make_shared<PyObject, Py_<i64>>((i64)0, nullptr);
-
+        _tp_object = pkpy::make_shared<PyObject, Py_<i64>>(DUMMY_VAL, nullptr);
+        _tp_type = pkpy::make_shared<PyObject, Py_<i64>>(DUMMY_VAL, nullptr);
         _types["object"] = _tp_object;
         _types["type"] = _tp_type;
 
@@ -843,6 +844,7 @@ public:
         _tp_native_iterator = new_type_object("_native_iterator");
         _tp_bounded_method = new_type_object("_bounded_method");
         _tp_super = new_type_object("super");
+        _tp_exception = new_type_object("Exception");
 
         this->None = new_object(new_type_object("NoneType"), DUMMY_VAL);
         this->Ellipsis = new_object(new_type_object("ellipsis"), DUMMY_VAL);
@@ -891,25 +893,23 @@ public:
 
     /***** Error Reporter *****/
 private:
+    bool _error_lock = false;
+
     void _error(const _Str& name, const _Str& msg){
-        auto e = _Error0(name, msg, true);
-        std::stack<_Str> snapshots = _cleanErrorAndGetSnapshots();
-        while (!snapshots.empty()){
-            e.st_push(snapshots.top());
-            snapshots.pop();
-        }
-        throw e;
+        if(_error_lock) UNREACHABLE();
+        auto e = _Exception(name, msg, true);
+        top_frame()->push(PyException(e));
+        _raise();
     }
 
-    std::stack<_Str> _cleanErrorAndGetSnapshots(){
-        std::stack<_Str> snapshots;
-        while (!callstack.empty()){
-            if(snapshots.size() < 8){
-                snapshots.push(callstack.back()->curr_snapshot());
-            }
-            callstack.pop_back();
-        }
-        return snapshots;
+    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;
     }
 
 public: