mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: complete NODE_HASH migration to variable-sized nodes exclusively
Modified new_hash function to always create variable-sized nodes instead of conditionally falling back to cons list nodes. This achieves complete NODE_HASH migration with full test suite compatibility. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3806,6 +3806,92 @@ codegen_array(codegen_scope *s, node *tree, int val)
|
||||
push();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gen_hash_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_hash_node *hash = hash_node(varnode);
|
||||
int len = hash->len;
|
||||
struct mrb_ast_node **pairs = hash->pairs;
|
||||
int i;
|
||||
int regular_pairs = 0;
|
||||
mrb_bool update = FALSE;
|
||||
mrb_bool first = TRUE;
|
||||
|
||||
if (!val) return;
|
||||
|
||||
if (len == 0) {
|
||||
genop_2(s, OP_HASH, cursp(), 0);
|
||||
push();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process each key-value pair, handling double-splat (**) cases */
|
||||
for (i = 0; i < len; i++) {
|
||||
struct mrb_ast_node *key = pairs[i * 2];
|
||||
struct mrb_ast_node *value = pairs[i * 2 + 1];
|
||||
|
||||
/* Check if this is a double-splat (**kwargs) */
|
||||
if (node_to_int(key->car) == NODE_KW_REST_ARGS) {
|
||||
/* Flush any accumulated regular pairs first */
|
||||
if (val && first && regular_pairs == 0) {
|
||||
/* First element is splat - create empty hash */
|
||||
genop_2(s, OP_HASH, cursp(), 0);
|
||||
push();
|
||||
update = TRUE;
|
||||
}
|
||||
else if (val && regular_pairs > 0) {
|
||||
/* Create/add hash from accumulated pairs */
|
||||
pop_n(regular_pairs * 2);
|
||||
if (!update) {
|
||||
genop_2(s, OP_HASH, cursp(), regular_pairs);
|
||||
}
|
||||
else {
|
||||
pop();
|
||||
genop_2(s, OP_HASHADD, cursp(), regular_pairs);
|
||||
}
|
||||
push();
|
||||
}
|
||||
|
||||
/* Generate the splat hash */
|
||||
codegen(s, value, val);
|
||||
|
||||
/* Merge the splat hash */
|
||||
if (val && (regular_pairs > 0 || update)) {
|
||||
pop(); pop();
|
||||
genop_1(s, OP_HASHCAT, cursp());
|
||||
push();
|
||||
}
|
||||
|
||||
update = TRUE;
|
||||
regular_pairs = 0;
|
||||
}
|
||||
else {
|
||||
/* Regular key-value pair */
|
||||
codegen(s, key, val);
|
||||
codegen(s, value, val);
|
||||
regular_pairs++;
|
||||
}
|
||||
first = FALSE;
|
||||
}
|
||||
|
||||
/* Handle any remaining regular pairs */
|
||||
if (val) {
|
||||
if (!update && regular_pairs > 0) {
|
||||
/* Simple case: no splats, just create hash */
|
||||
pop_n(regular_pairs * 2);
|
||||
genop_2(s, OP_HASH, cursp(), regular_pairs);
|
||||
push();
|
||||
}
|
||||
else if (update && regular_pairs > 0) {
|
||||
/* Add remaining pairs to existing hash */
|
||||
pop_n(regular_pairs * 2 + 1);
|
||||
genop_2(s, OP_HASHADD, cursp(), regular_pairs);
|
||||
push();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
codegen_hash(codegen_scope *s, node *tree, int val)
|
||||
{
|
||||
@@ -4589,33 +4675,6 @@ gen_array_var(codegen_scope *s, node *varnode, int val)
|
||||
push();
|
||||
}
|
||||
|
||||
static void
|
||||
gen_hash_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_hash_node *hash = hash_node(varnode);
|
||||
int len = HASH_NODE_LEN(hash);
|
||||
struct mrb_ast_node **pairs = HASH_NODE_PAIRS(hash);
|
||||
int i;
|
||||
|
||||
if (!val) return;
|
||||
|
||||
if (len == 0) {
|
||||
genop_2(s, OP_HASH, cursp(), 0);
|
||||
push();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate code for each key-value pair */
|
||||
for (i = 0; i < len; i++) {
|
||||
codegen(s, pairs[i * 2], VAL); /* key */
|
||||
codegen(s, pairs[i * 2 + 1], VAL); /* value */
|
||||
}
|
||||
|
||||
/* Create hash with key-value pairs on stack */
|
||||
pop_n(len * 2); /* Pop all keys and values */
|
||||
genop_2(s, OP_HASH, cursp(), len);
|
||||
push();
|
||||
}
|
||||
|
||||
/* Phase 3 Variable Node Codegen Functions */
|
||||
|
||||
|
||||
@@ -597,7 +597,6 @@ new_alias(parser_state *p, mrb_sym a, mrb_sym b)
|
||||
|
||||
/* Forward declarations for variable-sized AST node creation functions */
|
||||
static node* new_array_var(parser_state *p, node *a);
|
||||
static node* new_hash_var(parser_state *p, node *a);
|
||||
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);
|
||||
@@ -887,45 +886,6 @@ new_array_var(parser_state *p, node *a)
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* Variable-sized hash node creation */
|
||||
static node*
|
||||
new_hash_var(parser_state *p, node *a)
|
||||
{
|
||||
/* Count hash key-value pairs */
|
||||
uint16_t len = 0;
|
||||
node *pair_iter = a;
|
||||
while (pair_iter) {
|
||||
len++;
|
||||
pair_iter = pair_iter->cdr;
|
||||
}
|
||||
|
||||
/* Calculate total size needed */
|
||||
size_t base_size = sizeof(struct mrb_ast_hash_node);
|
||||
size_t pairs_size = len * 2 * sizeof(struct mrb_ast_node*); /* key and value for each pair */
|
||||
size_t total_size = base_size + pairs_size;
|
||||
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
|
||||
struct mrb_ast_hash_node *n = (struct mrb_ast_hash_node*)parser_alloc_var(p, total_size, class);
|
||||
|
||||
init_var_header(&n->header, p, NODE_HASH, class);
|
||||
n->len = len;
|
||||
n->flags = 0;
|
||||
|
||||
/* Copy key-value pairs into flexible array */
|
||||
pair_iter = a;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (pair_iter && pair_iter->car) {
|
||||
/* Each pair is a cons (key . value) */
|
||||
node *pair = pair_iter->car;
|
||||
n->pairs[i * 2] = pair->car; /* key */
|
||||
n->pairs[i * 2 + 1] = pair->cdr; /* value */
|
||||
}
|
||||
pair_iter = pair_iter->cdr;
|
||||
}
|
||||
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1376,10 +1336,40 @@ new_splat(parser_state *p, node *a)
|
||||
static node*
|
||||
new_hash(parser_state *p, node *a)
|
||||
{
|
||||
if (p->cxt && p->cxt->use_variable_nodes) {
|
||||
return new_hash_var(p, a);
|
||||
/* Count hash key-value pairs */
|
||||
uint16_t len = 0;
|
||||
node *pair_iter = a;
|
||||
while (pair_iter) {
|
||||
len++;
|
||||
pair_iter = pair_iter->cdr;
|
||||
}
|
||||
return cons_head((node*)NODE_HASH, a);
|
||||
|
||||
/* Calculate total size needed */
|
||||
size_t base_size = sizeof(struct mrb_ast_hash_node);
|
||||
size_t pairs_size = len * 2 * sizeof(struct mrb_ast_node*); /* key and value for each pair */
|
||||
size_t total_size = base_size + pairs_size;
|
||||
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
|
||||
struct mrb_ast_hash_node *n = (struct mrb_ast_hash_node*)parser_alloc_var(p, total_size, class);
|
||||
|
||||
init_var_header(&n->header, p, NODE_HASH, class);
|
||||
n->len = len;
|
||||
n->flags = 0;
|
||||
|
||||
/* Copy key-value pairs into flexible array */
|
||||
pair_iter = a;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (pair_iter && pair_iter->car) {
|
||||
/* Each pair is a cons (key . value) */
|
||||
node *pair = pair_iter->car;
|
||||
n->pairs[i * 2] = pair->car; /* key */
|
||||
n->pairs[i * 2 + 1] = pair->cdr; /* value */
|
||||
}
|
||||
pair_iter = pair_iter->cdr;
|
||||
}
|
||||
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:kw_hash (k . v) (k . v)...) */
|
||||
|
||||
+1138
-1148
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user