@@ -6,12 +6,12 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/
6
6
7
7
*/
8
8
9
- use crate :: function:: { OptionalArg , PyFuncArgs } ;
9
+ use crate :: function:: OptionalArg ;
10
10
use crate :: obj:: objfunction:: PyMethod ;
11
- use crate :: obj:: objstr;
11
+ use crate :: obj:: objstr:: PyStringRef ;
12
12
use crate :: obj:: objtype:: { PyClass , PyClassRef } ;
13
13
use crate :: pyobject:: {
14
- PyContext , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject , TypeProtocol ,
14
+ PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject , TypeProtocol ,
15
15
} ;
16
16
use crate :: scope:: NameProtocol ;
17
17
use crate :: vm:: VirtualMachine ;
@@ -20,6 +20,7 @@ use super::objtype;
20
20
21
21
pub type PySuperRef = PyRef < PySuper > ;
22
22
23
+ #[ pyclass]
23
24
#[ derive( Debug ) ]
24
25
pub struct PySuper {
25
26
obj : PyObjectRef ,
@@ -33,8 +34,130 @@ impl PyValue for PySuper {
33
34
}
34
35
}
35
36
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
+ }
36
158
pub fn init ( context : & PyContext ) {
37
159
let super_type = & context. types . super_type ;
160
+ PySuper :: extend_class ( context, super_type) ;
38
161
39
162
let super_doc = "super() -> same as super(__class__, <first argument>)\n \
40
163
super(type) -> unbound super object\n \
@@ -51,139 +174,6 @@ pub fn init(context: &PyContext) {
51
174
super().cmeth(arg)\n ";
52
175
53
176
extend_class ! ( context, super_type, {
54
- "__new__" => context. new_rustfunc( super_new) ,
55
- "__getattribute__" => context. new_rustfunc( super_getattribute) ,
56
177
"__doc__" => context. new_str( super_doc. to_string( ) ) ,
57
- "__str__" => context. new_rustfunc( super_str) ,
58
- "__repr__" => context. new_rustfunc( super_repr) ,
59
178
} ) ;
60
179
}
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