From d4e299bce00ec30cc52c0c32710c4b7b5b342ca9 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 3 Feb 2023 23:04:15 +0800 Subject: [PATCH] up --- src/codeobject.h | 19 ++++++++++++++++ src/compiler.h | 4 +++- src/error.h | 10 ++++++--- src/opcodes.h | 3 +++ src/pocketpy.h | 2 +- src/vm.h | 58 ++++++++++++++++++++++++------------------------ 6 files changed, 62 insertions(+), 34 deletions(-) diff --git a/src/codeobject.h b/src/codeobject.h index 81157e5b..ebb2e229 100644 --- a/src/codeobject.h +++ b/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>> 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; diff --git a/src/compiler.h b/src/compiler.h index 8ff028cd..f3f3291b 100644 --- a/src/compiler.h +++ b/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; } diff --git a/src/error.h b/src/error.h index a4b85d92..69516b79 100644 --- a/src/error.h +++ b/src/error.h @@ -67,7 +67,7 @@ struct SourceMetadata { typedef pkpy::shared_ptr _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); diff --git a/src/opcodes.h b/src/opcodes.h index 34b8b215..eff6ba75 100644 --- a/src/opcodes.h +++ b/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 \ No newline at end of file diff --git a/src/pocketpy.h b/src/pocketpy.h index 21b83e50..71a4b769 100644 --- a/src/pocketpy.h +++ b/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()); diff --git a/src/vm.h b/src/vm.h index c7378204..4eb75ae0 100644 --- a/src/vm.h +++ b/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()); - }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>((i64)1, _tp_type); + PyVar obj = pkpy::make_shared>(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>((i64)0, _tp_type); + PyVar obj = pkpy::make_shared>(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 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>((i64)0, nullptr); - _tp_type = pkpy::make_shared>((i64)0, nullptr); - + _tp_object = pkpy::make_shared>(DUMMY_VAL, nullptr); + _tp_type = pkpy::make_shared>(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: