mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Fixed argument forwarding in instance_exec
However, on C, there is no easy way to pass keyword arguments. Therefore, when called `Kernel#instance_exec` on C, keyword arguments are converted to positional arguments. This is a limitation of current mruby. fixed #6389
This commit is contained in:
@@ -195,6 +195,7 @@ mrb_int mrb_ci_bidx(mrb_callinfo *ci);
|
||||
mrb_int mrb_ci_nregs(mrb_callinfo *ci);
|
||||
mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p);
|
||||
mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
|
||||
mrb_value mrb_object_exec(mrb_state *mrb, mrb_value self, struct RClass *target_class);
|
||||
mrb_value mrb_mod_module_eval(mrb_state*, mrb_value);
|
||||
mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mruby/class.h>
|
||||
#include <mruby/hash.h>
|
||||
#include <mruby/proc.h>
|
||||
#include <mruby/internal.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
/*
|
||||
@@ -93,18 +94,7 @@ nil_to_i(mrb_state *mrb, mrb_value obj)
|
||||
static mrb_value
|
||||
obj_instance_exec(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_int argc;
|
||||
mrb_value blk;
|
||||
struct RClass *c;
|
||||
|
||||
mrb_get_args(mrb, "*&!", &argv, &argc, &blk);
|
||||
c = mrb_singleton_class_ptr(mrb, self);
|
||||
if (mrb->c->ci->cci > 0) {
|
||||
return mrb_yield_with_class(mrb, blk, argc, argv, self, c);
|
||||
}
|
||||
mrb_vm_ci_target_class_set(mrb->c->ci, c);
|
||||
return mrb_yield_cont(mrb, blk, self, argc, argv);
|
||||
return mrb_object_exec(mrb, self, mrb_singleton_class_ptr(mrb, self));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <mruby.h>
|
||||
|
||||
static mrb_value
|
||||
obj_instance_exec_from_c(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int argc;
|
||||
const mrb_value *argv;
|
||||
mrb_value blk;
|
||||
mrb_get_args(mrb, "*&!", &argv, &argc, &blk);
|
||||
return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "instance_exec"), argc, argv, blk);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_object_ext_gem_test(mrb_state *mrb)
|
||||
{
|
||||
mrb_define_method(mrb, mrb->kernel_module, "instance_exec_from_c", obj_instance_exec_from_c, MRB_ARGS_ANY());
|
||||
}
|
||||
@@ -51,3 +51,17 @@ assert('instance_exec on primitives with class and module definition') do
|
||||
Object.remove_const :A
|
||||
end
|
||||
end
|
||||
|
||||
assert('argument forwarding via instance_exec') do
|
||||
assert_equal [[], {}, nil], instance_exec { |*args, **kw, &blk| [args, kw, blk] }
|
||||
assert_equal [[1, 2, 3], {}, nil], instance_exec(1, 2, 3) { |*args, **kw, &blk| [args, kw, blk] }
|
||||
assert_equal [[], { a: 1 }, nil], instance_exec(a: 1) { |*args, **kw, &blk| [args, kw, blk] }
|
||||
end
|
||||
|
||||
assert('argument forwarding via instance_exec from c') do
|
||||
assert_equal [[], {}, nil], instance_exec_from_c { |*args, **kw, &blk| [args, kw, blk] }
|
||||
assert_equal [[1, 2, 3], {}, nil], instance_exec_from_c(1, 2, 3) { |*args, **kw, &blk| [args, kw, blk] }
|
||||
|
||||
# currently there is no easy way to call a method from C passing keyword arguments
|
||||
#assert_equal [[], { a: 1 }, nil], instance_exec_from_c(a: 1) { |*args, **kw, &blk| [args, kw, blk] }
|
||||
end
|
||||
|
||||
@@ -837,6 +837,31 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
|
||||
}
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_object_exec(mrb_state *mrb, mrb_value self, struct RClass *target_class)
|
||||
{
|
||||
mrb_callinfo *ci = mrb->c->ci;
|
||||
if (ci->cci > 0) {
|
||||
const mrb_value *argv;
|
||||
mrb_int argc;
|
||||
mrb_value blk;
|
||||
mrb_get_args(mrb, "*!&!", &argv, &argc, &blk);
|
||||
return mrb_yield_with_class(mrb, blk, argc, argv, self, target_class);
|
||||
}
|
||||
|
||||
int bidx = mrb_ci_bidx(ci);
|
||||
mrb_value blk = ci->stack[bidx];
|
||||
if (mrb_nil_p(blk)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
|
||||
}
|
||||
|
||||
mrb_assert(mrb_proc_p(blk));
|
||||
mrb_gc_protect(mrb, blk);
|
||||
ci->stack[bidx] = mrb_nil_value();
|
||||
ci->u.target_class = target_class;
|
||||
return mrb_exec_irep(mrb, self, mrb_proc_ptr(blk));
|
||||
}
|
||||
|
||||
/* 15.3.1.3.4 */
|
||||
/* 15.3.1.3.44 */
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user