示例#1
0
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
    mp_import_stat_t stat = mp_import_stat(vstr_null_terminated_str(path));
    DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
    if (stat == MP_IMPORT_STAT_DIR) {
        return stat;
    }
    vstr_add_str(path, ".py");
    stat = mp_import_stat(vstr_null_terminated_str(path));
    if (stat == MP_IMPORT_STAT_FILE) {
        return stat;
    }
    return MP_IMPORT_STAT_NO_EXIST;
}
STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
    mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
    if (stat == MP_IMPORT_STAT_FILE) {
        return stat;
    }

    #if MICROPY_PERSISTENT_CODE_LOAD
    vstr_ins_byte(path, path->len - 2, 'm');
    stat = mp_import_stat_any(vstr_null_terminated_str(path));
    if (stat == MP_IMPORT_STAT_FILE) {
        return stat;
    }
    #endif

    return MP_IMPORT_STAT_NO_EXIST;
}
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
    #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER
    char *file_str = vstr_null_terminated_str(file);
    #endif
    printf("+++++++++do_load: %s\n",file_str);
    _do_load = 1;
    // If we support frozen modules (either as str or mpy) then try to find the
    // requested filename in the list of frozen module filenames.
    #if MICROPY_MODULE_FROZEN
    void *modref;
    int frozen_type = mp_find_frozen_module(file_str, file->len, &modref);
    #endif

    // If we support frozen str modules and the compiler is enabled, and we
    // found the filename in the list of frozen files, then load and execute it.
    #if MICROPY_MODULE_FROZEN_STR
    if (frozen_type == MP_FROZEN_STR) {
        do_load_from_lexer(module_obj, modref);
        goto _return;
    }
    #endif

    // If we support frozen mpy modules and we found a corresponding file (and
    // its data) in the list of frozen files, execute it.
    #if MICROPY_MODULE_FROZEN_MPY
    if (frozen_type == MP_FROZEN_MPY) {
        do_execute_raw_code(module_obj, modref);
        goto _return;
    }
    #endif

    // If we support loading .mpy files then check if the file extension is of
    // the correct format and, if so, load and execute the file.
    #if MICROPY_PERSISTENT_CODE_LOAD
    if (file_str[file->len - 3] == 'm') {
        mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);
        do_execute_raw_code(module_obj, raw_code);
        goto _return;
    }
    #endif

    // If we can compile scripts then load the file and compile and execute it.
    #if MICROPY_ENABLE_COMPILER
    {
        mp_lexer_t *lex = mp_lexer_new_from_file(file_str);
        do_load_from_lexer(module_obj, lex);
        goto _return;
    }
    #else

    // If we get here then the file was not frozen and we can't compile scripts.
    mp_raise_msg(&mp_type_ImportError, "script compilation not supported");
    #endif
