mruby-compiler: add NODE_MARG for parameter destructuring

Implement NODE_MARG as a dedicated node type for parameter destructuring
to separate it architecturally from general multiple assignment (NODE_MASGN).
This resolves crashes when dumping parameter destructuring nodes and
improves code organization.

Key changes:
- Add NODE_MARG to node type enum
- Create new_marg() function for parameter destructuring
- Consolidate new_masgn() and new_marg() using shared helper
- Fix parameter context checks in lambda_body() to use NODE_MARG only
- Enable shared dumping logic for both NODE_MASGN and NODE_MARG
- Optimize memory management with immediate RHS cleanup
- Combine gen_assignment() cases for code deduplication

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-09-30 10:50:55 +09:00
parent eae2501ff1
commit 791f631191
4 changed files with 1266 additions and 1294 deletions
+9 -2
View File
@@ -2471,7 +2471,7 @@ lambda_body(codegen_scope *s, node *locals, struct mrb_ast_args *args, node *bod
node *n = margs;
pos = 1; /* Start from register 1 (after self). */
while (n) {
if (get_node_type(n->car) == NODE_MASGN) { /* If the argument is a mass assignment (e.g., |(a,b)| ). */
if (get_node_type(n->car) == NODE_MARG) { /* If the argument is a mass assignment (e.g., |(a,b)| ). */
struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
/* Use dedicated parameter destructuring logic instead of general codegen_masgn */
int nn = 0;
@@ -2498,7 +2498,7 @@ lambda_body(codegen_scope *s, node *locals, struct mrb_ast_args *args, node *bod
node *n = pargs;
pos = ma+oa+ra+1; /* Calculate starting register for post-mandatory args. */
while (n) {
if (get_node_type(n->car) == NODE_MASGN) { /* If argument is a mass assignment. */
if (get_node_type(n->car) == NODE_MARG) { /* If argument is a mass assignment. */
struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
/* Use dedicated parameter destructuring logic instead of general codegen_masgn */
int nn = 0;
@@ -2933,6 +2933,8 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
gen_xvar_assignment(s, tree, rhs, sp, val, OP_SETCONST);
break;
case NODE_MASGN:
case NODE_MARG:
/* Multiple assignment: expressions (MASGN) and parameter destructuring (MARG) */
codegen_masgn(s, tree, rhs, sp, val);
return;
case NODE_LVAR:
@@ -5667,6 +5669,11 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_masgn(s, tree, NULL, 0, val);
break;
case NODE_MARG:
/* Parameter destructuring should be handled inline by lambda_body */
/* This case should not be reached in normal execution */
break;
case NODE_OP_ASGN:
codegen_op_asgn(s, tree, val);
break;
+1
View File
@@ -29,6 +29,7 @@ enum node_type {
NODE_OR,
NODE_NOT,
NODE_MASGN,
NODE_MARG,
NODE_ASGN,
NODE_OP_ASGN,
NODE_CALL,
+22 -40
View File
@@ -1034,7 +1034,7 @@ static void
local_add_margs(parser_state *p, node *n)
{
while (n) {
if (get_node_type(n->car) == NODE_MASGN) {
if (get_node_type(n->car) == NODE_MARG) {
struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
node *rhs = masgn_n->rhs;
@@ -1045,6 +1045,8 @@ local_add_margs(parser_state *p, node *n)
local_add_f(p, node_to_sym(t->car));
t = t->cdr;
}
/* Clear cons list RHS immediately after use */
masgn_n->rhs = NULL;
}
/* Process nested destructuring in lhs components */
@@ -1059,6 +1061,7 @@ local_add_margs(parser_state *p, node *n)
}
}
static void
local_add_lv(parser_state *p, node *lv)
{
@@ -1255,14 +1258,12 @@ new_asgn(parser_state *p, node *a, node *b)
return (node*)n;
}
/* (:masgn mlhs=(pre rest post) mrhs) */
/* Helper function to create MASGN/MARG nodes */
static node*
new_masgn(parser_state *p, node *a, node *b)
new_masgn_helper(parser_state *p, node *a, node *b, enum node_type node_type)
{
void_expr_error(p, b);
struct mrb_ast_masgn_node *n = (struct mrb_ast_masgn_node*)parser_palloc(p, sizeof(struct mrb_ast_masgn_node));
init_var_header(&n->header, p, NODE_MASGN);
init_var_header(&n->header, p, node_type);
/* Extract pre, rest, post from cons list structure (a b c) */
if (a) {
@@ -1294,38 +1295,19 @@ new_masgn(parser_state *p, node *a, node *b)
return (node*)n;
}
/* (:masgn mlhs mrhs) no check */
/* (:masgn mlhs=(pre rest post) mrhs) */
static node*
new_masgn_param(parser_state *p, node *a, node *b)
new_masgn(parser_state *p, node *a, node *b)
{
struct mrb_ast_masgn_node *n = (struct mrb_ast_masgn_node*)parser_palloc(p, sizeof(struct mrb_ast_masgn_node));
init_var_header(&n->header, p, NODE_MASGN);
void_expr_error(p, b);
return new_masgn_helper(p, a, b, NODE_MASGN);
}
/* Extract pre, rest, post from cons list structure (a b c) */
if (a) {
n->pre = a->car; /* Pre-splat variables */
if (a->cdr) {
n->rest = a->cdr->car; /* Splat variable (or -1 for anonymous) */
if (a->cdr->cdr) {
n->post = a->cdr->cdr->car; /* Post-splat variables */
}
else {
n->post = NULL;
}
}
else {
n->rest = NULL;
n->post = NULL;
}
}
else {
n->pre = NULL;
n->rest = NULL;
n->post = NULL;
}
n->rhs = b;
return (node*)n;
/* (:marg mlhs mrhs) no check - for parameter destructuring */
static node*
new_marg(parser_state *p, node *a)
{
return new_masgn_helper(p, a, p->locals->car, NODE_MARG);
}
/* (:asgn lhs rhs) */
@@ -4398,7 +4380,7 @@ f_arg_item : f_norm_arg
}
f_margs rparen
{
$$ = new_masgn_param(p, $3, p->locals->car);
$$ = new_marg(p, $3);
local_resume(p, $<nd>2);
local_add_f(p, 0);
}
@@ -7900,7 +7882,8 @@ dump_node(mrb_state *mrb, node *tree, int offset)
break;
case NODE_MASGN:
printf("NODE_MASGN:\n");
case NODE_MARG:
printf("%s:\n", get_node_type(tree) == NODE_MASGN ? "NODE_MASGN" : "NODE_MARG");
/* Handle pre-splat variables */
if (MASGN_NODE_PRE(tree)) {
dump_prefix(offset+1, lineno);
@@ -8441,9 +8424,8 @@ dump_node(mrb_state *mrb, node *tree, int offset)
break;
default:
/* Fallback: treat as a traditional cons-list and recursively dump */
printf("unknown node type %d (0x%x), dumping as list:\n", nodetype, (unsigned)nodetype);
dump_recur(mrb, tree, offset+1);
/* Fallback: unknown node type - skip like codegen.c does */
printf("unknown node type %d (0x%x)\n", nodetype, (unsigned)nodetype);
break;
}
#endif
File diff suppressed because it is too large Load Diff