source: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/src/method.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: 15.2 KB
Line 
1#include "mruby.h"
2#include "mruby/array.h"
3#include "mruby/class.h"
4#include "mruby/variable.h"
5#include "mruby/proc.h"
6#include "mruby/string.h"
7
8static struct RObject *
9method_object_alloc(mrb_state *mrb, struct RClass *mclass)
10{
11 return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass);
12}
13
14static void
15bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner)
16{
17 if (!mrb_module_p(owner) &&
18 mrb_class_ptr(owner) != mrb_obj_class(mrb, recv) &&
19 !mrb_obj_is_kind_of(mrb, recv, mrb_class_ptr(owner))) {
20 if (mrb_sclass_p(owner)) {
21 mrb_raise(mrb, E_TYPE_ERROR, "singleton method called for a different object");
22 } else {
23 mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %v", owner);
24 }
25 }
26}
27
28static mrb_value
29unbound_method_bind(mrb_state *mrb, mrb_value self)
30{
31 struct RObject *me;
32 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
33 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
34 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
35 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
36 mrb_value recv;
37
38 mrb_get_args(mrb, "o", &recv);
39 bind_check(mrb, recv, owner);
40 me = method_object_alloc(mrb, mrb_class_get(mrb, "Method"));
41 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), owner);
42 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), recv);
43 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), name);
44 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), proc);
45 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), klass);
46
47 return mrb_obj_value(me);
48}
49
50#define IV_GET(value, name) mrb_iv_get(mrb, value, mrb_intern_lit(mrb, name))
51static mrb_value
52method_eql(mrb_state *mrb, mrb_value self)
53{
54 mrb_value other, receiver, orig_proc, other_proc;
55 struct RClass *owner, *klass;
56 struct RProc *orig_rproc, *other_rproc;
57
58 mrb_get_args(mrb, "o", &other);
59 if (!mrb_obj_is_instance_of(mrb, other, mrb_class(mrb, self)))
60 return mrb_false_value();
61
62 if (mrb_class(mrb, self) != mrb_class(mrb, other))
63 return mrb_false_value();
64
65 klass = mrb_class_ptr(IV_GET(self, "_klass"));
66 if (klass != mrb_class_ptr(IV_GET(other, "_klass")))
67 return mrb_false_value();
68
69 owner = mrb_class_ptr(IV_GET(self, "_owner"));
70 if (owner != mrb_class_ptr(IV_GET(other, "_owner")))
71 return mrb_false_value();
72
73 receiver = IV_GET(self, "_recv");
74 if (!mrb_obj_equal(mrb, receiver, IV_GET(other, "_recv")))
75 return mrb_false_value();
76
77 orig_proc = IV_GET(self, "_proc");
78 other_proc = IV_GET(other, "_proc");
79 if (mrb_nil_p(orig_proc) && mrb_nil_p(other_proc)) {
80 if (mrb_symbol(IV_GET(self, "_name")) == mrb_symbol(IV_GET(other, "_name")))
81 return mrb_true_value();
82 else
83 return mrb_false_value();
84 }
85
86 if (mrb_nil_p(orig_proc))
87 return mrb_false_value();
88 if (mrb_nil_p(other_proc))
89 return mrb_false_value();
90
91 orig_rproc = mrb_proc_ptr(orig_proc);
92 other_rproc = mrb_proc_ptr(other_proc);
93 if (MRB_PROC_CFUNC_P(orig_rproc)) {
94 if (!MRB_PROC_CFUNC_P(other_rproc))
95 return mrb_false_value();
96 if (orig_rproc->body.func != other_rproc->body.func)
97 return mrb_false_value();
98 }
99 else {
100 if (MRB_PROC_CFUNC_P(other_rproc))
101 return mrb_false_value();
102 if (orig_rproc->body.irep != other_rproc->body.irep)
103 return mrb_false_value();
104 }
105
106 return mrb_true_value();
107}
108
109#undef IV_GET
110
111static mrb_value
112mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner,
113 int argc, mrb_value *argv, mrb_value block)
114{
115 mrb_value ret;
116 mrb_sym orig_mid = mrb->c->ci->mid;
117
118 mrb->c->ci->mid = mrb_symbol(name);
119 if (mrb_nil_p(proc)) {
120 mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv);
121 mrb_ary_unshift(mrb, missing_argv, name);
122 ret = mrb_funcall_argv(mrb, recv, mrb_intern_lit(mrb, "method_missing"), argc + 1, RARRAY_PTR(missing_argv));
123 }
124 else if (!mrb_nil_p(block)) {
125 /*
126 workaround since `mrb_yield_with_class` does not support passing block as parameter
127 need new API that initializes `mrb->c->stack[argc+1]` with block passed by argument
128 */
129 ret = mrb_funcall_with_block(mrb, recv, mrb_symbol(name), argc, argv, block);
130 }
131 else {
132 ret = mrb_yield_with_class(mrb, proc, argc, argv, recv, owner);
133 }
134 mrb->c->ci->mid = orig_mid;
135 return ret;
136}
137
138static mrb_value
139method_call(mrb_state *mrb, mrb_value self)
140{
141 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
142 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
143 mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
144 struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")));
145 mrb_int argc;
146 mrb_value *argv, block;
147
148 mrb_get_args(mrb, "*&", &argv, &argc, &block);
149 return mcall(mrb, recv, proc, name, owner, argc, argv, block);
150}
151
152static mrb_value
153method_bcall(mrb_state *mrb, mrb_value self)
154{
155 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
156 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
157 mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
158 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
159 mrb_int argc;
160 mrb_value *argv, block;
161
162 mrb_get_args(mrb, "o*&", &recv, &argv, &argc, &block);
163 bind_check(mrb, recv, owner);
164 return mcall(mrb, recv, proc, name, mrb_class_ptr(owner), argc, argv, block);
165}
166
167static mrb_value
168method_unbind(mrb_state *mrb, mrb_value self)
169{
170 struct RObject *ume;
171 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
172 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
173 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
174 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
175
176 ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod"));
177 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_owner"), owner);
178 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_recv"), mrb_nil_value());
179 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_name"), name);
180 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_proc"), proc);
181 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_klass"), klass);
182
183 return mrb_obj_value(ume);
184}
185
186static struct RProc *
187method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
188{
189 mrb_method_t m = mrb_method_search_vm(mrb, cp, mid);
190 if (MRB_METHOD_UNDEF_P(m))
191 return NULL;
192 if (MRB_METHOD_PROC_P(m))
193 return MRB_METHOD_PROC(m);
194 return mrb_proc_new_cfunc(mrb, MRB_METHOD_FUNC(m));
195}
196
197static mrb_value
198method_super_method(mrb_state *mrb, mrb_value self)
199{
200 mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
201 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
202 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
203 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
204 struct RClass *super, *rklass;
205 struct RProc *proc;
206 struct RObject *me;
207
208 switch (mrb_type(klass)) {
209 case MRB_TT_SCLASS:
210 super = mrb_class_ptr(klass)->super->super;
211 break;
212 case MRB_TT_ICLASS:
213 super = mrb_class_ptr(klass)->super;
214 break;
215 default:
216 super = mrb_class_ptr(owner)->super;
217 break;
218 }
219
220 proc = method_search_vm(mrb, &super, mrb_symbol(name));
221 if (!proc)
222 return mrb_nil_value();
223
224 rklass = super;
225 while (super->tt == MRB_TT_ICLASS)
226 super = super->c;
227
228 me = method_object_alloc(mrb, mrb_obj_class(mrb, self));
229 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(super));
230 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), recv);
231 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), name);
232 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), mrb_obj_value(proc));
233 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), mrb_obj_value(rklass));
234
235 return mrb_obj_value(me);
236}
237
238static mrb_value
239method_arity(mrb_state *mrb, mrb_value self)
240{
241 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
242 mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc));
243 return mrb_fixnum_value(arity);
244}
245
246static mrb_value
247method_source_location(mrb_state *mrb, mrb_value self)
248{
249 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
250 struct RProc *rproc;
251 struct RClass *orig;
252 mrb_value ret;
253
254 if (mrb_nil_p(proc))
255 return mrb_nil_value();
256
257 rproc = mrb_proc_ptr(proc);
258 orig = rproc->c;
259 rproc->c = mrb->proc_class;
260 ret = mrb_funcall(mrb, proc, "source_location", 0);
261 rproc->c = orig;
262 return ret;
263}
264
265static mrb_value
266method_parameters(mrb_state *mrb, mrb_value self)
267{
268 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
269 struct RProc *rproc;
270 struct RClass *orig;
271 mrb_value ret;
272
273 if (mrb_nil_p(proc)) {
274 mrb_value rest = mrb_symbol_value(mrb_intern_lit(mrb, "rest"));
275 mrb_value arest = mrb_ary_new_from_values(mrb, 1, &rest);
276 return mrb_ary_new_from_values(mrb, 1, &arest);
277 }
278
279 rproc = mrb_proc_ptr(proc);
280 orig = rproc->c;
281 rproc->c = mrb->proc_class;
282 ret = mrb_funcall(mrb, proc, "parameters", 0);
283 rproc->c = orig;
284 return ret;
285}
286
287static mrb_value
288method_to_s(mrb_state *mrb, mrb_value self)
289{
290 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
291 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
292 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
293 mrb_value str = mrb_str_new_lit(mrb, "#<");
294 struct RClass *rklass;
295
296 mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, self));
297 mrb_str_cat_lit(mrb, str, ": ");
298 rklass = mrb_class_ptr(klass);
299 if (mrb_class_ptr(owner) == rklass) {
300 mrb_str_concat(mrb, str, owner);
301 mrb_str_cat_lit(mrb, str, "#");
302 mrb_str_concat(mrb, str, name);
303 }
304 else {
305 mrb_str_cat_cstr(mrb, str, mrb_class_name(mrb, rklass));
306 mrb_str_cat_lit(mrb, str, "(");
307 mrb_str_concat(mrb, str, owner);
308 mrb_str_cat_lit(mrb, str, ")#");
309 mrb_str_concat(mrb, str, name);
310 }
311 mrb_str_cat_lit(mrb, str, ">");
312 return str;
313}
314
315static void
316mrb_search_method_owner(mrb_state *mrb, struct RClass *c, mrb_value obj, mrb_sym name, struct RClass **owner, struct RProc **proc, mrb_bool unbound)
317{
318 mrb_value ret;
319
320 *owner = c;
321 *proc = method_search_vm(mrb, owner, name);
322 if (!*proc) {
323 if (unbound) {
324 goto name_error;
325 }
326 if (!mrb_respond_to(mrb, obj, mrb_intern_lit(mrb, "respond_to_missing?"))) {
327 goto name_error;
328 }
329 ret = mrb_funcall(mrb, obj, "respond_to_missing?", 2, mrb_symbol_value(name), mrb_true_value());
330 if (!mrb_test(ret)) {
331 goto name_error;
332 }
333 *owner = c;
334 }
335
336 while ((*owner)->tt == MRB_TT_ICLASS)
337 *owner = (*owner)->c;
338
339 return;
340
341name_error:
342 mrb_raisef(mrb, E_NAME_ERROR, "undefined method '%n' for class '%C'", name, c);
343}
344
345static mrb_value
346mrb_kernel_method(mrb_state *mrb, mrb_value self)
347{
348 struct RClass *owner;
349 struct RProc *proc;
350 struct RObject *me;
351 mrb_sym name;
352
353 mrb_get_args(mrb, "n", &name);
354
355 mrb_search_method_owner(mrb, mrb_class(mrb, self), self, name, &owner, &proc, FALSE);
356
357 me = method_object_alloc(mrb, mrb_class_get(mrb, "Method"));
358 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(owner));
359 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), self);
360 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), mrb_symbol_value(name));
361 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), proc ? mrb_obj_value(proc) : mrb_nil_value());
362 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), mrb_obj_value(mrb_class(mrb, self)));
363
364 return mrb_obj_value(me);
365}
366
367static mrb_value
368mrb_module_instance_method(mrb_state *mrb, mrb_value self)
369{
370 struct RClass *owner;
371 struct RProc *proc;
372 struct RObject *ume;
373 mrb_sym name;
374
375 mrb_get_args(mrb, "n", &name);
376
377 mrb_search_method_owner(mrb, mrb_class_ptr(self), self, name, &owner, &proc, TRUE);
378
379 ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod"));
380 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(owner));
381 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_recv"), mrb_nil_value());
382 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_name"), mrb_symbol_value(name));
383 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_proc"), proc ? mrb_obj_value(proc) : mrb_nil_value());
384 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_klass"), self);
385
386 return mrb_obj_value(ume);
387}
388
389static mrb_value
390method_owner(mrb_state *mrb, mrb_value self)
391{
392 return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
393}
394
395static mrb_value
396method_receiver(mrb_state *mrb, mrb_value self)
397{
398 return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
399}
400
401static mrb_value
402method_name(mrb_state *mrb, mrb_value self)
403{
404 return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
405}
406
407void
408mrb_mruby_method_gem_init(mrb_state* mrb)
409{
410 struct RClass *unbound_method = mrb_define_class(mrb, "UnboundMethod", mrb->object_class);
411 struct RClass *method = mrb_define_class(mrb, "Method", mrb->object_class);
412
413 mrb_undef_class_method(mrb, unbound_method, "new");
414 mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1));
415 mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE());
416 mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1));
417 mrb_define_method(mrb, unbound_method, "eql?", method_eql, MRB_ARGS_REQ(1));
418 mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE());
419 mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE());
420 mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE());
421 mrb_define_method(mrb, unbound_method, "source_location", method_source_location, MRB_ARGS_NONE());
422 mrb_define_method(mrb, unbound_method, "parameters", method_parameters, MRB_ARGS_NONE());
423 mrb_define_method(mrb, unbound_method, "bind_call", method_bcall, MRB_ARGS_REQ(1)|MRB_ARGS_ANY());
424 mrb_define_method(mrb, unbound_method, "owner", method_owner, MRB_ARGS_NONE());
425 mrb_define_method(mrb, unbound_method, "name", method_name, MRB_ARGS_NONE());
426
427 mrb_undef_class_method(mrb, method, "new");
428 mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1));
429 mrb_define_method(mrb, method, "eql?", method_eql, MRB_ARGS_REQ(1));
430 mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE());
431 mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE());
432 mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY());
433 mrb_define_method(mrb, method, "[]", method_call, MRB_ARGS_ANY());
434 mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE());
435 mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE());
436 mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE());
437 mrb_define_method(mrb, method, "source_location", method_source_location, MRB_ARGS_NONE());
438 mrb_define_method(mrb, method, "parameters", method_parameters, MRB_ARGS_NONE());
439 mrb_define_method(mrb, method, "owner", method_owner, MRB_ARGS_NONE());
440 mrb_define_method(mrb, method, "receiver", method_receiver, MRB_ARGS_NONE());
441 mrb_define_method(mrb, method, "name", method_name, MRB_ARGS_NONE());
442
443 mrb_define_method(mrb, mrb->kernel_module, "method", mrb_kernel_method, MRB_ARGS_REQ(1));
444
445 mrb_define_method(mrb, mrb->module_class, "instance_method", mrb_module_instance_method, MRB_ARGS_REQ(1));
446}
447
448void
449mrb_mruby_method_gem_final(mrb_state* mrb)
450{
451}
Note: See TracBrowser for help on using the repository browser.