diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/builtin.h | 6 | ||||
-rw-r--r-- | py/builtinimport.c | 9 | ||||
-rw-r--r-- | py/builtintables.c | 150 | ||||
-rw-r--r-- | py/builtintables.h | 2 | ||||
-rw-r--r-- | py/makeqstrdata.py | 4 | ||||
-rw-r--r-- | py/modarray.c | 25 | ||||
-rw-r--r-- | py/modcollections.c | 25 | ||||
-rw-r--r-- | py/modmath.c (renamed from py/builtinmath.c) | 0 | ||||
-rw-r--r-- | py/modmicropython.c (renamed from py/builtinmp.c) | 1 | ||||
-rw-r--r-- | py/mpconfig.h | 8 | ||||
-rw-r--r-- | py/obj.c | 28 | ||||
-rw-r--r-- | py/obj.h | 44 | ||||
-rw-r--r-- | py/objarray.c | 12 | ||||
-rw-r--r-- | py/objexcept.c | 66 | ||||
-rw-r--r-- | py/objmodule.c | 45 | ||||
-rw-r--r-- | py/objmodule.h | 4 | ||||
-rw-r--r-- | py/objstr.c | 91 | ||||
-rw-r--r-- | py/objtype.c | 4 | ||||
-rw-r--r-- | py/py.mk | 7 | ||||
-rw-r--r-- | py/qstr.c | 8 | ||||
-rw-r--r-- | py/qstrdefs.h | 8 | ||||
-rw-r--r-- | py/runtime.c | 187 | ||||
-rw-r--r-- | py/runtime.h | 1 | ||||
-rw-r--r-- | py/vm.c | 15 |
24 files changed, 435 insertions, 315 deletions
diff --git a/py/builtin.h b/py/builtin.h index d9414045de..45da172d10 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -1,4 +1,4 @@ -mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args); +mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj); @@ -6,7 +6,6 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bytes_obj); // Temporary hack MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj); @@ -30,9 +29,10 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_range_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_str_obj); MP_DECLARE_CONST_FUN_OBJ(mp_namedtuple_obj); +extern const mp_obj_module_t mp_module_array; +extern const mp_obj_module_t mp_module_collections; extern const mp_obj_module_t mp_module_math; extern const mp_obj_module_t mp_module_micropython; diff --git a/py/builtinimport.c b/py/builtinimport.c index 2b9b3a30b9..882b128df1 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -12,6 +12,7 @@ #include "lexerunix.h" #include "parse.h" #include "obj.h" +#include "objmodule.h" #include "parsehelper.h" #include "compile.h" #include "runtime0.h" @@ -128,7 +129,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { rt_globals_set(old_globals); } -mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { +mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { /* printf("import:\n"); for (int i = 0; i < n_args; i++) { @@ -156,7 +157,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { const char *mod_str = (const char*)mp_obj_str_get_data(args[0], &mod_len); // check if module already exists - mp_obj_t module_obj = mp_obj_module_get(mp_obj_str_get_qstr(args[0])); + mp_obj_t module_obj = mp_module_get(mp_obj_str_get_qstr(args[0])); if (module_obj != MP_OBJ_NULL) { // If it's not a package, return module right away char *p = strchr(mod_str, '.'); @@ -169,7 +170,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { } // Otherwise, we need to return top-level package qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); - return mp_obj_module_get(pkg_name); + return mp_module_get(pkg_name); } uint last = 0; @@ -200,7 +201,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name))); } - module_obj = mp_obj_module_get(mod_name); + module_obj = mp_module_get(mod_name); if (module_obj == MP_OBJ_NULL) { // module not already loaded, so load it! diff --git a/py/builtintables.c b/py/builtintables.c new file mode 100644 index 0000000000..0aa0b66a72 --- /dev/null +++ b/py/builtintables.c @@ -0,0 +1,150 @@ +#include <stdlib.h> + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "builtin.h" +#include "builtintables.h" +#include "objarray.h" + +// builtins +// we put these tables in ROM because they're always needed and take 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 + +typedef struct _mp_builtin_elem_t { + qstr qstr; + mp_obj_t elem; +} mp_builtin_elem_t; + +STATIC const mp_builtin_elem_t builtin_object_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_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_RuntimeError, (mp_obj_t)&mp_type_RuntimeError }, + { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration }, + { MP_QSTR_SyntaxError, (mp_obj_t)&mp_type_SyntaxError }, + { MP_QSTR_SystemError, (mp_obj_t)&mp_type_SystemError }, + { 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 }, + // 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 +}; + +STATIC const mp_builtin_elem_t builtin_module_table[] = { + { MP_QSTR_micropython, (mp_obj_t)&mp_module_micropython }, + + { MP_QSTR_array, (mp_obj_t)&mp_module_array }, + { MP_QSTR_collections, (mp_obj_t)&mp_module_collections }, + +#if MICROPY_ENABLE_FLOAT + { MP_QSTR_math, (mp_obj_t)&mp_module_math }, +#endif + + // extra builtin modules as defined by a port + MICROPY_EXTRA_BUILTIN_MODULES + + { MP_QSTR_, MP_OBJ_NULL }, // end of list sentinel +}; + +STATIC mp_obj_t mp_builtin_tables_lookup(const mp_builtin_elem_t *table, qstr q) { + for (; table->qstr != MP_QSTR_; table++) { + if (table->qstr == q) { + return table->elem; + } + } + return MP_OBJ_NULL; +} + +mp_obj_t mp_builtin_tables_lookup_object(qstr q) { + return mp_builtin_tables_lookup(&builtin_object_table[0], q); +} + +mp_obj_t mp_builtin_tables_lookup_module(qstr q) { + return mp_builtin_tables_lookup(&builtin_module_table[0], q); +} diff --git a/py/builtintables.h b/py/builtintables.h new file mode 100644 index 0000000000..9b22b66e03 --- /dev/null +++ b/py/builtintables.h @@ -0,0 +1,2 @@ +mp_obj_t mp_builtin_tables_lookup_object(qstr q); +mp_obj_t mp_builtin_tables_lookup_module(qstr q); diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 934bc43beb..7413365712 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -18,9 +18,9 @@ codepoint2name[ord('/')] = 'slash' # this must match the equivalent function in qstr.c def compute_hash(qstr): - hash = 0 + hash = 5381 for char in qstr: - hash += ord(char) + hash = (hash * 33) ^ ord(char) return hash & 0xffff def do_work(infiles): diff --git a/py/modarray.c b/py/modarray.c new file mode 100644 index 0000000000..2544f7ed59 --- /dev/null +++ b/py/modarray.c @@ -0,0 +1,25 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "map.h" +#include "builtin.h" + +STATIC const mp_map_elem_t mp_module_array_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array }, +}; + +STATIC const mp_map_t mp_module_array_globals = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_array_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_array_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_array_globals_table, +}; + +const mp_obj_module_t mp_module_array = { + .base = { &mp_type_module }, + .name = MP_QSTR_array, + .globals = (mp_map_t*)&mp_module_array_globals, +}; diff --git a/py/modcollections.c b/py/modcollections.c new file mode 100644 index 0000000000..ad951d5e9e --- /dev/null +++ b/py/modcollections.c @@ -0,0 +1,25 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "map.h" +#include "builtin.h" + +STATIC const mp_map_elem_t mp_module_collections_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_collections) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_namedtuple), (mp_obj_t)&mp_namedtuple_obj }, +}; + +STATIC const mp_map_t mp_module_collections_globals = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_collections_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_collections_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_collections_globals_table, +}; + +const mp_obj_module_t mp_module_collections = { + .base = { &mp_type_module }, + .name = MP_QSTR_collections, + .globals = (mp_map_t*)&mp_module_collections_globals, +}; diff --git a/py/builtinmath.c b/py/modmath.c index b814822531..b814822531 100644 --- a/py/builtinmath.c +++ b/py/modmath.c diff --git a/py/builtinmp.c b/py/modmicropython.c index 3b73517963..96ceb811c9 100644 --- a/py/builtinmp.c +++ b/py/modmicropython.c @@ -1,4 +1,3 @@ - #include "misc.h" #include "mpconfig.h" #include "qstr.h" diff --git a/py/mpconfig.h b/py/mpconfig.h index 5b13c46480..09cc37913a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -125,10 +125,16 @@ typedef double mp_float_t; #define MICROPY_PATH_MAX (512) #endif -// Additional builtin function definitions - see runtime.c:builtin_table for format. +// Additional builtin function definitions - see builtintables.c:builtin_object_table for format. #ifndef MICROPY_EXTRA_BUILTINS #define MICROPY_EXTRA_BUILTINS #endif + +// Additional builtin module definitions - see builtintables.c:builtin_module_table for format. +#ifndef MICROPY_EXTRA_BUILTIN_MODULES +#define MICROPY_EXTRA_BUILTIN_MODULES +#endif + /*****************************************************************************/ /* Miscellaneous settings */ @@ -206,21 +206,29 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { } #endif -mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o_in, machine_int_t n) { - if (MP_OBJ_IS_TYPE(o_in, &tuple_type) || MP_OBJ_IS_TYPE(o_in, &list_type)) { +void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) { + if (MP_OBJ_IS_TYPE(o, &tuple_type)) { + mp_obj_tuple_get(o, len, items); + } else if (MP_OBJ_IS_TYPE(o, &list_type)) { + mp_obj_list_get(o, len, items); + } else { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); + } +} + +void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) { + if (MP_OBJ_IS_TYPE(o, &tuple_type) || MP_OBJ_IS_TYPE(o, &list_type)) { uint seq_len; - mp_obj_t *seq_items; - if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) { - mp_obj_tuple_get(o_in, &seq_len, &seq_items); + if (MP_OBJ_IS_TYPE(o, &tuple_type)) { + mp_obj_tuple_get(o, &seq_len, items); } else { - mp_obj_list_get(o_in, &seq_len, &seq_items); + mp_obj_list_get(o, &seq_len, items); } - if (seq_len != n) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", n, seq_len)); + if (seq_len != len) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", len, seq_len)); } - return seq_items; } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o_in))); + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); } } @@ -175,7 +175,6 @@ struct _mp_obj_type_t { abs float complex hash bool int none str equal int str - get_array_n tuple list unpack seq list tuple */ @@ -192,17 +191,12 @@ extern const mp_obj_type_t mp_type_ArithmeticError; extern const mp_obj_type_t mp_type_AssertionError; extern const mp_obj_type_t mp_type_AttributeError; extern const mp_obj_type_t mp_type_BufferError; -extern const mp_obj_type_t mp_type_BytesWarning; -extern const mp_obj_type_t mp_type_DeprecationWarning; extern const mp_obj_type_t mp_type_EOFError; -extern const mp_obj_type_t mp_type_EnvironmentError; extern const mp_obj_type_t mp_type_Exception; extern const mp_obj_type_t mp_type_FloatingPointError; -extern const mp_obj_type_t mp_type_FutureWarning; extern const mp_obj_type_t mp_type_GeneratorExit; extern const mp_obj_type_t mp_type_IOError; extern const mp_obj_type_t mp_type_ImportError; -extern const mp_obj_type_t mp_type_ImportWarning; extern const mp_obj_type_t mp_type_IndentationError; extern const mp_obj_type_t mp_type_IndexError; extern const mp_obj_type_t mp_type_KeyError; @@ -212,43 +206,16 @@ extern const mp_obj_type_t mp_type_NameError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_OSError; extern const mp_obj_type_t mp_type_OverflowError; -extern const mp_obj_type_t mp_type_PendingDeprecationWarning; -extern const mp_obj_type_t mp_type_ReferenceError; -extern const mp_obj_type_t mp_type_ResourceWarning; extern const mp_obj_type_t mp_type_RuntimeError; -extern const mp_obj_type_t mp_type_RuntimeWarning; +extern const mp_obj_type_t mp_type_StopIteration; extern const mp_obj_type_t mp_type_SyntaxError; -extern const mp_obj_type_t mp_type_SyntaxWarning; extern const mp_obj_type_t mp_type_SystemError; -extern const mp_obj_type_t mp_type_SystemExit; -extern const mp_obj_type_t mp_type_TabError; extern const mp_obj_type_t mp_type_TypeError; extern const mp_obj_type_t mp_type_UnboundLocalError; -extern const mp_obj_type_t mp_type_UserWarning; extern const mp_obj_type_t mp_type_ValueError; -extern const mp_obj_type_t mp_type_Warning; extern const mp_obj_type_t mp_type_ZeroDivisionError; -extern const mp_obj_type_t mp_type_StopIteration; -/*extern const mp_obj_type_t mp_type_BaseException; -extern const mp_obj_type_t mp_type_AssertionError; -extern const mp_obj_type_t mp_type_AttributeError; -extern const mp_obj_type_t mp_type_ImportError; -extern const mp_obj_type_t mp_type_IndentationError; -extern const mp_obj_type_t mp_type_IndexError; -extern const mp_obj_type_t mp_type_KeyError; -extern const mp_obj_type_t mp_type_NameError; -extern const mp_obj_type_t mp_type_SyntaxError; -extern const mp_obj_type_t mp_type_TypeError; -extern const mp_obj_type_t mp_type_ValueError; -extern const mp_obj_type_t mp_type_OverflowError; -extern const mp_obj_type_t mp_type_OSError; -extern const mp_obj_type_t mp_type_NotImplementedError; -extern const mp_obj_type_t mp_type_StopIteration; -extern const mp_obj_type_t mp_type_ZeroDivisionError;*/ - // Constant objects, globally accessible - extern const mp_obj_t mp_const_none; extern const mp_obj_t mp_const_false; extern const mp_obj_t mp_const_true; @@ -295,7 +262,7 @@ mp_obj_t mp_obj_new_module(qstr module_name); mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in); const char *mp_obj_get_type_str(mp_obj_t o_in); -bool mp_obj_is_subclass_fast(mp_obj_t object, mp_obj_t classinfo); // arguments should be type objects +bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); @@ -312,7 +279,8 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif //qstr mp_obj_get_qstr(mp_obj_t arg); -mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o, machine_int_t n); +void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items); +void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items); uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return NULL */ @@ -419,7 +387,7 @@ void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *sto extern const mp_obj_type_t zip_type; // array -extern const mp_obj_type_t array_type; +extern const mp_obj_type_t mp_type_array; uint mp_obj_array_len(mp_obj_t self_in); mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items); @@ -456,8 +424,6 @@ typedef struct _mp_obj_module_t { struct _mp_map_t *globals; } mp_obj_module_t; extern const mp_obj_type_t mp_type_module; -mp_obj_t mp_obj_new_module(qstr module_name); -mp_obj_t mp_obj_module_get(qstr module_name); struct _mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in); // staticmethod and classmethod types; defined here so we can make const versions diff --git a/py/objarray.c b/py/objarray.c index ee43bde960..69f60e000a 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -121,7 +121,7 @@ STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { - assert(MP_OBJ_IS_TYPE(self_in, &array_type)); + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array)); mp_obj_array_t *self = self_in; if (self->free == 0) { int item_sz = mp_binary_get_size(self->typecode); @@ -154,7 +154,7 @@ STATIC const mp_method_t array_type_methods[] = { { NULL, NULL }, }; -const mp_obj_type_t array_type = { +const mp_obj_type_t mp_type_array = { { &mp_type_type }, .name = MP_QSTR_array, .print = array_print, @@ -169,7 +169,7 @@ const mp_obj_type_t array_type = { STATIC mp_obj_array_t *array_new(char typecode, uint n) { mp_obj_array_t *o = m_new_obj(mp_obj_array_t); - o->base.type = &array_type; + o->base.type = &mp_type_array; o->typecode = typecode; o->free = 0; o->len = n; @@ -190,7 +190,7 @@ mp_obj_t mp_obj_new_bytearray(uint n, void *items) { // Create bytearray which references specified memory area mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) { mp_obj_array_t *o = m_new_obj(mp_obj_array_t); - o->base.type = &array_type; + o->base.type = &mp_type_array; o->typecode = BYTEARRAY_TYPECODE; o->free = 0; o->len = n; @@ -207,7 +207,7 @@ typedef struct _mp_obj_array_it_t { machine_uint_t cur; } mp_obj_array_it_t; -mp_obj_t array_it_iternext(mp_obj_t self_in) { +STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) { mp_obj_array_it_t *self = self_in; if (self->cur < self->array->len) { return mp_binary_get_val(self->array->typecode, self->array->items, self->cur++); @@ -222,7 +222,7 @@ STATIC const mp_obj_type_t array_it_type = { .iternext = array_it_iternext, }; -mp_obj_t array_iterator_new(mp_obj_t array_in) { +STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) { mp_obj_array_t *array = array_in; mp_obj_array_it_t *o = m_new_obj(mp_obj_array_it_t); o->base.type = &array_it_type; diff --git a/py/objexcept.c b/py/objexcept.c index f96523ed23..c75e3d3a57 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -55,16 +55,31 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_ o->base.type = type; o->traceback = MP_OBJ_NULL; o->msg = NULL; + o->args.base.type = &tuple_type; o->args.len = n_args; memcpy(o->args.items, args, n_args * sizeof(mp_obj_t)); return o; } +STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_exception_t *self = self_in; + if (attr == MP_QSTR_args) { + dest[0] = &self->args; + } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) { + if (self->args.len == 0) { + dest[0] = mp_const_none; + } else { + dest[0] = self->args.items[0]; + } + } +} + const mp_obj_type_t mp_type_BaseException = { { &mp_type_type }, .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, + .load_attr = exception_load_attr, }; #define MP_DEFINE_EXCEPTION_BASE(base_name) \ @@ -76,13 +91,14 @@ const mp_obj_type_t mp_type_ ## exc_name = { \ .name = MP_QSTR_ ## exc_name, \ .print = mp_obj_exception_print, \ .make_new = mp_obj_exception_make_new, \ + .load_attr = exception_load_attr, \ .bases_tuple = (mp_obj_t)&mp_type_ ## base_name ## _base_tuple, \ }; // List of all exceptions, arranged as in the table at: // http://docs.python.org/3.3/library/exceptions.html MP_DEFINE_EXCEPTION_BASE(BaseException) -MP_DEFINE_EXCEPTION(SystemExit, BaseException) +//MP_DEFINE_EXCEPTION(SystemExit, BaseException) //MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) MP_DEFINE_EXCEPTION(Exception, BaseException) @@ -96,7 +112,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(AssertionError, Exception) MP_DEFINE_EXCEPTION(AttributeError, Exception) MP_DEFINE_EXCEPTION(BufferError, Exception) - MP_DEFINE_EXCEPTION(EnvironmentError, Exception) + //MP_DEFINE_EXCEPTION(EnvironmentError, Exception) MP_DEFINE_EXCEPTION(EOFError, Exception) MP_DEFINE_EXCEPTION(ImportError, Exception) MP_DEFINE_EXCEPTION(IOError, Exception) @@ -126,7 +142,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(TimeoutError, OSError)*/ MP_DEFINE_EXCEPTION(FileExistsError, OSError) MP_DEFINE_EXCEPTION(FileNotFoundError, OSError) - MP_DEFINE_EXCEPTION(ReferenceError, Exception) + //MP_DEFINE_EXCEPTION(ReferenceError, Exception) MP_DEFINE_EXCEPTION(RuntimeError, Exception) MP_DEFINE_EXCEPTION_BASE(RuntimeError) MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError) @@ -134,7 +150,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION_BASE(SyntaxError) MP_DEFINE_EXCEPTION(IndentationError, SyntaxError) MP_DEFINE_EXCEPTION_BASE(IndentationError) - MP_DEFINE_EXCEPTION(TabError, IndentationError) + //MP_DEFINE_EXCEPTION(TabError, IndentationError) MP_DEFINE_EXCEPTION(SystemError, Exception) MP_DEFINE_EXCEPTION(TypeError, Exception) MP_DEFINE_EXCEPTION(ValueError, Exception) @@ -193,20 +209,20 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char } // return true if the given object is an exception type -// TODO make this work for user defined exceptions bool mp_obj_is_exception_type(mp_obj_t self_in) { if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) { + // optimisation when self_in is a builtin exception mp_obj_type_t *self = self_in; - return self->make_new == mp_obj_exception_make_new; - } else { - return false; + if (self->make_new == mp_obj_exception_make_new) { + return true; + } } + return mp_obj_is_subclass_fast(self_in, &mp_type_BaseException); } // return true if the given object is an instance of an exception type -// TODO make this work for user defined exceptions bool mp_obj_is_exception_instance(mp_obj_t self_in) { - return mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new; + return mp_obj_is_exception_type(mp_obj_get_type(self_in)); } // return true if exception (type or instance) is a subclass of given @@ -218,26 +234,30 @@ bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type) { void mp_obj_exception_clear_traceback(mp_obj_t self_in) { // make sure self_in is an exception instance - assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new); - mp_obj_exception_t *self = self_in; + // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) + if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) { + mp_obj_exception_t *self = self_in; - // just set the traceback to the null object - // we don't want to call any memory management functions here - self->traceback = MP_OBJ_NULL; + // just set the traceback to the null object + // we don't want to call any memory management functions here + self->traceback = MP_OBJ_NULL; + } } void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) { // make sure self_in is an exception instance - assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new); - mp_obj_exception_t *self = self_in; + // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) + if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) { + mp_obj_exception_t *self = self_in; - // for traceback, we are just using the list object for convenience, it's not really a list of Python objects - if (self->traceback == MP_OBJ_NULL) { - self->traceback = mp_obj_new_list(0, NULL); + // for traceback, we are just using the list object for convenience, it's not really a list of Python objects + if (self->traceback == MP_OBJ_NULL) { + self->traceback = mp_obj_new_list(0, NULL); + } + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file); + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line); + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block); } - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file); - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line); - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block); } void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) { diff --git a/py/objmodule.c b/py/objmodule.c index e0778b4cf2..a388ca3f37 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -6,9 +6,12 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objmodule.h" #include "runtime.h" #include "map.h" -#include "builtin.h" +#include "builtintables.h" + +STATIC mp_map_t mp_loaded_modules_map; // TODO: expose as sys.modules STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_module_t *self = self_in; @@ -39,7 +42,7 @@ const mp_obj_type_t mp_type_module = { }; mp_obj_t mp_obj_new_module(qstr module_name) { - mp_map_elem_t *el = mp_map_lookup(rt_loaded_modules_get(), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + mp_map_elem_t *el = mp_map_lookup(&mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); // We could error out if module already exists, but let C extensions // add new members to existing modules. if (el->value != MP_OBJ_NULL) { @@ -62,9 +65,27 @@ mp_obj_t mp_obj_new_module(qstr module_name) { return o; } -mp_obj_t mp_obj_module_get(qstr module_name) { +mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); + mp_obj_module_t *self = self_in; + return self->globals; +} + +/******************************************************************************/ +// Global module table and related functions + +void mp_module_init(void) { + mp_map_init(&mp_loaded_modules_map, 3); +} + +void mp_module_deinit(void) { + mp_map_deinit(&mp_loaded_modules_map); +} + +// returns MP_OBJ_NULL if not found +mp_obj_t mp_module_get(qstr module_name) { // lookup module - mp_map_elem_t *el = mp_map_lookup(rt_loaded_modules_get(), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + mp_map_elem_t *el = mp_map_lookup(&mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); // module found, return it if (el != NULL) { @@ -72,18 +93,10 @@ mp_obj_t mp_obj_module_get(qstr module_name) { } // module not found, look for builtin module names -#if MICROPY_ENABLE_FLOAT - if (module_name == MP_QSTR_math) { - return (mp_obj_t)&mp_module_math; - } -#endif - - // no module found, return NULL object - return MP_OBJ_NULL; + // it will return MP_OBJ_NULL if nothing found + return mp_builtin_tables_lookup_module(module_name); } -mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_module)); - mp_obj_module_t *self = self_in; - return self->globals; +void mp_module_register(qstr qstr, mp_obj_t module) { + mp_map_lookup(&mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } diff --git a/py/objmodule.h b/py/objmodule.h new file mode 100644 index 0000000000..270551da4f --- /dev/null +++ b/py/objmodule.h @@ -0,0 +1,4 @@ +void mp_module_init(void); +void mp_module_deinit(void); +mp_obj_t mp_module_get(qstr module_name); +void mp_module_register(qstr qstr, mp_obj_t module); diff --git a/py/objstr.c b/py/objstr.c index 35a948700c..00586a3b3b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -186,19 +186,26 @@ wrong_args: // like strstr but with specified length and allows \0 bytes // TODO replace with something more efficient/standard -STATIC const byte *find_subbytes(const byte *haystack, uint hlen, const byte *needle, uint nlen) { +STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, const byte *needle, machine_uint_t nlen, machine_int_t direction) { if (hlen >= nlen) { - for (uint i = 0; i <= hlen - nlen; i++) { - bool found = true; - for (uint j = 0; j < nlen; j++) { - if (haystack[i + j] != needle[j]) { - found = false; - break; - } + machine_uint_t str_index, str_index_end; + if (direction > 0) { + str_index = 0; + str_index_end = hlen - nlen; + } else { + str_index = hlen - nlen; + str_index_end = 0; + } + for (;;) { + if (memcmp(&haystack[str_index], needle, nlen) == 0) { + //found + return haystack + str_index; } - if (found) { - return haystack + i; + if (str_index == str_index_end) { + //not found + break; } + str_index += direction; } } return NULL; @@ -260,7 +267,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { /* NOTE `a in b` is `b.__contains__(a)` */ if (MP_OBJ_IS_STR(rhs_in)) { GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); - return MP_BOOL(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len) != NULL); + return MP_BOOL(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL); } break; @@ -382,7 +389,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) { return res; } -STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction) { assert(2 <= n_args && n_args <= 4); assert(MP_OBJ_IS_STR(args[0])); assert(MP_OBJ_IS_STR(args[1])); @@ -392,7 +399,6 @@ STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { machine_uint_t start = 0; machine_uint_t end = haystack_len; - /* TODO use a non-exception-throwing mp_get_index */ if (n_args >= 3 && args[2] != mp_const_none) { start = mp_get_index(&str_type, haystack_len, args[2], true); } @@ -400,20 +406,24 @@ STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { end = mp_get_index(&str_type, haystack_len, args[3], true); } - const byte *p = find_subbytes(haystack + start, haystack_len - start, needle, needle_len); + const byte *p = find_subbytes(haystack + start, end - start, needle, needle_len, direction); if (p == NULL) { // not found return MP_OBJ_NEW_SMALL_INT(-1); } else { // found - machine_int_t pos = p - haystack; - if (pos + needle_len > end) { - pos = -1; - } - return MP_OBJ_NEW_SMALL_INT(pos); + return MP_OBJ_NEW_SMALL_INT(p - haystack); } } +STATIC mp_obj_t str_find(uint n_args, const mp_obj_t *args) { + return str_finder(n_args, args, 1); +} + +STATIC mp_obj_t str_rfind(uint n_args, const mp_obj_t *args) { + return str_finder(n_args, args, -1); +} + // TODO: (Much) more variety in args STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) { GET_STR_DATA_LEN(self_in, str, str_len); @@ -424,15 +434,6 @@ STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) { return MP_BOOL(memcmp(str, prefix, prefix_len) == 0); } -STATIC bool chr_in_str(const byte* const str, const machine_uint_t str_len, int c) { - for (machine_uint_t i = 0; i < str_len; i++) { - if (str[i] == c) { - return true; - } - } - return false; -} - STATIC mp_obj_t str_strip(uint n_args, const mp_obj_t *args) { assert(1 <= n_args && n_args <= 2); assert(MP_OBJ_IS_STR(args[0])); @@ -457,7 +458,7 @@ STATIC mp_obj_t str_strip(uint n_args, const mp_obj_t *args) { bool first_good_char_pos_set = false; machine_uint_t last_good_char_pos = 0; for (machine_uint_t i = 0; i < orig_str_len; i++) { - if (!chr_in_str(chars_to_del, chars_to_del_len, orig_str[i])) { + if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) { last_good_char_pos = i; if (!first_good_char_pos_set) { first_good_char_pos = i; @@ -547,7 +548,7 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) { const byte *old_occurrence; const byte *offset_ptr = str; machine_uint_t offset_num = 0; - while ((old_occurrence = find_subbytes(offset_ptr, str_len - offset_num, old, old_len)) != NULL) { + while ((old_occurrence = find_subbytes(offset_ptr, str_len - offset_num, old, old_len, 1)) != NULL) { // copy from just after end of last occurrence of to-be-replaced string to right before start of next occurrence if (data != NULL) { memcpy(data + replaced_str_index, offset_ptr, old_occurrence - offset_ptr); @@ -601,7 +602,6 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) { machine_uint_t start = 0; machine_uint_t end = haystack_len; - /* TODO use a non-exception-throwing mp_get_index */ if (n_args >= 3 && args[2] != mp_const_none) { start = mp_get_index(&str_type, haystack_len, args[2], true); } @@ -648,27 +648,12 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t di result[2] = self_in; } - if (str_len >= sep_len) { - machine_uint_t str_index, str_index_end; - if (direction > 0) { - str_index = 0; - str_index_end = str_len - sep_len; - } else { - str_index = str_len - sep_len; - str_index_end = 0; - } - for (;;) { - if (memcmp(&str[str_index], sep, sep_len) == 0) { - result[0] = mp_obj_new_str(str, str_index, false); - result[1] = arg; - result[2] = mp_obj_new_str(str + str_index + sep_len, str_len - str_index - sep_len, false); - break; - } - if (str_index == str_index_end) { - break; - } - str_index += direction; - } + const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction); + if (position_ptr != NULL) { + machine_uint_t position = position_ptr - str; + result[0] = mp_obj_new_str(str, position, false); + result[1] = arg; + result[2] = mp_obj_new_str(str + position + sep_len, str_len - position - sep_len, false); } return mp_obj_new_tuple(3, result); @@ -697,6 +682,7 @@ STATIC machine_int_t str_get_buffer(mp_obj_t self_in, buffer_info_t *bufinfo, in } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind); STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split); STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith); @@ -709,6 +695,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); STATIC const mp_method_t str_type_methods[] = { { "find", &str_find_obj }, + { "rfind", &str_rfind_obj }, { "join", &str_join_obj }, { "split", &str_split_obj }, { "startswith", &str_startswith_obj }, diff --git a/py/objtype.c b/py/objtype.c index 4898c5ccb4..9cb29744c7 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -469,7 +469,7 @@ mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj) { // object and classinfo should be type objects // (but the function will fail gracefully if they are not) -bool mp_obj_is_subclass_fast(mp_obj_t object, mp_obj_t classinfo) { +bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { for (;;) { if (object == classinfo) { return true; @@ -482,7 +482,7 @@ bool mp_obj_is_subclass_fast(mp_obj_t object, mp_obj_t classinfo) { return false; } - mp_obj_type_t *self = object; + const mp_obj_type_t *self = object; // for a const struct, this entry might be NULL if (self->bases_tuple == MP_OBJ_NULL) { @@ -74,8 +74,11 @@ PY_O_BASENAME = \ builtin.o \ builtinimport.o \ builtinevex.o \ - builtinmp.o \ - builtinmath.o \ + builtintables.o \ + modarray.o \ + modcollections.o \ + modmath.o \ + modmicropython.o \ vm.o \ showbc.o \ repl.o \ @@ -18,7 +18,7 @@ // A qstr is an index into the qstr pool. // The data for a qstr contains (hash, length, data). // For now we use very simple encoding, just to get the framework correct: -// - hash is 2 bytes (simply the sum of data bytes) +// - hash is 2 bytes (see function below) // - length is 2 bytes // - data follows // - \0 terminated (for now, so they can be printed using printf) @@ -28,10 +28,12 @@ #define Q_GET_LENGTH(q) ((q)[2] | ((q)[3] << 8)) #define Q_GET_DATA(q) ((q) + 4) +// this must match the equivalent function in makeqstrdata.py machine_uint_t qstr_compute_hash(const byte *data, uint len) { - machine_uint_t hash = 0; + // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html + machine_uint_t hash = 5381; for (const byte *top = data + len; data < top; data++) { - hash += *data; + hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data } return hash & 0xffff; } diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 898e67582f..1c8afe797d 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -17,6 +17,7 @@ Q(__repl_print__) Q(__bool__) Q(__len__) +Q(__iter__) Q(__getitem__) Q(__setitem__) Q(__add__) @@ -39,7 +40,6 @@ Q(AssertionError) Q(AttributeError) Q(BufferError) Q(EOFError) -Q(EnvironmentError) Q(Exception) Q(FileExistsError) Q(FileNotFoundError) @@ -56,16 +56,12 @@ Q(NameError) Q(NotImplementedError) Q(OSError) Q(OverflowError) -Q(ReferenceError) Q(RuntimeError) Q(SyntaxError) Q(SystemError) -Q(SystemExit) -Q(TabError) Q(TypeError) Q(UnboundLocalError) Q(ValueError) -Q(Warning) Q(ZeroDivisionError) Q(None) @@ -78,6 +74,7 @@ Q(NoneType) Q(abs) Q(all) Q(any) +Q(args) Q(array) Q(bool) Q(bytearray) @@ -123,6 +120,7 @@ Q(str) Q(sys) Q(tuple) Q(type) +Q(value) Q(zip) Q(append) 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, diff --git a/py/runtime.h b/py/runtime.h index 7215cc8890..3980e50cc0 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -12,6 +12,7 @@ mp_obj_t rt_get_cell(mp_obj_t cell); void rt_set_cell(mp_obj_t cell, mp_obj_t val); void rt_store_name(qstr qstr, mp_obj_t obj); void rt_store_global(qstr qstr, mp_obj_t obj); +void rt_delete_name(qstr qstr); mp_obj_t rt_unary_op(int op, mp_obj_t arg); mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs); mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args); @@ -124,6 +124,7 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i // outer exception handling loop for (;;) { +outer_dispatch_loop: if (nlr_push(&nlr) == 0) { // If we have exception to inject, now that we finish setting up // execution context, raise it. This works as if RAISE_VARARGS @@ -283,6 +284,11 @@ dispatch_loop: sp -= 3; break; + case MP_BC_DELETE_NAME: + DECODE_QSTR; + rt_delete_name(qst); + break; + case MP_BC_DUP_TOP: obj1 = TOP(); PUSH(obj1); @@ -637,6 +643,15 @@ unwind_return: } else { // exception occurred + // check if it's a StopIteration within a for block + if (*save_ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) { + ip = save_ip + 1; + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + --sp; // pop the exhausted iterator + ip += unum; // jump to after for-block + goto outer_dispatch_loop; // continue with dispatch loop + } + // set file and line number that the exception occurred at // TODO: don't set traceback for exceptions re-raised by END_FINALLY. // But consider how to handle nested exceptions. |