Skip to content

Commit b9132e3

Browse files
committed
Convert objsuper to new arg style
1 parent 7807b36 commit b9132e3

File tree

1 file changed

+126
-136
lines changed

1 file changed

+126
-136
lines changed

vm/src/obj/objsuper.rs

Lines changed: 126 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/
66
77
*/
88

9-
use crate::function::{OptionalArg, PyFuncArgs};
9+
use crate::function::OptionalArg;
1010
use crate::obj::objfunction::PyMethod;
11-
use crate::obj::objstr;
11+
use crate::obj::objstr::PyStringRef;
1212
use crate::obj::objtype::{PyClass, PyClassRef};
1313
use crate::pyobject::{
14-
PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
14+
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
1515
};
1616
use crate::scope::NameProtocol;
1717
use crate::vm::VirtualMachine;
@@ -20,6 +20,7 @@ use super::objtype;
2020

2121
pub type PySuperRef = PyRef<PySuper>;
2222

23+
#[pyclass]
2324
#[derive(Debug)]
2425
pub struct PySuper {
2526
obj: PyObjectRef,
@@ -33,8 +34,130 @@ impl PyValue for PySuper {
3334
}
3435
}
3536

37+
#[pyimpl]
38+
impl PySuper {
39+
#[pymethod(name = "__repr__")]
40+
fn repr(&self, _vm: &VirtualMachine) -> String {
41+
let class_type_str = if let Ok(type_class) = self.typ.clone().downcast::<PyClass>() {
42+
type_class.name.clone()
43+
} else {
44+
"NONE".to_string()
45+
};
46+
match self.obj_type.clone().downcast::<PyClass>() {
47+
Ok(obj_class_typ) => format!(
48+
"<super: <class '{}'>, <{} object>>",
49+
class_type_str, obj_class_typ.name
50+
),
51+
_ => format!("<super: <class '{}'> NULL>", class_type_str),
52+
}
53+
}
54+
55+
#[pymethod(name = "__getattribute__")]
56+
fn getattribute(&self, name: PyStringRef, vm: &VirtualMachine) -> PyResult {
57+
let inst = self.obj.clone();
58+
let typ = self.typ.clone();
59+
60+
match typ.payload::<PyClass>() {
61+
Some(PyClass { ref mro, .. }) => {
62+
for class in mro {
63+
if let Ok(item) = vm.get_attribute(class.as_object().clone(), name.clone()) {
64+
if item.payload_is::<PyMethod>() {
65+
// This is a classmethod
66+
return Ok(item);
67+
}
68+
return Ok(vm.ctx.new_bound_method(item, inst.clone()));
69+
}
70+
}
71+
Err(vm.new_attribute_error(format!(
72+
"{} has no attribute '{}'",
73+
inst,
74+
name.as_str()
75+
)))
76+
}
77+
_ => panic!("not Class"),
78+
}
79+
}
80+
81+
#[pymethod(name = "__new__")]
82+
fn new(
83+
cls: PyClassRef,
84+
py_type: OptionalArg<PyClassRef>,
85+
py_obj: OptionalArg<PyObjectRef>,
86+
vm: &VirtualMachine,
87+
) -> PyResult<PySuperRef> {
88+
// Get the type:
89+
let py_type = if let OptionalArg::Present(ty) = py_type {
90+
ty.clone()
91+
} else {
92+
match vm.current_scope().load_cell(vm, "__class__") {
93+
Some(obj) => PyClassRef::try_from_object(vm, obj)?,
94+
_ => {
95+
return Err(vm.new_type_error(
96+
"super must be called with 1 argument or from inside class method"
97+
.to_string(),
98+
));
99+
}
100+
}
101+
};
102+
103+
// Check type argument:
104+
if !objtype::isinstance(py_type.as_object(), &vm.get_type()) {
105+
return Err(vm.new_type_error(format!(
106+
"super() argument 1 must be type, not {}",
107+
py_type.class().name
108+
)));
109+
}
110+
111+
// Get the bound object:
112+
let py_obj = if let OptionalArg::Present(obj) = py_obj {
113+
obj.clone()
114+
} else {
115+
let frame = vm.current_frame().expect("no current frame for super()");
116+
if let Some(first_arg) = frame.code.arg_names.get(0) {
117+
match vm.get_locals().get_item_option(first_arg, vm)? {
118+
Some(obj) => obj.clone(),
119+
_ => {
120+
return Err(vm.new_type_error(format!(
121+
"super arguement {} was not supplied",
122+
first_arg
123+
)));
124+
}
125+
}
126+
} else {
127+
return Err(vm.new_type_error(
128+
"super must be called with 1 argument or from inside class method".to_string(),
129+
));
130+
}
131+
};
132+
133+
// Check obj type:
134+
let obj_type = if !objtype::isinstance(&py_obj, &py_type) {
135+
let is_subclass = if let Ok(py_obj) = PyClassRef::try_from_object(vm, py_obj.clone()) {
136+
objtype::issubclass(&py_obj, &py_type)
137+
} else {
138+
false
139+
};
140+
if !is_subclass {
141+
return Err(vm.new_type_error(
142+
"super(type, obj): obj must be an instance or subtype of type".to_string(),
143+
));
144+
}
145+
PyClassRef::try_from_object(vm, py_obj.clone())?
146+
} else {
147+
py_obj.class()
148+
};
149+
150+
PySuper {
151+
obj: py_obj,
152+
typ: py_type.into_object(),
153+
obj_type: obj_type.into_object(),
154+
}
155+
.into_ref_with_type(vm, cls)
156+
}
157+
}
36158
pub fn init(context: &PyContext) {
37159
let super_type = &context.types.super_type;
160+
PySuper::extend_class(context, super_type);
38161

39162
let super_doc = "super() -> same as super(__class__, <first argument>)\n\
40163
super(type) -> unbound super object\n\
@@ -51,139 +174,6 @@ pub fn init(context: &PyContext) {
51174
super().cmeth(arg)\n";
52175

53176
extend_class!(context, super_type, {
54-
"__new__" => context.new_rustfunc(super_new),
55-
"__getattribute__" => context.new_rustfunc(super_getattribute),
56177
"__doc__" => context.new_str(super_doc.to_string()),
57-
"__str__" => context.new_rustfunc(super_str),
58-
"__repr__" => context.new_rustfunc(super_repr),
59178
});
60179
}
61-
62-
fn super_str(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
63-
vm.call_method(&zelf, "__repr__", vec![])
64-
}
65-
66-
fn super_repr(zelf: PyObjectRef, _vm: &VirtualMachine) -> String {
67-
let super_obj = zelf.downcast::<PySuper>().unwrap();
68-
let class_type_str = if let Ok(type_class) = super_obj.typ.clone().downcast::<PyClass>() {
69-
type_class.name.clone()
70-
} else {
71-
"NONE".to_string()
72-
};
73-
match super_obj.obj_type.clone().downcast::<PyClass>() {
74-
Ok(obj_class_typ) => format!(
75-
"<super: <class '{}'>, <{} object>>",
76-
class_type_str, obj_class_typ.name
77-
),
78-
_ => format!("<super: <class '{}'> NULL>", class_type_str),
79-
}
80-
}
81-
82-
fn super_getattribute(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
83-
arg_check!(
84-
vm,
85-
args,
86-
required = [
87-
(super_obj, Some(vm.ctx.super_type())),
88-
(name_str, Some(vm.ctx.str_type()))
89-
]
90-
);
91-
92-
let inst = super_obj.payload::<PySuper>().unwrap().obj.clone();
93-
let typ = super_obj.payload::<PySuper>().unwrap().typ.clone();
94-
95-
match typ.payload::<PyClass>() {
96-
Some(PyClass { ref mro, .. }) => {
97-
for class in mro {
98-
if let Ok(item) = vm.get_attribute(class.as_object().clone(), name_str.clone()) {
99-
if item.payload_is::<PyMethod>() {
100-
// This is a classmethod
101-
return Ok(item);
102-
}
103-
return Ok(vm.ctx.new_bound_method(item, inst.clone()));
104-
}
105-
}
106-
Err(vm.new_attribute_error(format!(
107-
"{} has no attribute '{}'",
108-
inst,
109-
objstr::get_value(name_str)
110-
)))
111-
}
112-
_ => panic!("not Class"),
113-
}
114-
}
115-
116-
fn super_new(
117-
cls: PyClassRef,
118-
py_type: OptionalArg<PyClassRef>,
119-
py_obj: OptionalArg<PyObjectRef>,
120-
vm: &VirtualMachine,
121-
) -> PyResult<PySuperRef> {
122-
// Get the type:
123-
let py_type = if let OptionalArg::Present(ty) = py_type {
124-
ty.clone()
125-
} else {
126-
match vm.current_scope().load_cell(vm, "__class__") {
127-
Some(obj) => PyClassRef::try_from_object(vm, obj)?,
128-
_ => {
129-
return Err(vm.new_type_error(
130-
"super must be called with 1 argument or from inside class method".to_string(),
131-
));
132-
}
133-
}
134-
};
135-
136-
// Check type argument:
137-
if !objtype::isinstance(py_type.as_object(), &vm.get_type()) {
138-
return Err(vm.new_type_error(format!(
139-
"super() argument 1 must be type, not {}",
140-
py_type.class().name
141-
)));
142-
}
143-
144-
// Get the bound object:
145-
let py_obj = if let OptionalArg::Present(obj) = py_obj {
146-
obj.clone()
147-
} else {
148-
let frame = vm.current_frame().expect("no current frame for super()");
149-
if let Some(first_arg) = frame.code.arg_names.get(0) {
150-
match vm.get_locals().get_item_option(first_arg, vm)? {
151-
Some(obj) => obj.clone(),
152-
_ => {
153-
return Err(vm.new_type_error(format!(
154-
"super arguement {} was not supplied",
155-
first_arg
156-
)));
157-
}
158-
}
159-
} else {
160-
return Err(vm.new_type_error(
161-
"super must be called with 1 argument or from inside class method".to_string(),
162-
));
163-
}
164-
};
165-
166-
// Check obj type:
167-
let obj_type = if !objtype::isinstance(&py_obj, &py_type) {
168-
let is_subclass = if let Ok(py_obj) = PyClassRef::try_from_object(vm, py_obj.clone()) {
169-
objtype::issubclass(&py_obj, &py_type)
170-
} else {
171-
false
172-
};
173-
if !is_subclass {
174-
return Err(vm.new_type_error(
175-
"super(type, obj): obj must be an instance or subtype of type".to_string(),
176-
));
177-
}
178-
PyClassRef::try_from_object(vm, py_obj.clone())?
179-
} else {
180-
py_obj.class()
181-
};
182-
183-
PySuper {
184-
obj: py_obj,
185-
typ: py_type.into_object(),
186-
obj_type: obj_type.into_object(),
187-
}
188-
.into_ref_with_type(vm, cls)
189-
}

0 commit comments

Comments
 (0)