py: Allow builtins to be overridden.
This patch adds a configuration option (MICROPY_CAN_OVERRIDE_BUILTINS)
which, when enabled, allows to override all names within the builtins
module. A builtins override dict is created the first time the user
assigns to a name in the builtins model, and then that dict is searched
first on subsequent lookups. Note that this implementation doesn't
allow deleting of names.
This patch also does some refactoring of builtins code, creating the
modbuiltins.c file.
Addresses issue #959.
diff --git a/py/objmodule.c b/py/objmodule.c
index 7f765ff..5ffb368 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -34,7 +34,7 @@
#include "obj.h"
#include "objmodule.h"
#include "runtime.h"
-#include "builtintables.h"
+#include "builtin.h"
STATIC mp_map_t mp_loaded_modules_map; // TODO: expose as sys.modules
@@ -65,13 +65,28 @@
STATIC bool module_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
mp_obj_module_t *self = self_in;
+ mp_obj_dict_t *dict = self->globals;
+ if (dict->map.table_is_fixed_array) {
+ #if MICROPY_CAN_OVERRIDE_BUILTINS
+ if (dict == &mp_module_builtins_globals) {
+ if (mp_module_builtins_override_dict == NULL) {
+ mp_module_builtins_override_dict = mp_obj_new_dict(1);
+ }
+ dict = mp_module_builtins_override_dict;
+ } else
+ #endif
+ {
+ // can't delete or store to fixed map
+ return false;
+ }
+ }
if (value == MP_OBJ_NULL) {
// delete attribute
- mp_obj_dict_delete(self->globals, MP_OBJ_NEW_QSTR(attr));
+ mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr));
} else {
// store attribute
// TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
- mp_obj_dict_store(self->globals, MP_OBJ_NEW_QSTR(attr), value);
+ mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), value);
}
return true;
}
@@ -117,6 +132,69 @@
/******************************************************************************/
// Global module table and related functions
+STATIC const mp_map_elem_t mp_builtin_module_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___main__), (mp_obj_t)&mp_module___main__ },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_builtins), (mp_obj_t)&mp_module_builtins },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
+
+#if MICROPY_PY_ARRAY
+ { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array },
+#endif
+#if MICROPY_PY_IO
+ { MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
+#endif
+#if MICROPY_PY_COLLECTIONS
+ { MP_OBJ_NEW_QSTR(MP_QSTR__collections), (mp_obj_t)&mp_module_collections },
+#endif
+#if MICROPY_PY_STRUCT
+ { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_struct },
+#endif
+
+#if MICROPY_PY_BUILTINS_FLOAT
+#if MICROPY_PY_MATH
+ { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&mp_module_math },
+#endif
+#if MICROPY_PY_CMATH
+ { MP_OBJ_NEW_QSTR(MP_QSTR_cmath), (mp_obj_t)&mp_module_cmath },
+#endif
+#endif
+#if MICROPY_PY_SYS
+ { MP_OBJ_NEW_QSTR(MP_QSTR_sys), (mp_obj_t)&mp_module_sys },
+#endif
+#if MICROPY_PY_GC && MICROPY_ENABLE_GC
+ { MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&mp_module_gc },
+#endif
+
+ // extmod modules
+
+#if MICROPY_PY_UCTYPES
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
+#endif
+#if MICROPY_PY_UZLIB
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uzlib), (mp_obj_t)&mp_module_uzlib },
+#endif
+#if MICROPY_PY_UJSON
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
+#endif
+#if MICROPY_PY_URE
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ure), (mp_obj_t)&mp_module_ure },
+#endif
+#if MICROPY_PY_UHEAPQ
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uheapq), (mp_obj_t)&mp_module_uheapq },
+#endif
+#if MICROPY_PY_UHASHLIB
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib },
+#endif
+#if MICROPY_PY_UBINASCII
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii), (mp_obj_t)&mp_module_ubinascii },
+#endif
+
+ // extra builtin modules as defined by a port
+ MICROPY_PORT_BUILTIN_MODULES
+};
+
+STATIC MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
+
void mp_module_init(void) {
mp_map_init(&mp_loaded_modules_map, 3);
}
@@ -132,7 +210,7 @@
if (el == NULL) {
// module not found, look for builtin module names
- el = mp_map_lookup((mp_map_t*)&mp_builtin_module_dict_obj.map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
+ el = mp_map_lookup((mp_map_t*)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
if (el == NULL) {
return MP_OBJ_NULL;
}