mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
mbed-mruby
How to use
Class
src/proc.c@0:158c61bb030f, 2015-03-25 (annotated)
- Committer:
- mzta
- Date:
- Wed Mar 25 17:36:16 2015 +0000
- Revision:
- 0:158c61bb030f
mirb_mbed initial commit;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mzta | 0:158c61bb030f | 1 | /* |
mzta | 0:158c61bb030f | 2 | ** proc.c - Proc class |
mzta | 0:158c61bb030f | 3 | ** |
mzta | 0:158c61bb030f | 4 | ** See Copyright Notice in mruby.h |
mzta | 0:158c61bb030f | 5 | */ |
mzta | 0:158c61bb030f | 6 | |
mzta | 0:158c61bb030f | 7 | #include "mruby.h" |
mzta | 0:158c61bb030f | 8 | #include "mruby/class.h" |
mzta | 0:158c61bb030f | 9 | #include "mruby/proc.h" |
mzta | 0:158c61bb030f | 10 | #include "mruby/opcode.h" |
mzta | 0:158c61bb030f | 11 | |
mzta | 0:158c61bb030f | 12 | static mrb_code call_iseq[] = { |
mzta | 0:158c61bb030f | 13 | MKOP_A(OP_CALL, 0), |
mzta | 0:158c61bb030f | 14 | }; |
mzta | 0:158c61bb030f | 15 | |
mzta | 0:158c61bb030f | 16 | struct RProc * |
mzta | 0:158c61bb030f | 17 | mrb_proc_new(mrb_state *mrb, mrb_irep *irep) |
mzta | 0:158c61bb030f | 18 | { |
mzta | 0:158c61bb030f | 19 | struct RProc *p; |
mzta | 0:158c61bb030f | 20 | mrb_callinfo *ci = mrb->c->ci; |
mzta | 0:158c61bb030f | 21 | |
mzta | 0:158c61bb030f | 22 | p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); |
mzta | 0:158c61bb030f | 23 | p->target_class = 0; |
mzta | 0:158c61bb030f | 24 | if (ci) { |
mzta | 0:158c61bb030f | 25 | if (ci->proc) |
mzta | 0:158c61bb030f | 26 | p->target_class = ci->proc->target_class; |
mzta | 0:158c61bb030f | 27 | if (!p->target_class) |
mzta | 0:158c61bb030f | 28 | p->target_class = ci->target_class; |
mzta | 0:158c61bb030f | 29 | } |
mzta | 0:158c61bb030f | 30 | p->body.irep = irep; |
mzta | 0:158c61bb030f | 31 | p->env = 0; |
mzta | 0:158c61bb030f | 32 | mrb_irep_incref(mrb, irep); |
mzta | 0:158c61bb030f | 33 | |
mzta | 0:158c61bb030f | 34 | return p; |
mzta | 0:158c61bb030f | 35 | } |
mzta | 0:158c61bb030f | 36 | |
mzta | 0:158c61bb030f | 37 | static struct REnv* |
mzta | 0:158c61bb030f | 38 | env_new(mrb_state *mrb, int nlocals) |
mzta | 0:158c61bb030f | 39 | { |
mzta | 0:158c61bb030f | 40 | struct REnv *e; |
mzta | 0:158c61bb030f | 41 | |
mzta | 0:158c61bb030f | 42 | e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env); |
mzta | 0:158c61bb030f | 43 | MRB_SET_ENV_STACK_LEN(e, nlocals); |
mzta | 0:158c61bb030f | 44 | e->mid = mrb->c->ci->mid; |
mzta | 0:158c61bb030f | 45 | e->cioff = mrb->c->ci - mrb->c->cibase; |
mzta | 0:158c61bb030f | 46 | e->stack = mrb->c->stack; |
mzta | 0:158c61bb030f | 47 | |
mzta | 0:158c61bb030f | 48 | return e; |
mzta | 0:158c61bb030f | 49 | } |
mzta | 0:158c61bb030f | 50 | |
mzta | 0:158c61bb030f | 51 | static void |
mzta | 0:158c61bb030f | 52 | closure_setup(mrb_state *mrb, struct RProc *p, int nlocals) |
mzta | 0:158c61bb030f | 53 | { |
mzta | 0:158c61bb030f | 54 | struct REnv *e; |
mzta | 0:158c61bb030f | 55 | |
mzta | 0:158c61bb030f | 56 | if (!mrb->c->ci->env) { |
mzta | 0:158c61bb030f | 57 | e = env_new(mrb, nlocals); |
mzta | 0:158c61bb030f | 58 | mrb->c->ci->env = e; |
mzta | 0:158c61bb030f | 59 | } |
mzta | 0:158c61bb030f | 60 | else { |
mzta | 0:158c61bb030f | 61 | e = mrb->c->ci->env; |
mzta | 0:158c61bb030f | 62 | } |
mzta | 0:158c61bb030f | 63 | p->env = e; |
mzta | 0:158c61bb030f | 64 | } |
mzta | 0:158c61bb030f | 65 | |
mzta | 0:158c61bb030f | 66 | struct RProc * |
mzta | 0:158c61bb030f | 67 | mrb_closure_new(mrb_state *mrb, mrb_irep *irep) |
mzta | 0:158c61bb030f | 68 | { |
mzta | 0:158c61bb030f | 69 | struct RProc *p = mrb_proc_new(mrb, irep); |
mzta | 0:158c61bb030f | 70 | |
mzta | 0:158c61bb030f | 71 | closure_setup(mrb, p, mrb->c->ci->proc->body.irep->nlocals); |
mzta | 0:158c61bb030f | 72 | return p; |
mzta | 0:158c61bb030f | 73 | } |
mzta | 0:158c61bb030f | 74 | |
mzta | 0:158c61bb030f | 75 | MRB_API struct RProc * |
mzta | 0:158c61bb030f | 76 | mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func) |
mzta | 0:158c61bb030f | 77 | { |
mzta | 0:158c61bb030f | 78 | struct RProc *p; |
mzta | 0:158c61bb030f | 79 | |
mzta | 0:158c61bb030f | 80 | p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); |
mzta | 0:158c61bb030f | 81 | p->body.func = func; |
mzta | 0:158c61bb030f | 82 | p->flags |= MRB_PROC_CFUNC; |
mzta | 0:158c61bb030f | 83 | p->env = 0; |
mzta | 0:158c61bb030f | 84 | |
mzta | 0:158c61bb030f | 85 | return p; |
mzta | 0:158c61bb030f | 86 | } |
mzta | 0:158c61bb030f | 87 | |
mzta | 0:158c61bb030f | 88 | MRB_API struct RProc * |
mzta | 0:158c61bb030f | 89 | mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv) |
mzta | 0:158c61bb030f | 90 | { |
mzta | 0:158c61bb030f | 91 | struct RProc *p = mrb_proc_new_cfunc(mrb, func); |
mzta | 0:158c61bb030f | 92 | struct REnv *e; |
mzta | 0:158c61bb030f | 93 | int i; |
mzta | 0:158c61bb030f | 94 | |
mzta | 0:158c61bb030f | 95 | p->env = e = env_new(mrb, argc); |
mzta | 0:158c61bb030f | 96 | MRB_ENV_UNSHARE_STACK(e); |
mzta | 0:158c61bb030f | 97 | e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); |
mzta | 0:158c61bb030f | 98 | if (argv) { |
mzta | 0:158c61bb030f | 99 | for (i = 0; i < argc; ++i) { |
mzta | 0:158c61bb030f | 100 | e->stack[i] = argv[i]; |
mzta | 0:158c61bb030f | 101 | } |
mzta | 0:158c61bb030f | 102 | } |
mzta | 0:158c61bb030f | 103 | else { |
mzta | 0:158c61bb030f | 104 | for (i = 0; i < argc; ++i) { |
mzta | 0:158c61bb030f | 105 | SET_NIL_VALUE(e->stack[i]); |
mzta | 0:158c61bb030f | 106 | } |
mzta | 0:158c61bb030f | 107 | } |
mzta | 0:158c61bb030f | 108 | return p; |
mzta | 0:158c61bb030f | 109 | } |
mzta | 0:158c61bb030f | 110 | |
mzta | 0:158c61bb030f | 111 | MRB_API struct RProc * |
mzta | 0:158c61bb030f | 112 | mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals) |
mzta | 0:158c61bb030f | 113 | { |
mzta | 0:158c61bb030f | 114 | return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL); |
mzta | 0:158c61bb030f | 115 | } |
mzta | 0:158c61bb030f | 116 | |
mzta | 0:158c61bb030f | 117 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 118 | mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx) |
mzta | 0:158c61bb030f | 119 | { |
mzta | 0:158c61bb030f | 120 | struct RProc *p = mrb->c->ci->proc; |
mzta | 0:158c61bb030f | 121 | struct REnv *e = p->env; |
mzta | 0:158c61bb030f | 122 | |
mzta | 0:158c61bb030f | 123 | if (!MRB_PROC_CFUNC_P(p)) { |
mzta | 0:158c61bb030f | 124 | mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc."); |
mzta | 0:158c61bb030f | 125 | } |
mzta | 0:158c61bb030f | 126 | if (!e) { |
mzta | 0:158c61bb030f | 127 | mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); |
mzta | 0:158c61bb030f | 128 | } |
mzta | 0:158c61bb030f | 129 | if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { |
mzta | 0:158c61bb030f | 130 | mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", |
mzta | 0:158c61bb030f | 131 | mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); |
mzta | 0:158c61bb030f | 132 | } |
mzta | 0:158c61bb030f | 133 | |
mzta | 0:158c61bb030f | 134 | return e->stack[idx]; |
mzta | 0:158c61bb030f | 135 | } |
mzta | 0:158c61bb030f | 136 | |
mzta | 0:158c61bb030f | 137 | MRB_API void |
mzta | 0:158c61bb030f | 138 | mrb_proc_copy(struct RProc *a, struct RProc *b) |
mzta | 0:158c61bb030f | 139 | { |
mzta | 0:158c61bb030f | 140 | a->flags = b->flags; |
mzta | 0:158c61bb030f | 141 | a->body = b->body; |
mzta | 0:158c61bb030f | 142 | if (!MRB_PROC_CFUNC_P(a)) { |
mzta | 0:158c61bb030f | 143 | a->body.irep->refcnt++; |
mzta | 0:158c61bb030f | 144 | } |
mzta | 0:158c61bb030f | 145 | a->target_class = b->target_class; |
mzta | 0:158c61bb030f | 146 | a->env = b->env; |
mzta | 0:158c61bb030f | 147 | } |
mzta | 0:158c61bb030f | 148 | |
mzta | 0:158c61bb030f | 149 | static mrb_value |
mzta | 0:158c61bb030f | 150 | mrb_proc_initialize(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 151 | { |
mzta | 0:158c61bb030f | 152 | mrb_value blk; |
mzta | 0:158c61bb030f | 153 | |
mzta | 0:158c61bb030f | 154 | mrb_get_args(mrb, "&", &blk); |
mzta | 0:158c61bb030f | 155 | if (mrb_nil_p(blk)) { |
mzta | 0:158c61bb030f | 156 | /* Calling Proc.new without a block is not implemented yet */ |
mzta | 0:158c61bb030f | 157 | mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); |
mzta | 0:158c61bb030f | 158 | } |
mzta | 0:158c61bb030f | 159 | else { |
mzta | 0:158c61bb030f | 160 | mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(blk)); |
mzta | 0:158c61bb030f | 161 | } |
mzta | 0:158c61bb030f | 162 | return self; |
mzta | 0:158c61bb030f | 163 | } |
mzta | 0:158c61bb030f | 164 | |
mzta | 0:158c61bb030f | 165 | static mrb_value |
mzta | 0:158c61bb030f | 166 | mrb_proc_init_copy(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 167 | { |
mzta | 0:158c61bb030f | 168 | mrb_value proc; |
mzta | 0:158c61bb030f | 169 | |
mzta | 0:158c61bb030f | 170 | mrb_get_args(mrb, "o", &proc); |
mzta | 0:158c61bb030f | 171 | if (mrb_type(proc) != MRB_TT_PROC) { |
mzta | 0:158c61bb030f | 172 | mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc"); |
mzta | 0:158c61bb030f | 173 | } |
mzta | 0:158c61bb030f | 174 | mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(proc)); |
mzta | 0:158c61bb030f | 175 | return self; |
mzta | 0:158c61bb030f | 176 | } |
mzta | 0:158c61bb030f | 177 | |
mzta | 0:158c61bb030f | 178 | int |
mzta | 0:158c61bb030f | 179 | mrb_proc_cfunc_p(struct RProc *p) |
mzta | 0:158c61bb030f | 180 | { |
mzta | 0:158c61bb030f | 181 | return MRB_PROC_CFUNC_P(p); |
mzta | 0:158c61bb030f | 182 | } |
mzta | 0:158c61bb030f | 183 | |
mzta | 0:158c61bb030f | 184 | mrb_value |
mzta | 0:158c61bb030f | 185 | mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self) |
mzta | 0:158c61bb030f | 186 | { |
mzta | 0:158c61bb030f | 187 | return (p->body.func)(mrb, self); |
mzta | 0:158c61bb030f | 188 | } |
mzta | 0:158c61bb030f | 189 | |
mzta | 0:158c61bb030f | 190 | mrb_code* |
mzta | 0:158c61bb030f | 191 | mrb_proc_iseq(mrb_state *mrb, struct RProc *p) |
mzta | 0:158c61bb030f | 192 | { |
mzta | 0:158c61bb030f | 193 | return p->body.irep->iseq; |
mzta | 0:158c61bb030f | 194 | } |
mzta | 0:158c61bb030f | 195 | |
mzta | 0:158c61bb030f | 196 | /* 15.2.17.4.2 */ |
mzta | 0:158c61bb030f | 197 | static mrb_value |
mzta | 0:158c61bb030f | 198 | mrb_proc_arity(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 199 | { |
mzta | 0:158c61bb030f | 200 | struct RProc *p = mrb_proc_ptr(self); |
mzta | 0:158c61bb030f | 201 | mrb_code *iseq = mrb_proc_iseq(mrb, p); |
mzta | 0:158c61bb030f | 202 | mrb_aspec aspec; |
mzta | 0:158c61bb030f | 203 | int ma, ra, pa, arity; |
mzta | 0:158c61bb030f | 204 | |
mzta | 0:158c61bb030f | 205 | if (MRB_PROC_CFUNC_P(p)) { |
mzta | 0:158c61bb030f | 206 | /* TODO cfunc aspec not implemented yet */ |
mzta | 0:158c61bb030f | 207 | return mrb_fixnum_value(-1); |
mzta | 0:158c61bb030f | 208 | } |
mzta | 0:158c61bb030f | 209 | |
mzta | 0:158c61bb030f | 210 | /* arity is depend on OP_ENTER */ |
mzta | 0:158c61bb030f | 211 | if (GET_OPCODE(*iseq) != OP_ENTER) { |
mzta | 0:158c61bb030f | 212 | return mrb_fixnum_value(0); |
mzta | 0:158c61bb030f | 213 | } |
mzta | 0:158c61bb030f | 214 | |
mzta | 0:158c61bb030f | 215 | aspec = GETARG_Ax(*iseq); |
mzta | 0:158c61bb030f | 216 | ma = MRB_ASPEC_REQ(aspec); |
mzta | 0:158c61bb030f | 217 | ra = MRB_ASPEC_REST(aspec); |
mzta | 0:158c61bb030f | 218 | pa = MRB_ASPEC_POST(aspec); |
mzta | 0:158c61bb030f | 219 | arity = ra ? -(ma + pa + 1) : ma + pa; |
mzta | 0:158c61bb030f | 220 | |
mzta | 0:158c61bb030f | 221 | return mrb_fixnum_value(arity); |
mzta | 0:158c61bb030f | 222 | } |
mzta | 0:158c61bb030f | 223 | |
mzta | 0:158c61bb030f | 224 | /* 15.3.1.2.6 */ |
mzta | 0:158c61bb030f | 225 | /* 15.3.1.3.27 */ |
mzta | 0:158c61bb030f | 226 | /* |
mzta | 0:158c61bb030f | 227 | * call-seq: |
mzta | 0:158c61bb030f | 228 | * lambda { |...| block } -> a_proc |
mzta | 0:158c61bb030f | 229 | * |
mzta | 0:158c61bb030f | 230 | * Equivalent to <code>Proc.new</code>, except the resulting Proc objects |
mzta | 0:158c61bb030f | 231 | * check the number of parameters passed when called. |
mzta | 0:158c61bb030f | 232 | */ |
mzta | 0:158c61bb030f | 233 | static mrb_value |
mzta | 0:158c61bb030f | 234 | proc_lambda(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 235 | { |
mzta | 0:158c61bb030f | 236 | mrb_value blk; |
mzta | 0:158c61bb030f | 237 | struct RProc *p; |
mzta | 0:158c61bb030f | 238 | |
mzta | 0:158c61bb030f | 239 | mrb_get_args(mrb, "&", &blk); |
mzta | 0:158c61bb030f | 240 | if (mrb_nil_p(blk)) { |
mzta | 0:158c61bb030f | 241 | mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); |
mzta | 0:158c61bb030f | 242 | } |
mzta | 0:158c61bb030f | 243 | p = mrb_proc_ptr(blk); |
mzta | 0:158c61bb030f | 244 | if (!MRB_PROC_STRICT_P(p)) { |
mzta | 0:158c61bb030f | 245 | struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c); |
mzta | 0:158c61bb030f | 246 | mrb_proc_copy(p2, p); |
mzta | 0:158c61bb030f | 247 | p2->flags |= MRB_PROC_STRICT; |
mzta | 0:158c61bb030f | 248 | return mrb_obj_value(p2); |
mzta | 0:158c61bb030f | 249 | } |
mzta | 0:158c61bb030f | 250 | return blk; |
mzta | 0:158c61bb030f | 251 | } |
mzta | 0:158c61bb030f | 252 | |
mzta | 0:158c61bb030f | 253 | void |
mzta | 0:158c61bb030f | 254 | mrb_init_proc(mrb_state *mrb) |
mzta | 0:158c61bb030f | 255 | { |
mzta | 0:158c61bb030f | 256 | struct RProc *m; |
mzta | 0:158c61bb030f | 257 | mrb_irep *call_irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); |
mzta | 0:158c61bb030f | 258 | static const mrb_irep mrb_irep_zero = { 0 }; |
mzta | 0:158c61bb030f | 259 | |
mzta | 0:158c61bb030f | 260 | *call_irep = mrb_irep_zero; |
mzta | 0:158c61bb030f | 261 | call_irep->flags = MRB_ISEQ_NO_FREE; |
mzta | 0:158c61bb030f | 262 | call_irep->iseq = call_iseq; |
mzta | 0:158c61bb030f | 263 | call_irep->ilen = 1; |
mzta | 0:158c61bb030f | 264 | |
mzta | 0:158c61bb030f | 265 | mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 266 | mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); |
mzta | 0:158c61bb030f | 267 | mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 268 | |
mzta | 0:158c61bb030f | 269 | m = mrb_proc_new(mrb, call_irep); |
mzta | 0:158c61bb030f | 270 | mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m); |
mzta | 0:158c61bb030f | 271 | mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m); |
mzta | 0:158c61bb030f | 272 | |
mzta | 0:158c61bb030f | 273 | mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */ |
mzta | 0:158c61bb030f | 274 | mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */ |
mzta | 0:158c61bb030f | 275 | } |
mzta | 0:158c61bb030f | 276 |