mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: convert new_masgn to always use variable-sized nodes
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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) */
|
||||
|
||||
+1140
-1128
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user