This commit is contained in:
blueloveTH 2023-02-03 23:04:15 +08:00
parent 27f6290605
commit d4e299bce0
6 changed files with 62 additions and 34 deletions

View File

@ -244,6 +244,25 @@ public:
inline void jump_abs(int i){ next_ip = i; } 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 = 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){ void jump_abs_safe(int target){
const Bytecode& prev = code->co_code[ip]; const Bytecode& prev = code->co_code[ip];
int i = prev.block; int i = prev.block;

View File

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

View File

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

View File

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

View File

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

View File

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