mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: implement variable-sized nodes for control flows
added variable-sized nodes for control flow and string/regex variants: - control flow: break, next, redo, retry, while_mod, until_mod - string/regex: xstr, dxstr, dregx, heredoc, dsym - proper integration with existing codegen patterns - maintains backward compatibility with traditional nodes - tested with control flow and string interpolation Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5586,6 +5586,103 @@ gen_block_var(codegen_scope *s, node *varnode, int val)
|
||||
push();
|
||||
}
|
||||
|
||||
static void
|
||||
gen_break_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_break_node *n = (struct mrb_ast_break_node*)varnode;
|
||||
codegen_break(s, n->value, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_next_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_next_node *n = (struct mrb_ast_next_node*)varnode;
|
||||
codegen_next(s, n->value, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_redo_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
codegen_redo(s, NULL, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_retry_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
codegen_retry(s, NULL, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_while_mod_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_while_mod_node *n = (struct mrb_ast_while_mod_node*)varnode;
|
||||
// Stack allocation for compatibility with existing codegen
|
||||
struct mrb_ast_node temp_tree = { .car = n->condition, .cdr = n->body };
|
||||
codegen_while_until(s, (node*)&temp_tree, val, NODE_WHILE_MOD);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_until_mod_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_until_mod_node *n = (struct mrb_ast_until_mod_node*)varnode;
|
||||
// Stack allocation for compatibility with existing codegen
|
||||
struct mrb_ast_node temp_tree = { .car = n->condition, .cdr = n->body };
|
||||
codegen_while_until(s, (node*)&temp_tree, val, NODE_UNTIL_MOD);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_xstr_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_xstr_node *n = (struct mrb_ast_xstr_node*)varnode;
|
||||
// Stack allocation for compatibility with existing codegen
|
||||
mrb_int len;
|
||||
const char *str = mrb_sym2name_len(s->mrb, n->name, &len);
|
||||
struct mrb_ast_node temp_car = { .car = (node*)str, .cdr = int_to_node((int)len) };
|
||||
struct mrb_ast_node temp_tree = { .car = (node*)&temp_car, .cdr = NULL };
|
||||
codegen_xstr(s, (node*)&temp_tree, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_dxstr_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_dxstr_node *n = (struct mrb_ast_dxstr_node*)varnode;
|
||||
codegen_dxstr(s, n->list, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_dregx_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_dregx_node *n = (struct mrb_ast_dregx_node*)varnode;
|
||||
// Stack allocation for compatibility with existing codegen
|
||||
struct mrb_ast_node temp_tree = { .car = n->list, .cdr = int_to_node(n->options) };
|
||||
codegen_dregx(s, (node*)&temp_tree, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_heredoc_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_heredoc_node *n = (struct mrb_ast_heredoc_node*)varnode;
|
||||
// For heredocs, we need to handle them similar to strings
|
||||
if (val) {
|
||||
mrb_int len;
|
||||
const char *str = mrb_sym2name_len(s->mrb, n->name, &len);
|
||||
int off = new_lit_str(s, str, (int)len);
|
||||
genop_2(s, OP_STRING, cursp(), off);
|
||||
push();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gen_dsym_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_dsym_node *n = (struct mrb_ast_dsym_node*)varnode;
|
||||
// Generate dstr first, then convert to symbol
|
||||
if (val) {
|
||||
codegen_heredoc_dstr(s, n->list, VAL);
|
||||
genop_1(s, OP_INTERN, cursp());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gen_args_tail_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
@@ -5770,6 +5867,50 @@ codegen_variable_node(codegen_scope *s, node *varnode, int val)
|
||||
gen_args_tail_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_BREAK:
|
||||
gen_break_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_NEXT:
|
||||
gen_next_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_REDO:
|
||||
gen_redo_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_RETRY:
|
||||
gen_retry_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_WHILE_MOD:
|
||||
gen_while_mod_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_UNTIL_MOD:
|
||||
gen_until_mod_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_XSTR:
|
||||
gen_xstr_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_DXSTR:
|
||||
gen_dxstr_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_DREGX:
|
||||
gen_dregx_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_HEREDOC:
|
||||
gen_heredoc_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
case NODE_DSYM:
|
||||
gen_dsym_var(s, varnode, val);
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE; /* Not handled, fall through to main codegen */
|
||||
}
|
||||
|
||||
@@ -655,4 +655,98 @@ struct mrb_ast_args_tail_node {
|
||||
#define ARGS_TAIL_NODE_KWREST(n) (args_tail_node(n)->kwrest)
|
||||
#define ARGS_TAIL_NODE_BLOCK(n) (args_tail_node(n)->block)
|
||||
|
||||
// Group 8: Control Flow Statements
|
||||
struct mrb_ast_break_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *value;
|
||||
};
|
||||
|
||||
struct mrb_ast_next_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *value;
|
||||
};
|
||||
|
||||
struct mrb_ast_redo_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
};
|
||||
|
||||
struct mrb_ast_retry_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
};
|
||||
|
||||
struct mrb_ast_while_mod_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *condition;
|
||||
struct mrb_ast_node *body;
|
||||
};
|
||||
|
||||
struct mrb_ast_until_mod_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *condition;
|
||||
struct mrb_ast_node *body;
|
||||
};
|
||||
|
||||
#define break_node(n) ((struct mrb_ast_break_node*)(n))
|
||||
#define next_node(n) ((struct mrb_ast_next_node*)(n))
|
||||
#define redo_node(n) ((struct mrb_ast_redo_node*)(n))
|
||||
#define retry_node(n) ((struct mrb_ast_retry_node*)(n))
|
||||
#define while_mod_node(n) ((struct mrb_ast_while_mod_node*)(n))
|
||||
#define until_mod_node(n) ((struct mrb_ast_until_mod_node*)(n))
|
||||
|
||||
#define BREAK_NODE_VALUE(n) (break_node(n)->value)
|
||||
#define NEXT_NODE_VALUE(n) (next_node(n)->value)
|
||||
#define WHILE_MOD_NODE_CONDITION(n) (while_mod_node(n)->condition)
|
||||
#define WHILE_MOD_NODE_BODY(n) (while_mod_node(n)->body)
|
||||
#define UNTIL_MOD_NODE_CONDITION(n) (until_mod_node(n)->condition)
|
||||
#define UNTIL_MOD_NODE_BODY(n) (until_mod_node(n)->body)
|
||||
|
||||
// Group 9: String and Regex Variants
|
||||
struct mrb_ast_xstr_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
mrb_sym name;
|
||||
};
|
||||
|
||||
struct mrb_ast_dxstr_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *list;
|
||||
};
|
||||
|
||||
struct mrb_ast_dregx_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *list;
|
||||
int options;
|
||||
};
|
||||
|
||||
struct mrb_ast_dregx_once_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *list;
|
||||
int options;
|
||||
};
|
||||
|
||||
struct mrb_ast_heredoc_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
mrb_sym name;
|
||||
};
|
||||
|
||||
struct mrb_ast_dsym_node {
|
||||
struct mrb_ast_var_header hdr;
|
||||
struct mrb_ast_node *list;
|
||||
};
|
||||
|
||||
#define xstr_node(n) ((struct mrb_ast_xstr_node*)(n))
|
||||
#define dxstr_node(n) ((struct mrb_ast_dxstr_node*)(n))
|
||||
#define dregx_node(n) ((struct mrb_ast_dregx_node*)(n))
|
||||
#define dregx_once_node(n) ((struct mrb_ast_dregx_once_node*)(n))
|
||||
#define heredoc_node(n) ((struct mrb_ast_heredoc_node*)(n))
|
||||
#define dsym_node(n) ((struct mrb_ast_dsym_node*)(n))
|
||||
|
||||
#define XSTR_NODE_NAME(n) (xstr_node(n)->name)
|
||||
#define DXSTR_NODE_LIST(n) (dxstr_node(n)->list)
|
||||
#define DREGX_NODE_LIST(n) (dregx_node(n)->list)
|
||||
#define DREGX_NODE_OPTIONS(n) (dregx_node(n)->options)
|
||||
#define DREGX_ONCE_NODE_LIST(n) (dregx_once_node(n)->list)
|
||||
#define DREGX_ONCE_NODE_OPTIONS(n) (dregx_once_node(n)->options)
|
||||
#define HEREDOC_NODE_NAME(n) (heredoc_node(n)->name)
|
||||
#define DSYM_NODE_LIST(n) (dsym_node(n)->list)
|
||||
|
||||
#endif /* MRUBY_COMPILER_NODE_H */
|
||||
|
||||
@@ -625,7 +625,18 @@ static node*
|
||||
new_while_mod(parser_state *p, node *a, node *b)
|
||||
{
|
||||
void_expr_error(p, a);
|
||||
return cons_head((node*)NODE_WHILE_MOD, cons(a, b));
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_WHILE_MOD, cons(a, b));
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_while_mod_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_while_mod_node *n = (struct mrb_ast_while_mod_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_WHILE_MOD, class);
|
||||
n->condition = a;
|
||||
n->body = b;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:until_mod cond body) */
|
||||
@@ -633,7 +644,18 @@ static node*
|
||||
new_until_mod(parser_state *p, node *a, node *b)
|
||||
{
|
||||
void_expr_error(p, a);
|
||||
return cons_head((node*)NODE_UNTIL_MOD, cons(a, b));
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_UNTIL_MOD, cons(a, b));
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_until_mod_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_until_mod_node *n = (struct mrb_ast_until_mod_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_UNTIL_MOD, class);
|
||||
n->condition = a;
|
||||
n->body = b;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:for var obj body) */
|
||||
@@ -1426,28 +1448,66 @@ new_return(parser_state *p, node *c)
|
||||
static node*
|
||||
new_break(parser_state *p, node *c)
|
||||
{
|
||||
return cons_head((node*)NODE_BREAK, c);
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_BREAK, c);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_break_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_break_node *n = (struct mrb_ast_break_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_BREAK, class);
|
||||
n->value = c;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:next . c) */
|
||||
static node*
|
||||
new_next(parser_state *p, node *c)
|
||||
{
|
||||
return cons_head((node*)NODE_NEXT, c);
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_NEXT, c);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_next_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_next_node *n = (struct mrb_ast_next_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_NEXT, class);
|
||||
n->value = c;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:redo) */
|
||||
static node*
|
||||
new_redo(parser_state *p)
|
||||
{
|
||||
return list1((node*)NODE_REDO);
|
||||
if (!p->var_nodes_enabled) {
|
||||
return list1((node*)NODE_REDO);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_redo_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_redo_node *n = (struct mrb_ast_redo_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_REDO, class);
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:retry) */
|
||||
static node*
|
||||
new_retry(parser_state *p)
|
||||
{
|
||||
return list1((node*)NODE_RETRY);
|
||||
if (!p->var_nodes_enabled) {
|
||||
return list1((node*)NODE_RETRY);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_retry_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_retry_node *n = (struct mrb_ast_retry_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_RETRY, class);
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:dot2 a b) */
|
||||
@@ -2203,21 +2263,51 @@ concat_string(parser_state *p, node *a, node *b)
|
||||
static node*
|
||||
new_xstr(parser_state *p, const char *s, int len)
|
||||
{
|
||||
return cons_head((node*)NODE_XSTR, cons((node*)strndup(s, len), int_to_node(len)));
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_XSTR, cons((node*)strndup(s, len), int_to_node(len)));
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_xstr_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_xstr_node *n = (struct mrb_ast_xstr_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_XSTR, class);
|
||||
n->name = mrb_intern(p->mrb, s, len);
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:xstr . a) */
|
||||
static node*
|
||||
new_dxstr(parser_state *p, node *a)
|
||||
{
|
||||
return cons_head((node*)NODE_DXSTR, a);
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_DXSTR, a);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_dxstr_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_dxstr_node *n = (struct mrb_ast_dxstr_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_DXSTR, class);
|
||||
n->list = a;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:dsym . a) */
|
||||
static node*
|
||||
new_dsym(parser_state *p, node *a)
|
||||
{
|
||||
return cons_head((node*)NODE_DSYM, a);
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_DSYM, a);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_dsym_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_dsym_node *n = (struct mrb_ast_dsym_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_DSYM, class);
|
||||
n->list = a;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:regx . (s . (opt . enc))) */
|
||||
@@ -2234,7 +2324,18 @@ new_regx(parser_state *p, const char *p1, const char* p2, const char* p3)
|
||||
static node*
|
||||
new_dregx(parser_state *p, node *a, node *b)
|
||||
{
|
||||
return cons_head((node*)NODE_DREGX, cons(a, b));
|
||||
if (!p->var_nodes_enabled) {
|
||||
return cons_head((node*)NODE_DREGX, cons(a, b));
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_dregx_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_dregx_node *n = (struct mrb_ast_dregx_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_DREGX, class);
|
||||
n->list = a;
|
||||
n->options = (int)(intptr_t)b;
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:backref . n) */
|
||||
@@ -2255,8 +2356,18 @@ new_nth_ref(parser_state *p, int n)
|
||||
static node*
|
||||
new_heredoc(parser_state *p)
|
||||
{
|
||||
parser_heredoc_info *inf = (parser_heredoc_info*)parser_palloc(p, sizeof(parser_heredoc_info));
|
||||
return cons_head((node*)NODE_HEREDOC, (node*)inf);
|
||||
if (!p->var_nodes_enabled) {
|
||||
parser_heredoc_info *inf = (parser_heredoc_info*)parser_palloc(p, sizeof(parser_heredoc_info));
|
||||
return cons_head((node*)NODE_HEREDOC, (node*)inf);
|
||||
}
|
||||
|
||||
size_t total_size = sizeof(struct mrb_ast_heredoc_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_heredoc_node *n = (struct mrb_ast_heredoc_node*)
|
||||
parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->hdr, p, NODE_HEREDOC, class);
|
||||
n->name = 0; // Will be set by heredoc processing
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+1514
-1403
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user