summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Sokolovsky <pfalcon@users.sourceforge.net>2014-01-20 00:03:34 +0200
committerPaul Sokolovsky <pfalcon@users.sourceforge.net>2014-01-20 00:38:39 +0200
commitd720ab5236015124a13c09175ed674e565414faa (patch)
tree201a5cca563eaad2e76651add86b8dc4de923c1a
parentf438b936e0edcbc3eab9af6cc3513db1f01ab17e (diff)
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.c7
-rw-r--r--py/obj.h1
-rw-r--r--py/objmodule.c22
3 files changed, 29 insertions, 1 deletions
diff --git a/py/builtinimport.c b/py/builtinimport.c
index e3c630a0a..92d5d5ac9 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
diff --git a/py/obj.h b/py/obj.h
index 510108eed..11ec4afe8 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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 e97e73192..fb7842e5a 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;