mruby-compiler: allow at-least-once loop behavior for mruby

mruby does not provide `begin ... end while cond` that behave at-least-once
loop, like CRuby does. It remains in TODO.md for long time. But finally we have
implemented the behavior.
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-07-06 07:36:53 +09:00
parent ebc10f3c57
commit ee30d1d0f8
5 changed files with 1845 additions and 1753 deletions
-1
View File
@@ -9,5 +9,4 @@
# Things to do (Things we need to consider)
- `begin ... end while cond` to behave as CRuby
- special variables ($1,$2..)
+2 -1
View File
@@ -3679,12 +3679,13 @@ codegen(codegen_scope *s, node *tree, int val)
if (!val) lp->reg = -1;
/* Jump to body start on first iteration */
uint32_t body_start = genjmp2_0(s, OP_JMP, cursp(), NOVAL);
uint32_t body_start = genjmp_0(s, OP_JMP);
/* pc0 is next target - condition check */
lp->pc0 = new_label(s);
codegen(s, tree->car, VAL);
pop();
uint32_t pos = JMPLINK_START;
if (nt == NODE_WHILE_MOD) {
pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL);
}
+2
View File
@@ -16,6 +16,8 @@ enum node_type {
NODE_WHEN,
NODE_WHILE,
NODE_UNTIL,
NODE_WHILE_MOD,
NODE_UNTIL_MOD,
NODE_ITER,
NODE_FOR,
NODE_BREAK,
+48 -2
View File
@@ -483,6 +483,22 @@ new_until(parser_state *p, node *a, node *b)
return cons((node*)NODE_UNTIL, cons(a, b));
}
/* (:while_mod cond body) */
static node*
new_while_mod(parser_state *p, node *a, node *b)
{
void_expr_error(p, a);
return cons((node*)NODE_WHILE_MOD, cons(a, b));
}
/* (:until_mod cond body) */
static node*
new_until_mod(parser_state *p, node *a, node *b)
{
void_expr_error(p, a);
return cons((node*)NODE_UNTIL_MOD, cons(a, b));
}
/* (:for var obj body) */
static node*
new_for(parser_state *p, node *v, node *o, node *b)
@@ -1794,11 +1810,21 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
}
| stmt modifier_while expr_value
{
$$ = new_while(p, cond($3), $1);
if ($1 && typen($1->car) == NODE_BEGIN) {
$$ = new_while_mod(p, cond($3), $1);
}
else {
$$ = new_while(p, cond($3), $1);
}
}
| stmt modifier_until expr_value
{
$$ = new_until(p, cond($3), $1);
if ($1 && typen($1->car) == NODE_BEGIN) {
$$ = new_until_mod(p, cond($3), $1);
}
else {
$$ = new_until(p, cond($3), $1);
}
}
| stmt modifier_rescue stmt
{
@@ -7283,6 +7309,26 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_WHILE_MOD:
printf("NODE_WHILE_MOD:\n");
dump_prefix(tree, offset+1);
printf("cond:\n");
mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(tree, offset+1);
printf("body:\n");
mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_UNTIL_MOD:
printf("NODE_UNTIL_MOD:\n");
dump_prefix(tree, offset+1);
printf("cond:\n");
mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(tree, offset+1);
printf("body:\n");
mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_FOR:
printf("NODE_FOR:\n");
dump_prefix(tree, offset+1);
File diff suppressed because it is too large Load Diff