_return:
   _do_load = 0;
   return;
}
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
    mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
    DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
    if (stat == MP_IMPORT_STAT_DIR) {
        return stat;
    }

    // not a directory, add .py and try as a file
    vstr_add_str(path, ".py");
    return stat_file_py_or_mpy(path);
}
示例#5
0
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
    mp_import_stat_t stat = mp_import_stat(vstr_null_terminated_str(path));
    DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
    if (stat == MP_IMPORT_STAT_DIR) {
        return stat;
    }

    vstr_add_str(path, ".py");
    stat = mp_import_stat(vstr_null_terminated_str(path));
    if (stat == MP_IMPORT_STAT_FILE) {
        return stat;
    }

    #if MICROPY_PERSISTENT_CODE_LOAD
    vstr_ins_byte(path, path->len - 2, 'm');
    stat = mp_import_stat(vstr_null_terminated_str(path));
    if (stat == MP_IMPORT_STAT_FILE) {
        return stat;
    }
    #endif

    return MP_IMPORT_STAT_NO_EXIST;
}
示例#6
0
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
    // create the lexer
    char *file_str = vstr_null_terminated_str(file);
    #if MICROPY_PERSISTENT_CODE_LOAD
    if (file_str[file->len - 3] == 'm') {
        mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);
        do_execute_raw_code(module_obj, raw_code);
    } else
    #endif
    {
        mp_lexer_t *lex = mp_lexer_new_from_file(file_str);
        do_load_from_lexer(module_obj, lex, file_str);
    }
}
示例#7
0
STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) {
    mp_lexer_t *lex = mp_lexer_new_from_file(file);
    if (lex == NULL) {
        printf("could not open file '%s' for reading\n", file);
        return 1;
    }

    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
        qstr source_name;
        if (source_file == NULL) {
            source_name = lex->source_name;
        } else {
            source_name = qstr_from_str(source_file);
        }

        #if MICROPY_PY___FILE__
        if (input_kind == MP_PARSE_FILE_INPUT) {
            mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
        }
        #endif

        mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
        mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, emit_opt, false);

        vstr_t vstr;
        vstr_init(&vstr, 16);
        if (output_file == NULL) {
            vstr_add_str(&vstr, file);
            vstr_cut_tail_bytes(&vstr, 2);
            vstr_add_str(&vstr, "mpy");
        } else {
            vstr_add_str(&vstr, output_file);
        }
        mp_raw_code_save_file(rc, vstr_null_terminated_str(&vstr));
        vstr_clear(&vstr);

        nlr_pop();
        return 0;
    } else {
        // uncaught exception
        mp_obj_print_exception(&mp_stderr_print, (mp_obj_t)nlr.ret_val);
        return 1;
    }
}
示例#8
0
void microbit_display_exception(mp_obj_t exc_in) {
    mp_uint_t n, *values;
    mp_obj_exception_get_traceback(exc_in, &n, &values);
    if (n >= 3) {
        vstr_t vstr;
        mp_print_t print;
        vstr_init_print(&vstr, 50, &print);
        #if MICROPY_ENABLE_SOURCE_LINE
        mp_printf(&print, "line %u ", values[1]);
        #endif
        if (mp_obj_is_native_exception_instance(exc_in)) {
            mp_obj_exception_t *exc = exc_in;
            mp_printf(&print, "%q ", exc->base.type->name);
            if (exc->args != NULL && exc->args->len != 0) {
                mp_obj_print_helper(&print, exc->args->items[0], PRINT_STR);
            }
        }
        mp_hal_display_string(vstr_null_terminated_str(&vstr));
        vstr_clear(&vstr);
    }
}
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
    #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER
    char *file_str = vstr_null_terminated_str(file);
    #endif

    #if MICROPY_PERSISTENT_CODE_LOAD
    if (file_str[file->len - 3] == 'm') {
        mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);
        do_execute_raw_code(module_obj, raw_code);
        return;
    }
    #endif

    #if MICROPY_ENABLE_COMPILER
    {
        mp_lexer_t *lex = mp_lexer_new_from_file(file_str);
        do_load_from_lexer(module_obj, lex, file_str);
    }
    #else
    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
        "script compilation not supported"));
    #endif
}
示例#10
0
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
#if DEBUG_PRINT
    DEBUG_printf("__import__:\n");
    for (mp_uint_t i = 0; i < n_args; i++) {
        DEBUG_printf("  ");
        mp_obj_print(args[i], PRINT_REPR);
        DEBUG_printf("\n");
    }
