Skip to content

Commit 3e07c19

Browse files
committed
Implement object.__getattribute__.
1 parent c8e842e commit 3e07c19

File tree

4 files changed

+121
-39
lines changed

4 files changed

+121
-39
lines changed

vm/src/obj/objbool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
1515
PyObjectKind::String { ref value } => !value.is_empty(),
1616
PyObjectKind::None { .. } => false,
1717
_ => {
18-
if let Ok(f) = objtype::get_attribute(vm, obj.clone(), &String::from("__bool__")) {
18+
if let Ok(f) = vm.get_attribute(obj.clone(), &String::from("__bool__")) {
1919
let bool_res = vm.invoke(f, PyFuncArgs::default())?;
2020
let v = match bool_res.borrow().kind {
2121
PyObjectKind::Integer { ref value } => !value.is_zero(),

vm/src/obj/objobject.rs

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::super::pyobject::{
55
use super::super::vm::VirtualMachine;
66
use super::objbool;
77
use super::objdict;
8+
use super::objstr;
89
use super::objtype;
910

1011
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 {
1516
Ok(obj)
1617
}
1718

18-
pub fn call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
19-
let instance = args.shift();
20-
let function = objtype::get_attribute(vm, instance, &String::from("__call__"))?;
21-
vm.invoke(function, args)
22-
}
23-
2419
pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) {
2520
(*object_type.borrow_mut()).kind = PyObjectKind::Class {
2621
name: String::from("object"),
@@ -101,6 +96,10 @@ pub fn init(context: &PyContext) {
10196
object.set_attr("__hash__", context.new_rustfunc(object_hash));
10297
object.set_attr("__str__", context.new_rustfunc(object_str));
10398
object.set_attr("__repr__", context.new_rustfunc(object_repr));
99+
object.set_attr(
100+
"__getattribute__",
101+
context.new_rustfunc(object_getattribute),
102+
);
104103
}
105104

106105
fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
@@ -114,3 +113,65 @@ fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
114113
_ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())),
115114
}
116115
}
116+
117+
fn object_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
118+
arg_check!(
119+
vm,
120+
args,
121+
required = [
122+
(obj, Some(vm.ctx.object())),
123+
(name_str, Some(vm.ctx.str_type()))
124+
]
125+
);
126+
let name = objstr::get_value(&name_str);
127+
trace!("object.__getattribute__({:?}, {:?})", obj, name);
128+
let cls = obj.typ();
129+
130+
if let Some(attr) = cls.get_attr(&name) {
131+
let attr_class = attr.typ();
132+
if attr_class.has_attr("__set__") {
133+
if let Some(descriptor) = attr_class.get_attr("__get__") {
134+
return vm.invoke(
135+
descriptor,
136+
PyFuncArgs {
137+
args: vec![attr, obj.clone(), cls],
138+
kwargs: vec![],
139+
},
140+
);
141+
}
142+
}
143+
}
144+
145+
if let Some(obj_attr) = obj.get_attr(&name) {
146+
Ok(obj_attr)
147+
} else if let Some(attr) = cls.get_attr(&name) {
148+
let attr_class = attr.typ();
149+
if let Some(descriptor) = attr_class.get_attr("__get__") {
150+
vm.invoke(
151+
descriptor,
152+
PyFuncArgs {
153+
args: vec![attr, obj.clone(), cls],
154+
kwargs: vec![],
155+
},
156+
)
157+
} else {
158+
Ok(attr)
159+
}
160+
} else {
161+
if let Some(getter) = cls.get_attr("__getattr__") {
162+
vm.invoke(
163+
getter,
164+
PyFuncArgs {
165+
args: vec![cls, name_str.clone()],
166+
kwargs: vec![],
167+
},
168+
)
169+
} else {
170+
let attribute_error = vm.context().exceptions.attribute_error.clone();
171+
Err(vm.new_exception(
172+
attribute_error,
173+
format!("{:?} object has no attribute {}", cls, name),
174+
))
175+
}
176+
}
177+
}

vm/src/obj/objtype.rs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -137,34 +137,34 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
137137
Ok(obj)
138138
}
139139

