@@ -87,7 +87,7 @@ void rt_init(void) {
8787 // init loaded modules table
8888 mp_map_init (& map_loaded_modules , 3 );
8989
90- // built-in exceptions (TODO, make these proper classes)
90+ // built-in exceptions (TODO, make these proper classes, and const if possible )
9191 mp_map_add_qstr (& map_builtins , MP_QSTR_AttributeError , mp_obj_new_exception (MP_QSTR_AttributeError ));
9292 mp_map_add_qstr (& map_builtins , MP_QSTR_IndexError , mp_obj_new_exception (MP_QSTR_IndexError ));
9393 mp_map_add_qstr (& map_builtins , MP_QSTR_KeyError , mp_obj_new_exception (MP_QSTR_KeyError ));
@@ -100,6 +100,7 @@ void rt_init(void) {
100100 mp_map_add_qstr (& map_builtins , MP_QSTR_OverflowError , mp_obj_new_exception (MP_QSTR_OverflowError ));
101101 mp_map_add_qstr (& map_builtins , MP_QSTR_OSError , mp_obj_new_exception (MP_QSTR_OSError ));
102102 mp_map_add_qstr (& map_builtins , MP_QSTR_AssertionError , mp_obj_new_exception (MP_QSTR_AssertionError ));
103+ mp_map_add_qstr (& map_builtins , MP_QSTR_StopIteration , mp_obj_new_exception (MP_QSTR_StopIteration ));
103104
104105 // built-in objects
105106 mp_map_add_qstr (& map_builtins , MP_QSTR_Ellipsis , mp_const_ellipsis );
@@ -805,7 +806,7 @@ mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
805806 // use load_method
806807 mp_obj_t dest [2 ];
807808 rt_load_method (base , attr , dest );
808- if (dest [1 ] == NULL ) {
809+ if (dest [1 ] == MP_OBJ_NULL ) {
809810 // load_method returned just a normal attribute
810811 return dest [0 ];
811812 } else {
@@ -814,9 +815,10 @@ mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
814815 }
815816}
816817
817- void rt_load_method (mp_obj_t base , qstr attr , mp_obj_t * dest ) {
818- DEBUG_OP_printf ("load method %p.%s\n" , base , qstr_str (attr ));
819-
818+ // no attribute found, returns: dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL
819+ // normal attribute found, returns: dest[0] == <attribute>, dest[1] == MP_OBJ_NULL
820+ // method attribute found, returns: dest[0] == <method>, dest[1] == <self>
821+ static void rt_load_method_maybe (mp_obj_t base , qstr attr , mp_obj_t * dest ) {
820822 // clear output to indicate no attribute/method found yet
821823 dest [0 ] = MP_OBJ_NULL ;
822824 dest [1 ] = MP_OBJ_NULL ;
@@ -830,7 +832,7 @@ void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
830832 }
831833
832834 // if nothing found yet, look for built-in and generic names
833- if (dest [0 ] == NULL ) {
835+ if (dest [0 ] == MP_OBJ_NULL ) {
834836 if (attr == MP_QSTR___next__ && type -> iternext != NULL ) {
835837 dest [0 ] = (mp_obj_t )& mp_builtin_next_obj ;
836838 dest [1 ] = base ;
@@ -861,8 +863,14 @@ void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
861863 }
862864 }
863865 }
866+ }
867+
868+ void rt_load_method (mp_obj_t base , qstr attr , mp_obj_t * dest ) {
869+ DEBUG_OP_printf ("load method %p.%s\n" , base , qstr_str (attr ));
870+
871+ rt_load_method_maybe (base , attr , dest );
864872
865- if (dest [0 ] == NULL ) {
873+ if (dest [0 ] == MP_OBJ_NULL ) {
866874 // no attribute/method called attr
867875 // following CPython, we give a more detailed error message for type objects
868876 if (MP_OBJ_IS_TYPE (base , & mp_const_type )) {
@@ -910,7 +918,16 @@ mp_obj_t rt_getiter(mp_obj_t o_in) {
910918 if (type -> getiter != NULL ) {
911919 return type -> getiter (o_in );
912920 } else {
913- nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "'%s' object is not iterable" , type -> name ));
921+ // check for __getitem__ method
922+ mp_obj_t dest [2 ];
923+ rt_load_method_maybe (o_in , qstr_from_str ("__getitem__" ), dest );
924+ if (dest [0 ] != MP_OBJ_NULL ) {
925+ // __getitem__ exists, create an iterator
926+ return mp_obj_new_getitem_iter (dest );
927+ } else {
928+ // object not iterable
929+ nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "'%s' object is not iterable" , type -> name ));
930+ }
914931 }
915932}
916933
0 commit comments