blueloveTH 3 лет назад
Родитель
Сommit
981fcbc8e5
7 измененных файлов с 71 добавлено и 60 удалено
  1. 2 2
      src/builtins.h
  2. 16 1
      src/codeobject.h
  3. 2 2
      src/compiler.h
  4. 8 18
      src/error.h
  5. 2 8
      src/pocketpy.h
  6. 27 29
      src/vm.h
  7. 14 0
      tests/_exception.py

+ 2 - 2
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
 

+ 16 - 1
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; i<s_data.size(); i++){
+            ss << UNION_TP_NAME(s_data[i]);
+            if(i != s_data.size()-1) ss << ", ";
+        }
+        ss << "]";
+        return ss.str();
+    }
+
     inline bool has_next_bytecode() const{ return next_ip < code->co_code.size(); }
 
     inline PyVar pop(){
@@ -247,7 +258,7 @@ public:
     inline void push(T&& obj){ s_data.push_back(std::forward<T>(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<std::pair<int, std::vector<PyVar>>> 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;

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

+ 8 - 18
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<SourceMetadata> _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();
     }
 };

+ 2 - 8
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) {

+ 27 - 29
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<PyVarDict>());
         }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:

+ 14 - 0
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()