ports/sh: make filesystem imports relative to current file

This commit is contained in:
Lephenixnoir 2023-12-17 18:47:26 +01:00
parent 5b52671c50
commit 61b2360b16
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
6 changed files with 70 additions and 3 deletions

View File

@ -22,6 +22,10 @@ extern const struct _mp_print_t mp_debug_print;
#define MICROPY_DEBUG_PRINTER (&mp_debug_print)
#endif
/* Custom option to use relative imports. For instance when working at the fs
root, 'import b' in '/folder/a.py' will import 'folder/b.py' not '/b.py'. */
#define MICROPY_RELATIVE_FILE_IMPORTS (1)
/* General feature set selection
Other options: BASIC_FEATURES, EXTRA_FEATURES, FULL_FEATURES, EVERYTHING */
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)

View File

@ -444,6 +444,7 @@ STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name,
} else {
// No-op. Nothing to load.
// mp_warning("%s is imported as namespace package", vstr_str(&path));
DEBUG_printf("%s is imported as namespace package\n", vstr_str(path));
}
// Remove /__init__.py suffix.
path->len = orig_path_len;
@ -522,6 +523,23 @@ mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) {
mp_obj_t top_module_obj = MP_OBJ_NULL;
mp_obj_t outer_module_obj = MP_OBJ_NULL;
#if MICROPY_RELATIVE_FILE_IMPORTS
size_t is_len;
mp_obj_t *is_items;
mp_obj_list_get(MP_STATE_VM(mp_import_stack), &is_len, &is_items);
if(is_len > 0) {
// Start next to last import
char const *prev = qstr_str(MP_OBJ_QSTR_VALUE(is_items[is_len - 1]));
char const *slash = strchr(prev, '/');
int prev_len = (slash ? slash : prev) - prev;
vstr_add_strn(&path, prev, prev_len);
outer_module_obj = mp_obj_new_module(MP_QSTR___blankmodule);
mp_store_attr(outer_module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));
DEBUG_printf("last import was '%s'\n", prev);
DEBUG_printf("starting in '%.*s'\n", (int)vstr_len(&path), vstr_str(&path));
}
#endif
// Search for the end of each component.
size_t current_component_start = 0;
for (size_t i = 1; i <= module_name_len; i++) {

View File

@ -176,6 +176,11 @@ typedef struct _mp_state_vm_t {
mp_obj_dict_t *mp_module_builtins_override_dict;
#endif
// list (stack) of nested imports for relative import resolution
#if MICROPY_RELATIVE_FILE_IMPORTS
mp_obj_t mp_import_stack;
#endif
// Include any root pointers registered with MP_REGISTER_ROOT_POINTER().
#ifndef NO_QSTR
// Only include root pointer definitions when not doing qstr extraction, because

View File

@ -1116,6 +1116,7 @@ mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
// list
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value);
mp_obj_t mp_obj_list_pop(mp_obj_t self_in, mp_obj_t index);
void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items);
void mp_obj_list_set_len(mp_obj_t self_in, size_t len);
void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);

View File

@ -290,6 +290,12 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) {
return ret;
}
mp_obj_t mp_obj_list_pop(mp_obj_t self_in, mp_obj_t index)
{
mp_obj_t args[] = {self_in, index};
return list_pop(2, args);
}
STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) {
MP_STACK_CHECK();
while (head < tail) {

View File

@ -119,6 +119,10 @@ void mp_init(void) {
MP_STATE_VM(mp_module_builtins_override_dict) = NULL;
#endif
#if MICROPY_RELATIVE_FILE_IMPORTS
MP_STATE_VM(mp_import_stack) = mp_obj_new_list(0, NULL);
#endif
#if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE
MP_STATE_VM(track_reloc_code_list) = MP_OBJ_NULL;
#endif
@ -1585,13 +1589,28 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i
mp_globals_set(globals);
mp_locals_set(locals);
#if MICROPY_RELATIVE_FILE_IMPORTS
char const *volatile name = qstr_str(lex->source_name);
(void)name;
if (parse_input_kind == MP_PARSE_FILE_INPUT) {
mp_obj_list_append(MP_STATE_VM(mp_import_stack), MP_OBJ_NEW_QSTR(lex->source_name));
#if DEBUG_PRINT
DEBUG_printf("pushing import: ", name);
mp_obj_print_helper(MICROPY_DEBUG_PRINTER, MP_STATE_VM(mp_import_stack), PRINT_REPR);
DEBUG_printf("\n");
#endif
}
#endif
nlr_buf_t nlr;
bool volatile failed = false;
mp_obj_t volatile ret;
if (nlr_push(&nlr) == 0) {
qstr source_name = lex->source_name;
mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind);
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, parse_input_kind == MP_PARSE_SINGLE_INPUT);
mp_obj_t ret;
if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {
// for compile only, return value is the module function
ret = module_fun;
@ -1604,13 +1623,27 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i
nlr_pop();
mp_globals_set(old_globals);
mp_locals_set(old_locals);
return ret;
} else {
// exception; restore context and re-raise same exception
mp_globals_set(old_globals);
mp_locals_set(old_locals);
nlr_jump(nlr.ret_val);
failed = true;
}
#if MICROPY_RELATIVE_FILE_IMPORTS
if (parse_input_kind == MP_PARSE_FILE_INPUT) {
mp_obj_list_pop(MP_STATE_VM(mp_import_stack), MP_OBJ_NEW_SMALL_INT(-1));
#if DEBUG_PRINT
DEBUG_printf("popping import: ", name);
mp_obj_print_helper(MICROPY_DEBUG_PRINTER, MP_STATE_VM(mp_import_stack), PRINT_REPR);
DEBUG_printf("\n");
#endif
}
#endif
if(failed)
nlr_jump(nlr.ret_val);
return ret;
}
#endif // MICROPY_ENABLE_COMPILER