summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/builtinimport.c20
-rw-r--r--py/makeqstrdata.py28
-rw-r--r--py/py.mk5
-rw-r--r--py/qstrdefs.h3
-rw-r--r--py/runtime.c44
-rw-r--r--py/showbc.c9
6 files changed, 78 insertions, 31 deletions
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 5102a9bde..501ced764 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -19,6 +19,13 @@
#include "runtime.h"
#include "builtin.h"
+#if 0 // print debugging info
+#define DEBUG_PRINT (1)
+#define DEBUG_printf DEBUG_printf
+#else // don't print debugging info
+#define DEBUG_printf(...) (void)0
+#endif
+
#define PATH_SEP_CHAR '/'
mp_obj_t mp_sys_path;
@@ -129,14 +136,14 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
}
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
- /*
- printf("import:\n");
+#if DEBUG_PRINT
+ printf("__import__:\n");
for (int i = 0; i < n_args; i++) {
printf(" ");
mp_obj_print(args[i], PRINT_REPR);
printf("\n");
}
- */
+#endif
mp_obj_t fromtuple = mp_const_none;
int level = 0;
@@ -158,6 +165,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
// check if module already exists
mp_obj_t module_obj = mp_module_get(mp_obj_str_get_qstr(args[0]));
if (module_obj != MP_OBJ_NULL) {
+ DEBUG_printf("Module already loaded\n");
// If it's not a package, return module right away
char *p = strchr(mod_str, '.');
if (p == NULL) {
@@ -171,6 +179,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
return mp_module_get(pkg_name);
}
+ DEBUG_printf("Module not yet loaded\n");
uint last = 0;
VSTR_FIXED(path, MICROPY_PATH_MAX)
@@ -182,6 +191,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
if (i == mod_len || mod_str[i] == '.') {
// create a qstr for the module name up to this depth
qstr mod_name = qstr_from_strn(mod_str, i);
+ DEBUG_printf("Processing module: %s\n", qstr_str(mod_name));
// find the file corresponding to the module name
mp_import_stat_t stat;
@@ -207,6 +217,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
module_obj = mp_obj_new_module(mod_name);
if (stat == MP_IMPORT_STAT_DIR) {
+ DEBUG_printf("%s is dir\n", vstr_str(&path));
vstr_add_char(&path, PATH_SEP_CHAR);
vstr_add_str(&path, "__init__.py");
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
@@ -217,6 +228,9 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
}
do_load(module_obj, &path);
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
+ // https://docs.python.org/3.3/reference/import.html
+ // "Specifically, any module that contains a __path__ attribute is considered a package."
+ mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str((byte*)vstr_str(&path), vstr_len(&path), false));
} else { // MP_IMPORT_STAT_FILE
do_load(module_obj, &path);
// TODO: We cannot just break here, at the very least, we must execute
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index e60f00044..81b003545 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -26,10 +26,10 @@ def compute_hash(qstr):
def do_work(infiles):
# read the qstrs in from the input files
qstrs = {}
+ cpp_header_blocks = 3
for infile in infiles:
with open(infile, 'rt') as f:
line_number = 0
- conditional = None
for line in f:
line_number += 1
line = line.strip()
@@ -38,17 +38,13 @@ def do_work(infiles):
if len(line) == 0 or line.startswith('//'):
continue
- if line[0] == '#':
- if conditional == "<endif>":
- assert line == "#endif"
- conditional = None
- else:
- assert conditional is None
- conditional = line
+ # We'll have 3 line-number lines for py/qstrdefs.h - initial, leaving it to
+ # go into other headers, and returning to it.
+ if line.startswith('# ') and 'py/qstrdefs.h' in line:
+ cpp_header_blocks -= 1
+ continue
+ if cpp_header_blocks != 0:
continue
-
- if conditional == "<endif>":
- assert False, "#endif expected before '%s'" % line
# verify line is of the correct form
match = re.match(r'Q\((.+)\)$', line)
@@ -65,21 +61,15 @@ def do_work(infiles):
continue
# add the qstr to the list, with order number to retain original order in file
- qstrs[ident] = (len(qstrs), ident, qstr, conditional)
- if conditional is not None:
- conditional = "<endif>"
+ qstrs[ident] = (len(qstrs), ident, qstr)
# process the qstrs, printing out the generated C header file
print('// This file was automatically generated by makeqstrdata.py')
print('')
- for order, ident, qstr, conditional in sorted(qstrs.values(), key=lambda x: x[0]):
+ for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
qhash = compute_hash(qstr)
qlen = len(qstr)
- if conditional:
- print(conditional)
print('Q({}, (const byte*)"\\x{:02x}\\x{:02x}\\x{:02x}\\x{:02x}" "{}")'.format(ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen & 0xff, (qlen >> 8) & 0xff, qstr))
- if conditional:
- print('#endif')
return True
diff --git a/py/py.mk b/py/py.mk
index ecc4a6a0d..23ba9ebe7 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -104,9 +104,10 @@ $(PY_BUILD)/py-version.h: FORCE
# Adding an order only dependency on $(PY_BUILD) causes $(PY_BUILD) to get
# created before we run the script to generate the .h
$(PY_BUILD)/qstrdefs.generated.h: | $(PY_BUILD)/
-$(PY_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(PY_SRC)/makeqstrdata.py
+$(PY_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(PY_SRC)/mpconfig.h
$(ECHO) "makeqstrdata $(PY_QSTR_DEFS) $(QSTR_DEFS)"
- $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(PY_QSTR_DEFS) $(QSTR_DEFS) > $@
+ $(CPP) $(CFLAGS) $(PY_QSTR_DEFS) -o $(PY_BUILD)/qstrdefs.preprocessed.h
+ $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(PY_BUILD)/qstrdefs.preprocessed.h $(QSTR_DEFS) > $@
# We don't know which source files actually need the generated.h (since
# it is #included from str.h). The compiler generated dependencies will cause
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 17948434b..d52b870e6 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -1,6 +1,6 @@
+#include "mpconfig.h"
// All the qstr definitions in this file are available as constants.
// That is, they are in ROM and you can reference them simply as MP_QSTR_xxxx.
-// TODO make it so we can use #defines here to select only those words that will be used
Q(__build_class__)
Q(__class__)
@@ -13,6 +13,7 @@ Q(__module__)
Q(__name__)
Q(__next__)
Q(__qualname__)
+Q(__path__)
Q(__repl_print__)
Q(__bool__)
diff --git a/py/runtime.c b/py/runtime.c
index 499905a0f..4793f054a 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1043,13 +1043,45 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) {
mp_obj_t mp_import_from(mp_obj_t module, qstr name) {
DEBUG_printf("import from %p %s\n", module, qstr_str(name));
- mp_obj_t x = mp_load_attr(module, name);
- /* TODO convert AttributeError to ImportError
- if (fail) {
- (ImportError, "cannot import name %s", qstr_str(name), NULL)
+ mp_obj_t dest[2];
+
+ mp_load_method_maybe(module, name, dest);
+
+ if (dest[1] != MP_OBJ_NULL) {
+ // Hopefully we can't import bound method from an object
+import_error:
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "Cannot import name '%s'", qstr_str(name)));
+ }
+
+ if (dest[0] != MP_OBJ_NULL) {
+ return dest[0];
+ }
+
+ // See if it's a package, then can try FS import
+ mp_load_method_maybe(module, MP_QSTR___path__, dest);
+ if (dest[0] == MP_OBJ_NULL) {
+ goto import_error;
}
- */
- return x;
+
+ mp_load_method_maybe(module, MP_QSTR___name__, dest);
+ uint pkg_name_len;
+ const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len);
+
+ char dot_name[pkg_name_len + 1 + qstr_len(name)];
+ memcpy(dot_name, pkg_name, pkg_name_len);
+ dot_name[pkg_name_len] = '.';
+ memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name));
+ qstr dot_name_q = qstr_from_strn(dot_name, sizeof(dot_name));
+
+ mp_obj_t args[5];
+ args[0] = MP_OBJ_NEW_QSTR(dot_name_q);
+ args[1] = mp_const_none; // TODO should be globals
+ args[2] = mp_const_none; // TODO should be locals
+ args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module
+ args[4] = 0;
+
+ // TODO lookup __import__ and call that instead of going straight to builtin implementation
+ return mp_builtin___import__(5, args);
}
void mp_import_all(mp_obj_t module) {
diff --git a/py/showbc.c b/py/showbc.c
index c1e420f43..08dec1e2b 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -101,11 +101,20 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("LOAD_CONST_ID %s", qstr_str(qstr));
break;
+ case MP_BC_LOAD_CONST_BYTES:
+ DECODE_QSTR;
+ printf("LOAD_CONST_BYTES %s", qstr_str(qstr));
+ break;
+
case MP_BC_LOAD_CONST_STRING:
DECODE_QSTR;
printf("LOAD_CONST_STRING %s", qstr_str(qstr));
break;
+ case MP_BC_LOAD_NULL:
+ printf("LOAD_NULL");
+ break;
+
case MP_BC_LOAD_FAST_0:
printf("LOAD_FAST_0");
break;