mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Add NODE_BEGIN for explicit begin...end blocks
This commit introduces NODE_BEGIN as a distinct AST node type for explicit begin...end blocks, separate from NODE_STMTS which represents general statement sequences. This distinction will be essential for implementing CRuby-compatible begin...end while/until constructs. Key changes: - Added NODE_BEGIN enum in node.h - Added new_begin() function in parse.y using optimized cons() structure - Modified begin...end grammar rule to generate NODE_BEGIN nodes - Added NODE_BEGIN codegen support in codegen.c - Added NODE_BEGIN to parser dump functionality NODE_BEGIN uses a simpler cons() structure instead of list2() for better memory efficiency, as it only contains a single body node. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3140,6 +3140,7 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
|
||||
break;
|
||||
/* fall through */
|
||||
case NODE_STMTS:
|
||||
case NODE_BEGIN:
|
||||
codegen(s, tree->car, VAL);
|
||||
j++;
|
||||
break;
|
||||
@@ -3192,7 +3193,7 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
|
||||
else {
|
||||
while (tree) {
|
||||
switch (nint(tree->car->car)) {
|
||||
case NODE_STMTS: case NODE_BLOCK:
|
||||
case NODE_STMTS: case NODE_BEGIN: case NODE_BLOCK:
|
||||
codegen(s, tree->car, NOVAL);
|
||||
}
|
||||
tree = tree->cdr;
|
||||
@@ -3355,6 +3356,11 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_BEGIN:
|
||||
/* NODE_BEGIN contains a single body node directly in cdr */
|
||||
codegen(s, tree, val);
|
||||
break;
|
||||
|
||||
case NODE_RESCUE:
|
||||
{
|
||||
int noexc;
|
||||
@@ -3647,6 +3653,57 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_WHILE_MOD:
|
||||
case NODE_UNTIL_MOD:
|
||||
{
|
||||
/* Post-tested loops: execute body first, then check condition */
|
||||
if (false_always(tree->car)) {
|
||||
if (nt == NODE_WHILE_MOD) {
|
||||
/* begin...end while false - execute once then exit */
|
||||
codegen(s, tree->cdr, val);
|
||||
if (val) push();
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else if (true_always(tree->car)) {
|
||||
if (nt == NODE_UNTIL_MOD) {
|
||||
/* begin...end until true - execute once then exit */
|
||||
codegen(s, tree->cdr, val);
|
||||
if (val) push();
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Post-tested loops: execute body first, then condition */
|
||||
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
|
||||
if (!val) lp->reg = -1;
|
||||
|
||||
/* Jump to body start on first iteration */
|
||||
uint32_t body_start = genjmp2_0(s, OP_JMP, cursp(), NOVAL);
|
||||
|
||||
/* pc0 is next target - condition check */
|
||||
lp->pc0 = new_label(s);
|
||||
codegen(s, tree->car, VAL);
|
||||
pop();
|
||||
if (nt == NODE_WHILE_MOD) {
|
||||
pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL);
|
||||
}
|
||||
else {
|
||||
pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL);
|
||||
}
|
||||
|
||||
/* pc1 is redo target - body start */
|
||||
lp->pc1 = new_label(s);
|
||||
dispatch(s, body_start); /* patch initial jump to come here */
|
||||
|
||||
codegen(s, tree->cdr, NOVAL);
|
||||
genjmp(s, OP_JMP, lp->pc0);
|
||||
|
||||
dispatch(s, pos);
|
||||
loop_pop(s, val);
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_FOR:
|
||||
for_body(s, tree);
|
||||
if (val) push();
|
||||
|
||||
@@ -23,6 +23,7 @@ enum node_type {
|
||||
NODE_REDO,
|
||||
NODE_RETRY,
|
||||
NODE_STMTS,
|
||||
NODE_BEGIN,
|
||||
NODE_RESCUE,
|
||||
NODE_ENSURE,
|
||||
NODE_AND,
|
||||
|
||||
@@ -394,6 +394,13 @@ new_stmts(parser_state *p, node *body)
|
||||
return cons((node*)NODE_STMTS, 0);
|
||||
}
|
||||
|
||||
/* (:begin body) */
|
||||
static node*
|
||||
new_begin(parser_state *p, node *body)
|
||||
{
|
||||
return cons((node*)NODE_BEGIN, body);
|
||||
}
|
||||
|
||||
#define newline_node(n) (n)
|
||||
|
||||
/* (:rescue body rescue else) */
|
||||
@@ -2740,7 +2747,7 @@ primary : literal
|
||||
keyword_end
|
||||
{
|
||||
p->cmdarg_stack = $<stack>2;
|
||||
$$ = $3;
|
||||
$$ = new_begin(p, $3);
|
||||
}
|
||||
| tLPAREN_ARG
|
||||
{
|
||||
@@ -4314,6 +4321,7 @@ void_expr_error(parser_state *p, node *n)
|
||||
}
|
||||
break;
|
||||
case NODE_STMTS:
|
||||
case NODE_BEGIN:
|
||||
if (n->cdr) {
|
||||
while (n->cdr) {
|
||||
n = n->cdr;
|
||||
@@ -7138,6 +7146,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
|
||||
dump_recur(mrb, tree, offset+1);
|
||||
break;
|
||||
|
||||
case NODE_BEGIN:
|
||||
printf("NODE_BEGIN:\n");
|
||||
mrb_parser_dump(mrb, tree, offset+1);
|
||||
break;
|
||||
|
||||
case NODE_RESCUE:
|
||||
printf("NODE_RESCUE:\n");
|
||||
if (tree->car) {
|
||||
|
||||
+1089
-1072
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user