diff options
author | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2014-01-20 00:03:34 +0200 |
---|---|---|
committer | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2014-01-20 00:38:39 +0200 |
commit | d720ab5236015124a13c09175ed674e565414faa (patch) | |
tree | 201a5cca563eaad2e76651add86b8dc4de923c1a | |
parent | f438b936e0edcbc3eab9af6cc3513db1f01ab17e (diff) | |
download | micropython-d720ab5236015124a13c09175ed674e565414faa.tar.gz micropython-d720ab5236015124a13c09175ed674e565414faa.zip |
Implement modules as singletons Python semantics.
In Python, importing module several times returns same underlying module
object. This also fixes import statement handling for builtin modules.
There're still issues:
1. CPython exposes set of loaded modules as sys.modules, we may want to
do that either.
2. Builtin modules are implicitly imported, which is not really correct.
We should separate registering a (builtin) module and importing a module.
CPython keeps builtin module names in sys.builtin_module_names .
-rw-r--r-- | py/builtinimport.c | 7 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objmodule.c | 22 |
3 files changed, 29 insertions, 1 deletions
diff --git a/py/builtinimport.c b/py/builtinimport.c index e3c630a0a4..92d5d5ac9f 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -28,8 +28,13 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { } */ - // find the file to import qstr mod_name = mp_obj_get_qstr(args[0]); + mp_obj_t loaded = mp_obj_module_get(mod_name); + if (loaded != MP_OBJ_NULL) { + return loaded; + } + + // find the file to import mp_lexer_t *lex = mp_import_open_file(mod_name); if (lex == NULL) { // TODO handle lexer error correctly @@ -356,6 +356,7 @@ extern const mp_obj_type_t gen_instance_type; // module extern const mp_obj_type_t module_type; 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/objmodule.c b/py/objmodule.c index e97e731929..fb7842e5af 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -17,6 +17,9 @@ typedef struct _mp_obj_module_t { mp_map_t *globals; } mp_obj_module_t; +// TODO: expose as sys.modules +static mp_map_t *loaded_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; print(env, "<module '%s' from '-unknown-file-'>", qstr_str(self->name)); @@ -46,14 +49,33 @@ const mp_obj_type_t module_type = { }; mp_obj_t mp_obj_new_module(qstr module_name) { + if (loaded_modules == NULL) { + loaded_modules = mp_map_new(1); + } + mp_map_elem_t *el = mp_map_lookup(loaded_modules, 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) { + return el->value; + } + mp_obj_module_t *o = m_new_obj(mp_obj_module_t); o->base.type = &module_type; o->name = module_name; o->globals = mp_map_new(1); + el->value = o; mp_map_lookup(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = mp_obj_new_str(module_name); return o; } +mp_obj_t mp_obj_module_get(qstr module_name) { + mp_map_elem_t *el = mp_map_lookup(loaded_modules, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + if (el == NULL) { + return NULL; + } + return el->value; +} + mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &module_type)); mp_obj_module_t *self = self_in; |