diff options
Diffstat (limited to 'mrbgems/mruby-eval/src/eval.c')
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 142 |
1 files changed, 111 insertions, 31 deletions
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index daf5b2a1e..eef1f5046 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -1,27 +1,36 @@ -#include "mruby.h" -#include "mruby/compile.h" -#include "mruby/irep.h" -#include "mruby/proc.h" -#include "mruby/opcode.h" +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/compile.h> +#include <mruby/irep.h> +#include <mruby/proc.h> +#include <mruby/opcode.h> static struct mrb_irep * get_closure_irep(mrb_state *mrb, int level) { - struct REnv *e = mrb->c->ci[-1].proc->env; + struct mrb_context *c = mrb->c; + struct REnv *e = c->ci[-1].proc->env; struct RProc *proc; if (level == 0) { - return mrb->c->ci[-1].proc->body.irep; + proc = c->ci[-1].proc; + if (MRB_PROC_CFUNC_P(proc)) { + return NULL; + } + return proc->body.irep; } - + while (--level) { e = (struct REnv*)e->c; if (!e) return NULL; } if (!e) return NULL; - proc = mrb->c->cibase[e->cioff].proc; + proc = c->cibase[e->cioff].proc; + if (!proc || MRB_PROC_CFUNC_P(proc)) { + return NULL; + } return proc->body.irep; } @@ -33,7 +42,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) int pos; for (level = 0; (virep = get_closure_irep(mrb, level)); level++) { - if (virep->lv == NULL) { + if (!virep || virep->lv == NULL) { continue; } for (pos = 0; pos < virep->nlocals - 1; pos++) { @@ -46,20 +55,46 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) return 0; } +static mrb_bool +potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) +{ + if (v >= nlocals) return FALSE; + /* skip arguments */ + if (v < argc+1) return FALSE; + return TRUE; +} static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) { size_t i; mrb_code c; - - for (i = 0; i < irep->rlen; i++) { - patch_irep(mrb, irep->reps[i], bnest + 1); - } + int argc = 0; for (i = 0; i < irep->ilen; i++) { c = irep->iseq[i]; switch(GET_OPCODE(c)){ + case OP_ENTER: + { + mrb_aspec ax = GETARG_Ax(c); + /* extra 1 means a slot for block */ + argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; + } + break; + + case OP_EPUSH: + patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1); + break; + + case OP_LAMBDA: + { + int arg_c = GETARG_c(c); + if (arg_c & OP_L_CAPTURE) { + patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1); + } + } + break; + case OP_SEND: if (GETARG_C(c) != 0) { break; @@ -75,7 +110,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) case OP_MOVE: /* src part */ - if (GETARG_B(c) < irep->nlocals) { + if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); if (arg != 0) { /* must replace */ @@ -83,7 +118,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) } } /* dst part */ - if (GETARG_A(c) < irep->nlocals) { + if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); if (arg != 0) { /* must replace */ @@ -102,6 +137,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha struct mrb_parser_state *p; struct RProc *proc; struct REnv *e; + struct mrb_context *c = mrb->c; if (!mrb_nil_p(binding)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil."); @@ -112,11 +148,15 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha if (file) { mrbc_filename(mrb, cxt, file); } + cxt->capture_errors = TRUE; + cxt->no_optimize = TRUE; + + p = mrb_parse_nstring(mrb, s, len, cxt); - p = mrb_parser_new(mrb); - p->s = s; - p->send = s + len; - mrb_parser_parse(p, cxt); + /* only occur when memory ran out */ + if (!p) { + mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state."); + } if (0 < p->nerr) { /* parse error */ @@ -129,22 +169,29 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha } proc = mrb_generate_code(mrb, p); - e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci[-1].proc->env); - e->mid = mrb->c->ci[-1].mid; - e->cioff = mrb->c->ci - mrb->c->cibase - 1; - e->stack = mrb->c->ci->stackent; - mrb->c->ci->env = e; + if (proc == NULL) { + /* codegen error */ + mrb_parser_free(p); + mrbc_context_free(mrb, cxt); + mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); + } + if (c->ci[-1].proc->target_class) { + proc->target_class = c->ci[-1].proc->target_class; + } + e = c->ci[-1].proc->env; + if (!e) e = c->ci[-1].env; + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e); + e->mid = c->ci[-1].mid; + e->cioff = c->ci - c->cibase - 1; + e->stack = c->ci->stackent; + MRB_SET_ENV_STACK_LEN(e, c->ci[-1].proc->body.irep->nlocals); + c->ci->env = e; proc->env = e; patch_irep(mrb, proc->body.irep, 0); mrb_parser_free(p); mrbc_context_free(mrb, cxt); - if (proc == NULL) { - /* codegen error */ - mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); - } - return proc; } @@ -170,10 +217,43 @@ f_eval(mrb_state *mrb, mrb_value self) return ret; } +mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); + +#define CI_ACC_SKIP -1 + +static mrb_value +f_instance_eval(mrb_state *mrb, mrb_value self) +{ + struct mrb_context *c = mrb->c; + mrb_value b; + mrb_int argc; mrb_value *argv; + + mrb_get_args(mrb, "*&", &argv, &argc, &b); + + if (mrb_nil_p(b)) { + char *s; + mrb_int len; + char *file = NULL; + mrb_int line = 1; + mrb_value cv; + + mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); + c->ci->acc = CI_ACC_SKIP; + cv = mrb_singleton_class(mrb, self); + c->ci->target_class = mrb_class_ptr(cv); + return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self); + } + else { + mrb_get_args(mrb, "&", &b); + return mrb_obj_instance_eval(mrb, self); + } +} + void mrb_mruby_eval_gem_init(mrb_state* mrb) { - mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(3)); + mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3)); + mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2)); } void |
