mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #5401 from dearblue/mcall
Reorganize `mcall()` in `mruby-method`
This commit is contained in:
@@ -131,15 +131,6 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc, mrb_func_t posthoo
|
||||
{
|
||||
/* no argument passed from eval() */
|
||||
mrb->c->ci->argc = 0;
|
||||
if (mrb->c->ci->acc < 0) {
|
||||
ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase;
|
||||
mrb_value ret = mrb_top_run(mrb, proc, self, 0);
|
||||
if (mrb->exc) {
|
||||
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
|
||||
}
|
||||
mrb->c->ci = mrb->c->cibase + cioff;
|
||||
return ret;
|
||||
}
|
||||
/* clear block */
|
||||
mrb->c->ci->stack[1] = mrb_nil_value();
|
||||
return mrb_exec_irep(mrb, self, proc, posthook);
|
||||
|
||||
@@ -6,12 +6,126 @@
|
||||
#include "mruby/string.h"
|
||||
#include "mruby/presym.h"
|
||||
|
||||
mrb_noreturn void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
|
||||
mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook);
|
||||
|
||||
static mrb_value
|
||||
args_shift(mrb_state *mrb)
|
||||
{
|
||||
mrb_value *argv = mrb->c->ci->stack + 1;
|
||||
|
||||
if (mrb->c->ci->argc > 0) {
|
||||
mrb_value obj = argv[0];
|
||||
memmove(argv, argv + 1, (mrb->c->ci->argc + 1 /* block */ - 1 /* first value */) * sizeof(mrb_value));
|
||||
mrb->c->ci->argc--;
|
||||
return obj;
|
||||
}
|
||||
else if (mrb->c->ci->argc < 0 && RARRAY_LEN(*argv) > 0) {
|
||||
return mrb_ary_shift(mrb, *argv);
|
||||
}
|
||||
else {
|
||||
mrb_argnum_error(mrb, 0, 1, -1);
|
||||
return mrb_undef_value(); /* not reached */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
args_unshift(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
mrb_value *argv = mrb->c->ci->stack + 1;
|
||||
|
||||
if (mrb->c->ci->argc >= 0) {
|
||||
mrb_value block = argv[mrb->c->ci->argc];
|
||||
argv[0] = mrb_ary_new_from_values(mrb, mrb->c->ci->argc, argv);
|
||||
argv[1] = block;
|
||||
mrb->c->ci->argc = -1;
|
||||
}
|
||||
|
||||
mrb_ary_unshift(mrb, *argv, obj);
|
||||
}
|
||||
|
||||
static struct RProc*
|
||||
method_missing_prepare(mrb_state *mrb, mrb_sym *mid, mrb_value recv, struct RClass **tc)
|
||||
{
|
||||
const mrb_sym id_method_missing = MRB_SYM(method_missing);
|
||||
|
||||
if (*mid == id_method_missing) {
|
||||
method_missing: ;
|
||||
int argc = mrb->c->ci->argc;
|
||||
mrb_value *argv = mrb->c->ci->stack + 1;
|
||||
mrb_value args = (argc < 0) ? argv[0] : mrb_ary_new_from_values(mrb, argc, argv);
|
||||
mrb_method_missing(mrb, *mid, recv, args);
|
||||
}
|
||||
|
||||
*tc = mrb_class(mrb, recv);
|
||||
mrb_method_t m = mrb_method_search_vm(mrb, tc, id_method_missing);
|
||||
if (MRB_METHOD_UNDEF_P(m)) {
|
||||
goto method_missing;
|
||||
}
|
||||
|
||||
struct RProc *proc;
|
||||
if (MRB_METHOD_FUNC_P(m)) {
|
||||
proc = mrb_proc_new_cfunc(mrb, MRB_METHOD_FUNC(m));
|
||||
MRB_PROC_SET_TARGET_CLASS(proc, *tc);
|
||||
}
|
||||
else {
|
||||
proc = MRB_METHOD_PROC(m);
|
||||
}
|
||||
|
||||
args_unshift(mrb, mrb_symbol_value(*mid));
|
||||
*mid = id_method_missing;
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
static struct RObject *
|
||||
method_object_alloc(mrb_state *mrb, struct RClass *mclass)
|
||||
{
|
||||
return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass);
|
||||
}
|
||||
|
||||
static struct RProc*
|
||||
method_extract_proc(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_proc));
|
||||
if (mrb_nil_p(obj)) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
mrb_check_type(mrb, obj, MRB_TT_PROC);
|
||||
return mrb_proc_ptr(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
method_extract_receiver(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return mrb_iv_get(mrb, self, MRB_SYM(_recv));
|
||||
}
|
||||
|
||||
static mrb_sym
|
||||
method_extract_mid(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_name));
|
||||
mrb_check_type(mrb, obj, MRB_TT_SYMBOL);
|
||||
return mrb_symbol(obj);
|
||||
}
|
||||
|
||||
static struct RClass*
|
||||
method_extract_owner(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_owner));
|
||||
switch (mrb_type(obj)) {
|
||||
case MRB_TT_CLASS:
|
||||
case MRB_TT_MODULE:
|
||||
case MRB_TT_SCLASS:
|
||||
break;
|
||||
default:
|
||||
mrb_raise(mrb, E_TYPE_ERROR, "not class/module as owner of method object");
|
||||
}
|
||||
return mrb_class_ptr(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner)
|
||||
{
|
||||
@@ -109,61 +223,40 @@ method_eql(mrb_state *mrb, mrb_value self)
|
||||
#undef IV_GET
|
||||
|
||||
static mrb_value
|
||||
mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner,
|
||||
mrb_int argc, const mrb_value *argv, mrb_value block)
|
||||
mcall(mrb_state *mrb, mrb_value self, mrb_value recv)
|
||||
{
|
||||
mrb_value ret;
|
||||
mrb_sym orig_mid = mrb->c->ci->mid;
|
||||
struct RProc *proc = method_extract_proc(mrb, self);
|
||||
mrb_sym mid = method_extract_mid(mrb, self);
|
||||
struct RClass *tc = method_extract_owner(mrb, self);
|
||||
|
||||
mrb->c->ci->mid = mrb_symbol(name);
|
||||
if (mrb_nil_p(proc)) {
|
||||
mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv);
|
||||
mrb_ary_unshift(mrb, missing_argv, name);
|
||||
ret = mrb_funcall_argv(mrb, recv, MRB_SYM(method_missing), argc + 1, RARRAY_PTR(missing_argv));
|
||||
}
|
||||
else if (!mrb_nil_p(block)) {
|
||||
/*
|
||||
workaround since `mrb_yield_with_class` does not support passing block as parameter
|
||||
need new API that initializes `mrb->c->stack[argc+1]` with block passed by argument
|
||||
*/
|
||||
ret = mrb_funcall_with_block(mrb, recv, mrb_symbol(name), argc, argv, block);
|
||||
if (mrb_undef_p(recv)) {
|
||||
recv = method_extract_receiver(mrb, self);
|
||||
}
|
||||
else {
|
||||
ret = mrb_yield_with_class(mrb, proc, argc, argv, recv, owner);
|
||||
bind_check(mrb, recv, mrb_obj_value(tc));
|
||||
}
|
||||
mrb->c->ci->mid = orig_mid;
|
||||
return ret;
|
||||
|
||||
if (!proc) {
|
||||
proc = method_missing_prepare(mrb, &mid, recv, &tc);
|
||||
}
|
||||
mrb->c->ci->mid = mid;
|
||||
mrb->c->ci->u.target_class = tc;
|
||||
|
||||
return mrb_exec_irep(mrb, recv, proc, NULL);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
method_call(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc));
|
||||
mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name));
|
||||
mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv));
|
||||
struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, MRB_SYM(_owner)));
|
||||
mrb_int argc;
|
||||
const mrb_value *argv;
|
||||
mrb_value block;
|
||||
|
||||
mrb_get_args(mrb, "*&", &argv, &argc, &block);
|
||||
return mcall(mrb, recv, proc, name, owner, argc, argv, block);
|
||||
return mcall(mrb, self, mrb_undef_value());
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
method_bcall(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc));
|
||||
mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name));
|
||||
mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv));
|
||||
mrb_value owner = mrb_iv_get(mrb, self, MRB_SYM(_owner));
|
||||
mrb_int argc;
|
||||
const mrb_value *argv;
|
||||
mrb_value block;
|
||||
|
||||
mrb_get_args(mrb, "o*&", &recv, &argv, &argc, &block);
|
||||
bind_check(mrb, recv, owner);
|
||||
return mcall(mrb, recv, proc, name, mrb_class_ptr(owner), argc, argv, block);
|
||||
mrb_value recv = args_shift(mrb);
|
||||
mrb_gc_protect(mrb, recv);
|
||||
return mcall(mrb, self, recv);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
|
||||
@@ -543,8 +543,8 @@ mrb_exec_irep_prepare_posthook(mrb_state *mrb, mrb_callinfo *ci, int nregs, mrb_
|
||||
*
|
||||
* However, if `proc` is a C function, it will be ignored.
|
||||
*/
|
||||
mrb_value
|
||||
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
|
||||
static mrb_value
|
||||
mrb_exec_irep_vm(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
|
||||
{
|
||||
mrb_callinfo *ci = mrb->c->ci;
|
||||
int keep, nregs;
|
||||
@@ -575,6 +575,31 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t postho
|
||||
return self;
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
|
||||
{
|
||||
mrb_callinfo *ci = mrb->c->ci;
|
||||
if (ci->acc >= 0) {
|
||||
return mrb_exec_irep_vm(mrb, self, p, posthook);
|
||||
}
|
||||
else {
|
||||
mrb_value ret;
|
||||
if (MRB_PROC_CFUNC_P(p)) {
|
||||
cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc);
|
||||
ret = MRB_PROC_CFUNC(p)(mrb, self);
|
||||
cipop(mrb);
|
||||
}
|
||||
else {
|
||||
int keep = (ci->argc < 0 ? 1 : ci->argc) + 2 /* receiver + block */;
|
||||
ret = mrb_top_run(mrb, p, self, keep);
|
||||
}
|
||||
if (mrb->exc && mrb->jmp) {
|
||||
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* 15.3.1.3.4 */
|
||||
/* 15.3.1.3.44 */
|
||||
/*
|
||||
@@ -638,7 +663,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
|
||||
}
|
||||
return MRB_METHOD_CFUNC(m)(mrb, self);
|
||||
}
|
||||
return mrb_exec_irep(mrb, self, MRB_METHOD_PROC(m), NULL);
|
||||
return mrb_exec_irep_vm(mrb, self, MRB_METHOD_PROC(m), NULL);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
@@ -826,7 +851,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const
|
||||
mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
|
||||
mrb->c->ci->stack[2] = mrb_nil_value();
|
||||
ci->argc = -1;
|
||||
return mrb_exec_irep(mrb, self, p, NULL);
|
||||
return mrb_exec_irep_vm(mrb, self, p, NULL);
|
||||
}
|
||||
|
||||
static struct RBreak*
|
||||
|
||||
Reference in New Issue
Block a user