mruby-compiler: convert new_masgn to always use variable-sized nodes

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-09-11 20:49:29 +09:00
parent 83707f7798
commit 88f3110215
3 changed files with 1339 additions and 1266 deletions
+157 -108
View File
@@ -154,6 +154,7 @@ static int catch_handler_new(codegen_scope *s);
static void catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target);
static void gen_massignment(codegen_scope *s, node *tree, int sp, int val);
static void gen_masgn_var(codegen_scope *s, node *varnode, node *rhs, int sp, int val);
static void codegen(codegen_scope *s, node *tree, int val);
static void raise_error(codegen_scope *s, const char *msg);
@@ -2472,8 +2473,11 @@ lambda_body(codegen_scope *s, node *tree, int blk)
node *n = margs;
pos = 1; /* Start from register 1 (after self). */
while (n) {
if (node_to_int(n->car->car) == NODE_MASGN) { /* If the argument is a mass assignment (e.g., |(a,b)| ). */
gen_massignment(s, n->car->cdr->car, pos, NOVAL);
if (node_to_int(n->car->car) == NODE_VARIABLE) {
if (VAR_NODE_TYPE(n->car->cdr) == NODE_MASGN) { /* 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->cdr;
gen_massignment(s, masgn_n->lhs, pos, NOVAL);
}
}
pos++;
n = n->cdr;
@@ -2483,8 +2487,11 @@ lambda_body(codegen_scope *s, node *tree, int blk)
node *n = pargs;
pos = ma+oa+ra+1; /* Calculate starting register for post-mandatory args. */
while (n) {
if (node_to_int(n->car->car) == NODE_MASGN) { /* If argument is a mass assignment. */
gen_massignment(s, n->car->cdr->car, pos, NOVAL);
if (node_to_int(n->car->car) == NODE_VARIABLE) {
if (VAR_NODE_TYPE(n->car->cdr) == NODE_MASGN) { /* If argument is a mass assignment. */
struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car->cdr;
gen_massignment(s, masgn_n->lhs, pos, NOVAL);
}
}
pos++;
n = n->cdr;
@@ -2926,7 +2933,6 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
case NODE_ARG:
case NODE_LVAR:
case NODE_NIL:
case NODE_MASGN:
if (rhs) {
codegen(s, rhs, VAL);
pop();
@@ -2970,6 +2976,9 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
case NODE_CONST:
gen_xvar_assignment(s, tree, rhs, sp, val, OP_SETCONST);
break;
case NODE_MASGN:
gen_masgn_var(s, tree->cdr, rhs, sp, val);
return;
default:
codegen_error(s, "unsupported variable-sized lhs");
break;
@@ -3091,10 +3100,6 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
}
break;
case NODE_MASGN:
gen_massignment(s, tree->car, sp, val);
break;
/* splat without assignment */
case NODE_NIL:
break;
@@ -3524,91 +3529,6 @@ codegen_op_asgn(codegen_scope *s, node *tree, int val)
}
}
static void
codegen_masgn(codegen_scope *s, node *tree, int val)
{
int len = 0, n = 0, post = 0;
node *t = tree->cdr, *p;
int rhs = cursp();
if (!val && node_to_int(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
/* fixed rhs */
t = t->cdr;
while (t) {
codegen(s, t->car, VAL);
len++;
t = t->cdr;
}
tree = tree->car;
if (tree->car) { /* pre */
t = tree->car;
n = 0;
while (t) {
if (n < len) {
gen_assignment(s, t->car, NULL, rhs+n, NOVAL);
n++;
}
else {
genop_1(s, OP_LOADNIL, rhs+n);
gen_assignment(s, t->car, NULL, rhs+n, NOVAL);
}
t = t->cdr;
}
}
t = tree->cdr;
if (t) {
if (t->cdr) { /* post count */
p = t->cdr->car;
while (p) {
post++;
p = p->cdr;
}
}
if (t->car) { /* rest (len - pre - post) */
int rn;
if (len < post + n) {
rn = 0;
}
else {
rn = len - post - n;
}
if (cursp() == rhs+n) {
genop_2(s, OP_ARRAY, cursp(), rn);
}
else {
genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn);
}
gen_assignment(s, t->car, NULL, cursp(), NOVAL);
n += rn;
}
if (t->cdr && t->cdr->car) {
t = t->cdr->car;
while (t) {
if (n<len) {
gen_assignment(s, t->car, NULL, rhs+n, NOVAL);
}
else {
genop_1(s, OP_LOADNIL, cursp());
gen_assignment(s, t->car, NULL, cursp(), NOVAL);
}
t = t->cdr;
n++;
}
}
}
pop_n(len);
}
else {
/* variable rhs */
codegen(s, t, VAL);
gen_massignment(s, tree->car, rhs, val);
if (!val) {
pop();
}
}
}
static void
codegen_lvar(codegen_scope *s, mrb_sym sym, int val)
{
@@ -4715,18 +4635,151 @@ gen_asgn_var(codegen_scope *s, node *varnode, int val)
}
static void
gen_masgn_var(codegen_scope *s, node *varnode, int val)
gen_masgn_var(codegen_scope *s, node *varnode, node *rhs, int sp, int val)
{
/* Simplified multiple assignment codegen */
node *rhs = MASGN_NODE_RHS(varnode);
if (rhs) {
codegen(s, rhs, VAL);
struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)varnode;
/* If called from codegen_variable_node context, use the embedded rhs */
if (!rhs && sp == 0) {
rhs = masgn_n->rhs;
sp = 0; /* Use register 0 as base for standalone assignment */
}
else if (val) {
genop_1(s, OP_LOADNIL, cursp());
push();
int len = 0, n = 0, post = 0;
node *t = rhs ? rhs : masgn_n->rhs, *p;
node *tree = masgn_n->lhs; /* Use tree variable like original */
int rhs_reg = sp;
if (!val && t && node_to_int(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
/* fixed rhs */
t = t->cdr;
while (t) {
codegen(s, t->car, VAL);
len++;
t = t->cdr;
}
if (tree && tree->car) { /* pre */
t = tree->car;
n = 0;
while (t) {
if (n < len) {
gen_assignment(s, t->car, NULL, rhs_reg+n, NOVAL);
n++;
}
else {
genop_1(s, OP_LOADNIL, rhs_reg+n);
gen_assignment(s, t->car, NULL, rhs_reg+n, NOVAL);
}
t = t->cdr;
}
}
if (tree) {
t = tree->cdr;
if (t) {
if (t->cdr) { /* post count */
p = t->cdr->car;
while (p) {
post++;
p = p->cdr;
}
}
if (t->car) { /* rest (len - pre - post) */
int rn;
if (len < post + n) {
rn = 0;
}
else {
rn = len - post - n;
}
if (cursp() == rhs_reg+n) {
genop_2(s, OP_ARRAY, cursp(), rn);
}
else {
genop_3(s, OP_ARRAY2, cursp(), rhs_reg+n, rn);
}
gen_assignment(s, t->car, NULL, cursp(), NOVAL);
n += rn;
}
if (t->cdr && t->cdr->car) {
t = t->cdr->car;
while (t) {
if (n<len) {
gen_assignment(s, t->car, NULL, rhs_reg+n, NOVAL);
}
else {
genop_1(s, OP_LOADNIL, cursp());
gen_assignment(s, t->car, NULL, cursp(), NOVAL);
}
t = t->cdr;
n++;
}
}
}
}
pop_n(len);
}
else {
/* variable rhs - implement gen_massignment logic directly for variable-sized nodes */
if (t) {
codegen(s, t, VAL);
rhs_reg = cursp() - 1; /* rhs is now at cursp()-1 */
}
/* Handle the lhs tree structure directly */
n = 0;
post = 0;
if (tree && tree->car) { /* pre */
node *pre = tree->car;
n = 0;
while (pre) {
int sp = cursp();
genop_3(s, OP_AREF, sp, rhs_reg, n);
push();
gen_assignment(s, pre->car, NULL, sp, NOVAL);
pop();
n++;
pre = pre->cdr;
}
}
if (tree) {
node *rest_part = tree->cdr;
if (rest_part) {
if (rest_part->cdr) { /* post count */
node *p = rest_part->cdr->car;
while (p) {
post++;
p = p->cdr;
}
}
gen_move(s, cursp(), rhs_reg, val);
push_n(post+1);
pop_n(post+1);
genop_3(s, OP_APOST, cursp(), n, post);
int nn = 1;
if (rest_part->car && rest_part->car != (node*)-1) { /* rest */
gen_assignment(s, rest_part->car, NULL, cursp(), NOVAL);
}
if (rest_part->cdr && rest_part->cdr->car) {
node *post_part = rest_part->cdr->car;
while (post_part) {
gen_assignment(s, post_part->car, NULL, cursp()+nn, NOVAL);
post_part = post_part->cdr;
nn++;
}
}
if (val) {
gen_move(s, cursp(), rhs_reg, 0);
}
}
}
if (!val && t) {
pop(); /* pop the rhs value */
}
}
/* TODO: Add proper multiple assignment logic here */
}
static void
@@ -5939,7 +5992,7 @@ codegen_variable_node(codegen_scope *s, node *varnode, int val)
return TRUE;
case NODE_MASGN:
gen_masgn_var(s, varnode, val);
gen_masgn_var(s, varnode, NULL, 0, val);
return TRUE;
case NODE_OP_ASGN:
@@ -6213,10 +6266,6 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_scall(s, tree, val);
break;
case NODE_MASGN:
codegen_masgn(s, tree, val);
break;
case NODE_OP_ASGN:
codegen_op_asgn(s, tree, val);
break;
+42 -30
View File
@@ -607,7 +607,6 @@ new_alias(parser_state *p, mrb_sym a, mrb_sym b)
/* Forward declarations for variable-sized AST node creation functions */
static node* new_def_var(parser_state *p, mrb_sym name, node *args, node *body);
static node* new_masgn_var(parser_state *p, node *lhs, node *rhs);
static node* new_op_asgn_var(parser_state *p, node *lhs, mrb_sym op, node *rhs);
/* (:if cond then else) */
@@ -872,22 +871,6 @@ new_def_var(parser_state *p, mrb_sym name, node *args, node *body)
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized multiple assignment node creation */
static node*
new_masgn_var(parser_state *p, node *lhs, node *rhs)
{
size_t total_size = sizeof(struct mrb_ast_masgn_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_masgn_node *n = (struct mrb_ast_masgn_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_MASGN, class);
n->lhs = lhs;
n->rhs = rhs;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized operator assignment node creation */
static node*
new_op_asgn_var(parser_state *p, node *lhs, mrb_sym op, node *rhs)
@@ -1465,16 +1448,29 @@ static void
local_add_margs(parser_state *p, node *n)
{
while (n) {
if (node_to_type(n->car->car) == NODE_MASGN) {
node *t = n->car->cdr->cdr;
if (node_to_type(n->car->car) == NODE_VARIABLE) {
if (VAR_NODE_TYPE(n->car->cdr) == NODE_MASGN) {
struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car->cdr;
node *lhs = masgn_n->lhs;
node *rhs = masgn_n->rhs;
n->car->cdr->cdr = NULL;
while (t) {
local_add_f(p, node_to_sym(t->car));
t = t->cdr;
/* For parameter destructuring, rhs contains the locals */
if (rhs) {
node *t = rhs;
while (t) {
local_add_f(p, node_to_sym(t->car));
t = t->cdr;
}
}
/* Process nested destructuring in lhs */
if (lhs && lhs->car) {
local_add_margs(p, lhs->car);
}
if (lhs && lhs->cdr && lhs->cdr->cdr && lhs->cdr->cdr->car) {
local_add_margs(p, lhs->cdr->cdr->car);
}
}
local_add_margs(p, n->car->cdr->car->car);
local_add_margs(p, n->car->cdr->car->cdr->cdr->car);
}
n = n->cdr;
}
@@ -1682,17 +1678,33 @@ static node*
new_masgn(parser_state *p, node *a, node *b)
{
void_expr_error(p, b);
if (p->var_nodes_enabled) {
return new_masgn_var(p, a, b);
}
return cons_head((node*)NODE_MASGN, cons(a, b));
size_t total_size = sizeof(struct mrb_ast_masgn_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_masgn_node *n = (struct mrb_ast_masgn_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_MASGN, class);
n->lhs = a;
n->rhs = b;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:masgn mlhs mrhs) no check */
static node*
new_masgn_param(parser_state *p, node *a, node *b)
{
return cons_head((node*)NODE_MASGN, cons(a, b));
size_t total_size = sizeof(struct mrb_ast_masgn_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_masgn_node *n = (struct mrb_ast_masgn_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_MASGN, class);
n->lhs = a;
n->rhs = b;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:asgn lhs rhs) */
File diff suppressed because it is too large Load Diff