ruby-changes:35797
From: nobu <ko1@a...>
Date: Sat, 11 Oct 2014 13:47:28 +0900 (JST)
Subject: [ruby-changes:35797] nobu:r47879 (trunk): parse.y: remove duplicate keys
nobu 2014-10-11 13:47:06 +0900 (Sat, 11 Oct 2014) New Revision: 47879 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47879 Log: parse.y: remove duplicate keys * parse.y (remove_duplicate_keys): remove duplicate literal keys, i.e., symbols and strings. [ruby-core:65368] [Bug #10315] Modified files: trunk/ChangeLog trunk/parse.y Index: ChangeLog =================================================================== --- ChangeLog (revision 47878) +++ ChangeLog (revision 47879) @@ -1,4 +1,7 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 -Sat Oct 11 13:46:58 2014 Nobuyoshi Nakada <nobu@r...> +Sat Oct 11 13:47:13 2014 Nobuyoshi Nakada <nobu@r...> + + * parse.y (remove_duplicate_keys): remove duplicate literal keys, + i.e., symbols and strings. [ruby-core:65368] [Bug #10315] * vm.c (kwmerge_i): override existing keys by new keys. [ruby-core:65368] [Bug #10315] Index: parse.y =================================================================== --- parse.y (revision 47878) +++ parse.y (revision 47879) @@ -430,6 +430,9 @@ static NODE *new_attr_op_assign_gen(stru https://github.com/ruby/ruby/blob/trunk/parse.y#L430 static NODE *new_const_op_assign_gen(struct parser_params *parser, NODE *lhs, ID op, NODE *rhs); #define new_const_op_assign(lhs, op, rhs) new_const_op_assign_gen(parser, (lhs), (op), (rhs)) +static NODE *new_hash_gen(struct parser_params *parser, NODE *hash); +#define new_hash(hash) new_hash_gen(parser, (hash)) + #define new_defined(expr) NEW_DEFINED(remove_begin_all(expr)) static NODE *match_op_gen(struct parser_params*,NODE*,NODE*); @@ -2348,7 +2351,7 @@ aref_args : none https://github.com/ruby/ruby/blob/trunk/parse.y#L2351 | args ',' assocs trailer { /*%%%*/ - $$ = arg_append($1, NEW_HASH($3)); + $$ = arg_append($1, new_hash($3)); /*% $$ = arg_add_assocs($1, $3); %*/ @@ -2356,7 +2359,7 @@ aref_args : none https://github.com/ruby/ruby/blob/trunk/parse.y#L2359 | assocs trailer { /*%%%*/ - $$ = NEW_LIST(NEW_HASH($1)); + $$ = NEW_LIST(new_hash($1)); /*% $$ = arg_add_assocs(arg_new(), $1); %*/ @@ -2386,7 +2389,7 @@ opt_call_args : none https://github.com/ruby/ruby/blob/trunk/parse.y#L2389 | args ',' assocs ',' { /*%%%*/ - $$ = arg_append($1, NEW_HASH($3)); + $$ = arg_append($1, new_hash($3)); /*% $$ = arg_add_assocs($1, $3); %*/ @@ -2394,7 +2397,7 @@ opt_call_args : none https://github.com/ruby/ruby/blob/trunk/parse.y#L2397 | assocs ',' { /*%%%*/ - $$ = NEW_LIST(NEW_HASH($1)); + $$ = NEW_LIST(new_hash($1)); /*% $$ = arg_add_assocs(arg_new(), $1); %*/ @@ -2421,7 +2424,7 @@ call_args : command https://github.com/ruby/ruby/blob/trunk/parse.y#L2424 | assocs opt_block_arg { /*%%%*/ - $$ = NEW_LIST(NEW_HASH($1)); + $$ = NEW_LIST(new_hash($1)); $$ = arg_blk_pass($$, $2); /*% $$ = arg_add_assocs(arg_new(), $1); @@ -2431,7 +2434,7 @@ call_args : command https://github.com/ruby/ruby/blob/trunk/parse.y#L2434 | args ',' assocs opt_block_arg { /*%%%*/ - $$ = arg_append($1, NEW_HASH($3)); + $$ = arg_append($1, new_hash($3)); $$ = arg_blk_pass($$, $4); /*% $$ = arg_add_optblock(arg_add_assocs($1, $3), $4); @@ -2675,7 +2678,7 @@ primary : literal https://github.com/ruby/ruby/blob/trunk/parse.y#L2678 | tLBRACE assoc_list '}' { /*%%%*/ - $$ = NEW_HASH($2); + $$ = new_hash($2); /*% $$ = dispatch1(hash, escape_Qundef($2)); %*/ @@ -9592,6 +9595,60 @@ dsym_node_gen(struct parser_params *pars https://github.com/ruby/ruby/blob/trunk/parse.y#L9595 } return node; } + +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; + node->nd_alen = 2; + node->nd_next->nd_end = node->nd_next; + node->nd_next->nd_next = 0; + if (*result) + list_concat(*result, node); + else + *result = node; + return ST_CONTINUE; +} + +static NODE * +remove_duplicate_keys(struct parser_params *parser, NODE *hash) +{ + st_table *literal_keys = st_init_numtable_with_size(hash->nd_alen / 2); + NODE *result = 0; + while (hash && hash->nd_head && hash->nd_next) { + NODE *head = hash->nd_head; + VALUE key = 0; + st_data_t data; + if (nd_type(head) == NODE_LIT) { + key = head->nd_lit; + if (st_lookup(literal_keys, key, &data)) { + rb_compile_warn(ruby_sourcefile, nd_line((NODE *)data), + "duplicated key at line %d ignored: %+"PRIsVALUE, + nd_line(head), head->nd_lit); + } + } + else { + key = (VALUE)head; + } + st_insert(literal_keys, (st_data_t)key, (st_data_t)hash); + hash = hash->nd_next->nd_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); + } + return result; +} + +static NODE * +new_hash_gen(struct parser_params *parser, NODE *hash) +{ + if (hash) hash = remove_duplicate_keys(parser, hash); + return NEW_HASH(hash); +} #endif /* !RIPPER */ #ifndef RIPPER -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/