sabme ua / mruby-mbed

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers eval.c Source File

eval.c

00001 #include "mruby.h"
00002 #include "mruby/class.h"
00003 #include "mruby/compile.h"
00004 #include "mruby/irep.h"
00005 #include "mruby/proc.h"
00006 #include "mruby/opcode.h"
00007 
00008 static struct mrb_irep *
00009 get_closure_irep(mrb_state *mrb, int level)
00010 {
00011   struct REnv *e = mrb->c->ci[-1].proc->env;
00012   struct RProc *proc;
00013 
00014   if (level == 0) {
00015     proc = mrb->c->ci[-1].proc;
00016     if (MRB_PROC_CFUNC_P(proc)) {
00017       return NULL;
00018     }
00019     return proc->body.irep;
00020   }
00021 
00022   while (--level) {
00023     e = (struct REnv*)e->c;
00024     if (!e) return NULL;
00025   }
00026 
00027   if (!e) return NULL;
00028   proc = mrb->c->cibase[e->cioff].proc;
00029 
00030   if (MRB_PROC_CFUNC_P(proc)) {
00031     return NULL;
00032   }
00033   return proc->body.irep;
00034 }
00035 
00036 static inline mrb_code
00037 search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
00038 {
00039   mrb_irep *virep;
00040   int level;
00041   int pos;
00042 
00043   for (level = 0; (virep = get_closure_irep(mrb, level)); level++) {
00044     if (!virep || virep->lv == NULL) {
00045       continue;
00046     }
00047     for (pos = 0; pos < virep->nlocals - 1; pos++) {
00048       if (vsym == virep->lv[pos].name) {
00049         return (MKARG_B(pos + 1) | MKARG_C(level + bnest));
00050       }
00051     }
00052   }
00053 
00054   return 0;
00055 }
00056 
00057 
00058 static void
00059 patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
00060 {
00061   size_t i;
00062   mrb_code c;
00063 
00064   for (i = 0; i < irep->ilen; i++) {
00065     c = irep->iseq[i];
00066     switch(GET_OPCODE(c)){
00067     case OP_EPUSH:
00068       patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1);
00069       break;
00070 
00071     case OP_LAMBDA:
00072       {
00073         int arg_c = GETARG_c(c);
00074         if (arg_c & OP_L_CAPTURE) {
00075           patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1);
00076         }
00077       }
00078       break;
00079 
00080     case OP_SEND:
00081       if (GETARG_C(c) != 0) {
00082         break;
00083       }
00084       {
00085         mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest);
00086         if (arg != 0) {
00087           /* must replace */
00088           irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
00089         }
00090       }
00091       break;
00092 
00093     case OP_MOVE:
00094       /* src part */
00095       if (GETARG_B(c) < irep->nlocals) {
00096         mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest);
00097         if (arg != 0) {
00098           /* must replace */
00099           irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
00100         }
00101       }
00102       /* dst part */
00103       if (GETARG_A(c) < irep->nlocals) {
00104         mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest);
00105         if (arg != 0) {
00106           /* must replace */
00107           irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg;
00108         }
00109       }
00110       break;
00111     }
00112   }
00113 }
00114 
00115 static struct RProc*
00116 create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, char *file, mrb_int line)
00117 {
00118   mrbc_context *cxt;
00119   struct mrb_parser_state *p;
00120   struct RProc *proc;
00121   struct REnv *e;
00122 
00123   if (!mrb_nil_p(binding)) {
00124     mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil.");
00125   }
00126 
00127   cxt = mrbc_context_new(mrb);
00128   cxt->lineno = line;
00129   if (file) {
00130     mrbc_filename(mrb, cxt, file);
00131   }
00132   cxt->capture_errors = TRUE;
00133 
00134   p = mrb_parse_nstring(mrb, s, len, cxt);
00135 
00136   /* only occur when memory ran out */
00137   if (!p) {
00138     mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state.");
00139   }
00140 
00141   if (0 < p->nerr) {
00142     /* parse error */
00143     char buf[256];
00144     int n;
00145     n = snprintf(buf, sizeof(buf), "line %d: %s\n", p->error_buffer[0].lineno, p->error_buffer[0].message);
00146     mrb_parser_free(p);
00147     mrbc_context_free(mrb, cxt);
00148     mrb_exc_raise(mrb, mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
00149   }
00150 
00151   proc = mrb_generate_code(mrb, p);
00152   if (proc == NULL) {
00153     /* codegen error */
00154     mrb_parser_free(p);
00155     mrbc_context_free(mrb, cxt);
00156     mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
00157   }
00158   if (mrb->c->ci[-1].proc->target_class) {
00159     proc->target_class = mrb->c->ci[-1].proc->target_class;
00160   }
00161   e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci[-1].proc->env);
00162   e->mid = mrb->c->ci[-1].mid;
00163   e->cioff = mrb->c->ci - mrb->c->cibase - 1;
00164   e->stack = mrb->c->ci->stackent;
00165   mrb->c->ci->env = e;
00166   proc->env = e;
00167   patch_irep(mrb, proc->body.irep, 0);
00168 
00169   mrb_parser_free(p);
00170   mrbc_context_free(mrb, cxt);
00171 
00172   return proc;
00173 }
00174 
00175 static mrb_value
00176 f_eval(mrb_state *mrb, mrb_value self)
00177 {
00178   char *s;
00179   mrb_int len;
00180   mrb_value binding = mrb_nil_value();
00181   char *file = NULL;
00182   mrb_int line = 1;
00183   mrb_value ret;
00184   struct RProc *proc;
00185 
00186   mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
00187 
00188   proc = create_proc_from_string(mrb, s, len, binding, file, line);
00189   ret = mrb_toplevel_run(mrb, proc);
00190   if (mrb->exc) {
00191     mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
00192   }
00193 
00194   return ret;
00195 }
00196 
00197 mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
00198 
00199 #define CI_ACC_SKIP    -1
00200 
00201 static mrb_value
00202 f_instance_eval(mrb_state *mrb, mrb_value self)
00203 {
00204   mrb_value b;
00205   mrb_int argc; mrb_value *argv;
00206 
00207   mrb_get_args(mrb, "*&", &argv, &argc, &b);
00208 
00209   if (mrb_nil_p(b)) {
00210     char *s;
00211     mrb_int len;
00212     char *file = NULL;
00213     mrb_int line = 1;
00214 
00215     mrb_get_args(mrb, "s|zi", &s, &len, &file, &line);
00216     mrb->c->ci->acc = CI_ACC_SKIP;
00217     if (mrb->c->ci->target_class->tt == MRB_TT_ICLASS) {
00218       mrb->c->ci->target_class = mrb->c->ci->target_class->c;
00219     }
00220     return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self);
00221   }
00222   else {
00223     mrb_get_args(mrb, "&", &b);
00224     return mrb_obj_instance_eval(mrb, self);
00225   }
00226 }
00227 
00228 void
00229 mrb_mruby_eval_gem_init(mrb_state* mrb)
00230 {
00231   mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3));
00232   mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2));
00233 }
00234 
00235 void
00236 mrb_mruby_eval_gem_final(mrb_state* mrb)
00237 {
00238 }
00239