py: Implement compile builtin, enabled only on unix port.
This should be pretty compliant with CPython, except perhaps for some corner cases to do with globals/locals context. Addresses issue #879.
This commit is contained in:
parent
e5a3759ff5
commit
c9fc620723
|
@ -35,6 +35,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj);
|
||||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
|
||||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj);
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj);
|
||||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
|
||||||
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_compile_obj);
|
||||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
|
||||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj);
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj);
|
||||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj);
|
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj);
|
||||||
|
|
|
@ -34,19 +34,87 @@
|
||||||
#include "lexerunix.h"
|
#include "lexerunix.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
#include "objfun.h"
|
||||||
#include "parsehelper.h"
|
#include "parsehelper.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "runtime0.h"
|
#include "runtime0.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
|
||||||
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) {
|
#if MICROPY_PY_BUILTINS_COMPILE
|
||||||
|
|
||||||
|
typedef struct _mp_obj_code_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
mp_obj_t module_fun;
|
||||||
|
} mp_obj_code_t;
|
||||||
|
|
||||||
|
STATIC const mp_obj_type_t mp_type_code = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_code,
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_t globals, mp_obj_t locals) {
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// a bit of a hack: fun_bc will re-set globals, so need to make sure it's
|
||||||
|
// the correct one
|
||||||
|
if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) {
|
||||||
|
mp_obj_fun_bc_t *fun_bc = self->module_fun;
|
||||||
|
fun_bc->globals = globals;
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute code
|
||||||
|
nlr_buf_t nlr;
|
||||||
|
if (nlr_push(&nlr) == 0) {
|
||||||
|
mp_obj_t ret = mp_call_function_0(self->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_obj_t mp_builtin_compile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
|
// get the source
|
||||||
mp_uint_t str_len;
|
mp_uint_t str_len;
|
||||||
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
||||||
|
|
||||||
// create the lexer
|
// get the filename
|
||||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
|
qstr filename = mp_obj_str_get_qstr(args[1]);
|
||||||
|
|
||||||
|
// create the lexer
|
||||||
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(filename, str, str_len, 0);
|
||||||
|
|
||||||
|
// get the compile mode
|
||||||
|
qstr mode = mp_obj_str_get_qstr(args[2]);
|
||||||
|
mp_parse_input_kind_t parse_input_kind;
|
||||||
|
switch (mode) {
|
||||||
|
case MP_QSTR_single: parse_input_kind = MP_PARSE_SINGLE_INPUT; break;
|
||||||
|
case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break;
|
||||||
|
case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break;
|
||||||
|
default:
|
||||||
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad compile mode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_obj_code_t *code = m_new_obj(mp_obj_code_t);
|
||||||
|
code->base.type = &mp_type_code;
|
||||||
|
code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile);
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_BUILTINS_COMPILE
|
||||||
|
|
||||||
|
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) {
|
||||||
// work out the context
|
// work out the context
|
||||||
mp_obj_dict_t *globals = mp_globals_get();
|
mp_obj_dict_t *globals = mp_globals_get();
|
||||||
mp_obj_dict_t *locals = mp_locals_get();
|
mp_obj_dict_t *locals = mp_locals_get();
|
||||||
|
@ -59,6 +127,18 @@ STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_pars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_BUILTINS_COMPILE
|
||||||
|
if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) {
|
||||||
|
return code_execute(args[0], globals, locals);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mp_uint_t 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);
|
||||||
|
|
||||||
return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);
|
return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&mp_builtin_any_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&mp_builtin_any_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bin), (mp_obj_t)&mp_builtin_bin_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_bin), (mp_obj_t)&mp_builtin_bin_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callable), (mp_obj_t)&mp_builtin_callable_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_callable), (mp_obj_t)&mp_builtin_callable_obj },
|
||||||
|
#if MICROPY_PY_BUILTINS_COMPILE
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_compile), (mp_obj_t)&mp_builtin_compile_obj },
|
||||||
|
#endif
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chr), (mp_obj_t)&mp_builtin_chr_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_chr), (mp_obj_t)&mp_builtin_chr_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dir), (mp_obj_t)&mp_builtin_dir_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_dir), (mp_obj_t)&mp_builtin_dir_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_divmod), (mp_obj_t)&mp_builtin_divmod_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_divmod), (mp_obj_t)&mp_builtin_divmod_obj },
|
||||||
|
|
|
@ -312,6 +312,11 @@ typedef double mp_float_t;
|
||||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Whether to support compile function
|
||||||
|
#ifndef MICROPY_PY_BUILTINS_COMPILE
|
||||||
|
#define MICROPY_PY_BUILTINS_COMPILE (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Whether to set __file__ for imported modules
|
// Whether to set __file__ for imported modules
|
||||||
#ifndef MICROPY_PY___FILE__
|
#ifndef MICROPY_PY___FILE__
|
||||||
#define MICROPY_PY___FILE__ (1)
|
#define MICROPY_PY___FILE__ (1)
|
||||||
|
|
|
@ -213,6 +213,12 @@ Q(value)
|
||||||
Q(write)
|
Q(write)
|
||||||
Q(zip)
|
Q(zip)
|
||||||
|
|
||||||
|
#if MICROPY_PY_BUILTINS_COMPILE
|
||||||
|
Q(compile)
|
||||||
|
Q(code)
|
||||||
|
Q(single)
|
||||||
|
#endif
|
||||||
|
|
||||||
Q(sep)
|
Q(sep)
|
||||||
Q(end)
|
Q(end)
|
||||||
|
|
||||||
|
|
|
@ -1189,6 +1189,13 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i
|
||||||
nlr_raise(module_fun);
|
nlr_raise(module_fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for compile only
|
||||||
|
if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {
|
||||||
|
mp_globals_set(old_globals);
|
||||||
|
mp_locals_set(old_locals);
|
||||||
|
return module_fun;
|
||||||
|
}
|
||||||
|
|
||||||
// complied successfully, execute it
|
// complied successfully, execute it
|
||||||
nlr_buf_t nlr;
|
nlr_buf_t nlr;
|
||||||
if (nlr_push(&nlr) == 0) {
|
if (nlr_push(&nlr) == 0) {
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||||
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||||
|
#define MICROPY_PY_BUILTINS_COMPILE (1)
|
||||||
#define MICROPY_PY_SYS_EXIT (1)
|
#define MICROPY_PY_SYS_EXIT (1)
|
||||||
#define MICROPY_PY_SYS_PLATFORM "linux"
|
#define MICROPY_PY_SYS_PLATFORM "linux"
|
||||||
#define MICROPY_PY_SYS_MAXSIZE (1)
|
#define MICROPY_PY_SYS_MAXSIZE (1)
|
||||||
|
|
Loading…
Reference in New Issue