GitHub

@@ -4514,6 +4514,99 @@ codegen_pattern(codegen_scope *s, node *pattern, int target, uint32_t *fail_pos)

45144514

}

45154515

break;

451645164517+

case NODE_PAT_HASH:

4518+

{

4519+

struct mrb_ast_pat_hash_node *pat_hash = pat_hash_node(pattern);

4520+

int hash_reg = cursp();

4521+

node *pair;

4522+

int num_keys = 0;

4523+4524+

/* Count keys */

4525+

for (pair = pat_hash->pairs; pair; pair = pair->cdr) num_keys++;

4526+4527+

/* Build array of keys to pass to deconstruct_keys */

4528+

/* Generate: target.deconstruct_keys([key1, key2, ...]) */

4529+

gen_move(s, cursp(), target, 0);

4530+

push();

4531+

if (pat_hash->rest == (node*)-1) {

4532+

/* **nil: pass nil to deconstruct_keys (exact match) */

4533+

genop_1(s, OP_LOADNIL, cursp());

4534+

push();

4535+

}

4536+

else if (num_keys > 0) {

4537+

/* Build array of expected keys */

4538+

int i = 0;

4539+

for (pair = pat_hash->pairs; pair; pair = pair->cdr, i++) {

4540+

node *key = pair->car->car;

4541+

if (get_node_type(key) == NODE_SYM) {

4542+

genop_2(s, OP_LOADSYM, cursp(), new_sym(s, sym_node(key)->symbol));

4543+

}

4544+

else {

4545+

/* String or other key - codegen it */

4546+

codegen(s, key, VAL);

4547+

}

4548+

push();

4549+

}

4550+

genop_2(s, OP_ARRAY, cursp() - num_keys, num_keys);

4551+

/* Adjust stack: we pushed num_keys items, now just need 1 for array */

4552+

for (i = 1; i < num_keys; i++) pop();

4553+

}

4554+

else {

4555+

/* Empty hash pattern or ** only: pass empty array */

4556+

genop_2(s, OP_ARRAY, cursp(), 0);

4557+

push();

4558+

}

4559+

genop_3(s, OP_SEND, hash_reg, new_sym(s, MRB_SYM_2(s->mrb, deconstruct_keys)), 1);

4560+

pop(); /* Pop argument */

4561+

/* hash_reg now contains the deconstructed hash */

4562+4563+

/* Match each key-pattern pair */

4564+

for (pair = pat_hash->pairs; pair; pair = pair->cdr) {

4565+

node *key = pair->car->car;

4566+

node *pat = pair->car->cdr;

4567+4568+

/* Generate: hash[key] */

4569+

gen_move(s, cursp(), hash_reg, 0);

4570+

push();

4571+

if (get_node_type(key) == NODE_SYM) {

4572+

genop_2(s, OP_LOADSYM, cursp(), new_sym(s, sym_node(key)->symbol));

4573+

}

4574+

else {

4575+

codegen(s, key, VAL);

4576+

}

4577+

push(); push(); pop(); pop(); pop();

4578+

genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, aref)), 1);

4579+4580+

/* Match pattern against value */

4581+

codegen_pattern(s, pat, cursp(), fail_pos);

4582+

}

4583+4584+

/* Handle rest pattern */

4585+

if (pat_hash->rest == (node*)-1) {

4586+

/* **nil: verify no extra keys (already handled by deconstruct_keys returning nil for unknown keys) */

4587+

/* The exact match behavior depends on deconstruct_keys implementation */

4588+

}

4589+

else if (pat_hash->rest && pat_hash->rest != (node*)-2) {

4590+

/* **var: capture remaining keys into a variable */

4591+

/* This requires computing: hash.reject {|k,v| [key1, key2, ...].include?(k) } */

4592+

/* For now, this is a more complex operation - we'll implement basic support */

4593+

struct mrb_ast_pat_var_node *rest_var = pat_var_node(pat_hash->rest);

4594+

if (rest_var->name) {

4595+

int var_idx = lv_idx(s, rest_var->name);

4596+

/* Simplified: just copy the hash for now */

4597+

/* Full implementation would filter out matched keys */

4598+

gen_move(s, cursp(), hash_reg, 0);

4599+

if (var_idx > 0) {

4600+

gen_move(s, var_idx, cursp(), 1);

4601+

}

4602+

}

4603+

}

4604+

/* ** (anonymous rest) - nothing to capture */

4605+4606+

pop(); /* Pop hash_reg */

4607+

}

4608+

break;

4609+45174610

default:

45184611

raise_error(s, "unsupported pattern type");

45194612

break;

Read the original on github.com ↗