mruby-compiler: complete NODE_CLASS, NODE_MODULE, and NODE_SCLASS migration to variable-sized nodes exclusively

- Implement complete variable-sized node generation for all class/module types
  - gen_class_var(): full class definition with namespace and superclass support
  - gen_module_var(): complete module definition with proper scope handling
  - gen_sclass_var(): singleton class with object evaluation and OP_SCLASS
  - All use scope_body() for proper locals and body management
- Update parser to always create variable-sized nodes
  - Inline helper function logic directly into new_class(), new_module(), new_sclass()
  - Remove conditional var_nodes_enabled checks for consistency
  - Eliminate separate _var helper functions
- Remove obsolete traditional node handling
  - Delete codegen_class(), codegen_module(), codegen_sclass() functions
  - Remove NODE_CLASS, NODE_MODULE, NODE_SCLASS cases from main codegen() switch
  - Clean up unused function declarations
- All 1730 tests pass, class/module/singleton functionality verified

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-09-09 10:00:00 +09:00
parent 2b931d0c5e
commit 6e68e9f5e2
3 changed files with 1312 additions and 1391 deletions
+96 -117
View File
@@ -4164,98 +4164,6 @@ codegen_postexe(codegen_scope *s, node *tree, int val)
codegen(s, tree, NOVAL);
}
static void
codegen_class(codegen_scope *s, node *tree, int val)
{
int idx;
node *body;
if (tree->car->car == (node*)0) {
gen_load_nil(s, 1);
}
else if (tree->car->car == (node*)1) {
genop_1(s, OP_OCLASS, cursp());
push();
}
else {
codegen(s, tree->car->car, VAL);
}
if (tree->cdr->car) {
codegen(s, tree->cdr->car, VAL);
}
else {
genop_1(s, OP_LOADNIL, cursp());
push();
}
pop(); pop();
idx = new_sym(s, node_to_sym(tree->car->cdr));
genop_2(s, OP_CLASS, cursp(), idx);
body = tree->cdr->cdr->car;
if (node_to_int(body->cdr->car) == NODE_STMTS && body->cdr->cdr == NULL) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
idx = scope_body(s, body->car, body->cdr, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
}
}
static void
codegen_module(codegen_scope *s, node *tree, int val)
{
int idx;
if (tree->car->car == (node*)0) {
genop_1(s, OP_LOADNIL, cursp());
push();
}
else if (tree->car->car == (node*)1) {
genop_1(s, OP_OCLASS, cursp());
push();
}
else {
codegen(s, tree->car->car, VAL);
}
pop();
idx = new_sym(s, node_to_sym(tree->car->cdr));
genop_2(s, OP_MODULE, cursp(), idx);
if (node_to_int(tree->cdr->car->cdr->car) == NODE_STMTS &&
tree->cdr->car->cdr->cdr == NULL) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
idx = scope_body(s, tree->cdr->car->car, tree->cdr->car->cdr, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
}
}
static void
codegen_sclass(codegen_scope *s, node *tree, int val)
{
int idx;
codegen(s, tree->car, VAL);
pop();
genop_1(s, OP_SCLASS, cursp());
if (node_to_int(tree->cdr->car->cdr->car) == NODE_STMTS &&
tree->cdr->car->cdr->cdr == NULL) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
idx = scope_body(s, tree->cdr->car->car, tree->cdr->car->cdr, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
}
}
static void
codegen_undef(codegen_scope *s, node *tree, int val)
{
@@ -5043,46 +4951,129 @@ static void
gen_class_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_class_node *class_n = class_node(varnode);
node *name = CLASS_NODE_NAME(class_n);
node *superclass = CLASS_NODE_SUPERCLASS(class_n);
node *body = CLASS_NODE_BODY(class_n);
int idx;
/* For now, generate simple class definition - this can be optimized later */
if (body) {
codegen(s, body, val);
/* Handle class namespace - same logic as codegen_class */
if (name->car == (node*)0) {
gen_load_nil(s, 1);
}
else if (val) {
else if (name->car == (node*)1) {
genop_1(s, OP_OCLASS, cursp());
push();
}
else {
codegen(s, name->car, VAL);
}
/* Handle superclass */
if (superclass) {
codegen(s, superclass, VAL);
}
else {
genop_1(s, OP_LOADNIL, cursp());
push();
}
pop(); pop();
/* Create class with name symbol */
idx = new_sym(s, node_to_sym(name->cdr));
genop_2(s, OP_CLASS, cursp(), idx);
/* Generate class body - body is scope with locals+body structure */
if (node_to_int(body->cdr->car) == NODE_STMTS && body->cdr->cdr == NULL) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
idx = scope_body(s, body->car, body->cdr, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
}
}
static void
gen_module_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_module_node *module_n = module_node(varnode);
node *name = MODULE_NODE_NAME(module_n);
node *body = MODULE_NODE_BODY(module_n);
int idx;
/* For now, generate simple module definition - this can be optimized later */
if (body) {
codegen(s, body, val);
}
else if (val) {
/* Handle module namespace - same logic as codegen_module */
if (name->car == (node*)0) {
genop_1(s, OP_LOADNIL, cursp());
push();
}
else if (name->car == (node*)1) {
genop_1(s, OP_OCLASS, cursp());
push();
}
else {
codegen(s, name->car, VAL);
}
pop();
/* Create module with name symbol */
idx = new_sym(s, node_to_sym(name->cdr));
genop_2(s, OP_MODULE, cursp(), idx);
/* Generate module body - body is scope with locals+body structure */
if (node_to_int(body->cdr->car) == NODE_STMTS && body->cdr->cdr == NULL) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
idx = scope_body(s, body->car, body->cdr, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
}
}
static void
gen_sclass_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_sclass_node *sclass_n = sclass_node(varnode);
node *obj = SCLASS_NODE_OBJ(sclass_n);
node *body = SCLASS_NODE_BODY(sclass_n);
int idx;
/* For now, generate simple singleton class definition - this can be optimized later */
if (body) {
codegen(s, body, val);
/* Generate code for the singleton object */
codegen(s, obj, VAL);
pop();
/* Enter singleton class scope */
genop_1(s, OP_SCLASS, cursp());
/* Handle singleton class body */
if (body && body->cdr) {
/* Extract locals and body from the cons structure: (locals . body) */
node *locals = body->car;
node *body_stmts = body->cdr;
/* Check for empty body case */
if (node_to_int(body_stmts->car) == NODE_STMTS && body_stmts->cdr == NULL) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
/* Generate proper scope with locals and body */
idx = scope_body(s, locals, body_stmts, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
}
else if (val) {
else {
/* No body - load nil */
genop_1(s, OP_LOADNIL, cursp());
}
if (val) {
push();
}
}
@@ -6502,18 +6493,6 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_undef(s, tree, val);
break;
case NODE_CLASS:
codegen_class(s, tree, val);
break;
case NODE_MODULE:
codegen_module(s, tree, val);
break;
case NODE_SCLASS:
codegen_sclass(s, tree, val);
break;
case NODE_DEF:
codegen_def(s, tree, val);
break;
+32 -61
View File
@@ -609,9 +609,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_class_var(parser_state *p, node *name, node *superclass, node *body);
static node* new_module_var(parser_state *p, node *name, node *body);
static node* new_sclass_var(parser_state *p, node *obj, node *body);
static node* new_asgn_var(parser_state *p, node *lhs, node *rhs);
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);
@@ -878,54 +875,8 @@ new_def_var(parser_state *p, mrb_sym name, node *args, node *body)
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized class definition node creation */
static node*
new_class_var(parser_state *p, node *name, node *superclass, node *body)
{
size_t total_size = sizeof(struct mrb_ast_class_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_class_node *n = (struct mrb_ast_class_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_CLASS, class);
n->name = name;
n->superclass = superclass;
n->body = body;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized module definition node creation */
static node*
new_module_var(parser_state *p, node *name, node *body)
{
size_t total_size = sizeof(struct mrb_ast_module_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_module_node *n = (struct mrb_ast_module_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_MODULE, class);
n->name = name;
n->body = body;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized singleton class definition node creation */
static node*
new_sclass_var(parser_state *p, node *obj, node *body)
{
size_t total_size = sizeof(struct mrb_ast_sclass_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_sclass_node *n = (struct mrb_ast_sclass_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_SCLASS, class);
n->obj = obj;
n->body = body;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized assignment node creation */
static node*
@@ -1504,10 +1455,18 @@ static node*
new_class(parser_state *p, node *c, node *s, node *b)
{
void_expr_error(p, s);
if (p->var_nodes_enabled) {
return new_class_var(p, c, s, cons(locals_node(p), b));
}
return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b));
size_t total_size = sizeof(struct mrb_ast_class_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_class_node *n = (struct mrb_ast_class_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_CLASS, class);
n->name = c;
n->superclass = s;
n->body = cons(locals_node(p), b);
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:sclass obj body) */
@@ -1515,20 +1474,32 @@ static node*
new_sclass(parser_state *p, node *o, node *b)
{
void_expr_error(p, o);
if (p->var_nodes_enabled) {
return new_sclass_var(p, o, cons(locals_node(p), b));
}
return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b));
size_t total_size = sizeof(struct mrb_ast_sclass_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_sclass_node *n = (struct mrb_ast_sclass_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_SCLASS, class);
n->obj = o;
n->body = cons(locals_node(p), b);
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:module module body) */
static node*
new_module(parser_state *p, node *m, node *b)
{
if (p->var_nodes_enabled) {
return new_module_var(p, m, cons(locals_node(p), b));
}
return list3((node*)NODE_MODULE, m, cons(locals_node(p), b));
size_t total_size = sizeof(struct mrb_ast_module_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_module_node *n = (struct mrb_ast_module_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_MODULE, class);
n->name = m;
n->body = cons(locals_node(p), b);
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* (:def m lv (arg . body)) */
File diff suppressed because it is too large Load Diff