diff options
Diffstat (limited to 'py/runtime.c')
-rw-r--r-- | py/runtime.c | 187 |
1 files changed, 41 insertions, 146 deletions
diff --git a/py/runtime.c b/py/runtime.c index bbd12895af..3e0ef98d8b 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -12,12 +12,13 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objmodule.h" #include "parsenum.h" #include "runtime0.h" #include "runtime.h" #include "map.h" #include "builtin.h" -#include "objarray.h" +#include "builtintables.h" #include "bc.h" #include "intdivmod.h" @@ -35,7 +36,6 @@ STATIC mp_map_t *map_locals; STATIC mp_map_t *map_globals; STATIC mp_map_t map_builtins; -STATIC mp_map_t map_loaded_modules; // TODO: expose as sys.modules typedef enum { MP_CODE_NONE, @@ -72,119 +72,6 @@ STATIC mp_code_t *unique_codes = NULL; FILE *fp_write_code = NULL; #endif -// builtins -// we put this table in ROM because it's always needed and takes up quite a bit of room in RAM -// in fact, it uses less ROM here in table form than the equivalent in code form initialising a dynamic mp_map_t object in RAM -// at the moment it's a linear table, but we could convert it to a const mp_map_t table with a simple preprocessing script -// if we wanted to allow dynamic modification of the builtins, we could provide an mp_map_t object which is searched before this one - -typedef struct _mp_builtin_elem_t { - qstr qstr; - mp_obj_t fun; -} mp_builtin_elem_t; - -STATIC const mp_builtin_elem_t builtin_table[] = { - // built-in core functions - { MP_QSTR___build_class__, (mp_obj_t)&mp_builtin___build_class___obj }, - { MP_QSTR___import__, (mp_obj_t)&mp_builtin___import___obj }, - { MP_QSTR___repl_print__, (mp_obj_t)&mp_builtin___repl_print___obj }, - - // built-in types - { MP_QSTR_bool, (mp_obj_t)&bool_type }, - { MP_QSTR_bytes, (mp_obj_t)&bytes_type }, -#if MICROPY_ENABLE_FLOAT - { MP_QSTR_complex, (mp_obj_t)&mp_type_complex }, -#endif - { MP_QSTR_dict, (mp_obj_t)&dict_type }, - { MP_QSTR_enumerate, (mp_obj_t)&enumerate_type }, - { MP_QSTR_filter, (mp_obj_t)&filter_type }, -#if MICROPY_ENABLE_FLOAT - { MP_QSTR_float, (mp_obj_t)&mp_type_float }, -#endif - { MP_QSTR_int, (mp_obj_t)&int_type }, - { MP_QSTR_list, (mp_obj_t)&list_type }, - { MP_QSTR_map, (mp_obj_t)&map_type }, - { MP_QSTR_object, (mp_obj_t)&mp_type_object }, - { MP_QSTR_set, (mp_obj_t)&set_type }, - { MP_QSTR_str, (mp_obj_t)&str_type }, - { MP_QSTR_super, (mp_obj_t)&super_type }, - { MP_QSTR_tuple, (mp_obj_t)&tuple_type }, - { MP_QSTR_type, (mp_obj_t)&mp_type_type }, - { MP_QSTR_zip, (mp_obj_t)&zip_type }, - - { MP_QSTR_classmethod, (mp_obj_t)&mp_type_classmethod }, - { MP_QSTR_staticmethod, (mp_obj_t)&mp_type_staticmethod }, - - // built-in user functions - { MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj }, - { MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj }, - { MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj }, - { MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj }, - { MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj }, - { MP_QSTR_dir, (mp_obj_t)&mp_builtin_dir_obj }, - { MP_QSTR_divmod, (mp_obj_t)&mp_builtin_divmod_obj }, - { MP_QSTR_eval, (mp_obj_t)&mp_builtin_eval_obj }, - { MP_QSTR_exec, (mp_obj_t)&mp_builtin_exec_obj }, - { MP_QSTR_hash, (mp_obj_t)&mp_builtin_hash_obj }, - { MP_QSTR_id, (mp_obj_t)&mp_builtin_id_obj }, - { MP_QSTR_isinstance, (mp_obj_t)&mp_builtin_isinstance_obj }, - { MP_QSTR_issubclass, (mp_obj_t)&mp_builtin_issubclass_obj }, - { MP_QSTR_iter, (mp_obj_t)&mp_builtin_iter_obj }, - { MP_QSTR_len, (mp_obj_t)&mp_builtin_len_obj }, - { MP_QSTR_max, (mp_obj_t)&mp_builtin_max_obj }, - { MP_QSTR_min, (mp_obj_t)&mp_builtin_min_obj }, - { MP_QSTR_next, (mp_obj_t)&mp_builtin_next_obj }, - { MP_QSTR_ord, (mp_obj_t)&mp_builtin_ord_obj }, - { MP_QSTR_pow, (mp_obj_t)&mp_builtin_pow_obj }, - { MP_QSTR_print, (mp_obj_t)&mp_builtin_print_obj }, - { MP_QSTR_range, (mp_obj_t)&mp_builtin_range_obj }, - { MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj }, - { MP_QSTR_sorted, (mp_obj_t)&mp_builtin_sorted_obj }, - { MP_QSTR_sum, (mp_obj_t)&mp_builtin_sum_obj }, - { MP_QSTR_bytearray, (mp_obj_t)&mp_builtin_bytearray_obj }, - - // built-in exceptions - { MP_QSTR_BaseException, (mp_obj_t)&mp_type_BaseException }, - { MP_QSTR_ArithmeticError, (mp_obj_t)&mp_type_ArithmeticError }, - { MP_QSTR_AssertionError, (mp_obj_t)&mp_type_AssertionError }, - { MP_QSTR_AttributeError, (mp_obj_t)&mp_type_AttributeError }, - { MP_QSTR_BufferError, (mp_obj_t)&mp_type_BufferError }, - { MP_QSTR_EOFError, (mp_obj_t)&mp_type_EOFError }, - { MP_QSTR_EnvironmentError, (mp_obj_t)&mp_type_EnvironmentError }, - { MP_QSTR_Exception, (mp_obj_t)&mp_type_Exception }, - { MP_QSTR_FloatingPointError, (mp_obj_t)&mp_type_FloatingPointError }, - { MP_QSTR_GeneratorExit, (mp_obj_t)&mp_type_GeneratorExit }, - { MP_QSTR_IOError, (mp_obj_t)&mp_type_IOError }, - { MP_QSTR_ImportError, (mp_obj_t)&mp_type_ImportError }, - { MP_QSTR_IndentationError, (mp_obj_t)&mp_type_IndentationError }, - { MP_QSTR_IndexError, (mp_obj_t)&mp_type_IndexError }, - { MP_QSTR_KeyError, (mp_obj_t)&mp_type_KeyError }, - { MP_QSTR_LookupError, (mp_obj_t)&mp_type_LookupError }, - { MP_QSTR_MemoryError, (mp_obj_t)&mp_type_MemoryError }, - { MP_QSTR_NameError, (mp_obj_t)&mp_type_NameError }, - { MP_QSTR_NotImplementedError, (mp_obj_t)&mp_type_NotImplementedError }, - { MP_QSTR_OSError, (mp_obj_t)&mp_type_OSError }, - { MP_QSTR_OverflowError, (mp_obj_t)&mp_type_OverflowError }, - { MP_QSTR_ReferenceError, (mp_obj_t)&mp_type_ReferenceError }, - { MP_QSTR_RuntimeError, (mp_obj_t)&mp_type_RuntimeError }, - { MP_QSTR_SyntaxError, (mp_obj_t)&mp_type_SyntaxError }, - { MP_QSTR_SystemError, (mp_obj_t)&mp_type_SystemError }, - { MP_QSTR_SystemExit, (mp_obj_t)&mp_type_SystemExit }, - { MP_QSTR_TabError, (mp_obj_t)&mp_type_TabError }, - { MP_QSTR_TypeError, (mp_obj_t)&mp_type_TypeError }, - { MP_QSTR_UnboundLocalError, (mp_obj_t)&mp_type_UnboundLocalError }, - { MP_QSTR_ValueError, (mp_obj_t)&mp_type_ValueError }, - { MP_QSTR_ZeroDivisionError, (mp_obj_t)&mp_type_ZeroDivisionError }, - { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration }, - // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ - // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation - - // Extra builtins as defined by a port - MICROPY_EXTRA_BUILTINS - - { MP_QSTR_, MP_OBJ_NULL }, // end of list sentinel -}; - // a good optimising compiler will inline this if necessary STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; @@ -193,23 +80,17 @@ STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { void rt_init(void) { // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) map_locals = map_globals = mp_map_new(1); - mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); // init built-in hash table mp_map_init(&map_builtins, 3); - // init loaded modules table - mp_map_init(&map_loaded_modules, 3); + // init global module stuff + mp_module_init(); - // built-in objects + // add some builtins that can't be done in ROM + mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); mp_map_add_qstr(&map_builtins, MP_QSTR_Ellipsis, mp_const_ellipsis); - mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array); - rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type); - - mp_obj_t m_collections = mp_obj_new_module(MP_QSTR_collections); - rt_store_attr(m_collections, MP_QSTR_namedtuple, (mp_obj_t)&mp_namedtuple_obj); - #if MICROPY_CPYTHON_COMPAT // Precreate sys module, so "import sys" didn't throw exceptions. mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys); @@ -221,10 +102,6 @@ void rt_init(void) { //sys_path = mp_obj_new_list(0, NULL); //rt_store_attr(m_sys, MP_QSTR_path, sys_path); - // we pre-import the micropython module - // probably shouldn't do this, so we are compatible with CPython - rt_store_name(MP_QSTR_micropython, (mp_obj_t)&mp_module_micropython); - // TODO: wastes one mp_code_t structure in mem next_unique_code_id = 1; // 0 indicates "no code" unique_codes_alloc = 0; @@ -238,8 +115,8 @@ void rt_init(void) { void rt_deinit(void) { m_del(mp_code_t, unique_codes, unique_codes_alloc); mp_map_free(map_globals); - mp_map_deinit(&map_loaded_modules); mp_map_deinit(&map_builtins); + mp_module_deinit(); #ifdef WRITE_CODE if (fp_write_code != NULL) { fclose(fp_write_code); @@ -428,10 +305,9 @@ mp_obj_t rt_load_global(qstr qstr) { if (elem == NULL) { elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP); if (elem == NULL) { - for (const mp_builtin_elem_t *e = &builtin_table[0]; e->qstr != MP_QSTR_; e++) { - if (e->qstr == qstr) { - return e->fun; - } + mp_obj_t o = mp_builtin_tables_lookup_object(qstr); + if (o != MP_OBJ_NULL) { + return o; } nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr))); } @@ -441,10 +317,13 @@ mp_obj_t rt_load_global(qstr qstr) { mp_obj_t rt_load_build_class(void) { DEBUG_OP_printf("load_build_class\n"); + // lookup __build_class__ in dynamic table of builtins first mp_map_elem_t *elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP); if (elem != NULL) { + // found user-defined __build_class__, return it return elem->value; } else { + // no user-defined __build_class__, return builtin one return (mp_obj_t)&mp_builtin___build_class___obj; } } @@ -462,6 +341,11 @@ void rt_store_name(qstr qstr, mp_obj_t obj) { mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj; } +void rt_delete_name(qstr qstr) { + DEBUG_OP_printf("delete name %s\n", qstr_str(qstr)); + mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); +} + void rt_store_global(qstr qstr, mp_obj_t obj) { DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj); mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj; @@ -996,7 +880,8 @@ void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { // no attribute/method called attr // following CPython, we give a more detailed error message for type objects if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%s' has no attribute '%s'", ((mp_obj_type_t*)base)->name, qstr_str(attr))); + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + "type object '%s' has no attribute '%s'", qstr_str(((mp_obj_type_t*)base)->name), qstr_str(attr))); } else { nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr))); } @@ -1040,15 +925,21 @@ mp_obj_t rt_getiter(mp_obj_t o_in) { if (type->getiter != NULL) { return type->getiter(o_in); } else { - // check for __getitem__ method + // check for __iter__ method mp_obj_t dest[2]; - rt_load_method_maybe(o_in, MP_QSTR___getitem__, dest); + rt_load_method_maybe(o_in, MP_QSTR___iter__, dest); if (dest[0] != MP_OBJ_NULL) { - // __getitem__ exists, create an iterator - return mp_obj_new_getitem_iter(dest); + // __iter__ exists, call it and return its result + return rt_call_method_n_kw(0, 0, dest); } else { - // object not iterable - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); + rt_load_method_maybe(o_in, MP_QSTR___getitem__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __getitem__ exists, create an iterator + return mp_obj_new_getitem_iter(dest); + } else { + // object not iterable + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); + } } } } @@ -1058,7 +949,15 @@ mp_obj_t rt_iternext(mp_obj_t o_in) { if (type->iternext != NULL) { return type->iternext(o_in); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); + // check for __next__ method + mp_obj_t dest[2]; + rt_load_method_maybe(o_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __next__ exists, call it and return its result + return rt_call_method_n_kw(0, 0, dest); + } else { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); + } } } @@ -1135,10 +1034,6 @@ void rt_globals_set(mp_map_t *m) { map_globals = m; } -mp_map_t *rt_loaded_modules_get(void) { - return &map_loaded_modules; -} - // these must correspond to the respective enum void *const rt_fun_table[RT_F_NUMBER_OF] = { rt_load_const_dec, |