mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-biding-eval: move essential part of the gem to mruby-eval
This change makes mruby-binding-eval gem nearly empty, but needed to make `eval(str, binding)` works as well as `binding.eval(str)`.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/internal.h>
|
||||
|
||||
/* 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));
|
||||
|
||||
Reference in New Issue
Block a user