Skip to content

Commit f587221

Browse files
committed
Separate get_method (magic methods) and get_attribute (full attribute access).
1 parent ac861a4 commit f587221

File tree

6 files changed

+30
-39
lines changed

6 files changed

+30
-39
lines changed

src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> bool
127127
}
128128
Err(err) => {
129129
// Enum rather than special string here.
130-
let msg = match vm.get_attribute(err.clone(), "msg") {
130+
let name = vm.new_str("msg".to_string());
131+
let msg = match vm.get_attribute(err.clone(), name) {
131132
Ok(value) => objstr::get_value(&value),
132133
Err(_) => panic!("Expected msg attribute on exception object!"),
133134
};

vm/src/builtins.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn dir_object(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyObjectRef {
5050

5151
fn builtin_abs(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5252
arg_check!(vm, args, required = [(x, None)]);
53-
match vm.get_attribute(x.clone(), &"__abs__") {
53+
match vm.get_method(x.clone(), "__abs__") {
5454
Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![], vec![])),
5555
Err(..) => Err(vm.new_type_error("bad operand for abs".to_string())),
5656
}
@@ -134,7 +134,7 @@ fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
134134

135135
fn builtin_divmod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
136136
arg_check!(vm, args, required = [(x, None), (y, None)]);
137-
match vm.get_attribute(x.clone(), &"__divmod__") {
137+
match vm.get_method(x.clone(), "__divmod__") {
138138
Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![y.clone()], vec![])),
139139
Err(..) => Err(vm.new_type_error("unsupported operand type(s) for divmod".to_string())),
140140
}
@@ -218,11 +218,7 @@ fn builtin_getattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
218218
args,
219219
required = [(obj, None), (attr, Some(vm.ctx.str_type()))]
220220
);
221-
if let PyObjectKind::String { ref value } = attr.borrow().kind {
222-
vm.get_attribute(obj.clone(), value)
223-
} else {
224-
panic!("argument checking failure: attr not string")
225-
}
221+
vm.get_attribute(obj.clone(), attr.clone())
226222
}
227223

228224
// builtin_globals
@@ -233,15 +229,11 @@ fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
233229
args,
234230
required = [(obj, None), (attr, Some(vm.ctx.str_type()))]
235231
);
236-
if let PyObjectKind::String { ref value } = attr.borrow().kind {
237-
let has_attr = match vm.get_attribute(obj.clone(), value) {
238-
Ok(..) => true,
239-
Err(..) => false,
240-
};
241-
Ok(vm.context().new_bool(has_attr))
242-
} else {
243-
panic!("argument checking failure: attr not string")
244-
}
232+
let has_attr = match vm.get_attribute(obj.clone(), attr.clone()) {
233+
Ok(..) => true,
234+
Err(..) => false,
235+
};
236+
Ok(vm.context().new_bool(has_attr))
245237
}
246238

247239
fn builtin_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -308,7 +300,7 @@ fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
308300
}
309301
_ => {
310302
let len_method_name = "__len__".to_string();
311-
match vm.get_attribute(obj.clone(), &len_method_name) {
303+
match vm.get_method(obj.clone(), &len_method_name) {
312304
Ok(value) => vm.invoke(value, PyFuncArgs::default()),
313305
Err(..) => Err(vm.context().new_str(
314306
format!(
@@ -444,7 +436,7 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
444436
optional = [(mod_value, Some(vm.ctx.int_type()))]
445437
);
446438
let pow_method_name = "__pow__".to_string();
447-
let result = match vm.get_attribute(x.clone(), &pow_method_name) {
439+
let result = match vm.get_method(x.clone(), &pow_method_name) {
448440
Ok(attrib) => vm.invoke(attrib, PyFuncArgs::new(vec![y.clone()], vec![])),
449441
Err(..) => Err(vm.new_type_error("unsupported operand type(s) for pow".to_string())),
450442
};
@@ -454,7 +446,7 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
454446
match mod_value {
455447
Some(mod_value) => {
456448
let mod_method_name = "__mod__".to_string();
457-
match vm.get_attribute(
449+
match vm.get_method(
458450
result.expect("result not defined").clone(),
459451
&mod_method_name,
460452
) {

vm/src/frame.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl Frame {
124124
&vm.ctx.exceptions.base_exception_type
125125
));
126126
let traceback = vm
127-
.get_attribute(exception.clone(), &"__traceback__".to_string())
127+
.get_method(exception.clone(), &"__traceback__".to_string())
128128
.unwrap();
129129
trace!("Adding to traceback: {:?} {:?}", traceback, lineno);
130130
let pos = vm.ctx.new_tuple(vec![
@@ -1007,6 +1007,7 @@ impl Frame {
10071007

10081008
fn load_attr(&mut self, vm: &mut VirtualMachine, attr_name: &str) -> FrameResult {
10091009
let parent = self.pop_value();
1010+
let attr_name = vm.new_str(attr_name.to_string());
10101011
let obj = vm.get_attribute(parent, attr_name)?;
10111012
self.push_value(obj);
10121013
Ok(None)

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) = vm.get_attribute(obj.clone(), &String::from("__bool__")) {
18+
if let Ok(f) = vm.get_method(obj.clone(), "__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/objtype.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,6 @@ fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
300300
Ok(vm.new_str(format!("<class '{}'>", type_name)))
301301
}
302302

303-
pub fn call(vm: &mut VirtualMachine, typ: PyObjectRef, args: PyFuncArgs) -> PyResult {
304-
let function = vm.get_attribute(typ, &String::from("__call__"))?;
305-
vm.invoke(function, args)
306-
}
307-
308303
#[cfg(test)]
309304
mod tests {
310305
use super::{linearise_mro, new};

vm/src/vm.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -408,19 +408,21 @@ impl VirtualMachine {
408408
Ok(elements)
409409
}
410410

411-
pub fn get_attribute(&mut self, obj: PyObjectRef, attr_name: &str) -> PyResult {
411+
// get_attribute should be used for full attribute access (usually from user code).
412+
pub fn get_attribute(&mut self, obj: PyObjectRef, attr_name: PyObjectRef) -> PyResult {
413+
self.call_method(&obj, "__getattribute__", vec![attr_name])
414+
}
415+
416+
// get_method should be used for internal access to magic methods (by-passing
417+
// the full getattribute look-up.
418+
pub fn get_method(&mut self, obj: PyObjectRef, method_name: &str) -> PyResult {
412419
let cls = obj.typ();
413-
if let Some(attr) = cls.get_attr("__getattribute__") {
414-
let name = self.new_str(attr_name.to_string());
415-
self.invoke(
416-
attr,
417-
PyFuncArgs {
418-
args: vec![obj.clone(), name],
419-
kwargs: vec![],
420-
},
421-
)
422-
} else {
423-
panic!("Everything should have a __getattribute__");
420+
match cls.get_attr(method_name) {
421+
Some(method) => self.call_get_descriptor(method, obj.clone()),
422+
None => {
423+
Err(self
424+
.new_type_error(format!("{:?} object has no method {:?}", obj, method_name)))
425+
}
424426
}
425427
}
426428

0 commit comments

Comments
 (0)