diff --git a/src/codeobject.h b/src/codeobject.h index 24a666b4..f0a114c1 100644 --- a/src/codeobject.h +++ b/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 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& other) const{ return id == other; } - bool operator!=(const std::vector& other) const{ return id != other; } - int depth() const{ return id.size(); } }; struct CodeObject { - _Source src; + pkpy::shared_ptr src; _Str name; - CodeObject(_Source src, _Str name) { + CodeObject(pkpy::shared_ptr src, _Str name) { this->src = src; this->name = name; } std::vector co_code; - PyVarList co_consts; - std::vector> co_names; - std::vector<_Str> co_global_names; - - std::vector co_blocks = { CodeBlock{NO_BLOCK, {}, -1} }; + PyVarList consts; + std::vector> names; + emhash8::HashMap<_Str, int> global_names; + std::vector 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 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 s_data; - int ip = -1; - int next_ip = 0; - int m_id; -public: - const _Code code; +struct Frame { + std::vector _data; + int _ip = -1; + int _next_ip = 0; + + const _Code co; PyVar _module; pkpy::shared_ptr _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 _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 _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; ico_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 - inline void push(T&& obj){ s_data.push_back(std::forward(obj)); } + inline void push(T&& obj){ _data.push_back(std::forward(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>> 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; } diff --git a/src/compiler.h b/src/compiler.h index 8c58841a..50e017e9 100644 --- a/src/compiler.h +++ b/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; 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( - pkpy::make_shared(source, filename, mode) + pkpy::make_shared(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 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"))){ diff --git a/src/error.h b/src/error.h index 5a4255ca..eecf56d1 100644 --- a/src/error.h +++ b/src/error.h @@ -17,7 +17,7 @@ enum CompileMode { JSON_MODE, }; -struct SourceMetadata { +struct SourceData { const char* source; _Str filename; std::vector 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 _Source; - class _Exception { _Str type; _Str msg; diff --git a/src/obj.h b/src/obj.h index 0aa5378c..70bbd3f9 100644 --- a/src/obj.h +++ b/src/obj.h @@ -75,13 +75,13 @@ typedef pkpy::shared_ptr _Func; typedef pkpy::shared_ptr _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_*)((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__]) \ No newline at end of file +#define UNION_TP_NAME(obj) UNION_GET(_Str, (obj)->type->attribs[__name__]) \ No newline at end of file diff --git a/src/opcodes.h b/src/opcodes.h index eff6ba75..f995ec74 100644 --- a/src/opcodes.h +++ b/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) diff --git a/src/parser.h b/src/parser.h index ccfc2019..18f56188 100644 --- a/src/parser.h +++ b/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 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 src) { this->src = src; this->token_start = src->source; this->curr_char = src->source; diff --git a/src/pocketpy.h b/src/pocketpy.h index 22082fdd..81c6d7af 100644 --- a/src/pocketpy.h +++ b/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; diff --git a/src/vm.h b/src/vm.h index c3a76338..732e83f1 100644 --- a/src/vm.h +++ b/src/vm.h @@ -23,7 +23,7 @@ class VM { std::vector _small_integers; // [-5, 256] protected: - std::deque< std::unique_ptr > callstack; + std::stack< std::unique_ptr > 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 - 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(std::forward(args)...)); - return callstack.back().get(); + callstack.emplace(std::make_unique(std::forward(args)...)); + return callstack.top().get(); } template PyVar _exec(Args&&... args){ - Frame* frame = __push_new_frame(std::forward(args)...); - i64 base_id = frame->id(); + Frame* frame = __new_frame(std::forward(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; iattribs[__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; ico_names.size(); i++){ - list.push_back(PyStr(code->co_names[i].first)); + for(int i=0; inames.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; ico_consts.size(); i++){ - PyVar obj = code->co_consts[i]; + for(int i=0; iconsts.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)); diff --git a/tests/_exception.py b/tests/_exception.py index fac04d8a..18403531 100644 --- a/tests/_exception.py +++ b/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)