11use super :: pyobject:: {
2- AttributeProtocol , PyFuncArgs , PyObject , PyObjectKind , PyObjectRef , PyResult , ToRust ,
3- TypeProtocol ,
2+ AttributeProtocol , IdProtocol , PyContext , PyFuncArgs , PyObject , PyObjectKind , PyObjectRef ,
3+ PyResult , ToRust , TypeProtocol ,
44} ;
55use super :: vm:: VirtualMachine ;
66use std:: collections:: HashMap ;
@@ -30,33 +30,62 @@ pub fn create_type() -> PyObjectRef {
3030 typ
3131}
3232
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) ,
4248 ) ;
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) ,
4952 ) ;
5053}
5154
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+
5280pub fn type_new ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
5381 debug ! ( "type.__new__{:?}" , args) ;
5482 if args. args . len ( ) == 2 {
5583 Ok ( args. args [ 1 ] . typ ( ) )
5684 } else if args. args . len ( ) == 4 {
5785 let typ = args. args [ 0 ] . clone ( ) ;
5886 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 ( ) ) ;
6089 let dict = args. args [ 3 ] . clone ( ) ;
6190 new ( typ, name, bases, dict)
6291 } else {
@@ -108,12 +137,61 @@ pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &String) -
108137 }
109138}
110139
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+
111187pub 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 ( ) ;
112190 Ok ( PyObject :: new (
113191 PyObjectKind :: Class {
114192 name : name,
115193 dict : dict,
116- mro : bases ,
194+ mro : mro ,
117195 } ,
118196 typ,
119197 ) )
@@ -123,3 +201,51 @@ pub fn call(vm: &mut VirtualMachine, typ: PyObjectRef, args: PyFuncArgs) -> PyRe
123201 let function = get_attribute ( vm, typ, & String :: from ( "__call__" ) ) ?;
124202 vm. invoke ( function, args)
125203}
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