#endif

    mp_obj_t module_name = args[0];
    mp_obj_t fromtuple = mp_const_none;
    mp_int_t level = 0;
    if (n_args >= 4) {
        fromtuple = args[3];
        if (n_args >= 5) {
            level = MP_OBJ_SMALL_INT_VALUE(args[4]);
        }
    }

    mp_uint_t mod_len;
    const char *mod_str = mp_obj_str_get_data(module_name, &mod_len);

    if (level != 0) {
        // What we want to do here is to take name of current module,
        // chop <level> trailing components, and concatenate with passed-in
        // module name, thus resolving relative import name into absolue.
        // This even appears to be correct per
        // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
        // "Relative imports use a module's __name__ attribute to determine that
        // module's position in the package hierarchy."
        level--;
        mp_obj_t this_name_q = mp_obj_dict_get(mp_globals_get(), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
        assert(this_name_q != MP_OBJ_NULL);
        #if MICROPY_CPYTHON_COMPAT
        if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) {
            // This is a module run by -m command-line switch, get its real name from backup attribute
            this_name_q = mp_obj_dict_get(mp_globals_get(), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
        }
        #endif
        mp_map_t *globals_map = mp_obj_dict_get_map(mp_globals_get());
        mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
        bool is_pkg = (elem != NULL);

#if DEBUG_PRINT
        DEBUG_printf("Current module/package: ");
        mp_obj_print(this_name_q, PRINT_REPR);
        DEBUG_printf(", is_package: %d", is_pkg);
        DEBUG_printf("\n");
#endif

        mp_uint_t this_name_l;
        const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);

        const char *p = this_name + this_name_l;
        if (!is_pkg) {
            // We have module, but relative imports are anchored at package, so
            // go there.
            chop_component(this_name, &p);
        }


        uint dots_seen = 0;
        while (level--) {
            chop_component(this_name, &p);
            dots_seen++;
        }

        if (dots_seen == 0 && level >= 1) {
            // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
            // "If the module's name does not contain any package information
            // (e.g. it is set to '__main__') then relative imports are
            // resolved as if the module were a top level module, regardless
            // of where the module is actually located on the file system."
            // Supposedly this if catches this condition and resolve it properly
            // TODO: But nobody knows for sure. This condition happens when
            // package's __init__.py does something like "import .submod". So,
            // maybe we should check for package here? But quote above doesn't
            // talk about packages, it talks about dot-less module names.
            DEBUG_printf("Warning: no dots in current module name and level>0\n");
            p = this_name + this_name_l;
        } else if (level != -1) {
            nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "Invalid relative import"));
        }

        uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
        char *new_mod = alloca(new_mod_l);
        memcpy(new_mod, this_name, p - this_name);
        if (mod_len != 0) {
            new_mod[p - this_name] = '.';
            memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len);
        }

        qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l);
        DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
        if (new_mod_q == MP_QSTR_) {
            // CPython raises SystemError
            nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "cannot perform relative import"));
        }
        module_name = MP_OBJ_NEW_QSTR(new_mod_q);
        mod_str = new_mod;
        mod_len = new_mod_l;
    }

    // check if module already exists
    qstr module_name_qstr = mp_obj_str_get_qstr(module_name);
    mp_obj_t module_obj = mp_module_get(module_name_qstr);
    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) {
            return module_obj;
        }
        // If fromlist is not empty, return leaf module
        if (fromtuple != mp_const_none) {
            return module_obj;
        }
        // Otherwise, we need to return top-level package
        qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
        return mp_module_get(pkg_name);
    }
    DEBUG_printf("Module not yet loaded\n");

    #if MICROPY_MODULE_FROZEN
    mp_lexer_t *lex = mp_find_frozen_module(mod_str, mod_len);
    if (lex != NULL) {
        module_obj = mp_obj_new_module(module_name_qstr);
        // if args[3] (fromtuple) has magic value False, set up
        // this module for command-line "-m" option (set module's
        // name to __main__ instead of real name).
        // TODO: Duplicated below too.
        if (fromtuple == mp_const_false) {
            mp_obj_module_t *o = module_obj;
            mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
        }
        do_load_from_lexer(module_obj, lex, mod_str);
        return module_obj;
    }
    #endif

    uint last = 0;
    VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
    module_obj = MP_OBJ_NULL;
    mp_obj_t top_module_obj = MP_OBJ_NULL;
    mp_obj_t outer_module_obj = MP_OBJ_NULL;
    uint i;
    for (i = 1; i <= mod_len; i++) {
        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));
            DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path));

            // find the file corresponding to the module name
            mp_import_stat_t stat;
            if (vstr_len(&path) == 0) {
                // first module in the dotted-name; search for a directory or file
                stat = find_file(mod_str, i, &path);
            } else {
                // latter module in the dotted-name; append to path
                vstr_add_char(&path, PATH_SEP_CHAR);
                vstr_add_strn(&path, mod_str + last, i - last);
                stat = stat_dir_or_file(&path);
            }
            DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path));

            if (stat == MP_IMPORT_STAT_NO_EXIST) {
                #if MICROPY_MODULE_WEAK_LINKS
                // check if there is a weak link to this module
                if (i == mod_len) {
                    mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP);
                    if (el == NULL) {
                        goto no_exist;
                    }
                    // found weak linked module
                    module_obj = el->value;
                } else {
                    no_exist:
                #else
                {
                #endif
                    // couldn't find the file, so fail
                    if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
                        nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found"));
                    } else {
                        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
                            "no module named '%q'", mod_name));
                    }
                }
            } else {
                // found the file, so get the module
                module_obj = mp_module_get(mod_name);
            }

            if (module_obj == MP_OBJ_NULL) {
                // module not already loaded, so load it!

                module_obj = mp_obj_new_module(mod_name);

                // if args[3] (fromtuple) has magic value False, set up
                // this module for command-line "-m" option (set module's
                // name to __main__ instead of real name).
                if (i == mod_len && fromtuple == mp_const_false) {
                    mp_obj_module_t *o = module_obj;
                    mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
                    #if MICROPY_CPYTHON_COMPAT
                    // Store real name in "__main__" attribute. Choosen semi-randonly, to reuse existing qstr's.
                    mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name));
                    #endif
                }

                if (stat == MP_IMPORT_STAT_DIR) {
                    DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path));
                    // https://docs.python.org/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(vstr_str(&path), vstr_len(&path), false));
                    vstr_add_char(&path, PATH_SEP_CHAR);
                    vstr_add_str(&path, "__init__.py");
                    if (mp_import_stat(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) {
                        vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
                        mp_warning("%s is imported as namespace package", vstr_str(&path));
                    } else {
                        do_load(module_obj, &path);
                        vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
                    }
                } else { // MP_IMPORT_STAT_FILE
                    do_load(module_obj, &path);
                    // TODO: We cannot just break here, at the very least, we must execute
                    // trailer code below. But otherwise if there're remaining components,
                    // that would be (??) object path within module, not modules path within FS.
                    // break;
                }
            }
            if (outer_module_obj != MP_OBJ_NULL) {
                qstr s = qstr_from_strn(mod_str + last, i - last);
                mp_store_attr(outer_module_obj, s, module_obj);
            }
            outer_module_obj = module_obj;
            if (top_module_obj == MP_OBJ_NULL) {
                top_module_obj = module_obj;
            }
            last = i + 1;
        }
    }
