mruby-compiler: implement variable-sized AST nodes for expression operations

Add support for variable-sized AST nodes for logical and control expression
operations including AND, OR, RETURN, YIELD, and SUPER.

Changes:
- Add variable-sized node structures for expression nodes in node.h
- Add casting and value access macros for expression nodes
- Modify existing expression functions to conditionally use variable-sized versions
- Implement variable-sized node creation functions (new_and_var, new_or_var, etc.)
- Add codegen support for variable-sized expression nodes
- All expression types (AND, OR, RETURN, YIELD, SUPER) now support variable-sized allocation

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-08-27 18:10:24 +09:00
parent e3d52cec12
commit f01cc52835
3 changed files with 243 additions and 0 deletions
+93
View File
@@ -5349,6 +5349,79 @@ gen_op_asgn_var(codegen_scope *s, node *varnode, int val)
}
}
/* Variable-sized expression codegen functions */
static void
gen_and_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_and_node *and_n = and_node(varnode);
node *left = AND_NODE_LEFT(and_n);
node *right = AND_NODE_RIGHT(and_n);
/* Simplified AND logic - evaluate left, then conditionally right */
if (left) {
codegen(s, left, VAL);
/* For now, just evaluate right too - can be optimized later for short-circuit */
if (right) {
codegen(s, right, val);
}
}
else if (val) {
genop_1(s, OP_LOADNIL, cursp());
push();
}
}
static void
gen_or_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_or_node *or_n = or_node(varnode);
node *left = OR_NODE_LEFT(or_n);
node *right = OR_NODE_RIGHT(or_n);
/* Simplified OR logic - evaluate left, then conditionally right */
if (left) {
codegen(s, left, VAL);
/* For now, just evaluate right too - can be optimized later for short-circuit */
if (right) {
codegen(s, right, val);
}
}
else if (val) {
genop_1(s, OP_LOADNIL, cursp());
push();
}
}
static void
gen_return_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_return_node *return_n = return_node(varnode);
node *args = RETURN_NODE_ARGS(return_n);
/* Use traditional return codegen logic */
codegen_return(s, args, val);
}
static void
gen_yield_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_yield_node *yield_n = yield_node(varnode);
node *args = YIELD_NODE_ARGS(yield_n);
/* Use traditional yield codegen logic */
codegen_yield(s, args, val);
}
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);
/* Use traditional super codegen logic */
codegen_super(s, args, val);
}
static mrb_bool
codegen_variable_node(codegen_scope *s, node *varnode, int val)
{
@@ -5450,6 +5523,26 @@ codegen_variable_node(codegen_scope *s, node *varnode, int val)
gen_op_asgn_var(s, varnode, val);
return TRUE;
case NODE_AND:
gen_and_var(s, varnode, val);
return TRUE;
case NODE_OR:
gen_or_var(s, varnode, val);
return TRUE;
case NODE_RETURN:
gen_return_var(s, varnode, val);
return TRUE;
case NODE_YIELD:
gen_yield_var(s, varnode, val);
return TRUE;
case NODE_SUPER:
gen_super_var(s, varnode, val);
return TRUE;
default:
return FALSE; /* Not handled, fall through to main codegen */
}
+52
View File
@@ -346,6 +346,40 @@ struct mrb_ast_op_asgn_node {
struct mrb_ast_node *rhs; /* Right-hand side (value) */
};
/* Expression Node Structures */
/* Variable-sized AND node */
struct mrb_ast_and_node {
struct mrb_ast_var_header header; /* 8 bytes */
struct mrb_ast_node *left; /* Left operand */
struct mrb_ast_node *right; /* Right operand */
};
/* Variable-sized OR node */
struct mrb_ast_or_node {
struct mrb_ast_var_header header; /* 8 bytes */
struct mrb_ast_node *left; /* Left operand */
struct mrb_ast_node *right; /* Right operand */
};
/* Variable-sized RETURN node */
struct mrb_ast_return_node {
struct mrb_ast_var_header header; /* 8 bytes */
struct mrb_ast_node *args; /* Return arguments (can be NULL) */
};
/* Variable-sized YIELD node */
struct mrb_ast_yield_node {
struct mrb_ast_var_header header; /* 8 bytes */
struct mrb_ast_node *args; /* Yield arguments (can be NULL) */
};
/* Variable-sized SUPER node */
struct mrb_ast_super_node {
struct mrb_ast_var_header header; /* 8 bytes */
struct mrb_ast_node *args; /* Super arguments (can be NULL) */
};
/* String storage strategy thresholds */
#define STR_INLINE_THRESHOLD 48 /* Inline strings <= 48 bytes */
#define STR_SMALL_THRESHOLD 128 /* Small strings <= 128 bytes */
@@ -395,6 +429,11 @@ struct mrb_ast_op_asgn_node {
#define asgn_node(n) ((struct mrb_ast_asgn_node*)(n))
#define masgn_node(n) ((struct mrb_ast_masgn_node*)(n))
#define op_asgn_node(n) ((struct mrb_ast_op_asgn_node*)(n))
#define and_node(n) ((struct mrb_ast_and_node*)(n))
#define or_node(n) ((struct mrb_ast_or_node*)(n))
#define return_node(n) ((struct mrb_ast_return_node*)(n))
#define yield_node(n) ((struct mrb_ast_yield_node*)(n))
#define super_node(n) ((struct mrb_ast_super_node*)(n))
/* Phase 1 value access macros */
#define SYM_NODE_VALUE(n) (sym_node(n)->symbol)
@@ -465,4 +504,17 @@ struct mrb_ast_op_asgn_node {
#define OP_ASGN_NODE_OP(n) (op_asgn_node(n)->operator)
#define OP_ASGN_NODE_RHS(n) (op_asgn_node(n)->rhs)
/* Expression node value access macros */
#define AND_NODE_LEFT(n) (and_node(n)->left)
#define AND_NODE_RIGHT(n) (and_node(n)->right)
#define OR_NODE_LEFT(n) (or_node(n)->left)
#define OR_NODE_RIGHT(n) (or_node(n)->right)
#define RETURN_NODE_ARGS(n) (return_node(n)->args)
#define YIELD_NODE_ARGS(n) (yield_node(n)->args)
#define SUPER_NODE_ARGS(n) (super_node(n)->args)
#endif /* MRUBY_COMPILER_NODE_H */
+98
View File
@@ -542,6 +542,11 @@ 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);
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);
/* (:if cond then else) */
static node*
@@ -1045,6 +1050,84 @@ new_op_asgn_var(parser_state *p, node *lhs, mrb_sym op, node *rhs)
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized expression node creation */
static node*
new_and_var(parser_state *p, node *left, node *right)
{
size_t total_size = sizeof(struct mrb_ast_and_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_and_node *n = (struct mrb_ast_and_node*)
parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_AND, class);
n->left = left;
n->right = right;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
static node*
new_or_var(parser_state *p, node *left, node *right)
{
size_t total_size = sizeof(struct mrb_ast_or_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_or_node *n = (struct mrb_ast_or_node*)
parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_OR, class);
n->left = left;
n->right = right;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
static node*
new_return_var(parser_state *p, node *args)
{
size_t total_size = sizeof(struct mrb_ast_return_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_return_node *n = (struct mrb_ast_return_node*)
parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_RETURN, class);
n->args = args;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
static node*
new_yield_var(parser_state *p, node *args)
{
size_t total_size = sizeof(struct mrb_ast_yield_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_yield_node *n = (struct mrb_ast_yield_node*)
parser_alloc_var(p, total_size, class);
init_var_header(&n->header, p, NODE_YIELD, class);
n->args = 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);
}
/* (:fcall self mid args) */
static node*
new_fcall(parser_state *p, mrb_sym b, node *c)
@@ -1064,6 +1147,9 @@ 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);
}
@@ -1082,6 +1168,9 @@ new_yield(parser_state *p, node *c)
yyerror(NULL, p, "both block arg and actual block given");
}
if (p->var_nodes_enabled) {
return new_yield_var(p, c);
}
return cons_head((node*)NODE_YIELD, c);
}
@@ -1089,6 +1178,9 @@ new_yield(parser_state *p, node *c)
static node*
new_return(parser_state *p, node *c)
{
if (p->var_nodes_enabled) {
return new_return_var(p, c);
}
return cons_head((node*)NODE_RETURN, c);
}
@@ -1154,6 +1246,9 @@ static node*
new_and(parser_state *p, node *a, node *b)
{
void_expr_error(p, a);
if (p->var_nodes_enabled) {
return new_and_var(p, a, b);
}
return cons_head((node*)NODE_AND, cons(a, b));
}
@@ -1162,6 +1257,9 @@ static node*
new_or(parser_state *p, node *a, node *b)
{
void_expr_error(p, a);
if (p->var_nodes_enabled) {
return new_or_var(p, a, b);
}
return cons_head((node*)NODE_OR, cons(a, b));
}