diff options
-rw-r--r-- | compile.c | 37 | ||||
-rw-r--r-- | parse.y | 40 |
2 files changed, 36 insertions, 41 deletions
@@ -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; } } @@ -14952,21 +14952,6 @@ dsym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc) } static int -append_literal_keys(st_data_t k, st_data_t v, st_data_t h) -{ - NODE *node = (NODE *)v; - NODE **result = (NODE **)h; - RNODE_LIST(node)->as.nd_alen = 2; - RNODE_LIST(RNODE_LIST(node)->nd_next)->as.nd_end = RNODE_LIST(node)->nd_next; - RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next = 0; - if (*result) - list_concat(*result, node); - else - *result = node; - return ST_CONTINUE; -} - -static int nd_type_st_key_enable_p(NODE *node) { switch (nd_type(node)) { @@ -15026,8 +15011,8 @@ nd_st_key_val(struct parser_params *p, NODE *node) } } -static NODE * -remove_duplicate_keys(struct parser_params *p, NODE *hash) +static void +warn_duplicate_keys(struct parser_params *p, NODE *hash) { struct st_hash_type literal_type = { literal_cmp, @@ -15035,50 +15020,31 @@ remove_duplicate_keys(struct parser_params *p, NODE *hash) }; st_table *literal_keys = st_init_table_with_size(&literal_type, RNODE_LIST(hash)->as.nd_alen / 2); - NODE *result = 0; - NODE *last_expr = 0; - rb_code_location_t loc = hash->nd_loc; while (hash && RNODE_LIST(hash)->nd_next) { NODE *head = RNODE_LIST(hash)->nd_head; NODE *value = RNODE_LIST(hash)->nd_next; NODE *next = RNODE_LIST(value)->nd_next; st_data_t key = (st_data_t)head; st_data_t data; - RNODE_LIST(value)->nd_next = 0; if (!head) { key = (st_data_t)value; } else if (nd_type_st_key_enable_p(head) && st_delete(literal_keys, (key = (st_data_t)nd_st_key(p, head), &key), &data)) { - NODE *dup_value = (RNODE_LIST((NODE *)data))->nd_next; rb_compile_warn(p->ruby_sourcefile, nd_line((NODE *)data), "key %+"PRIsVALUE" is duplicated and overwritten on line %d", nd_st_key_val(p, head), nd_line(head)); - if (dup_value == last_expr) { - RNODE_LIST(value)->nd_head = block_append(p, RNODE_LIST(dup_value)->nd_head, RNODE_LIST(value)->nd_head); - } - else { - RNODE_LIST(last_expr)->nd_head = block_append(p, RNODE_LIST(dup_value)->nd_head, RNODE_LIST(last_expr)->nd_head); - } } st_insert(literal_keys, (st_data_t)key, (st_data_t)hash); - last_expr = !head || nd_type_st_key_enable_p(head) ? value : head; hash = next; } - st_foreach(literal_keys, append_literal_keys, (st_data_t)&result); st_free_table(literal_keys); - if (hash) { - if (!result) result = hash; - else list_concat(result, hash); - } - result->nd_loc = loc; - return result; } static NODE * new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc) { - if (hash) hash = remove_duplicate_keys(p, hash); + if (hash) warn_duplicate_keys(p, hash); return NEW_HASH(hash, loc); } #endif |