diff options
Diffstat (limited to 'mrbgems/mruby-eval/src/eval.c')
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 114 |
1 files changed, 88 insertions, 26 deletions
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 5e8952f0d..146c6df08 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -4,6 +4,7 @@ #include <mruby/irep.h> #include <mruby/proc.h> #include <mruby/opcode.h> +#include <mruby/error.h> mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p); mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); @@ -30,7 +31,7 @@ get_closure_irep(mrb_state *mrb, int level) if (!e) return NULL; if (!MRB_ENV_STACK_SHARED_P(e)) return NULL; - + c = e->cxt.c; proc = c->cibase[e->cioff].proc; if (!proc || MRB_PROC_CFUNC_P(proc)) { @@ -39,6 +40,25 @@ get_closure_irep(mrb_state *mrb, int level) return proc->body.irep; } +/* search for irep lev above the bottom */ +static mrb_irep* +search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom) +{ + size_t i; + + for (i=0; i<top->rlen; i++) { + mrb_irep* tmp = top->reps[i]; + + if (tmp == bottom) return top; + tmp = search_irep(tmp, bnest-1, lev, bottom); + if (tmp) { + if (bnest == lev) return top; + return tmp; + } + } + return NULL; +} + static inline mrb_code search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) { @@ -60,6 +80,20 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) return 0; } +static int +irep_argc(mrb_irep *irep) +{ + mrb_code c; + + c = irep->iseq[0]; + if (GET_OPCODE(c) == OP_ENTER) { + mrb_aspec ax = GETARG_Ax(c); + /* extra 1 means a slot for block */ + return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; + } + return 0; +} + static mrb_bool potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) { @@ -70,32 +104,24 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) } static void -patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) +patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) { size_t i; mrb_code c; - int argc = 0; + int argc = irep_argc(irep); 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); + patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top); 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); + patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top); } } break; @@ -132,6 +158,34 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) } break; + case OP_GETUPVAR: + { + int lev = GETARG_C(c)+1; + mrb_irep *tmp = search_irep(top, bnest, lev, irep); + if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + } + break; + + case OP_SETUPVAR: + { + int lev = GETARG_C(c)+1; + mrb_irep *tmp = search_irep(top, bnest, lev, irep); + if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + } + break; + case OP_STOP: if (mrb->c->ci->acc >= 0) { irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL); @@ -159,10 +213,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con cxt = mrbc_context_new(mrb); cxt->lineno = line; - if (!file) { - file = "(eval)"; - } - mrbc_filename(mrb, cxt, file); + mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; cxt->no_optimize = TRUE; @@ -175,12 +226,22 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con if (0 < p->nerr) { /* parse error */ - char buf[256]; - int n; - n = snprintf(buf, sizeof(buf), "line %d: %s\n", p->error_buffer[0].lineno, p->error_buffer[0].message); + mrb_value str; + + if (file) { + str = mrb_format(mrb, " file %S line %S: %S", + mrb_str_new_cstr(mrb, file), + mrb_fixnum_value(p->error_buffer[0].lineno), + mrb_str_new_cstr(mrb, p->error_buffer[0].message)); + } + else { + str = mrb_format(mrb, " line %S: %S", + mrb_fixnum_value(p->error_buffer[0].lineno), + mrb_str_new_cstr(mrb, p->error_buffer[0].message)); + } mrb_parser_free(p); mrbc_context_free(mrb, cxt); - mrb_exc_raise(mrb, mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); + mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); } proc = mrb_generate_code(mrb, p); @@ -196,14 +257,15 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con 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->cxt.c = c; + e->cioff = c->ci - c->cibase; e->stack = c->ci->stackent; - MRB_SET_ENV_STACK_LEN(e, c->ci[-1].proc->body.irep->nlocals); + MRB_SET_ENV_STACK_LEN(e, c->ci->proc->body.irep->nlocals); c->ci->target_class = proc->target_class; c->ci->env = 0; proc->env = e; - patch_irep(mrb, proc->body.irep, 0); + patch_irep(mrb, proc->body.irep, 0, proc->body.irep); + /* mrb_codedump_all(mrb, proc); */ mrb_parser_free(p); mrbc_context_free(mrb, cxt); @@ -247,7 +309,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self) mrb_value b; mrb_int argc; mrb_value *argv; - mrb_get_args(mrb, "*&", &argv, &argc, &b); + mrb_get_args(mrb, "*!&", &argv, &argc, &b); if (mrb_nil_p(b)) { char *s; |
