mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #6412 from dearblue/OP_RETURN_BLK
Distinguish the call frame of the generator with `OP_RETURN_BLK`
This commit is contained in:
@@ -233,11 +233,12 @@ uvenv(mrb_state *mrb, mrb_int up)
|
||||
}
|
||||
|
||||
static inline const struct RProc*
|
||||
top_proc(mrb_state *mrb, const struct RProc *proc)
|
||||
top_proc(mrb_state *mrb, const struct RProc *proc, const struct REnv **envp)
|
||||
{
|
||||
while (proc->upper) {
|
||||
if (MRB_PROC_SCOPE_P(proc) || MRB_PROC_STRICT_P(proc))
|
||||
return proc;
|
||||
*envp = proc->e.env;
|
||||
proc = proc->upper;
|
||||
}
|
||||
return proc;
|
||||
@@ -2294,11 +2295,12 @@ RETRY_TRY_BLOCK:
|
||||
goto NORMAL_RETURN;
|
||||
}
|
||||
|
||||
const struct RProc *dst = top_proc(mrb, ci->proc);
|
||||
const struct REnv *env = ci->u.env;
|
||||
const struct RProc *dst = top_proc(mrb, ci->proc, &env);
|
||||
if (!MRB_PROC_ENV_P(dst) || dst->e.env->cxt == mrb->c) {
|
||||
/* check jump destination */
|
||||
for (ptrdiff_t i = ci - mrb->c->cibase; i >= 0; i--, ci--) {
|
||||
if (ci->proc == dst) {
|
||||
if (ci->u.env == env) {
|
||||
goto L_UNWINDING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,3 +532,89 @@ assert('BS Block 39') do
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
assert('BS Block 40 (https://github.com/mruby/mruby/issues/6411)') do
|
||||
assert_equal "GOOD" do
|
||||
Object.new.instance_eval do
|
||||
def test(&b)
|
||||
if b
|
||||
b.call
|
||||
else
|
||||
test { return "GOOD" }
|
||||
end
|
||||
"BAD"
|
||||
end
|
||||
|
||||
test
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "GOOD" do
|
||||
Object.new.instance_eval do
|
||||
# since Kernel#proc is defined in proc-ext
|
||||
def make_proc(&b)
|
||||
b
|
||||
end
|
||||
|
||||
def chocolate(&b)
|
||||
biscuit(&b)
|
||||
end
|
||||
|
||||
def biscuit(&b)
|
||||
if b
|
||||
b.call
|
||||
else
|
||||
b = make_proc { return "GOOD" }
|
||||
chocolate(&b)
|
||||
end
|
||||
"BAD"
|
||||
end
|
||||
|
||||
biscuit
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal [0, 1, 2, 3] do
|
||||
Object.new.instance_eval do
|
||||
def test(a = [], &b)
|
||||
if b
|
||||
b.call
|
||||
else
|
||||
if a.empty?
|
||||
a << 0
|
||||
test(a)
|
||||
else
|
||||
a << 1
|
||||
test(a) { return 1 }
|
||||
end
|
||||
a << 2
|
||||
end
|
||||
a << 3
|
||||
end
|
||||
|
||||
test
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal [0, 1, 3, 2, 3, 2, 3] do
|
||||
Object.new.instance_eval do
|
||||
def test(a = [], &b)
|
||||
if b
|
||||
b.call
|
||||
else
|
||||
if a.empty?
|
||||
a << 0
|
||||
test(a)
|
||||
else
|
||||
a << 1
|
||||
test(a, &-> { return 1 })
|
||||
end
|
||||
a << 2
|
||||
end
|
||||
a << 3
|
||||
end
|
||||
|
||||
test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user