mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers proc.c Source File

proc.c

00001 /*
00002 ** proc.c - Proc class
00003 **
00004 ** See Copyright Notice in mruby.h
00005 */
00006 
00007 #include "mruby.h"
00008 #include "mruby/class.h"
00009 #include "mruby/proc.h"
00010 #include "mruby/opcode.h"
00011 
00012 static mrb_code call_iseq[] = {
00013   MKOP_A(OP_CALL, 0),
00014 };
00015 
00016 struct RProc *
00017 mrb_proc_new(mrb_state *mrb, mrb_irep *irep)
00018 {
00019   struct RProc *p;
00020   mrb_callinfo *ci = mrb->c->ci;
00021 
00022   p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
00023   p->target_class = 0;
00024   if (ci) {
00025     if (ci->proc)
00026       p->target_class = ci->proc->target_class;
00027     if (!p->target_class)
00028       p->target_class = ci->target_class;
00029   }
00030   p->body.irep = irep;
00031   p->env = 0;
00032   mrb_irep_incref(mrb, irep);
00033 
00034   return p;
00035 }
00036 
00037 static struct REnv*
00038 env_new(mrb_state *mrb, int nlocals)
00039 {
00040   struct REnv *e;
00041 
00042   e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
00043   MRB_SET_ENV_STACK_LEN(e, nlocals);
00044   e->mid = mrb->c->ci->mid;
00045   e->cioff = mrb->c->ci - mrb->c->cibase;
00046   e->stack = mrb->c->stack;
00047 
00048   return e;
00049 }
00050 
00051 static void
00052 closure_setup(mrb_state *mrb, struct RProc *p, int nlocals)
00053 {
00054   struct REnv *e;
00055 
00056   if (!mrb->c->ci->env) {
00057     e = env_new(mrb, nlocals);
00058     mrb->c->ci->env = e;
00059   }
00060   else {
00061     e = mrb->c->ci->env;
00062   }
00063   p->env = e;
00064 }
00065 
00066 struct RProc *
00067 mrb_closure_new(mrb_state *mrb, mrb_irep *irep)
00068 {
00069   struct RProc *p = mrb_proc_new(mrb, irep);
00070 
00071   closure_setup(mrb, p, mrb->c->ci->proc->body.irep->nlocals);
00072   return p;
00073 }
00074 
00075 MRB_API struct RProc *
00076 mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
00077 {
00078   struct RProc *p;
00079 
00080   p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
00081   p->body.func = func;
00082   p->flags |= MRB_PROC_CFUNC;
00083   p->env = 0;
00084 
00085   return p;
00086 }
00087 
00088 MRB_API struct RProc *
00089 mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv)
00090 {
00091   struct RProc *p = mrb_proc_new_cfunc(mrb, func);
00092   struct REnv *e;
00093   int i;
00094 
00095   p->env = e = env_new(mrb, argc);
00096   MRB_ENV_UNSHARE_STACK(e);
00097   e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc);
00098   if (argv) {
00099     for (i = 0; i < argc; ++i) {
00100       e->stack[i] = argv[i];
00101     }
00102   }
00103   else {
00104     for (i = 0; i < argc; ++i) {
00105       SET_NIL_VALUE(e->stack[i]);
00106     }
00107   }
00108   return p;
00109 }
00110 
00111 MRB_API struct RProc *
00112 mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals)
00113 {
00114   return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL);
00115 }
00116 
00117 MRB_API mrb_value
00118 mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
00119 {
00120   struct RProc *p = mrb->c->ci->proc;
00121   struct REnv *e = p->env;
00122 
00123   if (!MRB_PROC_CFUNC_P(p)) {
00124     mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc.");
00125   }
00126   if (!e) {
00127     mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv.");
00128   }
00129   if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) {
00130     mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)",
00131                mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e)));
00132   }
00133 
00134   return e->stack[idx];
00135 }
00136 
00137 MRB_API void
00138 mrb_proc_copy(struct RProc *a, struct RProc *b)
00139 {
00140   a->flags = b->flags;
00141   a->body = b->body;
00142   if (!MRB_PROC_CFUNC_P(a)) {
00143     a->body.irep->refcnt++;
00144   }
00145   a->target_class = b->target_class;
00146   a->env = b->env;
00147 }
00148 
00149 static mrb_value
00150 mrb_proc_initialize(mrb_state *mrb, mrb_value self)
00151 {
00152   mrb_value blk;
00153 
00154   mrb_get_args(mrb, "&", &blk);
00155   if (mrb_nil_p(blk)) {
00156     /* Calling Proc.new without a block is not implemented yet */
00157     mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
00158   }
00159   else {
00160     mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(blk));
00161   }
00162   return self;
00163 }
00164 
00165 static mrb_value
00166 mrb_proc_init_copy(mrb_state *mrb, mrb_value self)
00167 {
00168   mrb_value proc;
00169 
00170   mrb_get_args(mrb, "o", &proc);
00171   if (mrb_type(proc) != MRB_TT_PROC) {
00172     mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
00173   }
00174   mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(proc));
00175   return self;
00176 }
00177 
00178 int
00179 mrb_proc_cfunc_p(struct RProc *p)
00180 {
00181   return MRB_PROC_CFUNC_P(p);
00182 }
00183 
00184 mrb_value
00185 mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self)
00186 {
00187   return (p->body.func)(mrb, self);
00188 }
00189 
00190 mrb_code*
00191 mrb_proc_iseq(mrb_state *mrb, struct RProc *p)
00192 {
00193   return p->body.irep->iseq;
00194 }
00195 
00196 /* 15.2.17.4.2 */
00197 static mrb_value
00198 mrb_proc_arity(mrb_state *mrb, mrb_value self)
00199 {
00200   struct RProc *p = mrb_proc_ptr(self);
00201   mrb_code *iseq = mrb_proc_iseq(mrb, p);
00202   mrb_aspec aspec;
00203   int ma, ra, pa, arity;
00204 
00205   if (MRB_PROC_CFUNC_P(p)) {
00206     /* TODO cfunc aspec not implemented yet */
00207     return mrb_fixnum_value(-1);
00208   }
00209 
00210   /* arity is depend on OP_ENTER */
00211   if (GET_OPCODE(*iseq) != OP_ENTER) {
00212     return mrb_fixnum_value(0);
00213   }
00214 
00215   aspec = GETARG_Ax(*iseq);
00216   ma = MRB_ASPEC_REQ(aspec);
00217   ra = MRB_ASPEC_REST(aspec);
00218   pa = MRB_ASPEC_POST(aspec);
00219   arity = ra ? -(ma + pa + 1) : ma + pa;
00220 
00221   return mrb_fixnum_value(arity);
00222 }
00223 
00224 /* 15.3.1.2.6  */
00225 /* 15.3.1.3.27 */
00226 /*
00227  * call-seq:
00228  *   lambda { |...| block }  -> a_proc
00229  *
00230  * Equivalent to <code>Proc.new</code>, except the resulting Proc objects
00231  * check the number of parameters passed when called.
00232  */
00233 static mrb_value
00234 proc_lambda(mrb_state *mrb, mrb_value self)
00235 {
00236   mrb_value blk;
00237   struct RProc *p;
00238 
00239   mrb_get_args(mrb, "&", &blk);
00240   if (mrb_nil_p(blk)) {
00241     mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
00242   }
00243   p = mrb_proc_ptr(blk);
00244   if (!MRB_PROC_STRICT_P(p)) {
00245     struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c);
00246     mrb_proc_copy(p2, p);
00247     p2->flags |= MRB_PROC_STRICT;
00248     return mrb_obj_value(p2);
00249   }
00250   return blk;
00251 }
00252 
00253 void
00254 mrb_init_proc(mrb_state *mrb)
00255 {
00256   struct RProc *m;
00257   mrb_irep *call_irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
00258   static const mrb_irep mrb_irep_zero = { 0 };
00259 
00260   *call_irep = mrb_irep_zero;
00261   call_irep->flags = MRB_ISEQ_NO_FREE;
00262   call_irep->iseq = call_iseq;
00263   call_irep->ilen = 1;
00264 
00265   mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE());
00266   mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
00267   mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
00268 
00269   m = mrb_proc_new(mrb, call_irep);
00270   mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m);
00271   mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m);
00272 
00273   mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6  */
00274   mrb_define_method(mrb, mrb->kernel_module,       "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */
00275 }
00276