140-
pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &str) -> PyResult {
141-
let cls = obj.typ();
142-
trace!("get_attribute: {:?}, {:?}, {:?}", cls, obj, name);
143-
if let Some(attr) = cls.get_attr(name) {
144-
let attr_class = attr.typ();
145-
if let Some(descriptor) = attr_class.get_attr("__get__") {
146-
return vm.invoke(
147-
descriptor,
148-
PyFuncArgs {
149-
args: vec![attr, obj, cls],
150-
kwargs: vec![],
151-
},
152-
);
153-
}
154-
}
140+
// pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &str) -> PyResult {
141+
// let cls = obj.typ();
142+
// trace!("get_attribute: {:?}, {:?}, {:?}", cls, obj, name);
143+
// if let Some(attr) = cls.get_attr(name) {
144+
// let attr_class = attr.typ();
145+
// if let Some(descriptor) = attr_class.get_attr("__get__") {
146+
// return vm.invoke(
147+
// descriptor,
148+
// PyFuncArgs {
149+
// args: vec![attr, obj, cls],
150+
// kwargs: vec![],
151+
// },
152+
// );
153+
// }
154+
// }
155155

156-
if let Some(obj_attr) = obj.get_attr(name) {
157-
Ok(obj_attr)
158-
} else if let Some(cls_attr) = cls.get_attr(name) {
159-
Ok(cls_attr)
160-
} else {
161-
let attribute_error = vm.context().exceptions.attribute_error.clone();
162-
Err(vm.new_exception(
163-
attribute_error,
164-
format!("{:?} object has no attribute {}", cls, name),
165-
))
166-
}
167-
}
156+
// if let Some(obj_attr) = obj.get_attr(name) {
157+
// Ok(obj_attr)
158+
// } else if let Some(cls_attr) = cls.get_attr(name) {
159+
// Ok(cls_attr)
160+
// } else {
161+
// let attribute_error = vm.context().exceptions.attribute_error.clone();
162+
// Err(vm.new_exception(
163+
// attribute_error,
164+
// format!("{:?} object has no attribute {}", cls, name),
165+
// ))
166+
// }
167+
// }
168168

169169
pub fn get_attributes(obj: &PyObjectRef) -> HashMap<String, PyObjectRef> {
170170
// Gather all members here:
@@ -264,7 +264,7 @@ fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
264264
}
265265

266266
pub fn call(vm: &mut VirtualMachine, typ: PyObjectRef, args: PyFuncArgs) -> PyResult {
267-
let function = get_attribute(vm, typ, &String::from("__call__"))?;
267+
let function = vm.get_attribute(typ, &String::from("__call__"))?;
268268
vm.invoke(function, args)
269269
}
270270

vm/src/vm.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use super::obj::objlist;
1717
use super::obj::objobject;
1818
use super::obj::objtuple;
1919
use super::obj::objtype;
20-
use super::pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult};
20+
use super::pyobject::{
21+
AttributeProtocol, DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult,
22+
TypeProtocol,
23+
};
2124
use super::stdlib;
2225
use super::sysmodule;
2326

@@ -174,12 +177,18 @@ impl VirtualMachine {
174177
name: _,
175178
dict: _,
176179
mro: _,
177-
} => objtype::call(self, func_ref.clone(), args),
180+
} => {
181+
let function = self.get_attribute(func_ref.clone(), "__call__")?;
182+
self.invoke(function, args)
183+
}
178184
PyObjectKind::BoundMethod {
179185
ref function,
180186
ref object,
181187
} => self.invoke(function.clone(), args.insert(object.clone())),
182-
PyObjectKind::Instance { .. } => objobject::call(self, args.insert(func_ref.clone())),
188+
PyObjectKind::Instance { .. } => {
189+
let function = self.get_attribute(func_ref.clone(), "__call__")?;
190+
self.invoke(function, args)
191+
}
183192
ref kind => {
184193
unimplemented!("invoke unimplemented for: {:?}", kind);
185194
}
@@ -371,7 +380,19 @@ impl VirtualMachine {
371380
}
372381

373382
pub fn get_attribute(&mut self, obj: PyObjectRef, attr_name: &str) -> PyResult {
374-
objtype::get_attribute(self, obj.clone(), attr_name)
383+
let cls = obj.typ();
384+
if let Some(attr) = cls.get_attr("__getattribute__") {
385+
let name = self.new_str(attr_name.to_string());
386+
self.invoke(
387+
attr,
388+
PyFuncArgs {
389+
args: vec![obj.clone(), name],
390+
kwargs: vec![],
391+
},
392+
)
393+
} else {
394+
panic!("Everything should have a __getattribute__");
395+
}
375396
}
376397

377398
pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {

0 commit comments

Comments
 (0)