summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-eval/src
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-eval/src')
-rw-r--r--mrbgems/mruby-eval/src/eval.c92
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 {