aboutsummaryrefslogtreecommitdiff
path: root/py/builtinevex.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-10-25 21:59:14 +0100
committerDamien George <damien.p.george@gmail.com>2014-10-25 22:07:25 +0100
commitc9fc62072330421dbbcfa316569b51601a7f0349 (patch)
treed7044bdc0e84396822fea1e24f4220d8917ca847 /py/builtinevex.c
parente5a3759ff5478392f914ba7a7346da60d9735bf4 (diff)
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.
Diffstat (limited to 'py/builtinevex.c')
-rw-r--r--py/builtinevex.c84
1 files changed, 82 insertions, 2 deletions
diff --git a/py/builtinevex.c b/py/builtinevex.c
index e24055316..73f254c5c 100644
--- a/py/builtinevex.c
+++ b/py/builtinevex.c
@@ -34,19 +34,87 @@
#include "lexerunix.h"
#include "parse.h"
#include "obj.h"
+#include "objfun.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.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;
const char *str = mp_obj_str_get_data(args[0], &str_len);
+ // get the filename
+ qstr filename = mp_obj_str_get_qstr(args[1]);
+
// create the lexer
- mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
+ 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
mp_obj_dict_t *globals = mp_globals_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);
}