@@ -27,15 +27,13 @@ static mp_obj_t mp_obj_new_class(mp_obj_t class) {
2727 return o ;
2828}
2929
30- static mp_map_elem_t * mp_obj_class_lookup (mp_obj_t self_in , qstr attr , mp_map_lookup_kind_t lookup_kind ) {
30+ static mp_map_elem_t * mp_obj_class_lookup (const mp_obj_type_t * type , qstr attr , mp_map_lookup_kind_t lookup_kind ) {
3131 for (;;) {
32- assert (MP_OBJ_IS_TYPE (self_in , & mp_const_type ));
33- mp_obj_type_t * self = self_in ;
34- if (self -> locals_dict == NULL ) {
32+ if (type -> locals_dict == NULL ) {
3533 return NULL ;
3634 }
37- assert (MP_OBJ_IS_TYPE (self -> locals_dict , & dict_type )); // Micro Python restriction, for now
38- mp_map_t * locals_map = ((void * )self -> locals_dict + sizeof (mp_obj_base_t )); // XXX hack to get map object from dict object
35+ assert (MP_OBJ_IS_TYPE (type -> locals_dict , & dict_type )); // Micro Python restriction, for now
36+ mp_map_t * locals_map = ((void * )type -> locals_dict + sizeof (mp_obj_base_t )); // XXX hack to get map object from dict object
3937 mp_map_elem_t * elem = mp_map_lookup (locals_map , MP_OBJ_NEW_QSTR (attr ), lookup_kind );
4038 if (elem != NULL ) {
4139 return elem ;
@@ -44,25 +42,27 @@ static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lo
4442 // attribute not found, keep searching base classes
4543
4644 // for a const struct, this entry might be NULL
47- if (self -> bases_tuple == MP_OBJ_NULL ) {
45+ if (type -> bases_tuple == MP_OBJ_NULL ) {
4846 return NULL ;
4947 }
5048
5149 uint len ;
5250 mp_obj_t * items ;
53- mp_obj_tuple_get (self -> bases_tuple , & len , & items );
51+ mp_obj_tuple_get (type -> bases_tuple , & len , & items );
5452 if (len == 0 ) {
5553 return NULL ;
5654 }
5755 for (uint i = 0 ; i < len - 1 ; i ++ ) {
58- elem = mp_obj_class_lookup (items [i ], attr , lookup_kind );
56+ assert (MP_OBJ_IS_TYPE (items [i ], & mp_const_type ));
57+ elem = mp_obj_class_lookup ((mp_obj_type_t * )items [i ], attr , lookup_kind );
5958 if (elem != NULL ) {
6059 return elem ;
6160 }
6261 }
6362
6463 // search last base (simple tail recursion elimination)
65- self_in = items [len - 1 ];
64+ assert (MP_OBJ_IS_TYPE (items [len - 1 ], & mp_const_type ));
65+ type = (mp_obj_type_t * )items [len - 1 ];
6666 }
6767}
6868
@@ -73,11 +73,12 @@ static void class_print(void (*print)(void *env, const char *fmt, ...), void *en
7373// args are reverse in the array
7474static mp_obj_t class_make_new (mp_obj_t self_in , int n_args , const mp_obj_t * args ) {
7575 assert (MP_OBJ_IS_TYPE (self_in , & mp_const_type ));
76+ mp_obj_type_t * self = self_in ;
7677
7778 mp_obj_t o = mp_obj_new_class (self_in );
7879
7980 // look for __init__ function
80- mp_map_elem_t * init_fn = mp_obj_class_lookup (self_in , MP_QSTR___init__ , MP_MAP_LOOKUP );
81+ mp_map_elem_t * init_fn = mp_obj_class_lookup (self , MP_QSTR___init__ , MP_MAP_LOOKUP );
8182
8283 if (init_fn != NULL ) {
8384 // call __init__ function
@@ -114,7 +115,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
114115 dest [1 ] = elem -> value ;
115116 return ;
116117 }
117- elem = mp_obj_class_lookup (( mp_obj_t ) self -> base .type , attr , MP_MAP_LOOKUP );
118+ elem = mp_obj_class_lookup (self -> base .type , attr , MP_MAP_LOOKUP );
118119 if (elem != NULL ) {
119120 if (mp_obj_is_callable (elem -> value )) {
120121 // class member is callable so build a bound method
@@ -132,7 +133,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
132133static bool class_store_attr (mp_obj_t self_in , qstr attr , mp_obj_t value ) {
133134 // logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
134135 mp_obj_class_t * self = self_in ;
135- mp_map_elem_t * elem = mp_obj_class_lookup (( mp_obj_t ) self -> base .type , attr , MP_MAP_LOOKUP );
136+ mp_map_elem_t * elem = mp_obj_class_lookup (self -> base .type , attr , MP_MAP_LOOKUP );
136137 if (elem != NULL ) {
137138 elem -> value = value ;
138139 } else {
@@ -188,17 +189,47 @@ static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args)
188189
189190// for fail, do nothing; for attr, dest[1] = value; for method, dest[0] = self, dest[1] = method
190191static void type_load_attr (mp_obj_t self_in , qstr attr , mp_obj_t * dest ) {
191- mp_map_elem_t * elem = mp_obj_class_lookup (self_in , attr , MP_MAP_LOOKUP );
192+ assert (MP_OBJ_IS_TYPE (self_in , & mp_const_type ));
193+ mp_obj_type_t * self = self_in ;
194+ mp_map_elem_t * elem = mp_obj_class_lookup (self , attr , MP_MAP_LOOKUP );
192195 if (elem != NULL ) {
193196 dest [1 ] = elem -> value ;
194197 return ;
195198 }
199+
200+ // generic method lookup
201+ // this is a lookup in the class itself (ie not the classes type or instance)
202+ const mp_method_t * meth = self -> methods ;
203+ if (meth != NULL ) {
204+ for (; meth -> name != NULL ; meth ++ ) {
205+ if (strcmp (meth -> name , qstr_str (attr )) == 0 ) {
206+ // check if the methods are functions, static or class methods
207+ // see http://docs.python.org/3.3/howto/descriptor.html
208+ if (MP_OBJ_IS_TYPE (meth -> fun , & mp_type_staticmethod )) {
209+ // return just the function
210+ dest [1 ] = ((mp_obj_staticmethod_t * )meth -> fun )-> fun ;
211+ } else if (MP_OBJ_IS_TYPE (meth -> fun , & mp_type_classmethod )) {
212+ // return a bound method, with self being this class
213+ dest [1 ] = ((mp_obj_classmethod_t * )meth -> fun )-> fun ;
214+ dest [0 ] = self_in ;
215+ } else {
216+ // return just the function
217+ // TODO need to wrap in a type check for the first argument; eg list.append(1,1) needs to throw an exception
218+ dest [1 ] = (mp_obj_t )meth -> fun ;
219+ }
220+ return ;
221+ }
222+ }
223+ }
196224}
197225
198226static bool type_store_attr (mp_obj_t self_in , qstr attr , mp_obj_t value ) {
227+ assert (MP_OBJ_IS_TYPE (self_in , & mp_const_type ));
228+ mp_obj_type_t * self = self_in ;
229+
199230 // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
200231
201- mp_map_elem_t * elem = mp_obj_class_lookup (self_in , attr , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND );
232+ mp_map_elem_t * elem = mp_obj_class_lookup (self , attr , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND );
202233 if (elem != NULL ) {
203234 elem -> value = value ;
204235 return true;
@@ -284,3 +315,16 @@ static mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
284315}
285316
286317MP_DEFINE_CONST_FUN_OBJ_2 (mp_builtin_isinstance_obj , mp_builtin_isinstance );
318+
319+ /******************************************************************************/
320+ // staticmethod and classmethod types (probably should go in a different file)
321+
322+ const mp_obj_type_t mp_type_staticmethod = {
323+ { & mp_const_type },
324+ "staticmethod" ,
325+ };
326+
327+ const mp_obj_type_t mp_type_classmethod = {
328+ { & mp_const_type },
329+ "classmethod" ,
330+ };
0 commit comments