STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // create the lexer mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file)); if (lex == NULL) { // we verified the file exists using stat, but lexer could still fail nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", vstr_str(file))); } qstr source_name = mp_lexer_source_name(lex); // save the old context mp_obj_dict_t *old_locals = mp_locals_get(); mp_obj_dict_t *old_globals = mp_globals_get(); // set the new context mp_locals_set(mp_obj_module_get_globals(module_obj)); mp_globals_set(mp_obj_module_get_globals(module_obj)); // parse the imported script mp_parse_error_kind_t parse_error_kind; mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind); if (pn == MP_PARSE_NODE_NULL) { // parse error; clean up and raise exception mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind); mp_lexer_free(lex); mp_locals_set(old_locals); mp_globals_set(old_globals); nlr_raise(exc); } mp_lexer_free(lex); // compile the imported script mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false); mp_parse_node_free(pn); if (module_fun == mp_const_none) { // TODO handle compile error correctly mp_locals_set(old_locals); mp_globals_set(old_globals); nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "Syntax error in imported module")); } // complied successfully, execute it nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_call_function_0(module_fun); nlr_pop(); } else { // exception; restore context and re-raise same exception mp_locals_set(old_locals); mp_globals_set(old_globals); nlr_raise(nlr.ret_val); } mp_locals_set(old_locals); mp_globals_set(old_globals); }
STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { #if MICROPY_PY___FILE__ // TODO //qstr source_name = lex->source_name; //mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif // execute the module in its context mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); // save context mp_obj_dict_t *volatile old_globals = mp_globals_get(); mp_obj_dict_t *volatile old_locals = mp_locals_get(); // set new context mp_globals_set(mod_globals); mp_locals_set(mod_globals); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL); mp_call_function_0(module_fun); // finish nlr block, restore context nlr_pop(); mp_globals_set(old_globals); mp_locals_set(old_locals); } else { // exception; restore context and re-raise same exception mp_globals_set(old_globals); mp_locals_set(old_locals); nlr_raise(nlr.ret_val); } }
STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) { // TODO make this function more general and less of a hack mp_obj_dict_t *dict = NULL; if (n_args == 0) { // make a list of names in the local name space dict = mp_locals_get(); } else { // n_args == 1 // make a list of names in the given object if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { dict = mp_obj_module_get_globals(args[0]); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { type = args[0]; } else { type = mp_obj_get_type(args[0]); } if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)) { dict = type->locals_dict; } } } mp_obj_t dir = mp_obj_new_list(0, NULL); if (dict != NULL) { for (uint i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } } return dir; }
STATIC mp_obj_t pyb_help(uint n_args, const mp_obj_t *args) { if (n_args == 0) { // print a general help message printf("%s", help_text); } else { // try to print something sensible about the given object printf("object "); mp_obj_print(args[0], PRINT_STR); printf(" is of type %s\n", mp_obj_get_type_str(args[0])); mp_map_t *map = NULL; if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { map = mp_obj_dict_get_map(mp_obj_module_get_globals(args[0])); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { type = args[0]; } else { type = mp_obj_get_type(args[0]); } if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)) { map = mp_obj_dict_get_map(type->locals_dict); } } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { if (map->table[i].key != MP_OBJ_NULL) { pyb_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } } return mp_const_none; }
STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif // parse, compile and execute the module in its context mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals); }
STATIC void mp_help_print_obj(mp_obj_t obj) { #if MICROPY_PY_BUILTINS_HELP_MODULES if (obj == MP_OBJ_NEW_QSTR(MP_QSTR_modules)) { mp_help_print_modules(); return; } #endif // Extract method from bound method, for better error messages if (mp_obj_get_type(obj)->name == MP_QSTR_bound_method) { obj = ((mp_obj_t*)obj)[1]; // extract method } // Hook into platform-specific help for this object extern bool mp_plat_specific_help(mp_obj_t obj); if (mp_plat_specific_help(obj)) { return; } // try to print something sensible about the given object mp_print_str(MP_PYTHON_PRINTER, "object "); mp_obj_print(obj, PRINT_STR); mp_printf(MP_PYTHON_PRINTER, " is of type %s\n", mp_obj_get_type_str(obj)); mp_map_t *map = NULL; if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { map = mp_obj_dict_get_map(mp_obj_module_get_globals(obj)); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { type = obj; } else { type = mp_obj_get_type(obj); } if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)) { map = mp_obj_dict_get_map(type->locals_dict); } } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { if (map->table[i].key != MP_OBJ_NULL) { mp_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } }
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // create the lexer mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file)); if (lex == NULL) { // we verified the file exists using stat, but lexer could still fail nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", vstr_str(file))); } #if MICROPY_PY___FILE__ qstr source_name = mp_lexer_source_name(lex); mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif // parse, compile and execute the module in its context mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals); }
STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char *fname) { if (lex == NULL) { // we verified the file exists using stat, but lexer could still 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 '%s'", fname)); } } #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif // parse, compile and execute the module in its context mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals); }
STATIC mp_obj_t pyb_help(uint n_args, const mp_obj_t *args) { if (n_args == 0) { // print a general help message mp_printf(&mp_plat_print, "%s", help_text); } else { mp_obj_t args0 = args[0]; mp_obj_type_t *args0_type = mp_obj_get_type(args0); if (args0_type->name == MP_QSTR_bound_method) { args0 = ((mp_obj_t*)args0)[1]; // extract method args0_type = mp_obj_get_type(args0); } // see if we have specific help info for this instance for (size_t i = 0; i < MP_ARRAY_SIZE(help_table_instances); i++) { if (args0 == help_table_instances[i].obj) { mp_print_str(&mp_plat_print, help_table_instances[i].doc); //if (args0_type == &mp_type_module) { //TODO here we can list the things inside the module //} return mp_const_none; } } // see if we have specific help info for this type for (size_t i = 0; i < MP_ARRAY_SIZE(help_table_types); i++) { if (args0 == help_table_types[i].obj || args0_type == help_table_types[i].obj) { mp_print_str(&mp_plat_print, help_table_types[i].doc); return mp_const_none; } } // don't have specific help info, try instead to print something sensible mp_printf(&mp_plat_print, "object "); mp_obj_print(args0, PRINT_STR); mp_printf(&mp_plat_print, " is of type %q\n", args0_type->name); mp_map_t *map = NULL; if (args0_type == &mp_type_module) { map = mp_obj_dict_get_map(mp_obj_module_get_globals(args0)); } else { mp_obj_type_t *type; if (args0_type == &mp_type_type) { type = args0; } else { type = args0_type; } if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)) { map = mp_obj_dict_get_map(type->locals_dict); } } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { if (map->table[i].key != MP_OBJ_NULL) { pyb_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } } return mp_const_none; }
mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t *print, const char **compl_str) { // scan backwards to find start of "a.b.c" chain const char *org_str = str; const char *top = str + len; for (const char *s = top; --s >= str;) { if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) { ++s; str = s; break; } } // begin search in locals dict mp_obj_dict_t *dict = mp_locals_get(); for (;;) { // get next word in string to complete const char *s_start = str; while (str < top && *str != '.') { ++str; } mp_uint_t s_len = str - s_start; if (str < top) { // a complete word, lookup in current dict mp_obj_t obj = MP_OBJ_NULL; for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { obj = dict->map.table[i].value; break; } } } if (obj == MP_OBJ_NULL) { // lookup failed return 0; } // found an object of this name; try to get its dict if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { dict = mp_obj_module_get_globals(obj); } else { mp_obj_type_t *type; if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { type = MP_OBJ_TO_PTR(obj); } else { type = mp_obj_get_type(obj); } if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { dict = type->locals_dict; } else { // obj has no dict return 0; } } // skip '.' to move to next word ++str; } else { // end of string, do completion on this partial name // look for matches int n_found = 0; const char *match_str = NULL; mp_uint_t match_len = 0; for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { if (match_str == NULL) { match_str = d_str; match_len = d_len; } else { // search for longest common prefix of match_str and d_str // (assumes these strings are null-terminated) for (mp_uint_t j = s_len; j <= match_len && j <= d_len; ++j) { if (match_str[j] != d_str[j]) { match_len = j; break; } } } ++n_found; } } } // nothing found if (n_found == 0) { // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { static const char import_str[] = "import "; if (memcmp(s_start, import_str, s_len) == 0) { *compl_str = import_str + s_len; return sizeof(import_str) - 1 - s_len; } } return 0; } // 1 match found, or multiple matches with a common prefix if (n_found == 1 || match_len > s_len) { *compl_str = match_str + s_len; return match_len - s_len; } // multiple matches found, print them out #define WORD_SLOT_LEN (16) #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) int line_len = MAX_LINE_LEN; // force a newline for first word for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { gap += WORD_SLOT_LEN; } if (line_len + gap + d_len <= MAX_LINE_LEN) { // TODO optimise printing of gap? for (int j = 0; j < gap; ++j) { mp_print_str(print, " "); } mp_print_str(print, d_str); line_len += gap + d_len; } else { mp_printf(print, "\n%s", d_str); line_len = d_len; } } } } mp_print_str(print, "\n"); return (mp_uint_t)(-1); // indicate many matches } } }