diff --git a/py/builtinevex.c b/py/builtinevex.c index a115ec669e..e24055316e 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -40,66 +40,34 @@ #include "runtime.h" #include "builtin.h" -STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse_input_kind) { +STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) { mp_uint_t str_len; - const char *str = mp_obj_str_get_data(o_in, &str_len); + const char *str = mp_obj_str_get_data(args[0], &str_len); // create the lexer mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0); - qstr source_name = mp_lexer_source_name(lex); - // parse the string - mp_parse_error_kind_t parse_error_kind; - mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind); - - if (pn == MP_PARSE_NODE_NULL) { - // parse error; raise exception - mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind); - mp_lexer_free(lex); - nlr_raise(exc); - } - - mp_lexer_free(lex); - - // compile the string - mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false); - - // check if there was a compile error - if (mp_obj_is_exception_instance(module_fun)) { - nlr_raise(module_fun); - } - - // complied successfully, execute it - return mp_call_function_0(module_fun); -} - -STATIC mp_obj_t mp_builtin_eval(mp_obj_t o_in) { - return parse_compile_execute(o_in, MP_PARSE_EVAL_INPUT); -} - -MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_eval_obj, mp_builtin_eval); - -STATIC mp_obj_t mp_builtin_exec(uint n_args, const mp_obj_t *args) { - // Unconditional getting/setting assumes that these operations - // are cheap, which is the case when this comment was written. - mp_obj_dict_t *old_globals = mp_globals_get(); - mp_obj_dict_t *old_locals = mp_locals_get(); + // work out the context + mp_obj_dict_t *globals = mp_globals_get(); + mp_obj_dict_t *locals = mp_locals_get(); if (n_args > 1) { - mp_obj_t globals = args[1]; - mp_obj_t locals; + globals = args[1]; if (n_args > 2) { locals = args[2]; } else { locals = globals; } - mp_globals_set(globals); - mp_locals_set(locals); } - mp_obj_t res = parse_compile_execute(args[0], MP_PARSE_FILE_INPUT); - // TODO if the above call throws an exception, then we never get to reset the globals/locals - mp_globals_set(old_globals); - mp_locals_set(old_locals); - return res; + + return mp_parse_compile_execute(lex, parse_input_kind, globals, locals); } +STATIC mp_obj_t mp_builtin_eval(mp_uint_t n_args, const mp_obj_t *args) { + return eval_exec_helper(n_args, args, MP_PARSE_EVAL_INPUT); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj, 1, 3, mp_builtin_eval); + +STATIC mp_obj_t mp_builtin_exec(mp_uint_t n_args, const mp_obj_t *args) { + return eval_exec_helper(n_args, args, MP_PARSE_FILE_INPUT); +} MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj, 1, 3, mp_builtin_exec); diff --git a/py/builtinimport.c b/py/builtinimport.c index 04786b2104..ffdadf0227 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -111,56 +111,14 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { 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)); #if MICROPY_PY___FILE__ - mp_store_attr(module_obj, MP_QSTR___file__, mp_obj_new_str(vstr_str(file), vstr_len(file), false)); + qstr source_name = mp_lexer_source_name(lex); + mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif - // 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); - - if (mp_obj_is_exception_instance(module_fun)) { - mp_locals_set(old_locals); - mp_globals_set(old_globals); - nlr_raise(module_fun); - } - - // 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); + // 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); } mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) { diff --git a/py/compile.h b/py/compile.h index 983a443e95..cef20efce2 100644 --- a/py/compile.h +++ b/py/compile.h @@ -35,3 +35,6 @@ enum { // the compiler will free the parse tree (pn) before it returns mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is_repl); + +// this is implemented in runtime.c +mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals); diff --git a/py/runtime.c b/py/runtime.c index c7b95bf7dd..945713d18a 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include #include @@ -46,6 +47,9 @@ #include "smallint.h" #include "objgenerator.h" #include "lexer.h" +#include "parse.h" +#include "parsehelper.h" +#include "compile.h" #include "stackctrl.h" #if 0 // print debugging info @@ -1153,6 +1157,54 @@ void mp_globals_set(mp_obj_dict_t *d) { dict_globals = d; } +// this is implemented in this file so it can optimise access to locals/globals +mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals) { + // parse the string + mp_parse_error_kind_t parse_error_kind; + mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind); + + if (pn == MP_PARSE_NODE_NULL) { + // parse error; raise exception + mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind); + mp_lexer_free(lex); + nlr_raise(exc); + } + + qstr source_name = mp_lexer_source_name(lex); + mp_lexer_free(lex); + + // save context and set new context + mp_obj_dict_t *old_globals = mp_globals_get(); + mp_obj_dict_t *old_locals = mp_locals_get(); + mp_globals_set(globals); + mp_locals_set(locals); + + // compile the string + mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false); + + // check if there was a compile error + if (mp_obj_is_exception_instance(module_fun)) { + mp_globals_set(old_globals); + mp_locals_set(old_locals); + nlr_raise(module_fun); + } + + // complied successfully, execute it + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t ret = mp_call_function_0(module_fun); + 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_raise(nlr.ret_val); + } +} + void *m_malloc_fail(size_t num_bytes) { DEBUG_printf("memory allocation failed, allocating " UINT_FMT " bytes\n", num_bytes); nlr_raise((mp_obj_t)&mp_const_MemoryError_obj);