diff --git a/mrbgems/mruby-binding-core/src/binding-core.c b/mrbgems/mruby-binding-core/src/binding-core.c index fd7132406..dd9ed282a 100644 --- a/mrbgems/mruby-binding-core/src/binding-core.c +++ b/mrbgems/mruby-binding-core/src/binding-core.c @@ -390,6 +390,25 @@ mrb_f_binding(mrb_state *mrb, mrb_value self) return mrb_binding_new(mrb, proc, self, env); } +/* provided by mruby-eval */ +mrb_value mrb_f_eval(mrb_state *mrb, mrb_value self); + +static mrb_value +mrb_binding_eval(mrb_state *mrb, mrb_value binding) +{ + mrb_callinfo *ci = mrb->c->ci; + int argc = ci->n; + mrb_value *argv = ci->stack + 1; + + if (argc < 15) { + argv[0] = mrb_ary_new_from_values(mrb, argc, argv); + argv[1] = argv[argc]; /* copy block */ + ci->n = 15; + } + mrb_ary_splice(mrb, argv[0], 1, 0, binding); /* insert binding as 2nd argument */ + return mrb_f_eval(mrb, binding); +} + void mrb_mruby_binding_core_gem_init(mrb_state *mrb) { @@ -407,6 +426,7 @@ mrb_mruby_binding_core_gem_init(mrb_state *mrb) mrb_define_method(mrb, binding, "receiver", binding_receiver, MRB_ARGS_NONE()); mrb_define_method(mrb, binding, "source_location", binding_source_location, MRB_ARGS_NONE()); mrb_define_method(mrb, binding, "inspect", mrb_any_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, binding, "eval", mrb_binding_eval, MRB_ARGS_ANY()); } void diff --git a/mrbgems/mruby-binding-eval/src/binding.c b/mrbgems/mruby-binding-eval/src/binding.c index 9986d16f3..bd5674973 100644 --- a/mrbgems/mruby-binding-eval/src/binding.c +++ b/mrbgems/mruby-binding-eval/src/binding.c @@ -10,129 +10,10 @@ /* provided by mruby-eval */ mrb_value mrb_f_eval(mrb_state *mrb, mrb_value self); -/* provided by mruby-binding-core */ -const struct RProc *mrb_binding_extract_proc(mrb_state *mrb, mrb_value binding); -struct REnv *mrb_binding_extract_env(mrb_state *mrb, mrb_value binding); -/* provided by mruby-compiler */ -typedef mrb_bool mrb_parser_foreach_top_variable_func(mrb_state *mrb, mrb_sym sym, void *user); -void mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user); - -static void -binding_eval_error_check(mrb_state *mrb, struct mrb_parser_state *p, const char *file) -{ - if (!p) { - mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state (out of memory)"); - } - - if (0 < p->nerr) { - mrb_value str; - - if (file) { - str = mrb_format(mrb, "file %s line %d: %s", - file, - p->error_buffer[0].lineno, - p->error_buffer[0].message); - } - else { - str = mrb_format(mrb, "line %d: %s", - p->error_buffer[0].lineno, - p->error_buffer[0].message); - } - mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); - } -} - -#define LV_BUFFERS 8 - -struct expand_lvspace { - mrb_irep *irep; - struct REnv *env; - int numvar; - mrb_sym syms[LV_BUFFERS]; -}; - -static mrb_bool -expand_lvspace(mrb_state *mrb, mrb_sym sym, void *user) -{ - struct expand_lvspace *p = (struct expand_lvspace*)user; - mrb_int symlen; - const char *symname = mrb_sym_name_len(mrb, sym, &symlen); - - if (symname && symlen > 0) { - if (symname[0] != '&' && symname[0] != '*') { - p->syms[p->numvar++] = sym; - if (p->numvar >= LV_BUFFERS) { - mrb_proc_merge_lvar(mrb, p->irep, p->env, p->numvar, p->syms, NULL); - p->numvar = 0; - } - } - } - - return TRUE; -} - -struct binding_eval_prepare_body { - mrb_value binding; - const char *file; - mrbc_context *mrbc; - struct mrb_parser_state *pstate; -}; - -static mrb_value -binding_eval_prepare_body(mrb_state *mrb, void *opaque) -{ - struct binding_eval_prepare_body *p = (struct binding_eval_prepare_body*)opaque; - - const struct RProc *proc = mrb_binding_extract_proc(mrb, p->binding); - mrb_assert(!MRB_PROC_CFUNC_P(proc)); - p->mrbc->upper = proc; - binding_eval_error_check(mrb, p->pstate, p->file); - - struct expand_lvspace args = { - (mrb_irep*)proc->body.irep, - mrb_binding_extract_env(mrb, p->binding), - 0, - { 0 } - }; - mrb_parser_foreach_top_variable(mrb, p->pstate, expand_lvspace, &args); - if (args.numvar > 0) { - mrb_proc_merge_lvar(mrb, args.irep, args.env, args.numvar, args.syms, NULL); - } - - return mrb_nil_value(); -} - -static void -binding_eval_prepare(mrb_state *mrb, mrb_value binding) -{ - struct binding_eval_prepare_body d = { binding }; - mrb_int argc; - mrb_value *argv; - const char *expr; - mrb_int exprlen; - - mrb_get_args(mrb, "s|z*!", &expr, &exprlen, &d.file, &argv, &argc); - - /* `eval` should take (string[, file, line]) */ - if (argc > 3) mrb_argnum_error(mrb, argc, 1, 3); - - d.mrbc = mrbc_context_new(mrb); - mrbc_filename(mrb, d.mrbc, d.file ? d.file : "(eval)"); - d.mrbc->capture_errors = TRUE; - d.pstate = mrb_parse_nstring(mrb, expr, exprlen, d.mrbc); - - mrb_bool error; - mrb_value ret = mrb_protect_error(mrb, binding_eval_prepare_body, &d, &error); - if (d.pstate) mrb_parser_free(d.pstate); - if (d.mrbc) mrbc_context_free(mrb, d.mrbc); - if (error) mrb_exc_raise(mrb, ret); -} static mrb_value mrb_binding_eval(mrb_state *mrb, mrb_value binding) { - binding_eval_prepare(mrb, binding); - mrb_callinfo *ci = mrb->c->ci; int argc = ci->n; mrb_value *argv = ci->stack + 1; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 085d5bad0..d24246865 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -9,6 +9,14 @@ #include #include +/* provided by mruby-binding-core */ +const struct RProc * mrb_binding_extract_proc(mrb_state *mrb, mrb_value binding); +struct REnv * mrb_binding_extract_env(mrb_state *mrb, mrb_value binding); + +/* provided by mruby-compiler */ +typedef mrb_bool mrb_parser_foreach_top_variable_func(mrb_state *mrb, mrb_sym sym, void *user); +void mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user); + static struct RProc* create_proc_from_string(mrb_state *mrb, const char *s, mrb_int len, mrb_value binding, const char *file, mrb_int line) { @@ -146,6 +154,108 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc) return mrb_exec_irep(mrb, self, proc); } +static void +binding_eval_error_check(mrb_state *mrb, struct mrb_parser_state *p, const char *file) +{ + if (!p) { + mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state (out of memory)"); + } + + if (0 < p->nerr) { + mrb_value str; + + if (file) { + str = mrb_format(mrb, "file %s line %d: %s", + file, + p->error_buffer[0].lineno, + p->error_buffer[0].message); + } + else { + str = mrb_format(mrb, "line %d: %s", + p->error_buffer[0].lineno, + p->error_buffer[0].message); + } + mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); + } +} + +#define LV_BUFFERS 8 + +struct expand_lvspace { + mrb_irep *irep; + struct REnv *env; + int numvar; + mrb_sym syms[LV_BUFFERS]; +}; + +static mrb_bool +expand_lvspace(mrb_state *mrb, mrb_sym sym, void *user) +{ + struct expand_lvspace *p = (struct expand_lvspace*)user; + mrb_int symlen; + const char *symname = mrb_sym_name_len(mrb, sym, &symlen); + + if (symname && symlen > 0) { + if (symname[0] != '&' && symname[0] != '*') { + p->syms[p->numvar++] = sym; + if (p->numvar >= LV_BUFFERS) { + mrb_proc_merge_lvar(mrb, p->irep, p->env, p->numvar, p->syms, NULL); + p->numvar = 0; + } + } + } + + return TRUE; +} + +struct binding_eval_prepare_body { + mrb_value binding; + const char *file; + mrbc_context *mrbc; + struct mrb_parser_state *pstate; +}; + +static mrb_value +binding_eval_prepare_body(mrb_state *mrb, void *opaque) +{ + struct binding_eval_prepare_body *p = (struct binding_eval_prepare_body*)opaque; + + const struct RProc *proc = mrb_binding_extract_proc(mrb, p->binding); + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + p->mrbc->upper = proc; + binding_eval_error_check(mrb, p->pstate, p->file); + + struct expand_lvspace args = { + (mrb_irep*)proc->body.irep, + mrb_binding_extract_env(mrb, p->binding), + 0, + { 0 } + }; + mrb_parser_foreach_top_variable(mrb, p->pstate, expand_lvspace, &args); + if (args.numvar > 0) { + mrb_proc_merge_lvar(mrb, args.irep, args.env, args.numvar, args.syms, NULL); + } + + return mrb_nil_value(); +} + +static void +binding_eval_prepare(mrb_state *mrb, mrb_value binding, const char *expr, mrb_int exprlen, const char *file) +{ + struct binding_eval_prepare_body d = { binding }; + + d.mrbc = mrbc_context_new(mrb); + d.file = mrbc_filename(mrb, d.mrbc, file ? file : "(eval)"); + d.mrbc->capture_errors = TRUE; + d.pstate = mrb_parse_nstring(mrb, expr, exprlen, d.mrbc); + + mrb_bool error; + mrb_value ret = mrb_protect_error(mrb, binding_eval_prepare_body, &d, &error); + if (d.pstate) mrb_parser_free(d.pstate); + if (d.mrbc) mrbc_context_free(mrb, d.mrbc); + if (error) mrb_exc_raise(mrb, ret); +} + mrb_value mrb_f_eval(mrb_state *mrb, mrb_value self) { @@ -158,6 +268,9 @@ mrb_f_eval(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line); + if (!mrb_nil_p(binding)) { + binding_eval_prepare(mrb, binding, s, len, file); + } proc = create_proc_from_string(mrb, s, len, binding, file, line); if (!mrb_nil_p(binding)) { self = mrb_iv_get(mrb, binding, MRB_SYM(recv));