ruby-changes:35567
From: nobu <ko1@a...>
Date: Sat, 20 Sep 2014 10:48:56 +0900 (JST)
Subject: [ruby-changes:35567] nobu:r47649 (trunk): parse.y: quoted ID key
nobu 2014-09-20 10:48:43 +0900 (Sat, 20 Sep 2014) New Revision: 47649 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47649 Log: parse.y: quoted ID key * parse.y (assoc): allow quoted ID as a key of a hash literal. [ruby-core:34453] [Feature #4276] Modified files: trunk/ChangeLog trunk/ext/ripper/eventids2.c trunk/parse.y trunk/test/ripper/test_parser_events.rb trunk/test/ripper/test_scanner_events.rb trunk/test/ruby/test_hash.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 47648) +++ ChangeLog (revision 47649) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Sep 20 10:48:41 2014 Nobuyoshi Nakada <nobu@r...> + + * parse.y (assoc): allow quoted ID as a key of a hash literal. + [ruby-core:34453] [Feature #4276] + Sat Sep 20 10:23:00 2014 Nobuyoshi Nakada <nobu@r...> * compile.c (iseq_set_arguments): store local variable IDs in Index: parse.y =================================================================== --- parse.y (revision 47648) +++ parse.y (revision 47649) @@ -823,7 +823,7 @@ static void token_info_pop(struct parser https://github.com/ruby/ruby/blob/trunk/parse.y#L823 %token tAMPER "&" %token tLAMBDA "->" %token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG -%token tSTRING_DBEG tSTRING_DEND tSTRING_DVAR tSTRING_END tLAMBEG +%token tSTRING_DBEG tSTRING_DEND tSTRING_DVAR tSTRING_END tLAMBEG tLABEL_END /* * precedence table @@ -2305,14 +2305,24 @@ arg : lhs '=' arg https://github.com/ruby/ruby/blob/trunk/parse.y#L2305 $$ = dispatch1(defined, $4); %*/ } - | arg '?' arg opt_nl ':' arg + | arg '?' + { + $<val>$ = cond_stack; + cond_stack = 0; + COND_PUSH(1); + } + arg opt_nl ':' + { + cond_stack = $<val>3; + } + arg { /*%%%*/ value_expr($1); - $$ = NEW_IF(cond($1), $3, $6); + $$ = NEW_IF(cond($1), $4, $8); fixpos($$, $1); /*% - $$ = dispatch3(ifop, $1, $3, $6); + $$ = dispatch3(ifop, $1, $4, $8); %*/ } | primary @@ -4217,6 +4227,9 @@ string_content : tSTRING_CONTENT https://github.com/ruby/ruby/blob/trunk/parse.y#L4227 { $<node>$ = lex_strterm; lex_strterm = 0; + } + { + $<num>$ = lex_state; lex_state = EXPR_BEG; } { @@ -4228,12 +4241,13 @@ string_content : tSTRING_CONTENT https://github.com/ruby/ruby/blob/trunk/parse.y#L4241 cond_stack = $<val>1; cmdarg_stack = $<val>2; lex_strterm = $<node>3; - brace_nest = $<num>4; + lex_state = $<num>4; + brace_nest = $<num>5; /*%%%*/ - if ($5) $5->flags &= ~NODE_FL_NEWLINE; - $$ = new_evstr($5); + if ($6) $6->flags &= ~NODE_FL_NEWLINE; + $$ = new_evstr($6); /*% - $$ = dispatch1(string_embexpr, $5); + $$ = dispatch1(string_embexpr, $6); %*/ } ; @@ -4947,6 +4961,14 @@ assoc : arg_value tASSOC arg_value https://github.com/ruby/ruby/blob/trunk/parse.y#L4961 $$ = dispatch2(assoc_new, $1, $2); %*/ } + | tSTRING_BEG string_contents tLABEL_END arg_value + { + /*%%%*/ + $$ = list_append(NEW_LIST(dsym_node($2)), $4); + /*% + $$ = dispatch2(assoc_new, dispatch1(dyna_symbol, $2), $4); + %*/ + } | tDSTAR arg_value { /*%%%*/ @@ -7653,7 +7675,14 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7675 } else { token = parse_string(lex_strterm); - if (token == tSTRING_END || token == tREGEXP_END) { + if (token == tSTRING_END && (peek_n('\'', -1) || peek_n('"', -1))) { + if (((IS_lex_state(EXPR_BEG | EXPR_ENDFN) && !COND_P()) || IS_ARG()) && + IS_LABEL_SUFFIX(0)) { + nextc(); + token = tLABEL_END; + } + } + if (token == tSTRING_END || token == tREGEXP_END || token == tLABEL_END) { rb_gc_force_recycle((VALUE)lex_strterm); lex_strterm = 0; lex_state = EXPR_END; Index: ext/ripper/eventids2.c =================================================================== --- ext/ripper/eventids2.c (revision 47648) +++ ext/ripper/eventids2.c (revision 47649) @@ -46,6 +46,7 @@ static ID ripper_id_rational; https://github.com/ruby/ruby/blob/trunk/ext/ripper/eventids2.c#L46 static ID ripper_id_regexp_beg; static ID ripper_id_regexp_end; static ID ripper_id_label; +static ID ripper_id_label_end; static ID ripper_id_tlambda; static ID ripper_id_tlambeg; @@ -103,6 +104,7 @@ ripper_init_eventids2(void) https://github.com/ruby/ruby/blob/trunk/ext/ripper/eventids2.c#L104 ripper_id_regexp_beg = rb_intern_const("on_regexp_beg"); ripper_id_regexp_end = rb_intern_const("on_regexp_end"); ripper_id_label = rb_intern_const("on_label"); + ripper_id_label_end = rb_intern_const("on_label_end"); ripper_id_tlambda = rb_intern_const("on_tlambda"); ripper_id_tlambeg = rb_intern_const("on_tlambeg"); @@ -259,6 +261,7 @@ static const struct token_assoc { https://github.com/ruby/ruby/blob/trunk/ext/ripper/eventids2.c#L261 {tWORDS_BEG, &ripper_id_words_beg}, {tXSTRING_BEG, &ripper_id_backtick}, {tLABEL, &ripper_id_label}, + {tLABEL_END, &ripper_id_label_end}, {tLAMBDA, &ripper_id_tlambda}, {tLAMBEG, &ripper_id_tlambeg}, Index: test/ruby/test_hash.rb =================================================================== --- test/ruby/test_hash.rb (revision 47648) +++ test/ruby/test_hash.rb (revision 47649) @@ -1269,6 +1269,17 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1269 assert_equal(bug9381, hash[wrapper.new(5)]) end + def test_label_syntax + return unless @cls == Hash + + feature4935 = '[ruby-core:37553] [Feature #4935]' + x = 'world' + hash = assert_nothing_raised(SyntaxError) do + break eval(%q({foo: 1, "foo-bar": 2, "hello-#{x}": 3, 'hello-#{x}': 4})) + end + assert_equal({:foo => 1, :'foo-bar' => 2, :'hello-world' => 3, :'hello-#{x}' => 4}, hash) + end + class TestSubHash < TestHash class SubHash < Hash def reject(*) Index: test/ripper/test_parser_events.rb =================================================================== --- test/ripper/test_parser_events.rb (revision 47648) +++ test/ripper/test_parser_events.rb (revision 47649) @@ -548,6 +548,10 @@ class TestRipper::ParserEvents < Test::U https://github.com/ruby/ruby/blob/trunk/test/ripper/test_parser_events.rb#L548 thru_dyna_symbol = false parse(':"#{foo}"', :on_dyna_symbol) {thru_dyna_symbol = true} assert_equal true, thru_dyna_symbol + + thru_dyna_symbol = false + parse('{"#{foo}": 1}', :on_dyna_symbol) {thru_dyna_symbol = true} + assert_equal true, thru_dyna_symbol end def test_else Index: test/ripper/test_scanner_events.rb =================================================================== --- test/ripper/test_scanner_events.rb (revision 47648) +++ test/ripper/test_scanner_events.rb (revision 47649) @@ -878,6 +878,11 @@ class TestRipper::ScannerEvents < Test:: https://github.com/ruby/ruby/blob/trunk/test/ripper/test_scanner_events.rb#L878 scan('label', '{foo: 1}') end + def test_label_end + assert_equal %w(":), + scan('label_end', '{"foo-bar": 1}') + end + def test_tlambda assert_equal %w(->), scan('tlambda', '->{}') -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/