Skip to content

Commit 608a8ea

Browse files
committed
Improve traceback of exception
1 parent 514fea8 commit 608a8ea

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

vm/src/exceptions.rs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
use super::obj::objlist;
12
use super::obj::objstr;
3+
use super::obj::objtuple;
4+
use super::obj::objtype;
25
use super::pyobject::{
3-
create_type, AttributeProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult,
6+
create_type, AttributeProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol,
47
};
58
use super::vm::VirtualMachine;
69

@@ -17,13 +20,59 @@ fn exception_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
1720
Ok(vm.get_none())
1821
}
1922

23+
// Print exception including traceback:
2024
pub fn print_exception(vm: &mut VirtualMachine, exc: &PyObjectRef) {
25+
if let Some(tb) = exc.get_attr("__traceback__") {
26+
println!("Traceback (most recent call last):");
27+
if objtype::isinstance(tb.clone(), vm.ctx.list_type()) {
28+
let elements = objlist::get_elements(&tb);
29+
for element in elements {
30+
if objtype::isinstance(element.clone(), vm.ctx.tuple_type()) {
31+
let element = objtuple::get_elements(&element);
32+
let filename = if let Ok(x) = vm.to_str(element[0].clone()) {
33+
objstr::get_value(&x)
34+
} else {
35+
"<error>".to_string()
36+
};
37+
38+
let lineno = if let Ok(x) = vm.to_str(element[1].clone()) {
39+
objstr::get_value(&x)
40+
} else {
41+
"<error>".to_string()
42+
};
43+
44+
println!(" File {}, line {}, in ..", filename, lineno);
45+
} else {
46+
println!(" File ??");
47+
}
48+
}
49+
}
50+
} else {
51+
println!("No traceback set on exception");
52+
}
53+
2154
match vm.to_str(exc.clone()) {
22-
Ok(txt) => println!("Error: {}", objstr::get_value(&txt)),
55+
Ok(txt) => println!("{}", objstr::get_value(&txt)),
2356
Err(err) => println!("Error during error {:?}", err),
2457
}
2558
}
2659

60+
fn exception_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
61+
arg_check!(
62+
vm,
63+
args,
64+
required = [(exc, Some(vm.ctx.exceptions.exception_type.clone()))]
65+
);
66+
let type_name = objtype::get_type_name(&exc.typ());
67+
let msg = if let Some(m) = exc.get_attr("__msg__") {
68+
objstr::get_value(&m)
69+
} else {
70+
panic!("Error message must be set");
71+
};
72+
let s = format!("{}: {}", type_name, msg);
73+
Ok(vm.new_str(s))
74+
}
75+
2776
#[derive(Debug)]
2877
pub struct ExceptionZoo {
2978
pub base_exception_type: PyObjectRef,
@@ -112,6 +161,6 @@ impl ExceptionZoo {
112161
pub fn init(context: &PyContext) {
113162
let ref base_exception_type = context.exceptions.base_exception_type;
114163
base_exception_type.set_attr("__init__", context.new_rustfunc(exception_init));
115-
116-
// TODO: create a whole exception hierarchy somehow?
164+
let ref exception_type = context.exceptions.exception_type;
165+
exception_type.set_attr("__str__", context.new_rustfunc(exception_str));
117166
}

vm/src/vm.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ impl VirtualMachine {
6060
pub fn new_exception(&mut self, exc_type: PyObjectRef, msg: String) -> PyObjectRef {
6161
// TODO: maybe there is a clearer way to create an instance:
6262
info!("New exception created: {}", msg);
63-
let args: Vec<PyObjectRef> = Vec::new();
63+
let pymsg = self.new_str(msg);
64+
let args: Vec<PyObjectRef> = vec![pymsg];
6465
let args = PyFuncArgs {
6566
args: args,
6667
kwargs: vec![],

0 commit comments

Comments
 (0)