Merge branch 'master' of github.com:micropython/micropython
This commit is contained in:
commit
c42e4b6c53
|
@ -19,6 +19,13 @@
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "builtin.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 '/'
|
#define PATH_SEP_CHAR '/'
|
||||||
|
|
||||||
mp_obj_t mp_sys_path;
|
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) {
|
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||||
/*
|
#if DEBUG_PRINT
|
||||||
printf("import:\n");
|
printf("__import__:\n");
|
||||||
for (int i = 0; i < n_args; i++) {
|
for (int i = 0; i < n_args; i++) {
|
||||||
printf(" ");
|
printf(" ");
|
||||||
mp_obj_print(args[i], PRINT_REPR);
|
mp_obj_print(args[i], PRINT_REPR);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
*/
|
#endif
|
||||||
|
|
||||||
mp_obj_t fromtuple = mp_const_none;
|
mp_obj_t fromtuple = mp_const_none;
|
||||||
int level = 0;
|
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
|
// check if module already exists
|
||||||
mp_obj_t module_obj = mp_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 (module_obj != MP_OBJ_NULL) {
|
||||||
|
DEBUG_printf("Module already loaded\n");
|
||||||
// If it's not a package, return module right away
|
// If it's not a package, return module right away
|
||||||
char *p = strchr(mod_str, '.');
|
char *p = strchr(mod_str, '.');
|
||||||
if (p == NULL) {
|
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);
|
qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
|
||||||
return mp_module_get(pkg_name);
|
return mp_module_get(pkg_name);
|
||||||
}
|
}
|
||||||
|
DEBUG_printf("Module not yet loaded\n");
|
||||||
|
|
||||||
uint last = 0;
|
uint last = 0;
|
||||||
VSTR_FIXED(path, MICROPY_PATH_MAX)
|
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] == '.') {
|
if (i == mod_len || mod_str[i] == '.') {
|
||||||
// create a qstr for the module name up to this depth
|
// create a qstr for the module name up to this depth
|
||||||
qstr mod_name = qstr_from_strn(mod_str, i);
|
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
|
// find the file corresponding to the module name
|
||||||
mp_import_stat_t stat;
|
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);
|
module_obj = mp_obj_new_module(mod_name);
|
||||||
|
|
||||||
if (stat == MP_IMPORT_STAT_DIR) {
|
if (stat == MP_IMPORT_STAT_DIR) {
|
||||||
|
DEBUG_printf("%s is dir\n", vstr_str(&path));
|
||||||
vstr_add_char(&path, PATH_SEP_CHAR);
|
vstr_add_char(&path, PATH_SEP_CHAR);
|
||||||
vstr_add_str(&path, "__init__.py");
|
vstr_add_str(&path, "__init__.py");
|
||||||
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
|
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);
|
do_load(module_obj, &path);
|
||||||
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
|
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
|
} else { // MP_IMPORT_STAT_FILE
|
||||||
do_load(module_obj, &path);
|
do_load(module_obj, &path);
|
||||||
// TODO: We cannot just break here, at the very least, we must execute
|
// TODO: We cannot just break here, at the very least, we must execute
|
||||||
|
|
|
@ -26,10 +26,10 @@ def compute_hash(qstr):
|
||||||
def do_work(infiles):
|
def do_work(infiles):
|
||||||
# read the qstrs in from the input files
|
# read the qstrs in from the input files
|
||||||
qstrs = {}
|
qstrs = {}
|
||||||
|
cpp_header_blocks = 3
|
||||||
for infile in infiles:
|
for infile in infiles:
|
||||||
with open(infile, 'rt') as f:
|
with open(infile, 'rt') as f:
|
||||||
line_number = 0
|
line_number = 0
|
||||||
conditional = None
|
|
||||||
for line in f:
|
for line in f:
|
||||||
line_number += 1
|
line_number += 1
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
@ -38,17 +38,13 @@ def do_work(infiles):
|
||||||
if len(line) == 0 or line.startswith('//'):
|
if len(line) == 0 or line.startswith('//'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if line[0] == '#':
|
# We'll have 3 line-number lines for py/qstrdefs.h - initial, leaving it to
|
||||||
if conditional == "<endif>":
|
# go into other headers, and returning to it.
|
||||||
assert line == "#endif"
|
if line.startswith('# ') and 'py/qstrdefs.h' in line:
|
||||||
conditional = None
|
cpp_header_blocks -= 1
|
||||||
else:
|
continue
|
||||||
assert conditional is None
|
if cpp_header_blocks != 0:
|
||||||
conditional = line
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if conditional == "<endif>":
|
|
||||||
assert False, "#endif expected before '%s'" % line
|
|
||||||
|
|
||||||
# verify line is of the correct form
|
# verify line is of the correct form
|
||||||
match = re.match(r'Q\((.+)\)$', line)
|
match = re.match(r'Q\((.+)\)$', line)
|
||||||
|
@ -65,21 +61,15 @@ def do_work(infiles):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# add the qstr to the list, with order number to retain original order in file
|
# add the qstr to the list, with order number to retain original order in file
|
||||||
qstrs[ident] = (len(qstrs), ident, qstr, conditional)
|
qstrs[ident] = (len(qstrs), ident, qstr)
|
||||||
if conditional is not None:
|
|
||||||
conditional = "<endif>"
|
|
||||||
|
|
||||||
# process the qstrs, printing out the generated C header file
|
# process the qstrs, printing out the generated C header file
|
||||||
print('// This file was automatically generated by makeqstrdata.py')
|
print('// This file was automatically generated by makeqstrdata.py')
|
||||||
print('')
|
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)
|
qhash = compute_hash(qstr)
|
||||||
qlen = len(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))
|
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
|
return True
|
||||||
|
|
||||||
|
|
5
py/py.mk
5
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
|
# Adding an order only dependency on $(PY_BUILD) causes $(PY_BUILD) to get
|
||||||
# created before we run the script to generate the .h
|
# created before we run the script to generate the .h
|
||||||
$(PY_BUILD)/qstrdefs.generated.h: | $(PY_BUILD)/
|
$(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)"
|
$(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
|
# 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
|
# it is #included from str.h). The compiler generated dependencies will cause
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
#include "mpconfig.h"
|
||||||
// All the qstr definitions in this file are available as constants.
|
// 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.
|
// 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(__build_class__)
|
||||||
Q(__class__)
|
Q(__class__)
|
||||||
|
@ -13,6 +13,7 @@ Q(__module__)
|
||||||
Q(__name__)
|
Q(__name__)
|
||||||
Q(__next__)
|
Q(__next__)
|
||||||
Q(__qualname__)
|
Q(__qualname__)
|
||||||
|
Q(__path__)
|
||||||
Q(__repl_print__)
|
Q(__repl_print__)
|
||||||
|
|
||||||
Q(__bool__)
|
Q(__bool__)
|
||||||
|
|
44
py/runtime.c
44
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) {
|
mp_obj_t mp_import_from(mp_obj_t module, qstr name) {
|
||||||
DEBUG_printf("import from %p %s\n", module, qstr_str(name));
|
DEBUG_printf("import from %p %s\n", module, qstr_str(name));
|
||||||
|
|
||||||
mp_obj_t x = mp_load_attr(module, name);
|
mp_obj_t dest[2];
|
||||||
/* TODO convert AttributeError to ImportError
|
|
||||||
if (fail) {
|
mp_load_method_maybe(module, name, dest);
|
||||||
(ImportError, "cannot import name %s", qstr_str(name), NULL)
|
|
||||||
|
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)));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return x;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
void mp_import_all(mp_obj_t module) {
|
||||||
|
|
|
@ -101,11 +101,20 @@ void mp_byte_code_print(const byte *ip, int len) {
|
||||||
printf("LOAD_CONST_ID %s", qstr_str(qstr));
|
printf("LOAD_CONST_ID %s", qstr_str(qstr));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MP_BC_LOAD_CONST_BYTES:
|
||||||
|
DECODE_QSTR;
|
||||||
|
printf("LOAD_CONST_BYTES %s", qstr_str(qstr));
|
||||||
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_CONST_STRING:
|
case MP_BC_LOAD_CONST_STRING:
|
||||||
DECODE_QSTR;
|
DECODE_QSTR;
|
||||||
printf("LOAD_CONST_STRING %s", qstr_str(qstr));
|
printf("LOAD_CONST_STRING %s", qstr_str(qstr));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MP_BC_LOAD_NULL:
|
||||||
|
printf("LOAD_NULL");
|
||||||
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_FAST_0:
|
case MP_BC_LOAD_FAST_0:
|
||||||
printf("LOAD_FAST_0");
|
printf("LOAD_FAST_0");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
from pkg import mod
|
||||||
|
|
||||||
|
print(mod.foo())
|
||||||
|
|
||||||
|
import pkg.mod
|
||||||
|
print(mod is pkg.mod)
|
Loading…
Reference in New Issue