diff options
Diffstat (limited to 'mrbgems/mruby-eval/src')
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 92 |
1 files changed, 70 insertions, 22 deletions
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index ece769faf..8bfa2f112 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -1,4 +1,5 @@ #include "mruby.h" +#include "mruby/class.h" #include "mruby/compile.h" #include "mruby/irep.h" #include "mruby/proc.h" @@ -7,21 +8,29 @@ 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."); @@ -113,6 +149,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, cha mrbc_filename(mrb, cxt, file); } cxt->capture_errors = TRUE; + cxt->no_optimize = TRUE; p = mrb_parse_nstring(mrb, s, len, cxt); @@ -132,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; } @@ -180,6 +224,7 @@ mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); 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; @@ -192,7 +237,10 @@ f_instance_eval(mrb_state *mrb, mrb_value self) mrb_int line = 1; mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); - mrb->c->ci->acc = CI_ACC_SKIP; + c->ci->acc = CI_ACC_SKIP; + if (c->ci->target_class->tt == MRB_TT_ICLASS) { + c->ci->target_class = c->ci->target_class->c; + } return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self); } else { |