示例#11
0
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
    // create the lexer
    char *file_str = vstr_null_terminated_str(file);
    mp_lexer_t *lex = mp_lexer_new_from_file(file_str);
    do_load_from_lexer(module_obj, lex, file_str);
}
示例#12
0
int pyexec_friendly_repl(void) {
    vstr_t line;
    vstr_init(&line, 32);

#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
    // in host mode, we enable the LCD for the repl
    mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD")));
    mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
#endif

friendly_repl_reset:
    mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
    #if MICROPY_PY_BUILTINS_HELP
    mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
    #endif

    // to test ctrl-C
    /*
    {
        uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};
        for (;;) {
            nlr_buf_t nlr;
            printf("pyexec_repl: %p\n", x);
            mp_hal_set_interrupt_char(CHAR_CTRL_C);
            if (nlr_push(&nlr) == 0) {
                for (;;) {
                }
            } else {
                printf("break\n");
            }
        }
    }
    */

    for (;;) {
    input_restart:

        #if defined(USE_DEVICE_MODE)
        if (usb_vcp_is_enabled()) {
            // If the user gets to here and interrupts are disabled then
            // they'll never see the prompt, traceback etc. The USB REPL needs
            // interrupts to be enabled or no transfers occur. So we try to
            // do the user a favor and reenable interrupts.
            if (query_irq() == IRQ_STATE_DISABLED) {
                enable_irq(IRQ_STATE_ENABLED);
                mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n");
            }
        }
        #endif

        vstr_reset(&line);
        int ret = readline(&line, ">>> ");
        mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;

        if (ret == CHAR_CTRL_A) {
            // change to raw REPL
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&line);
            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
            return 0;
        } else if (ret == CHAR_CTRL_B) {
            // reset friendly REPL
            mp_hal_stdout_tx_str("\r\n");
            goto friendly_repl_reset;
        } else if (ret == CHAR_CTRL_C) {
            // break
            mp_hal_stdout_tx_str("\r\n");
            continue;
        } else if (ret == CHAR_CTRL_D) {
            // exit for a soft reset
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&line);
            return PYEXEC_FORCED_EXIT;
        } else if (ret == CHAR_CTRL_E) {
            // paste mode
            mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== ");
            vstr_reset(&line);
            for (;;) {
                char c = mp_hal_stdin_rx_chr();
                if (c == CHAR_CTRL_C) {
                    // cancel everything
                    mp_hal_stdout_tx_str("\r\n");
                    goto input_restart;
                } else if (c == CHAR_CTRL_D) {
                    // end of input
                    mp_hal_stdout_tx_str("\r\n");
                    break;
                } else {
                    // add char to buffer and echo
                    vstr_add_byte(&line, c);
                    if (c == '\r') {
                        mp_hal_stdout_tx_str("\r\n=== ");
                    } else {
                        mp_hal_stdout_tx_strn(&c, 1);
                    }
                }
            }
            parse_input_kind = MP_PARSE_FILE_INPUT;
        } else if (vstr_len(&line) == 0) {
            continue;
        } else {
            // got a line with non-zero length, see if it needs continuing
            while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
                vstr_add_byte(&line, '\n');
                ret = readline(&line, "... ");
                if (ret == CHAR_CTRL_C) {
                    // cancel everything
                    mp_hal_stdout_tx_str("\r\n");
                    goto input_restart;
                } else if (ret == CHAR_CTRL_D) {
                    // stop entering compound statement
                    break;
                }
            }
        }

        ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);
        if (ret & PYEXEC_FORCED_EXIT) {
            return ret;
        }
    }
}
示例#13
0
STATIC int pyexec_friendly_repl_process_char(int c) {
    int ret = readline_process_char(c);

    if (!repl.cont_line) {

        if (ret == CHAR_CTRL_A) {
            // change to raw REPL
            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
            mp_hal_stdout_tx_str("\r\n");
            pyexec_raw_repl_process_char(CHAR_CTRL_A);
            return 0;
        } else if (ret == CHAR_CTRL_B) {
            // reset friendly REPL
            mp_hal_stdout_tx_str("\r\n");
            mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
            #if MICROPY_PY_BUILTINS_HELP
            mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
            #endif
            goto input_restart;
        } else if (ret == CHAR_CTRL_C) {
            // break
            mp_hal_stdout_tx_str("\r\n");
            goto input_restart;
        } else if (ret == CHAR_CTRL_D) {
            // exit for a soft reset
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(MP_STATE_VM(repl_line));
            return PYEXEC_FORCED_EXIT;
        }

        if (ret < 0) {
            return 0;
        }

        if (!mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) {
            goto exec;
        }

        vstr_add_byte(MP_STATE_VM(repl_line), '\n');
        repl.cont_line = true;
        readline_note_newline("... ");
        return 0;

    } else {

        if (ret == CHAR_CTRL_C) {
           // cancel everything
           mp_hal_stdout_tx_str("\r\n");
           repl.cont_line = false;
           goto input_restart;
        } else if (ret == CHAR_CTRL_D) {
            // stop entering compound statement
            goto exec;
        }

        if (ret < 0) {
            return 0;
        }

        if (mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) {
            vstr_add_byte(MP_STATE_VM(repl_line), '\n');
            readline_note_newline("... ");
            return 0;
        }

exec: ;
        int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);
        if (ret & PYEXEC_FORCED_EXIT) {
            return ret;
        }

input_restart:
        vstr_reset(MP_STATE_VM(repl_line));
        repl.cont_line = false;
        readline_init(MP_STATE_VM(repl_line), ">>> ");
        return 0;
    }
}
示例#14
0
void mp_lexer_to_next(mp_lexer_t *lex) {
    // start new token text
    vstr_reset(&lex->vstr);

    // skip white space and comments
    bool had_physical_newline = skip_whitespace(lex, false);

    // set token source information
    lex->tok_line = lex->line;
    lex->tok_column = lex->column;

    if (lex->emit_dent < 0) {
        lex->tok_kind = MP_TOKEN_DEDENT;
        lex->emit_dent += 1;

    } else if (lex->emit_dent > 0) {
        lex->tok_kind = MP_TOKEN_INDENT;
        lex->emit_dent -= 1;

    } else if (had_physical_newline && lex->nested_bracket_level == 0) {
        lex->tok_kind = MP_TOKEN_NEWLINE;

        size_t num_spaces = lex->column - 1;
        if (num_spaces == indent_top(lex)) {
        } else if (num_spaces > indent_top(lex)) {
            indent_push(lex, num_spaces);
            lex->emit_dent += 1;
        } else {
            while (num_spaces < indent_top(lex)) {
                indent_pop(lex);
                lex->emit_dent -= 1;
            }
            if (num_spaces != indent_top(lex)) {
                lex->tok_kind = MP_TOKEN_DEDENT_MISMATCH;
            }
        }

    } else if (is_end(lex)) {
        lex->tok_kind = MP_TOKEN_END;

    } else if (is_string_or_bytes(lex)) {
        // a string or bytes literal

        // Python requires adjacent string/bytes literals to be automatically
        // concatenated.  We do it here in the tokeniser to make efficient use of RAM,
        // because then the lexer's vstr can be used to accumulate the string literal,
        // in contrast to creating a parse tree of strings and then joining them later
        // in the compiler.  It's also more compact in code size to do it here.

        // MP_TOKEN_END is used to indicate that this is the first string token
        lex->tok_kind = MP_TOKEN_END;

        // Loop to accumulate string/bytes literals
        do {
            // parse type codes
            bool is_raw = false;
            mp_token_kind_t kind = MP_TOKEN_STRING;
            int n_char = 0;
            if (is_char(lex, 'u')) {
                n_char = 1;
            } else if (is_char(lex, 'b')) {
                kind = MP_TOKEN_BYTES;
                n_char = 1;
                if (is_char_following(lex, 'r')) {
                    is_raw = true;
                    n_char = 2;
                }
            } else if (is_char(lex, 'r')) {
                is_raw = true;
                n_char = 1;
                if (is_char_following(lex, 'b')) {
                    kind = MP_TOKEN_BYTES;
                    n_char = 2;
                }
            }

            // Set or check token kind
            if (lex->tok_kind == MP_TOKEN_END) {
                lex->tok_kind = kind;
            } else if (lex->tok_kind != kind) {
                // Can't concatenate string with bytes
                break;
            }

            // Skip any type code characters
            if (n_char != 0) {
                next_char(lex);
                if (n_char == 2) {
                    next_char(lex);
                }
            }

            // Parse the literal
            parse_string_literal(lex, is_raw);

            // Skip whitespace so we can check if there's another string following
            skip_whitespace(lex, true);

        } while (is_string_or_bytes(lex));

    } else if (is_head_of_identifier(lex)) {
        lex->tok_kind = MP_TOKEN_NAME;

        // get first char (add as byte to remain 8-bit clean and support utf-8)
        vstr_add_byte(&lex->vstr, CUR_CHAR(lex));
        next_char(lex);

        // get tail chars
        while (!is_end(lex) && is_tail_of_identifier(lex)) {
            vstr_add_byte(&lex->vstr, CUR_CHAR(lex));
            next_char(lex);
        }

        // Check if the name is a keyword.
        // We also check for __debug__ here and convert it to its value.  This is
        // so the parser gives a syntax error on, eg, x.__debug__.  Otherwise, we
        // need to check for this special token in many places in the compiler.
        const char *s = vstr_null_terminated_str(&lex->vstr);
        for (size_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
            int cmp = strcmp(s, tok_kw[i]);
            if (cmp == 0) {
                lex->tok_kind = MP_TOKEN_KW_FALSE + i;
                if (lex->tok_kind == MP_TOKEN_KW___DEBUG__) {
                    lex->tok_kind = (MP_STATE_VM(mp_optimise_value) == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
                }
                break;
            } else if (cmp < 0) {
                // Table is sorted and comparison was less-than, so stop searching
                break;
            }
        }

    } else if (is_digit(lex) || (is_char(lex, '.') && is_following_digit(lex))) {
        bool forced_integer = false;
        if (is_char(lex, '.')) {
            lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG;
        } else {
            lex->tok_kind = MP_TOKEN_INTEGER;
            if (is_char(lex, '0') && is_following_base_char(lex)) {
                forced_integer = true;
            }
        }

        // get first char
        vstr_add_char(&lex->vstr, CUR_CHAR(lex));
        next_char(lex);

        // get tail chars
        while (!is_end(lex)) {
            if (!forced_integer && is_char_or(lex, 'e', 'E')) {
                lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG;
                vstr_add_char(&lex->vstr, 'e');
                next_char(lex);
                if (is_char(lex, '+') || is_char(lex, '-')) {
                    vstr_add_char(&lex->vstr, CUR_CHAR(lex));
                    next_char(lex);
                }
            } else if (is_letter(lex) || is_digit(lex) || is_char(lex, '.')) {
                if (is_char_or3(lex, '.', 'j', 'J')) {
                    lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG;
                }
                vstr_add_char(&lex->vstr, CUR_CHAR(lex));
                next_char(lex);
            } else {
                break;
            }
        }

    } else {
        // search for encoded delimiter or operator

        const char *t = tok_enc;
        size_t tok_enc_index = 0;
        for (; *t != 0 && !is_char(lex, *t); t += 1) {
            if (*t == 'e' || *t == 'c') {
                t += 1;
            }
            tok_enc_index += 1;
        }

        next_char(lex);

        if (*t == 0) {
            // didn't match any delimiter or operator characters
            lex->tok_kind = MP_TOKEN_INVALID;

        } else if (*t == '!') {
            // "!=" is a special case because "!" is not a valid operator
            if (is_char(lex, '=')) {
                next_char(lex);
                lex->tok_kind = MP_TOKEN_OP_NOT_EQUAL;
            } else {
                lex->tok_kind = MP_TOKEN_INVALID;
            }

        } else if (*t == '.') {
            // "." and "..." are special cases because ".." is not a valid operator
            if (is_char_and(lex, '.', '.')) {
                next_char(lex);
                next_char(lex);
                lex->tok_kind = MP_TOKEN_ELLIPSIS;
            } else {
                lex->tok_kind = MP_TOKEN_DEL_PERIOD;
            }

        } else {
            // matched a delimiter or operator character

            // get the maximum characters for a valid token
            t += 1;
            size_t t_index = tok_enc_index;
            while (*t == 'c' || *t == 'e') {
                t_index += 1;
                if (is_char(lex, t[1])) {
                    next_char(lex);
                    tok_enc_index = t_index;
                    if (*t == 'e') {
                        break;
                    }
                } else if (*t == 'c') {
                    break;
                }
                t += 2;
            }

            // set token kind
            lex->tok_kind = tok_enc_kind[tok_enc_index];

            // compute bracket level for implicit line joining
            if (lex->tok_kind == MP_TOKEN_DEL_PAREN_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACKET_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACE_OPEN) {
                lex->nested_bracket_level += 1;
            } else if (lex->tok_kind == MP_TOKEN_DEL_PAREN_CLOSE || lex->tok_kind == MP_TOKEN_DEL_BRACKET_CLOSE || lex->tok_kind == MP_TOKEN_DEL_BRACE_CLOSE) {
                lex->nested_bracket_level -= 1;
            }
        }
    }
}
示例#15
0
int pyexec_friendly_repl_process_char(int c) {
    int ret = readline_process_char(c);

    if (!repl.cont_line) {

        if (ret == CHAR_CTRL_A) {
            // change to raw REPL
            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&repl.line);
            return PYEXEC_SWITCH_MODE;
        } else if (ret == CHAR_CTRL_B) {
            // reset friendly REPL
            mp_hal_stdout_tx_str("\r\n");
            goto friendly_repl_reset;
        } else if (ret == CHAR_CTRL_C) {
            // break
            mp_hal_stdout_tx_str("\r\n");
            goto input_restart;
        } else if (ret == CHAR_CTRL_D) {
            // exit for a soft reset
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&repl.line);
            return PYEXEC_FORCED_EXIT;
        } else if (vstr_len(&repl.line) == 0) {
            //goto input_restart;
        }

        if (ret < 0) {
            return 0;
        }

        if (!mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) {
            goto exec;
        }

        vstr_add_byte(&repl.line, '\n');
        repl.cont_line = true;
        mp_hal_stdout_tx_str("... ");
        readline_note_newline();
        return 0;

    } else {

        if (ret == CHAR_CTRL_C) {
                // cancel everything
                mp_hal_stdout_tx_str("\r\n");
                repl.cont_line = false;
                goto input_restart;
        } else if (ret == CHAR_CTRL_D) {
                // stop entering compound statement
                goto exec;
        }

        if (ret < 0) {
            return 0;
        }

        if (mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) {
            vstr_add_byte(&repl.line, '\n');
            mp_hal_stdout_tx_str("... ");
            readline_note_newline();
            return 0;
        }

exec: ;
        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&repl.line), vstr_len(&repl.line), 0);
        if (lex == NULL) {
            printf("MemoryError\n");
        } else {
            int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
            if (ret & PYEXEC_FORCED_EXIT) {
                return ret;
            }
        }

