mruby-compiler: convert NODE_SUPER and NODE_ZSUPER to always use variable-sized nodes

- update NODE_ZSUPER to use mrb_ast_super_node instead of empty mrb_ast_zsuper_node
- convert new_super and new_zsuper to always create variable-sized nodes
- update call_with_block to handle NODE_SUPER/NODE_ZSUPER wrapped in NODE_VARIABLE
- inline codegen_super and codegen_zsuper into their gen_*_var functions
- remove traditional NODE_SUPER and NODE_ZSUPER cases from codegen

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-09-03 18:11:47 +09:00
parent 81311671c5
commit e02bb13d00
4 changed files with 1243 additions and 1262 deletions
+100 -124
View File
@@ -4791,110 +4791,6 @@ codegen_block_arg(codegen_scope *s, node *tree, int val)
}
static void
codegen_super(codegen_scope *s, node *tree, int val)
{
codegen_scope *s2 = s;
int lv = 0;
int n = 0, nk = 0, st = 0;
push();
while (!s2->mscope) {
lv++;
s2 = s2->prev;
if (!s2) break;
}
if (tree) {
node *args = tree->car;
if (args) {
st = n = gen_values(s, args, VAL, 14);
if (n < 0) {
st = 1; n = 15;
push();
}
}
/* keyword arguments */
if (tree->cdr->car) {
nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14);
if (nk < 0) {st++; nk = 15;}
else st += nk*2;
n |= nk<<4;
}
/* block arguments */
if (tree->cdr->cdr) {
codegen(s, tree->cdr->cdr, VAL);
}
else if (s2) gen_blkmove(s, s2->ainfo, lv);
else {
genop_1(s, OP_LOADNIL, cursp());
push();
}
}
else {
if (s2) gen_blkmove(s, s2->ainfo, lv);
else {
genop_1(s, OP_LOADNIL, cursp());
push();
}
}
st++;
pop_n(st+1);
genop_2(s, OP_SUPER, cursp(), n);
if (val) push();
}
static void
codegen_zsuper(codegen_scope *s, node *tree, int val)
{
codegen_scope *s2 = s;
int lv = 0;
uint16_t ainfo = 0;
int n = CALL_MAXARGS;
int sp = cursp();
push(); /* room for receiver */
while (!s2->mscope) {
lv++;
s2 = s2->prev;
if (!s2) break;
}
if (s2 && s2->ainfo > 0) {
ainfo = s2->ainfo;
}
if (lv > 0xf) codegen_error(s, "too deep nesting");
if (ainfo > 0) {
genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
push(); push(); push(); /* ARGARY pushes 3 values at most */
pop(); pop(); pop();
/* keyword arguments */
if (ainfo & 0x1) {
n |= CALL_MAXARGS<<4;
push();
}
/* block argument */
if (tree && tree->cdr && tree->cdr->cdr) {
push();
codegen(s, tree->cdr->cdr, VAL);
}
}
else {
/* block argument */
if (tree && tree->cdr && tree->cdr->cdr) {
codegen(s, tree->cdr->cdr, VAL);
}
else if (s2) {
gen_blkmove(s, 0, lv);
}
else {
genop_1(s, OP_LOADNIL, cursp());
}
n = 0;
}
s->sp = sp;
genop_2(s, OP_SUPER, cursp(), n);
if (val) push();
}
static void
codegen_yield(codegen_scope *s, node *tree, int val)
{
@@ -5330,11 +5226,8 @@ gen_asgn_var(codegen_scope *s, node *varnode, int val)
static void
gen_masgn_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_masgn_node *masgn_n = masgn_node(varnode);
node *rhs = MASGN_NODE_RHS(masgn_n);
/* Simplified multiple assignment codegen */
/* For now, just generate RHS value and then handle LHS assignment */
node *rhs = MASGN_NODE_RHS(varnode);
if (rhs) {
codegen(s, rhs, VAL);
}
@@ -5433,10 +5326,55 @@ static void
gen_super_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_super_node *super_n = super_node(varnode);
node *args = SUPER_NODE_ARGS(super_n);
node *tree = SUPER_NODE_ARGS(super_n);
/* Use traditional super codegen logic */
codegen_super(s, args, val);
codegen_scope *s2 = s;
int lv = 0;
int n = 0, nk = 0, st = 0;
push();
while (!s2->mscope) {
lv++;
s2 = s2->prev;
if (!s2) break;
}
if (tree) {
node *args = tree->car;
if (args) {
st = n = gen_values(s, args, VAL, 14);
if (n < 0) {
st = 1; n = 15;
push();
}
}
/* keyword arguments */
if (tree->cdr->car) {
nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14);
if (nk < 0) {st++; nk = 15;}
else st += nk*2;
n |= nk<<4;
}
/* block arguments */
if (tree->cdr->cdr) {
codegen(s, tree->cdr->cdr, VAL);
}
else if (s2) gen_blkmove(s, s2->ainfo, lv);
else {
genop_1(s, OP_LOADNIL, cursp());
push();
}
}
else {
if (s2) gen_blkmove(s, s2->ainfo, lv);
else {
genop_1(s, OP_LOADNIL, cursp());
push();
}
}
st++;
pop_n(st+1);
genop_2(s, OP_SUPER, cursp(), n);
if (val) push();
}
/* Variable-sized literal node generation functions */
@@ -5852,12 +5790,57 @@ gen_fcall_var(codegen_scope *s, node *varnode, int val)
static void
gen_zsuper_var(codegen_scope *s, node *varnode, int val)
{
(void)varnode; // suppress unused warning
// Create a simple stack structure
struct mrb_ast_node stack_node;
stack_node.car = (node*)NODE_ZSUPER;
stack_node.cdr = NULL;
codegen_zsuper(s, &stack_node, val);
/* NODE_ZSUPER now uses mrb_ast_super_node, which may have args */
struct mrb_ast_super_node *zsuper_n = super_node(varnode);
node *tree = zsuper_n->args; /* May be NULL or args added by call_with_block */
codegen_scope *s2 = s;
int lv = 0;
uint16_t ainfo = 0;
int n = CALL_MAXARGS;
int sp = cursp();
push(); /* room for receiver */
while (!s2->mscope) {
lv++;
s2 = s2->prev;
if (!s2) break;
}
if (s2 && s2->ainfo > 0) {
ainfo = s2->ainfo;
}
if (lv > 0xf) codegen_error(s, "too deep nesting");
if (ainfo > 0) {
genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
push(); push(); push(); /* ARGARY pushes 3 values at most */
pop(); pop(); pop();
/* keyword arguments */
if (ainfo & 0x1) {
n |= CALL_MAXARGS<<4;
push();
}
/* block argument - tree here is args, so check tree->cdr->cdr */
if (tree && tree->cdr && tree->cdr->cdr) {
push();
codegen(s, tree->cdr->cdr, VAL);
}
}
else {
/* block argument */
if (tree && tree->cdr && tree->cdr->cdr) {
codegen(s, tree->cdr->cdr, VAL);
}
else if (s2) {
gen_blkmove(s, 0, lv);
}
else {
genop_1(s, OP_LOADNIL, cursp());
}
n = 0;
}
s->sp = sp;
genop_2(s, OP_SUPER, cursp(), n);
if (val) push();
}
static void
@@ -6490,13 +6473,6 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_op_asgn(s, tree, val);
break;
case NODE_SUPER:
codegen_super(s, tree, val);
break;
case NODE_ZSUPER:
codegen_zsuper(s, tree, val);
break;
case NODE_RETURN:
codegen_return(s, tree, val);
+1 -4
View File
@@ -804,9 +804,6 @@ struct mrb_ast_fcall_node {
struct mrb_ast_node *args;
};
struct mrb_ast_zsuper_node {
struct mrb_ast_var_header hdr;
};
struct mrb_ast_lambda_node {
struct mrb_ast_var_header hdr;
@@ -920,7 +917,7 @@ struct mrb_ast_sdef_node {
};
#define fcall_node(n) ((struct mrb_ast_fcall_node*)(n))
#define zsuper_node(n) ((struct mrb_ast_zsuper_node*)(n))
#define zsuper_node(n) ((struct mrb_ast_super_node*)(n))
#define lambda_node(n) ((struct mrb_ast_lambda_node*)(n))
#define zarray_node(n) ((struct mrb_ast_zarray_node*)(n))
#define kw_hash_node(n) ((struct mrb_ast_kw_hash_node*)(n))
+31 -27
View File
@@ -612,7 +612,6 @@ static node* new_and_var(parser_state *p, node *left, node *right);
static node* new_or_var(parser_state *p, node *left, node *right);
static node* new_return_var(parser_state *p, node *args);
static node* new_yield_var(parser_state *p, node *args);
static node* new_super_var(parser_state *p, node *args);
static node* new_float_var(parser_state *p, const char *value);
/* (:if cond then else) */
@@ -1181,20 +1180,6 @@ new_yield_var(parser_state *p, node *args)
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
static node*
new_super_var(parser_state *p, node *args)
{
size_t total_size = sizeof(struct mrb_ast_super_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_super_node *n = (struct mrb_ast_super_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_SUPER, class);
n->args = args;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized literal node creation functions */
@@ -1335,21 +1320,27 @@ new_callargs(parser_state *p, node *a, node *b, node *c)
static node*
new_super(parser_state *p, node *c)
{
if (p->var_nodes_enabled) {
return new_super_var(p, c);
}
return cons_head((node*)NODE_SUPER, c);
size_t total_size = sizeof(struct mrb_ast_super_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_super_node *n = (struct mrb_ast_super_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_SUPER, class);
n->args = c;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:zsuper) */
static node*
new_zsuper(parser_state *p)
{
size_t total_size = sizeof(struct mrb_ast_zsuper_node);
size_t total_size = sizeof(struct mrb_ast_super_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_zsuper_node *zsuper_node = (struct mrb_ast_zsuper_node*)parser_alloc_var(p, total_size, class);
init_var_header(&zsuper_node->hdr, p, NODE_ZSUPER, class);
return cons_head((node*)NODE_VARIABLE, (node*)zsuper_node);
struct mrb_ast_super_node *n = (struct mrb_ast_super_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_ZSUPER, class);
n->args = NULL; /* zsuper initially has no args, but may be added by call_with_block */
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:yield . c) */
@@ -2317,10 +2308,23 @@ call_with_block(parser_state *p, node *a, node *b)
node *n;
switch (node_to_type(a->car)) {
case NODE_SUPER:
case NODE_ZSUPER:
if (!a->cdr) a->cdr = new_callargs(p, 0, 0, b);
else args_with_block(p, a->cdr, b);
case NODE_VARIABLE:
/* Handle variable-sized nodes wrapped in NODE_VARIABLE */
{
enum node_type var_type = VAR_NODE_TYPE(a->cdr);
if (var_type == NODE_SUPER || var_type == NODE_ZSUPER) {
/* For variable-sized super/zsuper nodes, we need to update the args field directly */
struct mrb_ast_super_node *super_n = super_node(a->cdr);
if (!super_n->args) {
super_n->args = new_callargs(p, 0, 0, b);
}
else {
args_with_block(p, super_n->args, b);
}
return;
}
}
/* For other variable-sized nodes, fall through to default */
break;
case NODE_CALL:
case NODE_FCALL:
File diff suppressed because it is too large Load Diff