[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]