friendly_repl_reset: // TODO
input_restart:
        pyexec_friendly_repl_reset();
        mp_hal_stdout_tx_str(">>> ");
        return 0;
    }
}
示例#16
0
STATIC int do_repl(void) {
    mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; "
        MICROPY_PY_SYS_PLATFORM " version\nUse Ctrl-D to exit, Ctrl-E for paste mode\n");

    #if MICROPY_USE_READLINE == 1

    // use MicroPython supplied readline

    vstr_t line;
    vstr_init(&line, 16);
    for (;;) {
        mp_hal_stdio_mode_raw();

    input_restart:
        vstr_reset(&line);
        int ret = readline(&line, ">>> ");
        mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;

        if (ret == CHAR_CTRL_C) {
            // cancel input
            mp_hal_stdout_tx_str("\r\n");
            goto input_restart;
        } else if (ret == CHAR_CTRL_D) {
            // EOF
            printf("\n");
            mp_hal_stdio_mode_orig();
            vstr_clear(&line);
            return 0;
        } else if (ret == CHAR_CTRL_E) {
            // paste mode
            mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== ");
            vstr_reset(&line);
            for (;;) {
                char c = mp_hal_stdin_rx_chr();
                if (c == CHAR_CTRL_C) {
                    // cancel everything
                    mp_hal_stdout_tx_str("\n");
                    goto input_restart;
                } else if (c == CHAR_CTRL_D) {
                    // end of input
                    mp_hal_stdout_tx_str("\n");
                    break;
                } else {
                    // add char to buffer and echo
                    vstr_add_byte(&line, c);
                    if (c == '\r') {
                        mp_hal_stdout_tx_str("\n=== ");
                    } else {
                        mp_hal_stdout_tx_strn(&c, 1);
                    }
                }
            }
            parse_input_kind = MP_PARSE_FILE_INPUT;
        } else if (line.len == 0) {
            if (ret != 0) {
                printf("\n");
            }
            goto input_restart;
        } else {
            // got a line with non-zero length, see if it needs continuing
            while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
                vstr_add_byte(&line, '\n');
                ret = readline(&line, "... ");
                if (ret == CHAR_CTRL_C) {
                    // cancel everything
                    printf("\n");
                    goto input_restart;
                } else if (ret == CHAR_CTRL_D) {
                    // stop entering compound statement
                    break;
                }
            }
        }

        mp_hal_stdio_mode_orig();

        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, false);
        ret = execute_from_lexer(lex, parse_input_kind, true);
        if (ret & FORCED_EXIT) {
            return ret;
        }
    }

    #else

    // use GNU or simple readline

    for (;;) {
        char *line = prompt(">>> ");
        if (line == NULL) {
            // EOF
            return 0;
        }
        while (mp_repl_continue_with_input(line)) {
            char *line2 = prompt("... ");
            if (line2 == NULL) {
                break;
            }
            char *line3 = strjoin(line, '\n', line2);
            free(line);
            free(line2);
            line = line3;
        }

        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
        int ret = execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true);
        if (ret & FORCED_EXIT) {
            return ret;
        }
        free(line);
    }

    #endif
}
示例#17
0
int pyexec_friendly_repl(void) {
    vstr_t line;
    vstr_init(&line, 32);

#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
    // in host mode, we enable the LCD for the repl
    mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD")));
    mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
#endif

friendly_repl_reset:
    mp_hal_stdout_tx_str("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
    mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");

    // to test ctrl-C
    /*
    {
        uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};
        for (;;) {
            nlr_buf_t nlr;
            printf("pyexec_repl: %p\n", x);
            mp_hal_set_interrupt_char(CHAR_CTRL_C);
            if (nlr_push(&nlr) == 0) {
                for (;;) {
                }
            } else {
                printf("break\n");
            }
        }
    }
    */

    for (;;) {
    input_restart:
        vstr_reset(&line);
        int ret = readline(&line, ">>> ");

        if (ret == CHAR_CTRL_A) {
            // change to raw REPL
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&line);
            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
            return 0;
        } else if (ret == CHAR_CTRL_B) {
            // reset friendly REPL
            mp_hal_stdout_tx_str("\r\n");
            goto friendly_repl_reset;
        } else if (ret == CHAR_CTRL_C) {
            // break
            mp_hal_stdout_tx_str("\r\n");
            continue;
        } else if (ret == CHAR_CTRL_D) {
            // exit for a soft reset
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&line);
            return PYEXEC_FORCED_EXIT;
        } else if (vstr_len(&line) == 0) {
            continue;
        }

        while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
            vstr_add_byte(&line, '\n');
            ret = readline(&line, "... ");
            if (ret == CHAR_CTRL_C) {
                // cancel everything
                mp_hal_stdout_tx_str("\r\n");
                goto input_restart;
            } else if (ret == CHAR_CTRL_D) {
                // stop entering compound statement
                break;
            }
        }

        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
        if (lex == NULL) {
            printf("MemoryError\n");
        } else {
            ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
            if (ret & PYEXEC_FORCED_EXIT) {
                return ret;
            }
        }
    }
}