diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 6f441ff419..5911420d50 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -15,7 +15,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result !value.is_empty(), PyObjectKind::None { .. } => false, _ => { - if let Ok(f) = objtype::get_attribute(vm, obj.clone(), &String::from("__bool__")) { + if let Ok(f) = vm.get_attribute(obj.clone(), &String::from("__bool__")) { let bool_res = vm.invoke(f, PyFuncArgs::default())?; let v = match bool_res.borrow().kind { PyObjectKind::Integer { ref value } => !value.is_zero(), diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 8e1aa37e14..08a723c031 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -5,6 +5,7 @@ use super::super::pyobject::{ use super::super::vm::VirtualMachine; use super::objbool; use super::objdict; +use super::objstr; use super::objtype; pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { @@ -15,12 +16,6 @@ pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { Ok(obj) } -pub fn call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { - let instance = args.shift(); - let function = objtype::get_attribute(vm, instance, &String::from("__call__"))?; - vm.invoke(function, args) -} - pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) { (*object_type.borrow_mut()).kind = PyObjectKind::Class { name: String::from("object"), @@ -101,6 +96,10 @@ pub fn init(context: &PyContext) { object.set_attr("__hash__", context.new_rustfunc(object_hash)); object.set_attr("__str__", context.new_rustfunc(object_str)); object.set_attr("__repr__", context.new_rustfunc(object_repr)); + object.set_attr( + "__getattribute__", + context.new_rustfunc(object_getattribute), + ); } fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { @@ -114,3 +113,65 @@ fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { _ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())), } } + +fn object_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [ + (obj, Some(vm.ctx.object())), + (name_str, Some(vm.ctx.str_type())) + ] + ); + let name = objstr::get_value(&name_str); + trace!("object.__getattribute__({:?}, {:?})", obj, name); + let cls = obj.typ(); + + if let Some(attr) = cls.get_attr(&name) { + let attr_class = attr.typ(); + if attr_class.has_attr("__set__") { + if let Some(descriptor) = attr_class.get_attr("__get__") { + return vm.invoke( + descriptor, + PyFuncArgs { + args: vec![attr, obj.clone(), cls], + kwargs: vec![], + }, + ); + } + } + } + + if let Some(obj_attr) = obj.get_attr(&name) { + Ok(obj_attr) + } else if let Some(attr) = cls.get_attr(&name) { + let attr_class = attr.typ(); + if let Some(descriptor) = attr_class.get_attr("__get__") { + vm.invoke( + descriptor, + PyFuncArgs { + args: vec![attr, obj.clone(), cls], + kwargs: vec![], + }, + ) + } else { + Ok(attr) + } + } else { + if let Some(getter) = cls.get_attr("__getattr__") { + vm.invoke( + getter, + PyFuncArgs { + args: vec![cls, name_str.clone()], + kwargs: vec![], + }, + ) + } else { + let attribute_error = vm.context().exceptions.attribute_error.clone(); + Err(vm.new_exception( + attribute_error, + format!("{:?} object has no attribute {}", cls, name), + )) + } + } +} diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 6c0ff19c04..41600854d0 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -137,34 +137,34 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { Ok(obj) } -pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &str) -> PyResult { - let cls = obj.typ(); - trace!("get_attribute: {:?}, {:?}, {:?}", cls, obj, name); - if let Some(attr) = cls.get_attr(name) { - let attr_class = attr.typ(); - if let Some(descriptor) = attr_class.get_attr("__get__") { - return vm.invoke( - descriptor, - PyFuncArgs { - args: vec![attr, obj, cls], - kwargs: vec![], - }, - ); - } - } +// pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &str) -> PyResult { +// let cls = obj.typ(); +// trace!("get_attribute: {:?}, {:?}, {:?}", cls, obj, name); +// if let Some(attr) = cls.get_attr(name) { +// let attr_class = attr.typ(); +// if let Some(descriptor) = attr_class.get_attr("__get__") { +// return vm.invoke( +// descriptor, +// PyFuncArgs { +// args: vec![attr, obj, cls], +// kwargs: vec![], +// }, +// ); +// } +// } - if let Some(obj_attr) = obj.get_attr(name) { - Ok(obj_attr) - } else if let Some(cls_attr) = cls.get_attr(name) { - Ok(cls_attr) - } else { - let attribute_error = vm.context().exceptions.attribute_error.clone(); - Err(vm.new_exception( - attribute_error, - format!("{:?} object has no attribute {}", cls, name), - )) - } -} +// if let Some(obj_attr) = obj.get_attr(name) { +// Ok(obj_attr) +// } else if let Some(cls_attr) = cls.get_attr(name) { +// Ok(cls_attr) +// } else { +// let attribute_error = vm.context().exceptions.attribute_error.clone(); +// Err(vm.new_exception( +// attribute_error, +// format!("{:?} object has no attribute {}", cls, name), +// )) +// } +// } pub fn get_attributes(obj: &PyObjectRef) -> HashMap { // Gather all members here: @@ -264,7 +264,7 @@ fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn call(vm: &mut VirtualMachine, typ: PyObjectRef, args: PyFuncArgs) -> PyResult { - let function = get_attribute(vm, typ, &String::from("__call__"))?; + let function = vm.get_attribute(typ, &String::from("__call__"))?; vm.invoke(function, args) } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 50fab0c51c..3235e01101 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -17,7 +17,10 @@ use super::obj::objlist; use super::obj::objobject; use super::obj::objtuple; use super::obj::objtype; -use super::pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult}; +use super::pyobject::{ + AttributeProtocol, DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, + TypeProtocol, +}; use super::stdlib; use super::sysmodule; @@ -174,12 +177,18 @@ impl VirtualMachine { name: _, dict: _, mro: _, - } => objtype::call(self, func_ref.clone(), args), + } => { + let function = self.get_attribute(func_ref.clone(), "__call__")?; + self.invoke(function, args) + } PyObjectKind::BoundMethod { ref function, ref object, } => self.invoke(function.clone(), args.insert(object.clone())), - PyObjectKind::Instance { .. } => objobject::call(self, args.insert(func_ref.clone())), + PyObjectKind::Instance { .. } => { + let function = self.get_attribute(func_ref.clone(), "__call__")?; + self.invoke(function, args) + } ref kind => { unimplemented!("invoke unimplemented for: {:?}", kind); } @@ -371,7 +380,19 @@ impl VirtualMachine { } pub fn get_attribute(&mut self, obj: PyObjectRef, attr_name: &str) -> PyResult { - objtype::get_attribute(self, obj.clone(), attr_name) + let cls = obj.typ(); + if let Some(attr) = cls.get_attr("__getattribute__") { + let name = self.new_str(attr_name.to_string()); + self.invoke( + attr, + PyFuncArgs { + args: vec![obj.clone(), name], + kwargs: vec![], + }, + ) + } else { + panic!("Everything should have a __getattribute__"); + } } pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {