blueloveTH %!s(int64=3) %!d(string=hai) anos
pai
achega
730201907c
Modificáronse 9 ficheiros con 170 adicións e 209 borrados
  1. 76 114
      src/codeobject.h
  2. 26 22
      src/compiler.h
  3. 3 5
      src/error.h
  4. 4 4
      src/obj.h
  5. 0 1
      src/opcodes.h
  6. 2 5
      src/parser.h
  7. 2 2
      src/pocketpy.h
  8. 55 56
      src/vm.h
  9. 2 0
      tests/_exception.py

+ 76 - 114
src/codeobject.h

@@ -20,7 +20,7 @@ struct Bytecode{
     uint8_t op;
     int arg;
     int line;
-    uint16_t block;     // the block id of this bytecode
+    uint16_t block;
 };
 
 _Str pad(const _Str& s, const int n){
@@ -38,100 +38,69 @@ enum CodeBlockType {
 
 struct CodeBlock {
     CodeBlockType type;
-    std::vector<int> id;
-    int parent;        // parent index in co_blocks
-
+    int parent;         // parent index in blocks
     int start;          // start index of this block in co_code, inclusive
     int end;            // end index of this block in co_code, exclusive
 
     std::string to_string() const {
         if(parent == -1) return "";
-        std::string s = "[";
-        for(int i = 0; i < id.size(); i++){
-            s += std::to_string(id[i]);
-            if(i != id.size()-1) s += "-";
-        }
-        s += ": type=";
-        s += std::to_string(type);
-        s += "]";
-        return s;
+        return "[B:" + std::to_string(type) + "]";
     }
-
-    bool operator==(const std::vector<int>& other) const{ return id == other; }
-    bool operator!=(const std::vector<int>& other) const{ return id != other; }
-    int depth() const{ return id.size(); }
 };
 
 struct CodeObject {
-    _Source src;
+    pkpy::shared_ptr<SourceData> src;
     _Str name;
 
-    CodeObject(_Source src, _Str name) {
+    CodeObject(pkpy::shared_ptr<SourceData> src, _Str name) {
         this->src = src;
         this->name = name;
     }
 
     std::vector<Bytecode> co_code;
-    PyVarList co_consts;
-    std::vector<std::pair<_Str, NameScope>> co_names;
-    std::vector<_Str> co_global_names;
-
-    std::vector<CodeBlock> co_blocks = { CodeBlock{NO_BLOCK, {}, -1} };
+    PyVarList consts;
+    std::vector<std::pair<_Str, NameScope>> names;
+    emhash8::HashMap<_Str, int> global_names;
+    std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, {}, -1} };
+    emhash8::HashMap<_Str, int> labels;
 
     // tmp variables
-    int _currBlockIndex = 0;
-    bool __isCurrBlockLoop() const {
-        return co_blocks[_currBlockIndex].type == FOR_LOOP || co_blocks[_currBlockIndex].type == WHILE_LOOP;
+    int _curr_block_i = 0;
+    bool __is_curr_block_loop() const {
+        return blocks[_curr_block_i].type == FOR_LOOP || blocks[_curr_block_i].type == WHILE_LOOP;
     }
 
     void __enter_block(CodeBlockType type){
-        const CodeBlock& currBlock = co_blocks[_currBlockIndex];
-        std::vector<int> copy(currBlock.id);
-        copy.push_back(-1);
-        int t = 0;
-        while(true){
-            copy[copy.size()-1] = t;
-            auto it = std::find(co_blocks.begin(), co_blocks.end(), copy);
-            if(it == co_blocks.end()) break;
-            t++;
-        }
-        co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex, (int)co_code.size()});
-        _currBlockIndex = co_blocks.size()-1;
+        const CodeBlock& currBlock = blocks[_curr_block_i];
+        blocks.push_back(CodeBlock{type, _curr_block_i, (int)co_code.size()});
+        _curr_block_i = blocks.size()-1;
     }
 
     void __exit_block(){
-        co_blocks[_currBlockIndex].end = co_code.size();
-        _currBlockIndex = co_blocks[_currBlockIndex].parent;
-        if(_currBlockIndex < 0) UNREACHABLE();
+        blocks[_curr_block_i].end = co_code.size();
+        _curr_block_i = blocks[_curr_block_i].parent;
+        if(_curr_block_i < 0) UNREACHABLE();
     }
 
-    // for goto use
-    // goto/label should be put at toplevel statements
-    emhash8::HashMap<_Str, int> co_labels;
-
-    void add_label(const _Str& label){
-        if(co_labels.find(label) != co_labels.end()){
-            _Str msg = "label '" + label + "' already exists";
-            throw std::runtime_error(msg.c_str());
-        }
-        co_labels[label] = co_code.size();
+    bool add_label(const _Str& label){
+        if(labels.contains(label)) return false;
+        labels[label] = co_code.size();
+        return true;
     }
 
     int add_name(_Str name, NameScope scope){
-        if(scope == NAME_LOCAL && std::find(co_global_names.begin(), co_global_names.end(), name) != co_global_names.end()){
-            scope = NAME_GLOBAL;
-        }
+        if(scope == NAME_LOCAL && global_names.contains(name)) scope = NAME_GLOBAL;
         auto p = std::make_pair(name, scope);
-        for(int i=0; i<co_names.size(); i++){
-            if(co_names[i] == p) return i;
+        for(int i=0; i<names.size(); i++){
+            if(names[i] == p) return i;
         }
-        co_names.push_back(p);
-        return co_names.size() - 1;
+        names.push_back(p);
+        return names.size() - 1;
     }
 
     int add_const(PyVar v){
-        co_consts.push_back(v);
-        return co_consts.size() - 1;
+        consts.push_back(v);
+        return consts.size() - 1;
     }
 
     void optimize_level_1(){
@@ -170,63 +139,61 @@ struct CodeObject {
     }
 };
 
-class Frame {
-private:
-    std::vector<PyVar> s_data;
-    int ip = -1;
-    int next_ip = 0;
-    int m_id;
-public:
-    const _Code code;
+struct Frame {
+    std::vector<PyVar> _data;
+    int _ip = -1;
+    int _next_ip = 0;
+
+    const _Code co;
     PyVar _module;
     pkpy::shared_ptr<PyVarDict> _locals;
+    i64 _id;
 
     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++;
+    Frame(const _Code co, PyVar _module, pkpy::shared_ptr<PyVarDict> _locals)
+        : co(co), _module(_module), _locals(_locals) {
+        static thread_local i64 kGlobalId = 0;
+        _id = kGlobalId++;
     }
 
     inline const Bytecode& next_bytecode() {
-        ip = next_ip;
-        next_ip = ip + 1;
-        return code->co_code[ip];
+        _ip = _next_ip;
+        _next_ip = _ip + 1;
+        return co->co_code[_ip];
     }
 
     _Str curr_snapshot(){
-        int line = code->co_code[ip].line;
-        return code->src->snapshot(line);
+        int line = co->co_code[_ip].line;
+        return co->src->snapshot(line);
     }
 
-    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 << ", ";
+        for(int i=0; i<_data.size(); i++){
+            ss << UNION_TP_NAME(_data[i]);
+            if(i != _data.size()-1) ss << ", ";
         }
         ss << "]";
         return ss.str();
     }
 
-    inline bool has_next_bytecode() const{ return next_ip < code->co_code.size(); }
+    inline bool has_next_bytecode() const {
+        return _next_ip < co->co_code.size();
+    }
 
     inline PyVar pop(){
-        if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
-        PyVar v = std::move(s_data.back());
-        s_data.pop_back();
+        if(_data.empty()) throw std::runtime_error("_data.empty() is true");
+        PyVar v = std::move(_data.back());
+        _data.pop_back();
         return v;
     }
 
     inline void __pop(){
-        if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
-        s_data.pop_back();
+        if(_data.empty()) throw std::runtime_error("_data.empty() is true");
+        _data.pop_back();
     }
 
     inline void try_deref(VM*, PyVar&);
@@ -244,73 +211,68 @@ public:
     }
 
     inline PyVar& top(){
-        if(s_data.empty()) throw std::runtime_error("s_data.empty() is true");
-        return s_data.back();
+        if(_data.empty()) throw std::runtime_error("_data.empty() is true");
+        return _data.back();
     }
 
     inline PyVar top_value_offset(VM* vm, int n){
-        PyVar value = s_data[s_data.size() + n];
+        PyVar value = _data[_data.size() + n];
         try_deref(vm, value);
         return value;
     }
 
     template<typename T>
-    inline void push(T&& obj){ s_data.push_back(std::forward<T>(obj)); }
+    inline void push(T&& obj){ _data.push_back(std::forward<T>(obj)); }
 
-    inline void jump_abs(int i){ next_ip = i; }
-    inline void jump_rel(int i){ next_ip += i; }
+    inline void jump_abs(int i){ _next_ip = i; }
+    inline void jump_rel(int i){ _next_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));
+        s_try_block.push(std::make_pair(co->co_code[_ip].block, _data));
     }
 
     inline void on_try_block_exit(){
         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;
+        _data = std::move(p.second);
+        _data.push_back(obj);
+        _next_ip = co->blocks[p.first].end;
         on_try_block_exit();
         return true;
     }
 
     void jump_abs_safe(int target){
-        const Bytecode& prev = code->co_code[ip];
+        const Bytecode& prev = co->co_code[_ip];
         int i = prev.block;
-        next_ip = target;
-        if(next_ip >= code->co_code.size()){
+        _next_ip = target;
+        if(_next_ip >= co->co_code.size()){
             while(i>=0){
-                if(code->co_blocks[i].type == FOR_LOOP) pop();
-                i = code->co_blocks[i].parent;
+                if(co->blocks[i].type == FOR_LOOP) pop();
+                i = co->blocks[i].parent;
             }
         }else{
-            const Bytecode& next = code->co_code[target];
+            const Bytecode& next = co->co_code[target];
             while(i>=0 && i!=next.block){
-                if(code->co_blocks[i].type == FOR_LOOP) pop();
-                i = code->co_blocks[i].parent;
+                if(co->blocks[i].type == FOR_LOOP) pop();
+                i = co->blocks[i].parent;
             }
             if(i!=next.block) throw std::runtime_error("invalid jump");
         }
     }
 
     pkpy::Args pop_n_values_reversed(VM* vm, int n){
-        int new_size = s_data.size() - n;
-        if(new_size < 0) throw std::runtime_error("stack_size() < n");
         pkpy::Args v(n);
         for(int i=n-1; i>=0; i--){
-            v[i] = std::move(s_data[new_size + i]);
+            v[i] = pop();
             try_deref(vm, v[i]);
         }
-        s_data.resize(new_size);
         return v;
     }
 

+ 26 - 22
src/compiler.h

@@ -17,8 +17,7 @@ struct GrammarRule{
 
 enum StringType { NORMAL_STRING, RAW_STRING, F_STRING };
 
-class Compiler {
-public:
+struct Compiler {
     std::unique_ptr<Parser> parser;
     std::stack<_Code> codes;
     bool isCompilingClass = false;
@@ -32,7 +31,7 @@ public:
     Compiler(VM* vm, const char* source, _Str filename, CompileMode mode){
         this->vm = vm;
         this->parser = std::make_unique<Parser>(
-            pkpy::make_shared<SourceMetadata>(source, filename, mode)
+            pkpy::make_shared<SourceData>(source, filename, mode)
         );
 
 // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
@@ -665,7 +664,7 @@ __LISTCOMP:
     int emit(Opcode opcode, int arg=-1, bool keepline=false) {
         int line = parser->prev.line;
         co()->co_code.push_back(
-            Bytecode{(uint8_t)opcode, arg, line, (uint16_t)co()->_currBlockIndex}
+            Bytecode{(uint8_t)opcode, arg, line, (uint16_t)co()->_curr_block_i}
         );
         int i = co()->co_code.size() - 1;
         if(keepline && i>=1) co()->co_code[i].line = co()->co_code[i-1].line;
@@ -808,31 +807,34 @@ __LISTCOMP:
         emit(OP_TRY_BLOCK_ENTER);
         compileBlockBody();
         emit(OP_TRY_BLOCK_EXIT);
-        int patch = emit(OP_JUMP_ABSOLUTE);
+        std::vector<int> patches = { emit(OP_JUMP_ABSOLUTE) };
         co()->__exit_block();
-        consume(TK("except"));
-        if(match(TK("@id"))){
-            int name_idx = co()->add_name(parser->prev.str(), NAME_SPECIAL);
-            emit(OP_EXCEPTION_MATCH, name_idx);
-        }else{
-            emit(OP_LOAD_TRUE);
-        }
-        int patch_2 = emit(OP_POP_JUMP_IF_FALSE);
-        emit(OP_POP_TOP);       // pop the exception on match
-        compileBlockBody();
-        emit(OP_JUMP_RELATIVE, 1);
-        patch_jump(patch_2);
+
+        do {
+            consume(TK("except"));
+            if(match(TK("@id"))){
+                int name_idx = co()->add_name(parser->prev.str(), NAME_SPECIAL);
+                emit(OP_EXCEPTION_MATCH, name_idx);
+            }else{
+                emit(OP_LOAD_TRUE);
+            }
+            int patch = emit(OP_POP_JUMP_IF_FALSE);
+            emit(OP_POP_TOP);       // pop the exception on match
+            compileBlockBody();
+            patches.push_back(emit(OP_JUMP_ABSOLUTE));
+            patch_jump(patch);
+        }while(peek() == TK("except"));
         emit(OP_RE_RAISE);      // no match, re-raise
-        patch_jump(patch);
+        for (int patch : patches) patch_jump(patch);
     }
 
     void compileStatement() {
         if (match(TK("break"))) {
-            if (!co()->__isCurrBlockLoop()) syntaxError("'break' outside loop");
+            if (!co()->__is_curr_block_loop()) syntaxError("'break' outside loop");
             consumeEndStatement();
             emit(OP_LOOP_BREAK);
         } else if (match(TK("continue"))) {
-            if (!co()->__isCurrBlockLoop()) syntaxError("'continue' not properly in loop");
+            if (!co()->__is_curr_block_loop()) syntaxError("'continue' not properly in loop");
             consumeEndStatement();
             emit(OP_LOOP_CONTINUE);
         } else if (match(TK("return"))) {
@@ -875,7 +877,9 @@ __LISTCOMP:
         } else if(match(TK("label"))){
             if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
             consume(TK(".")); consume(TK("@id"));
-            co()->add_label(parser->prev.str());
+            _Str label = parser->prev.str();
+            bool ok = co()->add_label(label);
+            if(!ok) syntaxError("label '" + label + "' already exists");
             consumeEndStatement();
         } else if(match(TK("goto"))){ // https://entrian.com/goto/
             if(mode() != EXEC_MODE) syntaxError("'goto' is only available in EXEC_MODE");
@@ -899,7 +903,7 @@ __LISTCOMP:
         } else if(match(TK("global"))){
             do {
                 consume(TK("@id"));
-                co()->co_global_names.push_back(parser->prev.str());
+                co()->global_names[parser->prev.str()] = 1;
             } while (match(TK(",")));
             consumeEndStatement();
         } else if(match(TK("pass"))){

+ 3 - 5
src/error.h

@@ -17,7 +17,7 @@ enum CompileMode {
     JSON_MODE,
 };
 
-struct SourceMetadata {
+struct SourceData {
     const char* source;
     _Str filename;
     std::vector<const char*> lineStarts;
@@ -33,7 +33,7 @@ struct SourceMetadata {
         return {_start, i};
     }
 
-    SourceMetadata(const char* source, _Str filename, CompileMode mode) {
+    SourceData(const char* source, _Str filename, CompileMode mode) {
         source = strdup(source);
         // Skip utf8 BOM if there is any.
         if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
@@ -62,13 +62,11 @@ struct SourceMetadata {
         return ss.str();
     }
 
-    ~SourceMetadata(){
+    ~SourceData(){
         free((void*)source);
     }
 };
 
-typedef pkpy::shared_ptr<SourceMetadata> _Source;
-
 class _Exception {
     _Str type;
     _Str msg;

+ 4 - 4
src/obj.h

@@ -75,13 +75,13 @@ typedef pkpy::shared_ptr<Function> _Func;
 typedef pkpy::shared_ptr<BaseIterator> _Iterator;
 
 struct PyObject {
-    PyVar _type;
+    PyVar type;
     PyVarDict attribs;
 
-    inline bool is_type(const PyVar& type) const noexcept{ return this->_type == type; }
+    inline bool is_type(const PyVar& type) const noexcept{ return this->type == type; }
     inline virtual void* value() = 0;
 
-    PyObject(const PyVar& type) : _type(type) {}
+    PyObject(const PyVar& type) : type(type) {}
     virtual ~PyObject() = default;
 };
 
@@ -95,4 +95,4 @@ struct Py_ : PyObject {
 
 #define UNION_GET(T, obj) (((Py_<T>*)((obj).get()))->_valueT)
 #define UNION_NAME(obj) UNION_GET(_Str, (obj)->attribs[__name__])
-#define UNION_TP_NAME(obj) UNION_GET(_Str, (obj)->_type->attribs[__name__])
+#define UNION_TP_NAME(obj) UNION_GET(_Str, (obj)->type->attribs[__name__])

+ 0 - 1
src/opcodes.h

@@ -42,7 +42,6 @@ OPCODE(JUMP_IF_TRUE_OR_POP)
 OPCODE(JUMP_IF_FALSE_OR_POP)
 
 OPCODE(GOTO)
-OPCODE(JUMP_RELATIVE)
 
 OPCODE(LOAD_CONST)
 OPCODE(LOAD_NONE)

+ 2 - 5
src/parser.h

@@ -90,7 +90,7 @@ enum Precedence {
 
 // The context of the parsing phase for the compiler.
 struct Parser {
-    _Source src;
+    pkpy::shared_ptr<SourceData> src;
 
     const char* token_start;
     const char* curr_char;
@@ -260,15 +260,12 @@ struct Parser {
         }
     }
     
-    // If the current char is [c] consume it and advance char by 1 and returns
-    // true otherwise returns false.
     bool matchchar(char c) {
         if (peekchar() != c) return false;
         eatchar_include_newline();
         return true;
     }
 
-    // Initialize the next token as the type.
     void set_next_token(_TokenType type, PyVar value=nullptr) {
         switch(type){
             case TK("{"): case TK("["): case TK("("): brackets_level++; break;
@@ -288,7 +285,7 @@ struct Parser {
         else set_next_token(one);
     }
 
-    Parser(_Source src) {
+    Parser(pkpy::shared_ptr<SourceData> src) {
         this->src = src;
         this->token_start = src->source;
         this->curr_char = src->source;

+ 2 - 2
src/pocketpy.h

@@ -107,7 +107,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
     _vm->bindBuiltinFunc<1>("dir", [](VM* vm, const pkpy::Args& args) {
         std::vector<_Str> names;
         for (auto& [k, _] : args[0]->attribs) names.push_back(k);
-        for (auto& [k, _] : args[0]->_type->attribs) {
+        for (auto& [k, _] : args[0]->type->attribs) {
             if (k.find("__") == 0) continue;
             if (std::find(names.begin(), names.end(), k) == names.end()) names.push_back(k);
         }
@@ -130,7 +130,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>("type", "__new__", CPP_LAMBDA(args[0]->type));
 
     _vm->bindStaticMethod<-1>("range", "__new__", [](VM* vm, const pkpy::Args& args) {
         _Range r;

+ 55 - 56
src/vm.h

@@ -23,7 +23,7 @@
 class VM {
     std::vector<PyVar> _small_integers;             // [-5, 256]
 protected:
-    std::deque< std::unique_ptr<Frame> > callstack;
+    std::stack< std::unique_ptr<Frame> > callstack;
     PyVar __py2py_call_signal;
     
     PyVar run_frame(Frame* frame){
@@ -35,24 +35,24 @@ protected:
             switch (byte.op)
             {
             case OP_NO_OP: break;       // do nothing
-            case OP_LOAD_CONST: frame->push(frame->code->co_consts[byte.arg]); break;
+            case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); break;
             case OP_LOAD_LAMBDA: {
-                PyVar obj = frame->code->co_consts[byte.arg];
+                PyVar obj = frame->co->consts[byte.arg];
                 setattr(obj, __module__, frame->_module);
                 frame->push(obj);
             } break;
             case OP_LOAD_NAME_REF: {
-                frame->push(PyRef(NameRef(frame->code->co_names[byte.arg])));
+                frame->push(PyRef(NameRef(frame->co->names[byte.arg])));
             } break;
             case OP_LOAD_NAME: {
-                frame->push(NameRef(frame->code->co_names[byte.arg]).get(this, frame));
+                frame->push(NameRef(frame->co->names[byte.arg]).get(this, frame));
             } break;
             case OP_STORE_NAME: {
-                const auto& p = frame->code->co_names[byte.arg];
+                const auto& p = frame->co->names[byte.arg];
                 NameRef(p).set(this, frame, frame->pop_value(this));
             } break;
             case OP_BUILD_ATTR_REF: {
-                const auto& attr = frame->code->co_names[byte.arg];
+                const auto& attr = frame->co->names[byte.arg];
                 PyVar obj = frame->pop_value(this);
                 frame->push(PyRef(AttrRef(obj, NameRef(attr))));
             } break;
@@ -111,7 +111,7 @@ protected:
                 } break;
             case OP_BUILD_CLASS:
                 {
-                    const _Str& clsName = frame->code->co_names[byte.arg].first;
+                    const _Str& clsName = frame->co->names[byte.arg].first;
                     PyVar clsBase = frame->pop_value(this);
                     if(clsBase == None) clsBase = _tp_object;
                     check_type(clsBase, _tp_type);
@@ -191,14 +191,14 @@ protected:
             case OP_EXCEPTION_MATCH:
                 {
                     const auto& _e = PyException_AS_C(frame->top());
-                    _Str name = frame->code->co_names[byte.arg].first;
+                    _Str name = frame->co->names[byte.arg].first;
                     frame->push(PyBool(_e.match_type(name)));
                 } break;
             case OP_RAISE:
                 {
                     PyVar obj = frame->pop_value(this);
                     _Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj));
-                    _Str type = frame->code->co_names[byte.arg].first;
+                    _Str type = frame->co->names[byte.arg].first;
                     _error(type, msg);
                 } break;
             case OP_RE_RAISE: _raise(); break;
@@ -237,11 +237,10 @@ protected:
                     frame->push(std::move(ret));
                 } break;
             case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break;
-            case OP_JUMP_RELATIVE: frame->jump_rel(byte.arg); break;
             case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break;
             case OP_GOTO: {
-                const _Str& label = frame->code->co_names[byte.arg].first;
-                int* target = frame->code->co_labels.try_get(label);
+                const _Str& label = frame->co->names[byte.arg].first;
+                int* target = frame->co->labels.try_get(label);
                 if(target == nullptr) _error("KeyError", "label '" + label + "' not found");
                 frame->jump_abs_safe(*target);
             } break;
@@ -266,18 +265,18 @@ protected:
                     if(it->hasNext()){
                         PyRef_AS_C(it->var)->set(this, frame, it->next());
                     }else{
-                        int blockEnd = frame->code->co_blocks[byte.block].end;
+                        int blockEnd = frame->co->blocks[byte.block].end;
                         frame->jump_abs_safe(blockEnd);
                     }
                 } break;
             case OP_LOOP_CONTINUE:
                 {
-                    int blockStart = frame->code->co_blocks[byte.block].start;
+                    int blockStart = frame->co->blocks[byte.block].start;
                     frame->jump_abs(blockStart);
                 } break;
             case OP_LOOP_BREAK:
                 {
-                    int blockEnd = frame->code->co_blocks[byte.block].end;
+                    int blockEnd = frame->co->blocks[byte.block].end;
                     frame->jump_abs_safe(blockEnd);
                 } break;
             case OP_JUMP_IF_FALSE_OR_POP:
@@ -303,7 +302,7 @@ protected:
                 } break;
             case OP_IMPORT_NAME:
                 {
-                    const _Str& name = frame->code->co_names[byte.arg].first;
+                    const _Str& name = frame->co->names[byte.arg].first;
                     auto it = _modules.find(name);
                     if(it == _modules.end()){
                         auto it2 = _lazy_modules.find(name);
@@ -332,12 +331,12 @@ protected:
             }
         }
 
-        if(frame->code->src->mode == EVAL_MODE || frame->code->src->mode == JSON_MODE){
-            if(frame->stack_size() != 1) throw std::runtime_error("stack size is not 1 in EVAL/JSON_MODE");
+        if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){
+            if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE");
             return frame->pop_value(this);
         }
 
-        if(frame->stack_size() != 0) throw std::runtime_error("stack not empty in EXEC_MODE");
+        if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE");
         return None;
     }
 
@@ -381,7 +380,7 @@ public:
 
     inline Frame* top_frame() const {
         if(callstack.empty()) UNREACHABLE();
-        return callstack.back().get();
+        return callstack.top().get();
     }
 
     PyVar asRepr(const PyVar& obj){
@@ -407,7 +406,7 @@ public:
     }
 
     PyVar fast_call(const _Str& name, pkpy::Args&& args){
-        PyObject* cls = args[0]->_type.get();
+        PyObject* cls = args[0]->type.get();
         while(cls != None.get()) {
             PyVar* val = cls->attribs.try_get(name);
             if(val != nullptr) return call(*val, std::move(args));
@@ -514,7 +513,7 @@ public:
             PyVar* it_m = (*callable)->attribs.try_get(__module__);
             PyVar _module = it_m != nullptr ? *it_m : top_frame()->_module;
             if(opCall){
-                __push_new_frame(fn->code, _module, _locals);
+                __new_frame(fn->code, _module, _locals);
                 return __py2py_call_signal;
             }
             return _exec(fn->code, _module, _locals);
@@ -533,46 +532,46 @@ public:
         }catch (const _Exception& e){
             *_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();
+        catch (const std::exception& e) {
+            *_stderr << "A std::exception occurred! It may be a bug, please report it!!\n";
+            *_stderr << e.what() << '\n';
+        }
+        callstack = {};
         return nullptr;
     }
 
     template<typename ...Args>
-    Frame* __push_new_frame(Args&&... args){
+    Frame* __new_frame(Args&&... args){
         if(callstack.size() > maxRecursionDepth){
             _error("RecursionError", "maximum recursion depth exceeded");
         }
-        callstack.emplace_back(std::make_unique<Frame>(std::forward<Args>(args)...));
-        return callstack.back().get();
+        callstack.emplace(std::make_unique<Frame>(std::forward<Args>(args)...));
+        return callstack.top().get();
     }
 
     template<typename ...Args>
     PyVar _exec(Args&&... args){
-        Frame* frame = __push_new_frame(std::forward<Args>(args)...);
-        i64 base_id = frame->id();
+        Frame* frame = __new_frame(std::forward<Args>(args)...);
+        i64 base_id = frame->_id;
         PyVar ret = nullptr;
         bool need_raise = false;
 
         while(true){
-            if(frame->id() < base_id) UNREACHABLE();
+            if(frame->_id < base_id) UNREACHABLE();
             try{
                 if(need_raise){ need_raise = false; _raise(); }
                 ret = run_frame(frame);
 
                 if(ret != __py2py_call_signal){
-                    if(frame->id() == base_id){         // [ frameBase<- ]
+                    if(frame->_id == base_id){      // [ frameBase<- ]
                         break;
                     }else{
-                        callstack.pop_back();
-                        frame = callstack.back().get();
+                        callstack.pop();
+                        frame = callstack.top().get();
                         frame->push(ret);
                     }
                 }else{
-                    frame = callstack.back().get();  // [ frameBase, newFrame<- ]
+                    frame = callstack.top().get();  // [ frameBase, newFrame<- ]
                 }
             }catch(HandledException& e){
                 continue;
@@ -580,11 +579,11 @@ public:
                 PyVar obj = frame->pop();
                 _Exception& _e = PyException_AS_C(obj);
                 _e.st_push(frame->curr_snapshot());
-                callstack.pop_back();
+                callstack.pop();
 
                 if(!callstack.empty()){
-                    frame = callstack.back().get();
-                    if(frame->id() < base_id) throw e;
+                    frame = callstack.top().get();
+                    if(frame->_id < base_id) throw e;
                     frame->push(obj);
                     need_raise = true;
                     continue;
@@ -593,7 +592,7 @@ public:
             }
         }
 
-        callstack.pop_back();
+        callstack.pop();
         return ret;
     }
 
@@ -651,7 +650,7 @@ public:
                 if(!(*root)->is_type(_tp_super)) break;
                 depth++;
             }
-            cls = (*root)->_type.get();
+            cls = (*root)->type.get();
             for(int i=0; i<depth; i++) cls = cls->attribs[__base__].get();
 
             it = (*root)->attribs.find(name);
@@ -659,7 +658,7 @@ public:
         }else{
             it = obj->attribs.find(name);
             if(it != obj->attribs.end()) return it->second;
-            cls = obj->_type.get();
+            cls = obj->type.get();
         }
 
         while(cls != None.get()) {
@@ -775,30 +774,30 @@ public:
             // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
             std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
             if(byte.op == OP_LOAD_CONST){
-                argStr += " (" + PyStr_AS_C(asRepr(code->co_consts[byte.arg])) + ")";
+                argStr += " (" + PyStr_AS_C(asRepr(code->consts[byte.arg])) + ")";
             }
             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) + ")";
+                argStr += " (" + code->names[byte.arg].first.__escape(true) + ")";
             }
             ss << pad(argStr, 20);      // may overflow
-            ss << code->co_blocks[byte.block].to_string();
+            ss << code->blocks[byte.block].to_string();
             if(i != code->co_code.size() - 1) ss << '\n';
         }
         _StrStream consts;
-        consts << "co_consts: ";
-        consts << PyStr_AS_C(asRepr(PyList(code->co_consts)));
+        consts << "consts: ";
+        consts << PyStr_AS_C(asRepr(PyList(code->consts)));
 
         _StrStream names;
-        names << "co_names: ";
+        names << "names: ";
         PyVarList list;
-        for(int i=0; i<code->co_names.size(); i++){
-            list.push_back(PyStr(code->co_names[i].first));
+        for(int i=0; i<code->names.size(); i++){
+            list.push_back(PyStr(code->names[i].first));
         }
         names << PyStr_AS_C(asRepr(PyList(list)));
         ss << '\n' << consts.str() << '\n' << names.str() << '\n';
 
-        for(int i=0; i<code->co_consts.size(); i++){
-            PyVar obj = code->co_consts[i];
+        for(int i=0; i<code->consts.size(); i++){
+            PyVar obj = code->consts[i];
             if(obj->is_type(_tp_function)){
                 const auto& f = PyFunction_AS_C(obj);
                 ss << disassemble(f->code);
@@ -881,9 +880,9 @@ public:
         this->__py2py_call_signal = new_object(new_type_object("_signal"), DUMMY_VAL);
 
         setattr(_tp_type, __base__, _tp_object);
-        _tp_type->_type = _tp_type;
+        _tp_type->type = _tp_type;
         setattr(_tp_object, __base__, None);
-        _tp_object->_type = _tp_type;
+        _tp_object->type = _tp_type;
         
         for (auto& [name, type] : _types) {
             setattr(type, __name__, PyStr(name));

+ 2 - 0
tests/_exception.py

@@ -8,6 +8,8 @@ def f():
     try:
         raise KeyError('foo')
     except A:   # will fail to catch
+        print("xx")
+    except:
         print("exception caught")
     print(123)