This commit is contained in:
blueloveTH 2023-02-04 04:07:48 +08:00
parent ef36a1d3a0
commit 981fcbc8e5
7 changed files with 71 additions and 60 deletions

View File

@ -201,7 +201,7 @@ class dict:
def __getitem__(self, key): def __getitem__(self, key):
ok, i = self.__probe(key) ok, i = self.__probe(key)
if not ok: if not ok:
raise KeyError(key) raise KeyError(repr(key))
return self._a[i][1] return self._a[i][1]
def __contains__(self, key): def __contains__(self, key):
@ -222,7 +222,7 @@ class dict:
def __delitem__(self, key): def __delitem__(self, key):
ok, i = self.__probe(key) ok, i = self.__probe(key)
if not ok: if not ok:
raise KeyError(key) raise KeyError(repr(key))
self._a[i] = None self._a[i] = None
self._len -= 1 self._len -= 1

View File

@ -204,6 +204,17 @@ public:
} }
inline int stack_size() const{ return s_data.size(); } 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 bool has_next_bytecode() const{ return next_ip < code->co_code.size(); }
inline PyVar pop(){ inline PyVar pop(){
@ -247,7 +258,7 @@ public:
inline void push(T&& obj){ s_data.push_back(std::forward<T>(obj)); } 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_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; std::stack<std::pair<int, std::vector<PyVar>>> s_try_block;
@ -259,10 +270,14 @@ public:
s_try_block.pop(); s_try_block.pop();
} }
inline int get_ip() const{ return ip; }
bool jump_to_exception_handler(){ bool jump_to_exception_handler(){
if(s_try_block.empty()) return false; if(s_try_block.empty()) return false;
PyVar obj = pop();
auto& p = s_try_block.top(); auto& p = s_try_block.top();
s_data = std::move(p.second); s_data = std::move(p.second);
s_data.push_back(obj);
next_ip = code->co_blocks[p.first].end; next_ip = code->co_blocks[p.first].end;
on_try_block_exit(); on_try_block_exit();
return true; return true;

View File

@ -910,8 +910,8 @@ __LISTCOMP:
// If last op is not an assignment, pop the result. // If last op is not an assignment, pop the result.
uint8_t lastOp = co()->co_code.back().op; uint8_t lastOp = co()->co_code.back().op;
if( lastOp!=OP_STORE_NAME && lastOp!=OP_STORE_REF){ if( lastOp!=OP_STORE_NAME && lastOp!=OP_STORE_REF){
if(mode()==SINGLE_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR); if(mode()==SINGLE_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR, -1, true);
emit(OP_POP_TOP); emit(OP_POP_TOP, -1, true);
} }
} }
} }

View File

@ -8,11 +8,7 @@ struct NeedMoreLines {
}; };
struct HandledException {}; struct HandledException {};
struct UnhandledException {};
struct UnhandledException {
PyVar obj;
UnhandledException(PyVar obj) : obj(obj) {}
};
enum CompileMode { enum CompileMode {
EXEC_MODE, EXEC_MODE,
@ -73,32 +69,26 @@ struct SourceMetadata {
typedef pkpy::shared_ptr<SourceMetadata> _Source; typedef pkpy::shared_ptr<SourceMetadata> _Source;
class _Exception : public std::exception { class _Exception {
_Str type; _Str type;
_Str msg; _Str msg;
bool is_runtime_error; bool is_re;
std::stack<_Str> stacktrace; std::stack<_Str> stacktrace;
mutable _Str _what_cached;
public: public:
_Exception(_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_re): type(type), msg(msg), is_re(is_re) {}
bool match_type(const _Str& type) const { return this->type == type;}
bool match_type(const _Str& type) const {
return this->type == type;
}
void st_push(_Str snapshot){ void st_push(_Str snapshot){
if(stacktrace.size() >= 8) return; if(stacktrace.size() >= 8) return;
stacktrace.push(snapshot); stacktrace.push(snapshot);
} }
const char* what() const noexcept override { _Str summary() const {
std::stack<_Str> st(stacktrace); std::stack<_Str> st(stacktrace);
_StrStream ss; _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(); } while(!st.empty()) { ss << st.top() << '\n'; st.pop(); }
ss << type << ": " << msg; ss << type << ": " << msg;
_what_cached = ss.str(); return ss.str();
return _what_cached.c_str();
} }
}; };

View File

@ -6,14 +6,7 @@
_Code VM::compile(_Str source, _Str filename, CompileMode mode) { _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{
return compiler.__fillCode(); return compiler.__fillCode();
}catch(_Exception& e){
throw e;
}catch(std::exception& e){
compiler.__throw_e("UnexpectedError", e.what());
return nullptr;
}
} }
#define BIND_NUM_ARITH_OPT(name, op) \ #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", "__eq__", CPP_LAMBDA(vm->PyBool(args[0] == args[1])));
_vm->bindMethod<1>("object", "__ne__", 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) { _vm->bindStaticMethod<-1>("range", "__new__", [](VM* vm, const pkpy::Args& args) {

View File

@ -29,8 +29,9 @@ protected:
PyVar run_frame(Frame* frame){ PyVar run_frame(Frame* frame){
while(frame->has_next_bytecode()){ while(frame->has_next_bytecode()){
const Bytecode& byte = frame->next_bytecode(); const Bytecode& byte = frame->next_bytecode();
//printf("[%d] %s (%d)\n", frame->stack_size(), OP_NAMES[byte.op], byte.arg); // if(frame->_module != builtins){
//printf("%s\n", frame->code->src->getLine(byte.line).c_str()); // printf("%d: %s (%d) %s\n", frame->get_ip(), OP_NAMES[byte.op], byte.arg, frame->stack_info().c_str());
// }
switch (byte.op) switch (byte.op)
{ {
case OP_NO_OP: break; // do nothing case OP_NO_OP: break; // do nothing
@ -530,16 +531,13 @@ public:
_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 _Exception& e){ }catch (const _Exception& e){
*_stderr << e.what() << '\n'; *_stderr << e.summary() << '\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';
} }
// 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; return nullptr;
} }
@ -564,22 +562,6 @@ public:
try{ try{
if(need_raise){ need_raise = false; _raise(); } if(need_raise){ need_raise = false; _raise(); }
ret = run_frame(frame); ret = run_frame(frame);
}catch(HandledException& e){
continue;
}catch(UnhandledException& e){
_Exception& _e = UNION_GET(_Exception, e.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);
need_raise = true;
continue;
}
throw _e;
}
if(ret != __py2py_call_signal){ if(ret != __py2py_call_signal){
if(frame->id() == base_id){ // [ frameBase<- ] if(frame->id() == base_id){ // [ frameBase<- ]
@ -592,6 +574,23 @@ public:
}else{ }else{
frame = callstack.back().get(); // [ frameBase, newFrame<- ] frame = callstack.back().get(); // [ frameBase, newFrame<- ]
} }
}catch(HandledException& e){
continue;
}catch(UnhandledException& e){
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(obj);
need_raise = true;
continue;
}
throw _e;
}
} }
callstack.pop_back(); callstack.pop_back();
@ -778,7 +777,7 @@ public:
if(byte.op == OP_LOAD_CONST){ if(byte.op == OP_LOAD_CONST){
argStr += " (" + PyStr_AS_C(asRepr(code->co_consts[byte.arg])) + ")"; 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) + ")"; argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")";
} }
ss << pad(argStr, 20); // may overflow ss << pad(argStr, 20); // may overflow
@ -879,6 +878,7 @@ public:
this->False = new_object(_tp_bool, false); this->False = new_object(_tp_bool, false);
this->builtins = new_module("builtins"); this->builtins = new_module("builtins");
this->_main = new_module("__main__"); this->_main = new_module("__main__");
this->__py2py_call_signal = new_object(new_type_object("_signal"), DUMMY_VAL);
setattr(_tp_type, __base__, _tp_object); setattr(_tp_type, __base__, _tp_object);
_tp_type->_type = _tp_type; _tp_type->_type = _tp_type;
@ -889,8 +889,6 @@ public:
setattr(type, __name__, PyStr(name)); 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"}; std::vector<_Str> publicTypes = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"};
for (auto& name : publicTypes) { for (auto& name : publicTypes) {
setattr(builtins, name, _types[name]); setattr(builtins, name, _types[name]);
@ -929,7 +927,7 @@ private:
void _raise(){ void _raise(){
bool ok = top_frame()->jump_to_exception_handler(); bool ok = top_frame()->jump_to_exception_handler();
if(ok) throw HandledException(); if(ok) throw HandledException();
throw UnhandledException(top_frame()->top()); else throw UnhandledException();
} }
public: public:

14
tests/_exception.py Normal file
View File

@ -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()