summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authoryui-knk <[email protected]>2024-01-02 16:17:47 +0900
committerYuichiro Kaneko <[email protected]>2024-01-07 16:18:16 +0900
commit83c98ead4e889710916a367c146884c987576e8b (patch)
tree8eb7f6900e1e594c1e5c0bab290f2b3dcf1f31dc /compile.c
parent9d3dcb86d1c95ceb75089595145bbfbc32a5c77c (diff)
Do not remove hash duplicated keys in parse.y
When hash keys are duplicated, e.g. `h = {k: 1, l: 2, k: 3}`, parser changes node structure for correct compilation. This generates tricky AST. This commit removes AST manipulation from parser to keep AST structure simple.
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/compile.c b/compile.c
index 5bda334c6e..4fab2edb7d 100644
--- a/compile.c
+++ b/compile.c
@@ -4588,6 +4588,28 @@ keyword_node_p(const NODE *const node)
return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
}
+static VALUE
+node_hash_unique_key_index(rb_node_hash_t *node_hash, int *count_ptr)
+{
+ NODE *node = node_hash->nd_head;
+ VALUE hash = rb_hash_new();
+ VALUE ary = rb_ary_new();
+
+ for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ VALUE key = RNODE_LIT(RNODE_LIST(node)->nd_head)->nd_lit;
+ VALUE idx = rb_hash_aref(hash, key);
+ if (!NIL_P(idx)) {
+ rb_ary_store(ary, FIX2INT(idx), Qfalse);
+ (*count_ptr)--;
+ }
+ rb_hash_aset(hash, key, INT2FIX(i));
+ rb_ary_store(ary, i, Qtrue);
+ (*count_ptr)++;
+ }
+
+ return ary;
+}
+
static int
compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
const NODE *const root_node,
@@ -4630,11 +4652,13 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
/* may be keywords */
node = RNODE_HASH(root_node)->nd_head;
{
- int len = (int)RNODE_LIST(node)->as.nd_alen / 2;
+ int len = 0;
+ VALUE key_index = node_hash_unique_key_index(RNODE_HASH(root_node), &len);
struct rb_callinfo_kwarg *kw_arg =
rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
VALUE *keywords = kw_arg->keywords;
int i = 0;
+ int j = 0;
kw_arg->references = 0;
kw_arg->keyword_len = len;
@@ -4643,10 +4667,15 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
const NODE *key_node = RNODE_LIST(node)->nd_head;
const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
- keywords[i] = RNODE_LIT(key_node)->nd_lit;
- NO_CHECK(COMPILE(ret, "keyword values", val_node));
+ int popped = TRUE;
+ if (rb_ary_entry(key_index, i)) {
+ keywords[j] = RNODE_LIT(key_node)->nd_lit;
+ j++;
+ popped = FALSE;
+ }
+ NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
}
- assert(i == len);
+ assert(j == len);
return TRUE;
}
}