source: EcnlProtoTool/trunk/mruby-2.1.1/src/proc.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 7.4 KB
Line 
1/*
2** proc.c - Proc class
3**
4** See Copyright Notice in mruby.h
5*/
6
7#include <mruby.h>
8#include <mruby/class.h>
9#include <mruby/proc.h>
10#include <mruby/opcode.h>
11
12static const mrb_code call_iseq[] = {
13 OP_CALL,
14};
15
16struct RProc*
17mrb_proc_new(mrb_state *mrb, mrb_irep *irep)
18{
19 struct RProc *p;
20 mrb_callinfo *ci = mrb->c->ci;
21
22 p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
23 if (ci) {
24 struct RClass *tc = NULL;
25
26 if (ci->proc) {
27 tc = MRB_PROC_TARGET_CLASS(ci->proc);
28 }
29 if (tc == NULL) {
30 tc = ci->target_class;
31 }
32 p->upper = ci->proc;
33 p->e.target_class = tc;
34 }
35 p->body.irep = irep;
36 mrb_irep_incref(mrb, irep);
37
38 return p;
39}
40
41static struct REnv*
42env_new(mrb_state *mrb, mrb_int nlocals)
43{
44 struct REnv *e;
45 mrb_callinfo *ci = mrb->c->ci;
46 int bidx;
47
48 e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL);
49 MRB_ENV_SET_STACK_LEN(e, nlocals);
50 bidx = ci->argc;
51 if (ci->argc < 0) bidx = 2;
52 else bidx += 1;
53 MRB_ENV_SET_BIDX(e, bidx);
54 e->mid = ci->mid;
55 e->stack = mrb->c->stack;
56 e->cxt = mrb->c;
57
58 return e;
59}
60
61static void
62closure_setup(mrb_state *mrb, struct RProc *p)
63{
64 mrb_callinfo *ci = mrb->c->ci;
65 struct RProc *up = p->upper;
66 struct REnv *e = NULL;
67
68 if (ci && ci->env) {
69 e = ci->env;
70 }
71 else if (up) {
72 struct RClass *tc = MRB_PROC_TARGET_CLASS(p);
73
74 e = env_new(mrb, up->body.irep->nlocals);
75 ci->env = e;
76 if (tc) {
77 e->c = tc;
78 mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc);
79 }
80 if (MRB_PROC_ENV_P(up) && MRB_PROC_ENV(up)->cxt == NULL) {
81 e->mid = MRB_PROC_ENV(up)->mid;
82 }
83 }
84 if (e) {
85 p->e.env = e;
86 p->flags |= MRB_PROC_ENVSET;
87 mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e);
88 }
89}
90
91struct RProc*
92mrb_closure_new(mrb_state *mrb, mrb_irep *irep)
93{
94 struct RProc *p = mrb_proc_new(mrb, irep);
95
96 closure_setup(mrb, p);
97 return p;
98}
99
100MRB_API struct RProc*
101mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
102{
103 struct RProc *p;
104
105 p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
106 p->body.func = func;
107 p->flags |= MRB_PROC_CFUNC_FL;
108 p->upper = 0;
109 p->e.target_class = 0;
110
111 return p;
112}
113
114MRB_API struct RProc*
115mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv)
116{
117 struct RProc *p = mrb_proc_new_cfunc(mrb, func);
118 struct REnv *e;
119 int i;
120
121 p->e.env = e = env_new(mrb, argc);
122 p->flags |= MRB_PROC_ENVSET;
123 mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e);
124 MRB_ENV_UNSHARE_STACK(e);
125 e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc);
126 if (argv) {
127 for (i = 0; i < argc; ++i) {
128 e->stack[i] = argv[i];
129 }
130 }
131 else {
132 for (i = 0; i < argc; ++i) {
133 SET_NIL_VALUE(e->stack[i]);
134 }
135 }
136 return p;
137}
138
139MRB_API struct RProc*
140mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals)
141{
142 return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL);
143}
144
145MRB_API mrb_value
146mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
147{
148 struct RProc *p = mrb->c->ci->proc;
149 struct REnv *e;
150
151 if (!p || !MRB_PROC_CFUNC_P(p)) {
152 mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc.");
153 }
154 e = MRB_PROC_ENV(p);
155 if (!e) {
156 mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv.");
157 }
158 if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) {
159 mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %i (expected: 0 <= index < %i)",
160 idx, MRB_ENV_STACK_LEN(e));
161 }
162
163 return e->stack[idx];
164}
165
166void
167mrb_proc_copy(struct RProc *a, struct RProc *b)
168{
169 if (a->body.irep) {
170 /* already initialized proc */
171 return;
172 }
173 a->flags = b->flags;
174 a->body = b->body;
175 if (!MRB_PROC_CFUNC_P(a) && a->body.irep) {
176 a->body.irep->refcnt++;
177 }
178 a->upper = b->upper;
179 a->e.env = b->e.env;
180 /* a->e.target_class = a->e.target_class; */
181}
182
183static mrb_value
184mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
185{
186 mrb_value blk;
187 mrb_value proc;
188 struct RProc *p;
189
190 /* Calling Proc.new without a block is not implemented yet */
191 mrb_get_args(mrb, "&!", &blk);
192 p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
193 mrb_proc_copy(p, mrb_proc_ptr(blk));
194 proc = mrb_obj_value(p);
195 mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, proc);
196 if (!MRB_PROC_STRICT_P(p) &&
197 mrb->c->ci > mrb->c->cibase && MRB_PROC_ENV(p) == mrb->c->ci[-1].env) {
198 p->flags |= MRB_PROC_ORPHAN;
199 }
200 return proc;
201}
202
203static mrb_value
204mrb_proc_init_copy(mrb_state *mrb, mrb_value self)
205{
206 mrb_value proc;
207
208 mrb_get_args(mrb, "o", &proc);
209 if (!mrb_proc_p(proc)) {
210 mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
211 }
212 mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(proc));
213 return self;
214}
215
216/* 15.2.17.4.2 */
217static mrb_value
218proc_arity(mrb_state *mrb, mrb_value self)
219{
220 return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self)));
221}
222
223/* 15.3.1.2.6 */
224/* 15.3.1.3.27 */
225/*
226 * call-seq:
227 * lambda { |...| block } -> a_proc
228 *
229 * Equivalent to <code>Proc.new</code>, except the resulting Proc objects
230 * check the number of parameters passed when called.
231 */
232static mrb_value
233proc_lambda(mrb_state *mrb, mrb_value self)
234{
235 mrb_value blk;
236 struct RProc *p;
237
238 mrb_get_args(mrb, "&", &blk);
239 if (mrb_nil_p(blk)) {
240 mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
241 }
242 if (!mrb_proc_p(blk)) {
243 mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
244 }
245 p = mrb_proc_ptr(blk);
246 if (!MRB_PROC_STRICT_P(p)) {
247 struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c);
248 mrb_proc_copy(p2, p);
249 p2->flags |= MRB_PROC_STRICT;
250 return mrb_obj_value(p2);
251 }
252 return blk;
253}
254
255mrb_int
256mrb_proc_arity(const struct RProc *p)
257{
258 struct mrb_irep *irep;
259 const mrb_code *pc;
260 mrb_aspec aspec;
261 int ma, op, ra, pa, arity;
262
263 if (MRB_PROC_CFUNC_P(p)) {
264 /* TODO cfunc aspec not implemented yet */
265 return -1;
266 }
267
268 irep = p->body.irep;
269 if (!irep) {
270 return 0;
271 }
272
273 pc = irep->iseq;
274 /* arity is depend on OP_ENTER */
275 if (*pc != OP_ENTER) {
276 return 0;
277 }
278
279 aspec = PEEK_W(pc+1);
280 ma = MRB_ASPEC_REQ(aspec);
281 op = MRB_ASPEC_OPT(aspec);
282 ra = MRB_ASPEC_REST(aspec);
283 pa = MRB_ASPEC_POST(aspec);
284 arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
285
286 return arity;
287}
288
289void
290mrb_init_proc(mrb_state *mrb)
291{
292 struct RProc *p;
293 mrb_method_t m;
294 mrb_irep *call_irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
295 static const mrb_irep mrb_irep_zero = { 0 };
296
297 *call_irep = mrb_irep_zero;
298 call_irep->flags = MRB_ISEQ_NO_FREE;
299 call_irep->iseq = call_iseq;
300 call_irep->ilen = 1;
301 call_irep->nregs = 2; /* receiver and block */
302
303 mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK());
304 mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
305 mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE());
306
307 p = mrb_proc_new(mrb, call_irep);
308 MRB_METHOD_FROM_PROC(m, p);
309 mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m);
310 mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m);
311
312 mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.2.6 */
313 mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.3.27 */
314}
Note: See TracBrowser for help on using the repository browser.