diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index bfd0f05c1..aaa1381ad 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1322,6 +1322,7 @@ for_body(codegen_scope *s, node *tree) /* construct loop */ lp = loop_push(s, LOOP_FOR); lp->pc1 = new_label(s); + genop_0(s, OP_NOP); /* for redo */ /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); @@ -2588,6 +2589,7 @@ codegen(codegen_scope *s, node *tree, int val) pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL); } lp->pc1 = new_label(s); + genop_0(s, OP_NOP); /* for redo */ codegen(s, tree->cdr, NOVAL); genjmp(s, OP_JMP, lp->pc0); dispatch(s, pos); @@ -3182,11 +3184,14 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_REDO: - if (!s->loop || s->loop->type == LOOP_BEGIN || s->loop->type == LOOP_RESCUE) { - raise_error(s, "unexpected redo"); - } - else { - genjmp(s, OP_JMPUW, s->loop->pc1); + for (const struct loopinfo *lp = s->loop; ; lp = lp->prev) { + if (!lp) { + raise_error(s, "unexpected redo"); + } + if (lp->type != LOOP_BEGIN && lp->type != LOOP_RESCUE) { + genjmp(s, OP_JMPUW, lp->pc1); + break; + } } if (val) push(); break; diff --git a/test/t/syntax.rb b/test/t/syntax.rb index dedbbd1c2..134cd957c 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -95,6 +95,43 @@ assert('redo', '11.5.2.4.5') do a.push(n) end assert_equal [1,3,4], a + + a = [] + limit = 3 + e = RuntimeError.new("!") + for i in 0...3 + begin + limit -= 1 + break unless limit > 0 + a.push i * 3 + 1 + raise e + rescue + a.push i * 3 + 2 + redo + ensure + a.push i * 3 + 3 + end + end + assert_equal [1, 2, 3, 1, 2, 3, 3], a + + a = [] + limit = 3 + e = RuntimeError.new("!") + for i in 0...3 + a.push i * 4 + 1 + begin + limit -= 1 + break unless limit > 0 + a.push i * 4 + 2 + raise e + rescue + a.push i * 4 + 3 + redo + ensure + a.push i * 4 + 4 + end + end + assert_equal [1, 2, 3, 4, 1, 2, 3, 4, 1, 4], a end assert('Abbreviated variable assignment', '11.4.2.3.2') do