summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/builtin.h6
-rw-r--r--py/builtinimport.c9
-rw-r--r--py/builtintables.c150
-rw-r--r--py/builtintables.h2
-rw-r--r--py/makeqstrdata.py4
-rw-r--r--py/modarray.c25
-rw-r--r--py/modcollections.c25
-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.h8
-rw-r--r--py/obj.c28
-rw-r--r--py/obj.h44
-rw-r--r--py/objarray.c12
-rw-r--r--py/objexcept.c66
-rw-r--r--py/objmodule.c45
-rw-r--r--py/objmodule.h4
-rw-r--r--py/objstr.c91
-rw-r--r--py/objtype.c4
-rw-r--r--py/py.mk7
-rw-r--r--py/qstr.c8
-rw-r--r--py/qstrdefs.h8
-rw-r--r--py/runtime.c187
-rw-r--r--py/runtime.h1
-rw-r--r--py/vm.c15
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 */
diff --git a/py/obj.c b/py/obj.c
index 717df51641..18f66a2b47 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -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)));
}
}
diff --git a/py/obj.h b/py/obj.h
index 9599d137dd..0a8b80e30b 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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) {
diff --git a/py/py.mk b/py/py.mk
index 624797d823..2247b6babb 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -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 \
diff --git a/py/qstr.c b/py/qstr.c
index aebc2921cf..e4b5c111b5 100644
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -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);
diff --git a/py/vm.c b/py/vm.c
index 48c4bdf04b..8ae619f9be 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -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.