diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index bf95ffef6..f671643a4 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -16,7 +16,7 @@ fn exception_init(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { vm.set_attr(&exc_self, "args", exc_args)?; // TODO: have an actual `traceback` object for __traceback__ - vm.set_attr(&exc_self, "__traceback__", vm.ctx.new_list(vec![]))?; + vm.set_attr(&exc_self, "__traceback__", vm.get_none())?; vm.set_attr(&exc_self, "__cause__", vm.get_none())?; vm.set_attr(&exc_self, "__context__", vm.get_none())?; vm.set_attr(&exc_self, "__suppress_context__", vm.new_bool(false))?; diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 3ccef016f..4ad898769 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -14,6 +14,7 @@ use crate::obj::objlist; use crate::obj::objslice::PySlice; use crate::obj::objstr; use crate::obj::objstr::PyString; +use crate::obj::objtraceback::PyTraceback; use crate::obj::objtuple::PyTuple; use crate::obj::objtype; use crate::obj::objtype::PyClassRef; @@ -80,6 +81,7 @@ enum UnwindReason { } #[pyclass] +#[derive(Clone)] pub struct Frame { pub code: PyCodeRef, // We need 1 stack per frame @@ -167,12 +169,6 @@ impl Frame { // #[cfg_attr(feature = "flame-it", flame("Frame"))] pub fn run(&self, vm: &VirtualMachine) -> PyResult { flame_guard!(format!("Frame::run({})", self.code.obj_name)); - - let filename = &self.code.source_path.to_string(); - - // This is the name of the object being run: - let run_obj_name = &self.code.obj_name.to_string(); - // Execute until return or exception: loop { let lineno = self.get_lineno(); @@ -191,16 +187,21 @@ impl Frame { &exception, &vm.ctx.exceptions.base_exception_type )); + let traceback = vm .get_attribute(exception.clone(), "__traceback__") .unwrap(); - vm_trace!("Adding to traceback: {:?} {:?}", traceback, lineno); - let raise_location = vm.ctx.new_tuple(vec![ - vm.ctx.new_str(filename.clone()), - vm.ctx.new_int(lineno.row()), - vm.ctx.new_str(run_obj_name.clone()), - ]); - objlist::PyListRef::try_from_object(vm, traceback)?.append(raise_location, vm); + let new_traceback = PyTraceback::new( + traceback, + self.clone().into_ref(vm), + self.lasti.get(), + lineno.row(), + vm, + ); + vm.set_attr(&exception, "__traceback__", new_traceback.into_ref(vm)) + .unwrap(); + vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, lineno); + match self.unwind_blocks(vm, UnwindReason::Raising { exception }) { Ok(None) => {} Ok(Some(result)) => { diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 24c47522a..0c3c6a7db 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -66,7 +66,6 @@ pub mod pyobject; pub mod scope; pub mod stdlib; mod sysmodule; -mod traceback; pub mod types; pub mod util; mod version; diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index ad7af74d5..d527d69d4 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -34,6 +34,7 @@ pub mod objslice; pub mod objstaticmethod; pub mod objstr; pub mod objsuper; +pub mod objtraceback; pub mod objtuple; pub mod objtype; pub mod objweakproxy; diff --git a/vm/src/obj/objtraceback.rs b/vm/src/obj/objtraceback.rs new file mode 100644 index 000000000..5547db691 --- /dev/null +++ b/vm/src/obj/objtraceback.rs @@ -0,0 +1,71 @@ +use crate::frame::FrameRef; +use crate::obj::objtype::PyClassRef; +use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyValue}; +use crate::vm::VirtualMachine; + +#[pyclass] +#[derive(Debug)] +pub struct PyTraceback { + next: Option, + frame: FrameRef, + lasti: usize, + lineno: usize, +} + +type PyTracebackRef = PyRef; + +impl PyValue for PyTraceback { + fn class(vm: &VirtualMachine) -> PyClassRef { + vm.ctx.traceback_type() + } +} + +#[pyimpl] +impl PyTraceback { + pub fn new( + next: PyObjectRef, + frame: FrameRef, + lasti: usize, + lineno: usize, + vm: &VirtualMachine, + ) -> Self { + let next = if vm.is_none(&next) { + None + } else { + let traceback: PyTracebackRef = + next.downcast().expect("next must be a traceback object"); + Some(traceback) + }; + + PyTraceback { + next, + frame, + lasti, + lineno, + } + } + + #[pyproperty(name = "tb_frame")] + fn frame(&self, _vm: &VirtualMachine) -> FrameRef { + self.frame.clone() + } + + #[pyproperty(name = "tb_lasti")] + fn lasti(&self, _vm: &VirtualMachine) -> usize { + self.lasti + } + + #[pyproperty(name = "tb_lineno")] + fn lineno(&self, _vm: &VirtualMachine) -> usize { + self.lineno + } + + #[pyproperty(name = "tb_next")] + fn next_get(&self, _vm: &VirtualMachine) -> Option { + self.next.as_ref().map(|x| x.clone()) + } +} + +pub fn init(context: &PyContext) { + PyTraceback::extend_class(context, &context.types.traceback_type); +} diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 6469b545a..eb9409433 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -349,6 +349,10 @@ impl PyContext { self.types.weakproxy_type.clone() } + pub fn traceback_type(&self) -> PyClassRef { + self.types.traceback_type.clone() + } + pub fn type_type(&self) -> PyClassRef { self.types.type_type.clone() } diff --git a/vm/src/traceback.rs b/vm/src/traceback.rs deleted file mode 100644 index 9cb95948d..000000000 --- a/vm/src/traceback.rs +++ /dev/null @@ -1,2 +0,0 @@ -// python tracebacks -// diff --git a/vm/src/types.rs b/vm/src/types.rs index b05ff7ccf..52612af46 100644 --- a/vm/src/types.rs +++ b/vm/src/types.rs @@ -29,6 +29,7 @@ use crate::obj::objslice; use crate::obj::objstaticmethod; use crate::obj::objstr; use crate::obj::objsuper; +use crate::obj::objtraceback; use crate::obj::objtuple; use crate::obj::objtype::{self, PyClass, PyClassRef}; use crate::obj::objweakproxy; @@ -93,6 +94,7 @@ pub struct TypeZoo { pub weakref_type: PyClassRef, pub weakproxy_type: PyClassRef, pub mappingproxy_type: PyClassRef, + pub traceback_type: PyClassRef, pub object_type: PyClassRef, } @@ -158,6 +160,7 @@ impl TypeZoo { let rangeiterator_type = create_type("range_iterator", &type_type, &object_type); let slice_type = create_type("slice", &type_type, &object_type); let mappingproxy_type = create_type("mappingproxy", &type_type, &object_type); + let traceback_type = create_type("traceback", &type_type, &object_type); Self { bool_type, @@ -212,6 +215,7 @@ impl TypeZoo { weakref_type, weakproxy_type, type_type, + traceback_type, } } } @@ -313,4 +317,5 @@ pub fn initialize_types(context: &PyContext) { objmodule::init(&context); objnamespace::init(&context); objmappingproxy::init(&context); + objtraceback::init(&context); }