@@ -27,6 +27,45 @@ 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 ) {
31+ 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 ) {
35+ return NULL ;
36+ }
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
39+ mp_map_elem_t * elem = mp_map_lookup (locals_map , MP_OBJ_NEW_QSTR (attr ), lookup_kind );
40+ if (elem != NULL ) {
41+ return elem ;
42+ }
43+
44+ // attribute not found, keep searching base classes
45+
46+ // for a const struct, this entry might be NULL
47+ if (self -> bases_tuple == MP_OBJ_NULL ) {
48+ return NULL ;
49+ }
50+
51+ uint len ;
52+ mp_obj_t * items ;
53+ mp_obj_tuple_get (self -> bases_tuple , & len , & items );
54+ if (len == 0 ) {
55+ return NULL ;
56+ }
57+ for (uint i = 0 ; i < len - 1 ; i ++ ) {
58+ elem = mp_obj_class_lookup (items [i ], attr , lookup_kind );
59+ if (elem != NULL ) {
60+ return elem ;
61+ }
62+ }
63+
64+ // search last base (simple tail recursion elimination)
65+ self_in = items [len - 1 ];
66+ }
67+ }
68+
3069static void class_print (void (* print )(void * env , const char * fmt , ...), void * env , mp_obj_t self_in ) {
3170 print (env , "<%s object at %p>" , mp_obj_get_type_str (self_in ), self_in );
3271}
@@ -102,17 +141,6 @@ static bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
102141 return true;
103142}
104143
105- mp_map_elem_t * mp_obj_class_lookup (mp_obj_t self_in , qstr attr , mp_map_lookup_kind_t lookup_kind ) {
106- assert (MP_OBJ_IS_TYPE (self_in , & mp_const_type ));
107- mp_obj_type_t * self = self_in ;
108- if (self -> locals == NULL ) {
109- return NULL ;
110- }
111- assert (MP_OBJ_IS_TYPE (self -> locals , & dict_type )); // Micro Python restriction, for now
112- mp_map_t * locals_map = ((void * )self -> locals + sizeof (mp_obj_base_t )); // XXX hack to get map object from dict object
113- return mp_map_lookup (locals_map , MP_OBJ_NEW_QSTR (attr ), lookup_kind );
114- }
115-
116144/******************************************************************************/
117145// type object
118146// - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
@@ -131,13 +159,10 @@ static mp_obj_t type_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args
131159 return mp_obj_get_type (args [0 ]);
132160
133161 case 3 :
134- {
135162 // args[2] = name
136163 // args[1] = bases tuple
137164 // args[0] = locals dict
138-
139- return mp_obj_new_type (mp_obj_get_qstr (args [2 ]), args [0 ]);
140- }
165+ return mp_obj_new_type (mp_obj_get_qstr (args [2 ]), args [1 ], args [0 ]);
141166
142167 default :
143168 nlr_jump (mp_obj_new_exception_msg (MP_QSTR_TypeError , "type takes at 1 or 3 arguments" ));
@@ -192,15 +217,70 @@ const mp_obj_type_t mp_const_type = {
192217 .store_attr = type_store_attr ,
193218};
194219
195- mp_obj_t mp_obj_new_type (qstr name , mp_obj_t local_dict ) {
220+ mp_obj_t mp_obj_new_type (qstr name , mp_obj_t bases_tuple , mp_obj_t locals_dict ) {
221+ assert (MP_OBJ_IS_TYPE (bases_tuple , & tuple_type )); // Micro Python restriction, for now
222+ assert (MP_OBJ_IS_TYPE (locals_dict , & dict_type )); // Micro Python restriction, for now
196223 mp_obj_type_t * o = m_new0 (mp_obj_type_t , 1 );
197224 o -> base .type = & mp_const_type ;
198225 o -> name = qstr_str (name );
199226 o -> print = class_print ;
200227 o -> make_new = class_make_new ;
201228 o -> load_attr = class_load_attr ;
202229 o -> store_attr = class_store_attr ;
203- o -> locals = local_dict ;
204- assert ( MP_OBJ_IS_TYPE ( o -> locals , & dict_type )); // Micro Python restriction, for now
230+ o -> bases_tuple = bases_tuple ;
231+ o -> locals_dict = locals_dict ;
205232 return o ;
206233}
234+
235+ /******************************************************************************/
236+ // built-ins specific to types
237+
238+ static mp_obj_t mp_builtin_issubclass (mp_obj_t object , mp_obj_t classinfo ) {
239+ if (!MP_OBJ_IS_TYPE (object , & mp_const_type )) {
240+ nlr_jump (mp_obj_new_exception_msg (MP_QSTR_TypeError , "issubclass() arg 1 must be a class" ));
241+ }
242+
243+ // TODO support a tuple of classes for second argument
244+ if (!MP_OBJ_IS_TYPE (classinfo , & mp_const_type )) {
245+ nlr_jump (mp_obj_new_exception_msg (MP_QSTR_TypeError , "issubclass() arg 2 must be a class" ));
246+ }
247+
248+ for (;;) {
249+ if (object == classinfo ) {
250+ return mp_const_true ;
251+ }
252+
253+ // not equivalent classes, keep searching base classes
254+
255+ assert (MP_OBJ_IS_TYPE (object , & mp_const_type ));
256+ mp_obj_type_t * self = object ;
257+
258+ // for a const struct, this entry might be NULL
259+ if (self -> bases_tuple == MP_OBJ_NULL ) {
260+ return mp_const_false ;
261+ }
262+
263+ uint len ;
264+ mp_obj_t * items ;
265+ mp_obj_tuple_get (self -> bases_tuple , & len , & items );
266+ if (len == 0 ) {
267+ return mp_const_false ;
268+ }
269+ for (uint i = 0 ; i < len - 1 ; i ++ ) {
270+ if (mp_builtin_issubclass (items [i ], classinfo ) == mp_const_true ) {
271+ return mp_const_true ;
272+ }
273+ }
274+
275+ // search last base (simple tail recursion elimination)
276+ object = items [len - 1 ];
277+ }
278+ }
279+
280+ MP_DEFINE_CONST_FUN_OBJ_2 (mp_builtin_issubclass_obj , mp_builtin_issubclass );
281+
282+ static mp_obj_t mp_builtin_isinstance (mp_obj_t object , mp_obj_t classinfo ) {
283+ return mp_builtin_issubclass (mp_obj_get_type (object ), classinfo );
284+ }
285+
286+ MP_DEFINE_CONST_FUN_OBJ_2 (mp_builtin_isinstance_obj , mp_builtin_isinstance );
0 commit comments