1
1
use super :: pyobject:: {
2
- AttributeProtocol , PyFuncArgs , PyObject , PyObjectKind , PyObjectRef , PyResult , ToRust ,
3
- TypeProtocol ,
2
+ AttributeProtocol , IdProtocol , PyContext , PyFuncArgs , PyObject , PyObjectKind , PyObjectRef ,
3
+ PyResult , ToRust , TypeProtocol ,
4
4
} ;
5
5
use super :: vm:: VirtualMachine ;
6
6
use std:: collections:: HashMap ;
@@ -30,33 +30,62 @@ pub fn create_type() -> PyObjectRef {
30
30
typ
31
31
}
32
32
33
- pub fn type_type_add_methods ( type_type : PyObjectRef , function_type : PyObjectRef ) {
34
- type_type. set_attr (
35
- & String :: from ( "__call__" ) ,
36
- PyObject :: new (
37
- PyObjectKind :: RustFunction {
38
- function : type_call,
39
- } ,
40
- function_type. clone ( ) ,
41
- ) ,
33
+ pub fn init ( context : & mut PyContext ) {
34
+ context
35
+ . type_type
36
+ . set_attr ( & String :: from ( "__call__" ) , context. new_rustfunc ( type_call) ) ;
37
+ context
38
+ . type_type
39
+ . set_attr ( & String :: from ( "__new__" ) , context. new_rustfunc ( type_new) ) ;
40
+
41
+ context. type_type . set_attr (
42
+ & String :: from ( "__mro__" ) ,
43
+ context. new_member_descriptor ( type_mro) ,
44
+ ) ;
45
+ context. type_type . set_attr (
46
+ & String :: from ( "__class__" ) ,
47
+ context. new_member_descriptor ( type_new) ,
42
48
) ;
43
- type_type. set_attr (
44
- & String :: from ( "__new__" ) ,
45
- PyObject :: new (
46
- PyObjectKind :: RustFunction { function : type_new } ,
47
- function_type. clone ( ) ,
48
- ) ,
49
+ context. type_type . set_attr (
50
+ & String :: from ( "__dict__" ) ,
51
+ context. new_member_descriptor ( type_dict) ,
49
52
) ;
50
53
}
51
54
55
+ fn type_mro ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
56
+ match _mro ( args. args [ 0 ] . clone ( ) ) {
57
+ Some ( mro) => Ok ( vm. context ( ) . new_tuple ( mro) ) ,
58
+ None => Err ( vm. new_exception ( "Only classes have an MRO." . to_string ( ) ) ) ,
59
+ }
60
+ }
61
+
62
+ fn _mro ( cls : PyObjectRef ) -> Option < Vec < PyObjectRef > > {
63
+ match cls. borrow ( ) . kind {
64
+ PyObjectKind :: Class { ref mro, .. } => {
65
+ let mut mro = mro. clone ( ) ;
66
+ mro. insert ( 0 , cls. clone ( ) ) ;
67
+ Some ( mro)
68
+ }
69
+ _ => None ,
70
+ }
71
+ }
72
+
73
+ fn type_dict ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
74
+ match args. args [ 0 ] . borrow ( ) . kind {
75
+ PyObjectKind :: Class { ref dict, .. } => Ok ( dict. clone ( ) ) ,
76
+ _ => Err ( vm. new_exception ( "type_dict must be called on a class." . to_string ( ) ) ) ,
77
+ }
78
+ }
79
+
52
80
pub fn type_new ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
53
81
debug ! ( "type.__new__{:?}" , args) ;
54
82
if args. args . len ( ) == 2 {
55
83
Ok ( args. args [ 1 ] . typ ( ) )
56
84
} else if args. args . len ( ) == 4 {
57
85
let typ = args. args [ 0 ] . clone ( ) ;
58
86
let name = args. args [ 1 ] . to_str ( ) . unwrap ( ) ;
59
- let bases = args. args [ 2 ] . to_vec ( ) . unwrap ( ) ;
87
+ let mut bases = args. args [ 2 ] . to_vec ( ) . unwrap ( ) ;
88
+ bases. push ( vm. context ( ) . object . clone ( ) ) ;
60
89
let dict = args. args [ 3 ] . clone ( ) ;
61
90
new ( typ, name, bases, dict)
62
91
} else {
@@ -108,12 +137,61 @@ pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &String) -
108
137
}
109
138
}
110
139
140
+ fn take_next_base (
141
+ mut bases : Vec < Vec < PyObjectRef > > ,
142
+ ) -> Option < ( PyObjectRef , Vec < Vec < PyObjectRef > > ) > {
143
+ let mut next = None ;
144
+
145
+ bases = bases. into_iter ( ) . filter ( |x| !x. is_empty ( ) ) . collect ( ) ;
146
+
147
+ for base in & bases {
148
+ let head = base[ 0 ] . clone ( ) ;
149
+ if !( & bases)
150
+ . into_iter ( )
151
+ . any ( |x| x[ 1 ..] . into_iter ( ) . any ( |x| x. get_id ( ) == head. get_id ( ) ) )
152
+ {
153
+ next = Some ( head) ;
154
+ break ;
155
+ }
156
+ }
157
+
158
+ if let Some ( head) = next {
159
+ for ref mut item in & mut bases {
160
+ if item[ 0 ] . get_id ( ) == head. get_id ( ) {
161
+ item. remove ( 0 ) ;
162
+ }
163
+ }
164
+ return Some ( ( head, bases) ) ;
165
+ }
166
+ None
167
+ }
168
+
169
+ fn linearise_mro ( mut bases : Vec < Vec < PyObjectRef > > ) -> Option < Vec < PyObjectRef > > {
170
+ debug ! ( "Linearising MRO: {:?}" , bases) ;
171
+ let mut result = vec ! [ ] ;
172
+ loop {
173
+ if ( & bases) . into_iter ( ) . all ( |x| x. is_empty ( ) ) {
174
+ break ;
175
+ }
176
+ match take_next_base ( bases) {
177
+ Some ( ( head, new_bases) ) => {
178
+ result. push ( head) ;
179
+ bases = new_bases;
180
+ }
181
+ None => return None ,
182
+ }
183
+ }
184
+ Some ( result)
185
+ }
186
+
111
187
pub fn new ( typ : PyObjectRef , name : String , bases : Vec < PyObjectRef > , dict : PyObjectRef ) -> PyResult {
188
+ let mros = bases. into_iter ( ) . map ( |x| _mro ( x) . unwrap ( ) ) . collect ( ) ;
189
+ let mro = linearise_mro ( mros) . unwrap ( ) ;
112
190
Ok ( PyObject :: new (
113
191
PyObjectKind :: Class {
114
192
name : name,
115
193
dict : dict,
116
- mro : bases ,
194
+ mro : mro ,
117
195
} ,
118
196
typ,
119
197
) )
@@ -123,3 +201,51 @@ pub fn call(vm: &mut VirtualMachine, typ: PyObjectRef, args: PyFuncArgs) -> PyRe
123
201
let function = get_attribute ( vm, typ, & String :: from ( "__call__" ) ) ?;
124
202
vm. invoke ( function, args)
125
203
}
204
+
205
+ #[ cfg( test) ]
206
+ mod tests {
207
+ use super :: { create_type, linearise_mro, new} ;
208
+ use super :: { IdProtocol , PyContext , PyObjectRef } ;
209
+
210
+ fn map_ids ( obj : Option < Vec < PyObjectRef > > ) -> Option < Vec < usize > > {
211
+ match obj {
212
+ Some ( vec) => Some ( vec. into_iter ( ) . map ( |x| x. get_id ( ) ) . collect ( ) ) ,
213
+ None => None ,
214
+ }
215
+ }
216
+
217
+ #[ test]
218
+ fn test_linearise ( ) {
219
+ let context = PyContext :: new ( ) ;
220
+ let object = context. object ;
221
+ let type_type = create_type ( ) ;
222
+
223
+ let a = new (
224
+ type_type. clone ( ) ,
225
+ String :: from ( "A" ) ,
226
+ vec ! [ object. clone( ) ] ,
227
+ type_type. clone ( ) ,
228
+ ) . unwrap ( ) ;
229
+ let b = new (
230
+ type_type. clone ( ) ,
231
+ String :: from ( "B" ) ,
232
+ vec ! [ object. clone( ) ] ,
233
+ type_type. clone ( ) ,
234
+ ) . unwrap ( ) ;
235
+
236
+ assert_eq ! (
237
+ map_ids( linearise_mro( vec![
238
+ vec![ object. clone( ) ] ,
239
+ vec![ object. clone( ) ]
240
+ ] ) ) ,
241
+ map_ids( Some ( vec![ object. clone( ) ] ) )
242
+ ) ;
243
+ assert_eq ! (
244
+ map_ids( linearise_mro( vec![
245
+ vec![ a. clone( ) , object. clone( ) ] ,
246
+ vec![ b. clone( ) , object. clone( ) ] ,
247
+ ] ) ) ,
248
+ map_ids( Some ( vec![ a. clone( ) , b. clone( ) , object. clone( ) ] ) )
249
+ ) ;
250
+ }
251
+ }
0 commit comments