Implement object.__getattribute__.

This commit is contained in:
Adam Kelly
2018-10-31 16:59:24 +00:00
parent c8e842eaab
commit 3e07c19ec4
4 changed files with 121 additions and 39 deletions

View File

@@ -15,7 +15,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
PyObjectKind::String { ref value } => !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(),

View File

@@ -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),
))
}
}
}

View File

@@ -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<String, PyObjectRef> {
// 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)
}

View File

@@ -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 {