...

...
This commit is contained in:
BLUELOVETH 2023-06-02 13:37:07 +08:00
parent acc8ab802f
commit 1614502741
8 changed files with 80 additions and 3 deletions

12
docs/modules/traceback.md Normal file
View File

@ -0,0 +1,12 @@
---
icon: package
label: traceback
---
### `trackback.print_exc() -> None`
Print the last exception and its traceback.
### `trackback.format_exc() -> str`
Return the last exception and its traceback as a string.

View File

@ -103,4 +103,36 @@ For example, `vm->bind__add__` is preferred over `vm->bind_method<1>(type, "__ad
### Bind a property ### Bind a property
You can use `vm->property(...)` to create a `property` object and assign it to an type object. a property is a python's `property` that attached to a type instance with a getter and an optional setter. It is a data descriptor. A property redirects attribute access to specific functions.
You can use `@property` to create python property or use `vm->property` to create native property.
```cpp
struct Point {
PY_CLASS(Point, test, Point);
int x;
int y;
Point(int x, int y) : x(x), y(y) {}
static void _register(VM *vm, auto mod, auto type) {
vm->bind_constructor<3>(type, [](VM *vm, auto args) {
auto x = CAST(i64, args[1]);
auto y = CAST(i64, args[2]);
return VAR_T(Point, x, y);
});
// getter and setter of property `x`
type->attr().set("x", vm->property([](VM* vm, ArgsView args){
Point& self = CAST(Point&, args[0]);
return VAR(self.x);
},
[](VM* vm, ArgsView args){
Point& self = CAST(Point&, args[0]);
self.x = CAST(int, args[1]);
return vm->None;
}));
}
};
```

View File

@ -583,6 +583,7 @@ __NEXT_STEP:;
_error(StrName(byte.arg), msg); _error(StrName(byte.arg), msg);
} DISPATCH(); } DISPATCH();
TARGET(RE_RAISE) _raise(); DISPATCH(); TARGET(RE_RAISE) _raise(); DISPATCH();
TARGET(POP_EXCEPTION) _last_exception = POPX(); DISPATCH();
/*****************************************/ /*****************************************/
TARGET(SETUP_DOCSTRING) TARGET(SETUP_DOCSTRING)
TOP()->attr().set(__doc__, co_consts[byte.arg]); TOP()->attr().set(__doc__, co_consts[byte.arg]);

View File

@ -624,7 +624,7 @@ __SUBSCR_END:
} }
int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE); int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
// pop the exception on match // pop the exception on match
ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); ctx()->emit(OP_POP_EXCEPTION, BC_NOARG, BC_KEEPLINE);
compile_block_body(); compile_block_body();
patches.push_back(ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)); patches.push_back(ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE));
ctx()->patch_jump(patch); ctx()->patch_jump(patch);

View File

@ -113,6 +113,7 @@ OPCODE(ASSERT)
OPCODE(EXCEPTION_MATCH) OPCODE(EXCEPTION_MATCH)
OPCODE(RAISE) OPCODE(RAISE)
OPCODE(RE_RAISE) OPCODE(RE_RAISE)
OPCODE(POP_EXCEPTION)
/**************************/ /**************************/
OPCODE(SETUP_DOCSTRING) OPCODE(SETUP_DOCSTRING)
OPCODE(FORMAT_STRING) OPCODE(FORMAT_STRING)

View File

@ -1155,6 +1155,22 @@ inline void add_module_math(VM* vm){
}); });
} }
inline void add_module_traceback(VM* vm){
PyObject* mod = vm->new_module("traceback");
vm->bind_func<0>(mod, "print_exc", [](VM* vm, ArgsView args) {
if(vm->_last_exception==nullptr) vm->ValueError("no exception");
Exception& e = CAST(Exception&, vm->_last_exception);
vm->_stdout(vm, e.summary());
return vm->None;
});
vm->bind_func<0>(mod, "format_exc", [](VM* vm, ArgsView args) {
if(vm->_last_exception==nullptr) vm->ValueError("no exception");
Exception& e = CAST(Exception&, vm->_last_exception);
return VAR(e.summary());
});
}
inline void add_module_dis(VM* vm){ inline void add_module_dis(VM* vm){
PyObject* mod = vm->new_module("dis"); PyObject* mod = vm->new_module("dis");
vm->bind_func<1>(mod, "dis", [](VM* vm, ArgsView args) { vm->bind_func<1>(mod, "dis", [](VM* vm, ArgsView args) {
@ -1306,6 +1322,7 @@ inline void VM::post_init(){
init_builtins(this); init_builtins(this);
#if !DEBUG_NO_BUILTIN_MODULES #if !DEBUG_NO_BUILTIN_MODULES
add_module_sys(this); add_module_sys(this);
add_module_traceback(this);
add_module_time(this); add_module_time(this);
add_module_json(this); add_module_json(this);
add_module_math(this); add_module_math(this);

View File

@ -123,6 +123,8 @@ public:
PyObject* StopIteration; PyObject* StopIteration;
PyObject* _main; // __main__ module PyObject* _main; // __main__ module
PyObject* _last_exception;
PrintFunc _stdout; PrintFunc _stdout;
PrintFunc _stderr; PrintFunc _stderr;
@ -142,6 +144,7 @@ public:
_stderr = [](VM* vm, const Str& s) { std::cerr << s; }; _stderr = [](VM* vm, const Str& s) { std::cerr << s; };
callstack.reserve(8); callstack.reserve(8);
_main = nullptr; _main = nullptr;
_last_exception = nullptr;
init_builtin_types(); init_builtin_types();
} }
@ -1448,7 +1451,8 @@ inline void ManagedHeap::mark() {
for(PyObject* obj: _no_gc) OBJ_MARK(obj); for(PyObject* obj: _no_gc) OBJ_MARK(obj);
for(auto& frame : vm->callstack.data()) frame._gc_mark(); for(auto& frame : vm->callstack.data()) frame._gc_mark();
for(PyObject* obj: vm->s_data) OBJ_MARK(obj); for(PyObject* obj: vm->s_data) OBJ_MARK(obj);
if(_gc_marker_ex != nullptr) _gc_marker_ex(vm); if(_gc_marker_ex) _gc_marker_ex(vm);
if(vm->_last_exception) OBJ_MARK(vm->_last_exception);
} }
inline Str obj_type_name(VM *vm, Type type){ inline Str obj_type_name(VM *vm, Type type){

10
tests/80_traceback.py Normal file
View File

@ -0,0 +1,10 @@
import traceback
try:
a = {'123': 4}
b = a[6]
except KeyError:
s = traceback.format_exc()
assert s == r'''Traceback (most recent call last):
KeyError: 6'''