source: EcnlProtoTool/trunk/mruby-1.2.0/src/proc.c@ 321

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

文字コードを設定

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