diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 2519733cb7..8bf23bf986 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -76,12 +76,19 @@ impl<'a, T> Iterator for Iter<'a, T> { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Scope { locals: RcList, pub globals: PyObjectRef, } +impl fmt::Debug for Scope { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: have a more informative Debug impl that DOESN'T recurse and cause a stack overflow + f.write_str("Scope") + } +} + impl Scope { pub fn new(locals: Option, globals: PyObjectRef) -> Scope { let locals = match locals { @@ -99,10 +106,7 @@ impl Scope { } pub fn get_only_locals(&self) -> Option { - match self.locals.iter().next() { - Some(dict) => Some(dict.clone()), - None => None, - } + self.locals.iter().next().cloned() } pub fn child_scope_with_locals(&self, locals: PyObjectRef) -> Scope { @@ -1211,22 +1215,25 @@ impl fmt::Debug for Frame { .stack .borrow() .iter() - .map(|elem| format!("\n > {:?}", elem)) - .collect::>() - .join(""); + .map(|elem| { + if elem.payload.as_any().is::() { + "\n > {frame}".to_string() + } else { + format!("\n > {:?}", elem) + } + }) + .collect::(); let block_str = self .blocks .borrow() .iter() .map(|elem| format!("\n > {:?}", elem)) - .collect::>() - .join(""); + .collect::(); let local_str = match self.scope.get_locals().payload::() { Some(dict) => objdict::get_key_value_pairs_from_content(&dict.entries.borrow()) .iter() .map(|elem| format!("\n {:?} = {:?}", elem.0, elem.1)) - .collect::>() - .join(""), + .collect::(), None => panic!("locals unexpectedly not wrapping a dict!",), }; write!( diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index 248ab3d539..2a0bffe45e 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -1,5 +1,6 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; +use std::fmt; use std::ops::{Deref, DerefMut}; use crate::pyobject::{ @@ -14,13 +15,20 @@ use super::objtype; pub type DictContentType = HashMap; -#[derive(Default, Debug)] +#[derive(Default)] pub struct PyDict { // TODO: should be private pub entries: RefCell, } pub type PyDictRef = PyRef; +impl fmt::Debug for PyDict { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: implement more detailed, non-recursive Debug formatter + f.write_str("dict") + } +} + impl PyValue for PyDict { fn required_type(ctx: &PyContext) -> PyObjectRef { ctx.dict_type() diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 290007e555..ff9d7c884c 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -14,13 +14,21 @@ use crate::pyobject::{ }; use crate::vm::{ReprGuard, VirtualMachine}; use num_traits::ToPrimitive; +use std::fmt; -#[derive(Debug, Default)] +#[derive(Default)] pub struct PyList { // TODO: shouldn't be public pub elements: RefCell>, } +impl fmt::Debug for PyList { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: implement more detailed, non-recursive Debug formatter + f.write_str("list") + } +} + impl From> for PyList { fn from(elements: Vec) -> Self { PyList { diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 78df11c739..02689fea0b 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -4,13 +4,19 @@ use super::objtype; use crate::obj::objproperty::PropertyBuilder; use crate::pyobject::{ AttributeProtocol, DictProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObjectRef, - PyRef, PyResult, TypeProtocol, + PyRef, PyResult, PyValue, TypeProtocol, }; use crate::vm::VirtualMachine; #[derive(Clone, Debug)] pub struct PyInstance; +impl PyValue for PyInstance { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.object() + } +} + pub type PyInstanceRef = PyRef; pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index bb8483a0e2..f46c6bcaed 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -3,8 +3,8 @@ */ use std::cell::{Cell, RefCell}; -use std::collections::hash_map::DefaultHasher; -use std::collections::HashMap; +use std::collections::{hash_map::DefaultHasher, HashMap}; +use std::fmt; use std::hash::{Hash, Hasher}; use super::objbool; @@ -17,11 +17,18 @@ use crate::pyobject::{ }; use crate::vm::{ReprGuard, VirtualMachine}; -#[derive(Debug, Default)] +#[derive(Default)] pub struct PySet { elements: RefCell>, } +impl fmt::Debug for PySet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: implement more detailed, non-recursive Debug formatter + f.write_str("set") + } +} + impl PyValue for PySet { fn required_type(ctx: &PyContext) -> PyObjectRef { ctx.set_type() diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 6be590a5ff..ccbfc46daf 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -1,4 +1,5 @@ use std::cell::{Cell, RefCell}; +use std::fmt; use std::hash::{Hash, Hasher}; use crate::pyobject::{ @@ -15,13 +16,20 @@ use super::objsequence::{ use super::objstr; use super::objtype; -#[derive(Debug, Default)] +#[derive(Default)] pub struct PyTuple { // TODO: shouldn't be public // TODO: tuples are immutable, remove this RefCell pub elements: RefCell>, } +impl fmt::Debug for PyTuple { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: implement more informational, non-recursive Debug formatter + f.write_str("tuple") + } +} + impl From> for PyTuple { fn from(elements: Vec) -> Self { PyTuple { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index c33653d07f..a68edc9c83 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -623,11 +623,7 @@ impl PyContext { } pub fn new_instance(&self, class: PyObjectRef, dict: Option) -> PyObjectRef { - let dict = if let Some(dict) = dict { - dict - } else { - PyAttributes::new() - }; + let dict = dict.unwrap_or_default(); PyObject { typ: class, dict: Some(RefCell::new(dict)), @@ -697,7 +693,7 @@ impl Default for PyContext { pub struct PyObject { pub typ: PyObjectRef, pub dict: Option>, // __dict__ member - pub payload: Box, + pub payload: Box, } /// A reference to a Python object. @@ -1557,7 +1553,7 @@ impl PyValue for PyIteratorValue { } impl PyObject { - pub fn new(payload: T, typ: PyObjectRef) -> PyObjectRef { + pub fn new(payload: T, typ: PyObjectRef) -> PyObjectRef { PyObject { typ, dict: Some(RefCell::new(PyAttributes::new())), @@ -1571,14 +1567,13 @@ impl PyObject { Rc::new(self) } + #[inline] pub fn payload(&self) -> Option<&T> { - self.payload.downcast_ref() + self.payload.as_any().downcast_ref() } } -// The intention is for this to replace `PyObjectPayload` once everything is -// converted to use `PyObjectPayload::AnyRustvalue`. -pub trait PyValue: Any + fmt::Debug + Sized { +pub trait PyValue: fmt::Debug + Sized + 'static { fn required_type(ctx: &PyContext) -> PyObjectRef; fn into_ref(self, ctx: &PyContext) -> PyRef { @@ -1603,6 +1598,17 @@ pub trait PyValue: Any + fmt::Debug + Sized { } } +pub trait PyObjectPayload: Any + fmt::Debug + 'static { + fn as_any(&self) -> &dyn Any; +} + +impl PyObjectPayload for T { + #[inline] + fn as_any(&self) -> &dyn Any { + self + } +} + impl FromPyObjectRef for PyRef { fn from_pyobj(obj: &PyObjectRef) -> Self { if let Some(_) = obj.payload::() { diff --git a/vm/src/stdlib/re.rs b/vm/src/stdlib/re.rs index 3aee2bf61f..4d6c024dae 100644 --- a/vm/src/stdlib/re.rs +++ b/vm/src/stdlib/re.rs @@ -197,7 +197,7 @@ fn match_end(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { /// Retrieve inner rust regex from python object: fn get_regex<'a>(obj: &'a PyObjectRef) -> &'a Regex { // TODO: Regex shouldn't be stored in payload directly, create newtype wrapper - if let Some(regex) = obj.payload.downcast_ref::() { + if let Some(regex) = obj.payload::() { return regex; } panic!("Inner error getting regex {:?}", obj); @@ -205,7 +205,7 @@ fn get_regex<'a>(obj: &'a PyObjectRef) -> &'a Regex { /// Retrieve inner rust match from python object: fn get_match<'a>(obj: &'a PyObjectRef) -> &'a PyMatch { - if let Some(value) = obj.payload.downcast_ref::() { + if let Some(value) = obj.payload::() { return value; } panic!("Inner error getting match {:?}", obj); diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs index 035954a7c7..e09a63ac6a 100644 --- a/wasm/lib/src/browser_module.rs +++ b/wasm/lib/src/browser_module.rs @@ -171,7 +171,7 @@ impl PyPromise { } pub fn get_promise_value(obj: &PyObjectRef) -> Promise { - if let Some(promise) = obj.payload.downcast_ref::() { + if let Some(promise) = obj.payload::() { return promise.value.clone(); } panic!("Inner error getting promise")