From 3711881a601d2f7e681710650a17b02db82757e6 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Mon, 11 Mar 2019 17:42:28 +0000 Subject: [PATCH 1/3] Add type_pyref() to TypeProtocol. --- vm/src/pyobject.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 0d348e1b68..6568e7e84c 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -791,6 +791,9 @@ pub trait TypeProtocol { fn typ(&self) -> PyObjectRef { self.type_ref().clone() } + fn type_pyref(&self) -> PyClassRef { + FromPyObjectRef::from_pyobj(self.type_ref()) + } fn type_ref(&self) -> &PyObjectRef; } @@ -1548,6 +1551,19 @@ pub trait PyValue: Any + fmt::Debug { fn required_type(ctx: &PyContext) -> PyObjectRef; } +impl FromPyObjectRef for PyRef { + fn from_pyobj(obj: &PyObjectRef) -> Self { + if let Some(_) = obj.payload::() { + PyRef { + obj: obj.clone(), + _payload: PhantomData, + } + } else { + panic!("Error getting inner type.") + } + } +} + #[cfg(test)] mod tests { use super::PyContext; From 1e39512e7402365a864beefac6c9a2759a1c2544 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Mon, 11 Mar 2019 17:43:12 +0000 Subject: [PATCH 2/3] Convert _mro to iterator. --- vm/src/obj/objobject.rs | 18 ++++----- vm/src/obj/objtype.rs | 86 +++++++++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 8b25e4a6b2..0906f2224a 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -1,3 +1,4 @@ +use super::objlist::PyList; use super::objstr; use super::objtype; use crate::obj::objproperty::PropertyBuilder; @@ -133,16 +134,13 @@ fn object_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.new_str(format!("<{} object at 0x{:x}>", type_name, address))) } -pub fn object_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(obj, None)]); - +pub fn object_dir(obj: PyObjectRef, vm: &mut VirtualMachine) -> PyList { let attributes = get_attributes(&obj); - Ok(vm.ctx.new_list( - attributes - .keys() - .map(|k| vm.ctx.new_str(k.to_string())) - .collect(), - )) + let attributes: Vec = attributes + .keys() + .map(|k| vm.ctx.new_str(k.to_string())) + .collect(); + PyList::from(attributes) } fn object_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -260,7 +258,7 @@ fn object_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes { // Get class attributes: - let mut attributes = objtype::get_attributes(&obj.typ()); + let mut attributes = objtype::get_attributes(obj.type_pyref()); // Get instance attributes: if let Some(dict) = &obj.dict { diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index b5124c37b9..991326d404 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -2,13 +2,15 @@ use std::cell::RefCell; use std::collections::HashMap; use crate::pyobject::{ - AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectRef, - PyRef, PyResult, PyValue, TypeProtocol, + AttributeProtocol, FromPyObjectRef, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, + PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; use crate::vm::VirtualMachine; use super::objdict; +use super::objlist::PyList; use super::objstr; +use super::objtuple::PyTuple; #[derive(Clone, Debug)] pub struct PyClass { @@ -24,6 +26,41 @@ impl PyValue for PyClass { } } +struct IterMro<'a> { + cls: &'a PyClassRef, + offset: Option, +} + +impl<'a> Iterator for IterMro<'a> { + type Item = &'a PyObjectRef; + + fn next(&mut self) -> Option { + match self.offset { + None => { + self.offset = Some(0); + Some(&self.cls.as_object()) + } + Some(offset) => { + if offset < self.cls.mro.len() { + self.offset = Some(offset + 1); + Some(&self.cls.mro[offset]) + } else { + None + } + } + } + } +} + +impl PyClassRef { + fn iter_mro(&self) -> IterMro { + IterMro { + cls: self, + offset: None, + } + } +} + /* * The magical type type */ @@ -60,22 +97,12 @@ pub fn init(ctx: &PyContext) { }); } -fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(cls, Some(vm.ctx.type_type()))]); - match _mro(cls.clone()) { - Some(mro) => Ok(vm.context().new_tuple(mro)), - None => Err(vm.new_type_error("Only classes have an MRO.".to_string())), - } +fn type_mro(cls: PyClassRef, _vm: &mut VirtualMachine) -> PyResult { + Ok(PyTuple::from(_mro(&cls))) } -fn _mro(cls: PyObjectRef) -> Option> { - if let Some(PyClass { ref mro, .. }) = cls.payload::() { - let mut mro = mro.clone(); - mro.insert(0, cls.clone()); - Some(mro) - } else { - None - } +fn _mro(cls: &PyClassRef) -> Vec { + cls.iter_mro().cloned().collect() } /// Determines if `obj` actually an instance of `cls`, this doesn't call __instancecheck__, so only @@ -212,24 +239,22 @@ pub fn type_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult } } -pub fn type_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(obj, None)]); - - let attributes = get_attributes(&obj); - Ok(vm.ctx.new_list( - attributes - .keys() - .map(|k| vm.ctx.new_str(k.to_string())) - .collect(), - )) +pub fn type_dir(obj: PyClassRef, vm: &mut VirtualMachine) -> PyList { + let attributes = get_attributes(obj); + let attributes: Vec = attributes + .keys() + .map(|k| vm.ctx.new_str(k.to_string())) + .collect(); + PyList::from(attributes) } -pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes { +pub fn get_attributes(cls: PyClassRef) -> PyAttributes { // Gather all members here: let mut attributes = PyAttributes::new(); - let mut base_classes = _mro(obj.clone()).expect("Type get_attributes on non-type"); + let mut base_classes: Vec<&PyObjectRef> = cls.iter_mro().collect(); base_classes.reverse(); + for bc in base_classes { if let Some(ref dict) = &bc.dict { for (name, value) in dict.borrow().iter() { @@ -294,7 +319,10 @@ pub fn new( bases: Vec, dict: HashMap, ) -> PyResult { - let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect(); + let mros = bases + .into_iter() + .map(|x| _mro(&FromPyObjectRef::from_pyobj(&x))) + .collect(); let mro = linearise_mro(mros).unwrap(); Ok(PyObject { payload: Box::new(PyClass { From 633a9b03651f6263ab8c5cd360878cdf351ee251 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Mon, 11 Mar 2019 17:54:14 +0000 Subject: [PATCH 3/3] Move more methods onto PyClassRef. --- vm/src/obj/objtype.rs | 87 ++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 991326d404..6125217a83 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -9,7 +9,7 @@ use crate::vm::VirtualMachine; use super::objdict; use super::objlist::PyList; -use super::objstr; +use super::objstr::{self, PyStringRef}; use super::objtuple::PyTuple; #[derive(Clone, Debug)] @@ -59,6 +59,35 @@ impl PyClassRef { offset: None, } } + + fn mro(self, _vm: &mut VirtualMachine) -> PyTuple { + PyTuple::from(_mro(&self)) + } + + fn dir(self, vm: &mut VirtualMachine) -> PyList { + let attributes = get_attributes(self); + let attributes: Vec = attributes + .keys() + .map(|k| vm.ctx.new_str(k.to_string())) + .collect(); + PyList::from(attributes) + } + + fn instance_check(self, obj: PyObjectRef, _vm: &mut VirtualMachine) -> bool { + isinstance(&obj, self.as_object()) + } + + fn subclass_check(self, subclass: PyObjectRef, _vm: &mut VirtualMachine) -> bool { + issubclass(&subclass, self.as_object()) + } + + fn repr(self, _vm: &mut VirtualMachine) -> String { + format!("", self.name) + } + + fn prepare(_name: PyStringRef, _bases: PyObjectRef, vm: &mut VirtualMachine) -> PyObjectRef { + vm.new_dict() + } } /* @@ -86,21 +115,17 @@ pub fn init(ctx: &PyContext) { extend_class!(&ctx, &ctx.type_type, { "__call__" => ctx.new_rustfunc(type_call), "__new__" => ctx.new_rustfunc(type_new), - "__mro__" => ctx.new_property(type_mro), - "__repr__" => ctx.new_rustfunc(type_repr), - "__prepare__" => ctx.new_rustfunc(type_prepare), + "__mro__" => ctx.new_property(PyClassRef::mro), + "__repr__" => ctx.new_rustfunc(PyClassRef::repr), + "__prepare__" => ctx.new_rustfunc(PyClassRef::prepare), "__getattribute__" => ctx.new_rustfunc(type_getattribute), - "__instancecheck__" => ctx.new_rustfunc(type_instance_check), - "__subclasscheck__" => ctx.new_rustfunc(type_subclass_check), + "__instancecheck__" => ctx.new_rustfunc(PyClassRef::instance_check), + "__subclasscheck__" => ctx.new_rustfunc(PyClassRef::subclass_check), "__doc__" => ctx.new_str(type_doc.to_string()), - "__dir__" => ctx.new_rustfunc(type_dir), + "__dir__" => ctx.new_rustfunc(PyClassRef::dir), }); } -fn type_mro(cls: PyClassRef, _vm: &mut VirtualMachine) -> PyResult { - Ok(PyTuple::from(_mro(&cls))) -} - fn _mro(cls: &PyClassRef) -> Vec { cls.iter_mro().cloned().collect() } @@ -111,15 +136,6 @@ pub fn isinstance(obj: &PyObjectRef, cls: &PyObjectRef) -> bool { issubclass(obj.type_ref(), &cls) } -fn type_instance_check(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [(typ, Some(vm.ctx.type_type())), (obj, None)] - ); - Ok(vm.new_bool(isinstance(obj, typ))) -} - /// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__, /// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic /// method. @@ -128,18 +144,6 @@ pub fn issubclass(subclass: &PyObjectRef, cls: &PyObjectRef) -> bool { subclass.is(&cls) || mro.iter().any(|c| c.is(&cls)) } -fn type_subclass_check(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [ - (cls, Some(vm.ctx.type_type())), - (subclass, Some(vm.ctx.type_type())) - ] - ); - Ok(vm.new_bool(issubclass(subclass, cls))) -} - pub fn get_type_name(typ: &PyObjectRef) -> String { if let Some(PyClass { name, .. }) = &typ.payload::() { name.clone() @@ -239,15 +243,6 @@ pub fn type_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult } } -pub fn type_dir(obj: PyClassRef, vm: &mut VirtualMachine) -> PyList { - let attributes = get_attributes(obj); - let attributes: Vec = attributes - .keys() - .map(|k| vm.ctx.new_str(k.to_string())) - .collect(); - PyList::from(attributes) -} - pub fn get_attributes(cls: PyClassRef) -> PyAttributes { // Gather all members here: let mut attributes = PyAttributes::new(); @@ -335,16 +330,6 @@ pub fn new( .into_ref()) } -fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(obj, Some(vm.ctx.type_type()))]); - let type_name = get_type_name(&obj); - Ok(vm.new_str(format!("", type_name))) -} - -fn type_prepare(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { - Ok(vm.new_dict()) -} - #[cfg(test)] mod tests { use super::{linearise_mro, new};