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"
8 static struct RObject *
9 method_object_alloc(mrb_state *mrb, struct RClass *mclass)
11 return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass);
15 unbound_method_bind(mrb_state *mrb, mrb_value self)
18 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner"));
19 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name"));
20 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
21 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass"));
24 mrb_get_args(mrb, "o", &recv);
26 if (mrb_type(owner) != MRB_TT_MODULE &&
27 mrb_class_ptr(owner) != mrb_obj_class(mrb, recv) &&
28 !mrb_obj_is_kind_of(mrb, recv, mrb_class_ptr(owner))) {
29 if (mrb_type(owner) == MRB_TT_SCLASS) {
30 mrb_raise(mrb, E_TYPE_ERROR, "singleton method called for a different object");
32 const char *s = mrb_class_name(mrb, mrb_class_ptr(owner));
33 mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %S", mrb_str_new_static(mrb, s, strlen(s)));
36 me = method_object_alloc(mrb, mrb_class_get(mrb, "Method"));
37 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@owner"), owner);
38 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@recv"), recv);
39 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@name"), name);
40 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "proc"), proc);
41 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@klass"), klass);
43 return mrb_obj_value(me);
46 #define IV_GET(value, name) mrb_iv_get(mrb, value, mrb_intern_lit(mrb, name))
48 method_eql(mrb_state *mrb, mrb_value self)
50 mrb_value other, receiver, orig_proc, other_proc;
51 struct RClass *owner, *klass;
52 struct RProc *orig_rproc, *other_rproc;
54 mrb_get_args(mrb, "o", &other);
55 if (!mrb_obj_is_instance_of(mrb, other, mrb_class(mrb, self)))
56 return mrb_false_value();
58 if (mrb_class(mrb, self) != mrb_class(mrb, other))
59 return mrb_false_value();
61 klass = mrb_class_ptr(IV_GET(self, "@klass"));
62 if (klass != mrb_class_ptr(IV_GET(other, "@klass")))
63 return mrb_false_value();
65 owner = mrb_class_ptr(IV_GET(self, "@owner"));
66 if (owner != mrb_class_ptr(IV_GET(other, "@owner")))
67 return mrb_false_value();
69 receiver = IV_GET(self, "@recv");
70 if (!mrb_obj_equal(mrb, receiver, IV_GET(other, "@recv")))
71 return mrb_false_value();
73 orig_proc = IV_GET(self, "proc");
74 other_proc = IV_GET(other, "proc");
75 if (mrb_nil_p(orig_proc) && mrb_nil_p(other_proc)) {
76 if (mrb_symbol(IV_GET(self, "@name")) == mrb_symbol(IV_GET(other, "@name")))
77 return mrb_true_value();
79 return mrb_false_value();
82 if (mrb_nil_p(orig_proc))
83 return mrb_false_value();
84 if (mrb_nil_p(other_proc))
85 return mrb_false_value();
87 orig_rproc = mrb_proc_ptr(orig_proc);
88 other_rproc = mrb_proc_ptr(other_proc);
89 if (MRB_PROC_CFUNC_P(orig_rproc)) {
90 if (!MRB_PROC_CFUNC_P(other_rproc))
91 return mrb_false_value();
92 if (orig_rproc->body.func != other_rproc->body.func)
93 return mrb_false_value();
96 if (MRB_PROC_CFUNC_P(other_rproc))
97 return mrb_false_value();
98 if (orig_rproc->body.irep != other_rproc->body.irep)
99 return mrb_false_value();
102 return mrb_true_value();
108 method_call(mrb_state *mrb, mrb_value self)
110 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
111 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name"));
112 mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@recv"));
113 struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner")));
115 mrb_value *argv, ret, block;
118 mrb_get_args(mrb, "*&", &argv, &argc, &block);
119 orig_mid = mrb->c->ci->mid;
120 mrb->c->ci->mid = mrb_symbol(name);
121 if (mrb_nil_p(proc)) {
122 mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv);
123 mrb_ary_unshift(mrb, missing_argv, name);
124 ret = mrb_funcall_argv(mrb, recv, mrb_intern_lit(mrb, "method_missing"), argc + 1, RARRAY_PTR(missing_argv));
126 else if (!mrb_nil_p(block)) {
128 workaround since `mrb_yield_with_class` does not support passing block as parameter
129 need new API that initializes `mrb->c->stack[argc+1]` with block passed by argument
131 ret = mrb_funcall_with_block(mrb, recv, mrb_symbol(name), argc, argv, block);
134 ret = mrb_yield_with_class(mrb, proc, argc, argv, recv, owner);
136 mrb->c->ci->mid = orig_mid;
141 method_unbind(mrb_state *mrb, mrb_value self)
144 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner"));
145 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name"));
146 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
147 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass"));
149 ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod"));
150 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@owner"), owner);
151 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@recv"), mrb_nil_value());
152 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@name"), name);
153 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "proc"), proc);
154 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@klass"), klass);
156 return mrb_obj_value(ume);
159 static struct RProc *
160 method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
162 mrb_method_t m = mrb_method_search_vm(mrb, cp, mid);
163 if (MRB_METHOD_UNDEF_P(m))
165 if (MRB_METHOD_PROC_P(m))
166 return MRB_METHOD_PROC(m);
167 return mrb_proc_new_cfunc(mrb, MRB_METHOD_FUNC(m));
171 method_super_method(mrb_state *mrb, mrb_value self)
173 mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@recv"));
174 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass"));
175 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner"));
176 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name"));
177 struct RClass *super, *rklass;
181 switch (mrb_type(klass)) {
183 super = mrb_class_ptr(klass)->super->super;
186 super = mrb_class_ptr(klass)->super;
189 super = mrb_class_ptr(owner)->super;
193 proc = method_search_vm(mrb, &super, mrb_symbol(name));
195 return mrb_nil_value();
198 while (super->tt == MRB_TT_ICLASS)
201 me = method_object_alloc(mrb, mrb_obj_class(mrb, self));
202 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@owner"), mrb_obj_value(super));
203 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@recv"), recv);
204 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@name"), name);
205 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "proc"), mrb_obj_value(proc));
206 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@klass"), mrb_obj_value(rklass));
208 return mrb_obj_value(me);
212 method_arity(mrb_state *mrb, mrb_value self)
214 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
220 return mrb_fixnum_value(-1);
222 rproc = mrb_proc_ptr(proc);
224 rproc->c = mrb->proc_class;
225 ret = mrb_funcall(mrb, proc, "arity", 0);
231 method_source_location(mrb_state *mrb, mrb_value self)
233 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
239 return mrb_nil_value();
241 rproc = mrb_proc_ptr(proc);
243 rproc->c = mrb->proc_class;
244 ret = mrb_funcall(mrb, proc, "source_location", 0);
250 method_parameters(mrb_state *mrb, mrb_value self)
252 mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc"));
257 if (mrb_nil_p(proc)) {
258 mrb_value rest = mrb_symbol_value(mrb_intern_lit(mrb, "rest"));
259 mrb_value arest = mrb_ary_new_from_values(mrb, 1, &rest);
260 return mrb_ary_new_from_values(mrb, 1, &arest);
263 rproc = mrb_proc_ptr(proc);
265 rproc->c = mrb->proc_class;
266 ret = mrb_funcall(mrb, proc, "parameters", 0);
272 method_to_s(mrb_state *mrb, mrb_value self)
274 mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@owner"));
275 mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@klass"));
276 mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@name"));
277 mrb_value str = mrb_str_new_lit(mrb, "#<");
278 struct RClass *rklass;
280 mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, self));
281 mrb_str_cat_lit(mrb, str, ": ");
282 rklass = mrb_class_ptr(klass);
283 if (mrb_class_ptr(owner) == rklass) {
284 mrb_str_cat_str(mrb, str, mrb_funcall(mrb, owner, "to_s", 0));
285 mrb_str_cat_lit(mrb, str, "#");
286 mrb_str_cat_str(mrb, str, mrb_funcall(mrb, name, "to_s", 0));
289 mrb_str_cat_cstr(mrb, str, mrb_class_name(mrb, rklass));
290 mrb_str_cat_lit(mrb, str, "(");
291 mrb_str_cat_str(mrb, str, mrb_funcall(mrb, owner, "to_s", 0));
292 mrb_str_cat_lit(mrb, str, ")#");
293 mrb_str_cat_str(mrb, str, mrb_funcall(mrb, name, "to_s", 0));
295 mrb_str_cat_lit(mrb, str, ">");
300 mrb_search_method_owner(mrb_state *mrb, struct RClass *c, mrb_value obj, mrb_sym name, struct RClass **owner, struct RProc **proc, mrb_bool unbound)
306 *proc = method_search_vm(mrb, owner, name);
311 if (!mrb_respond_to(mrb, obj, mrb_intern_lit(mrb, "respond_to_missing?"))) {
314 ret = mrb_funcall(mrb, obj, "respond_to_missing?", 2, mrb_symbol_value(name), mrb_true_value());
315 if (!mrb_test(ret)) {
321 while ((*owner)->tt == MRB_TT_ICLASS)
322 *owner = (*owner)->c;
327 s = mrb_class_name(mrb, c);
330 "undefined method '%S' for class '%S'",
331 mrb_sym2str(mrb, name),
332 mrb_str_new_static(mrb, s, strlen(s))
337 mrb_kernel_method(mrb_state *mrb, mrb_value self)
339 struct RClass *owner;
344 mrb_get_args(mrb, "n", &name);
346 mrb_search_method_owner(mrb, mrb_class(mrb, self), self, name, &owner, &proc, FALSE);
348 me = method_object_alloc(mrb, mrb_class_get(mrb, "Method"));
349 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@owner"), mrb_obj_value(owner));
350 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@recv"), self);
351 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@name"), mrb_symbol_value(name));
352 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "proc"), proc ? mrb_obj_value(proc) : mrb_nil_value());
353 mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "@klass"), mrb_obj_value(mrb_class(mrb, self)));
355 return mrb_obj_value(me);
359 mrb_module_instance_method(mrb_state *mrb, mrb_value self)
361 struct RClass *owner;
366 mrb_get_args(mrb, "n", &name);
368 mrb_search_method_owner(mrb, mrb_class_ptr(self), self, name, &owner, &proc, TRUE);
370 ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod"));
371 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@owner"), mrb_obj_value(owner));
372 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@recv"), mrb_nil_value());
373 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@name"), mrb_symbol_value(name));
374 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "proc"), proc ? mrb_obj_value(proc) : mrb_nil_value());
375 mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "@klass"), self);
377 return mrb_obj_value(ume);
381 mrb_mruby_method_gem_init(mrb_state* mrb)
383 struct RClass *unbound_method = mrb_define_class(mrb, "UnboundMethod", mrb->object_class);
384 struct RClass *method = mrb_define_class(mrb, "Method", mrb->object_class);
386 mrb_undef_class_method(mrb, unbound_method, "new");
387 mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1));
388 mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE());
389 mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1));
390 mrb_define_alias(mrb, unbound_method, "eql?", "==");
391 mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE());
392 mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE());
393 mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE());
394 mrb_define_method(mrb, unbound_method, "source_location", method_source_location, MRB_ARGS_NONE());
395 mrb_define_method(mrb, unbound_method, "parameters", method_parameters, MRB_ARGS_NONE());
397 mrb_undef_class_method(mrb, method, "new");
398 mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1));
399 mrb_define_alias(mrb, method, "eql?", "==");
400 mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE());
401 mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE());
402 mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY());
403 mrb_define_alias(mrb, method, "[]", "call");
404 mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE());
405 mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE());
406 mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE());
407 mrb_define_method(mrb, method, "source_location", method_source_location, MRB_ARGS_NONE());
408 mrb_define_method(mrb, method, "parameters", method_parameters, MRB_ARGS_NONE());
410 mrb_define_method(mrb, mrb->kernel_module, "method", mrb_kernel_method, MRB_ARGS_REQ(1));
412 mrb_define_method(mrb, mrb->module_class, "instance_method", mrb_module_instance_method, MRB_ARGS_REQ(1));
416 mrb_mruby_method_gem_final(mrb_state* mrb)