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

ruby-changes:39536

From: nobu <ko1@a...>
Date: Mon, 17 Aug 2015 20:57:39 +0900 (JST)
Subject: [ruby-changes:39536] nobu:r51617 (trunk): parse.y: fix block after conditional

nobu	2015-08-17 20:56:55 +0900 (Mon, 17 Aug 2015)

  New Revision: 51617

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51617

  Log:
    parse.y: fix block after conditional
    
    * parse.y: fix syntax error at do-block after a conditional
      operator.  separate label-allowed and after-a-label states from
      others as bit flags.  [ruby-dev:48790] [Bug #10653]

  Modified files:
    trunk/ChangeLog
    trunk/parse.y
    trunk/test/ruby/test_syntax.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 51616)
+++ ChangeLog	(revision 51617)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Mon Aug 17 20:56:36 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* parse.y: fix syntax error at do-block after a conditional
+	  operator.  separate label-allowed and after-a-label states from
+	  others as bit flags.  [ruby-dev:48790] [Bug #10653]
+
 Mon Aug 17 11:57:36 2015  Nobuyoshi Nakada  <nobu@r...>
 
 	* io.c (rb_io_each_codepoint): raise an exception at incomplete
Index: parse.y
===================================================================
--- parse.y	(revision 51616)
+++ parse.y	(revision 51617)
@@ -62,8 +62,8 @@ enum lex_state_bits { https://github.com/ruby/ruby/blob/trunk/parse.y#L62
     EXPR_FNAME_bit,		/* ignore newline, no reserved words. */
     EXPR_DOT_bit,		/* right after `.' or `::', no reserved words. */
     EXPR_CLASS_bit,		/* immediate after `class', no here document. */
-    EXPR_VALUE_bit,		/* alike EXPR_BEG but label is disallowed. */
-    EXPR_LABELARG_bit,		/* ignore significant, +/- is a sign. */
+    EXPR_LABEL_bit,		/* flag bit, label is allowed. */
+    EXPR_LABELED_bit,		/* flag bit, just after a label. */
     EXPR_MAX_STATE
 };
 /* examine combinations */
@@ -79,14 +79,17 @@ enum lex_state_e { https://github.com/ruby/ruby/blob/trunk/parse.y#L79
     DEF_EXPR(FNAME),
     DEF_EXPR(DOT),
     DEF_EXPR(CLASS),
-    DEF_EXPR(VALUE),
-    DEF_EXPR(LABELARG),
-    EXPR_BEG_ANY  =  (EXPR_BEG | EXPR_VALUE | EXPR_MID | EXPR_CLASS | EXPR_LABELARG),
+    DEF_EXPR(LABEL),
+    DEF_EXPR(LABELED),
+    EXPR_VALUE = EXPR_BEG,
+    EXPR_BEG_ANY  =  (EXPR_BEG | EXPR_MID | EXPR_CLASS),
     EXPR_ARG_ANY  =  (EXPR_ARG | EXPR_CMDARG),
     EXPR_END_ANY  =  (EXPR_END | EXPR_ENDARG | EXPR_ENDFN)
 };
 #define IS_lex_state_for(x, ls)	((x) & (ls))
+#define IS_lex_state_all_for(x, ls) (((x) & (ls)) == (ls))
 #define IS_lex_state(ls)	IS_lex_state_for(lex_state, (ls))
+#define IS_lex_state_all(ls)	IS_lex_state_all_for(lex_state, (ls))
 
 #if PARSER_DEBUG
 static const char *lex_state_name(enum lex_state_e state);
@@ -3016,7 +3019,7 @@ primary		: literal https://github.com/ruby/ruby/blob/trunk/parse.y#L3019
 		    {
 			$<num>4 = in_single;
 			in_single = 1;
-			lex_state = EXPR_ENDFN; /* force for args */
+			lex_state = EXPR_ENDFN|EXPR_LABEL; /* force for args */
 			local_push(0);
 			$<id>$ = current_arg;
 			current_arg = 0;
@@ -4487,6 +4490,7 @@ f_arglist	: '(' f_args rparen https://github.com/ruby/ruby/blob/trunk/parse.y#L4490
 		|   {
 			$<num>$ = parser->in_kwarg;
 			parser->in_kwarg = 1;
+			lex_state |= EXPR_LABEL; /* force for args */
 		    }
 		    f_args term
 		    {
@@ -5670,6 +5674,7 @@ rb_parser_compile_file_path(VALUE vparse https://github.com/ruby/ruby/blob/trunk/parse.y#L5674
 #define STR_FUNC_LABEL  0x40
 
 enum string_type {
+    str_label  = STR_FUNC_LABEL,
     str_squote = (0),
     str_dquote = (STR_FUNC_EXPAND),
     str_xquote = (STR_FUNC_EXPAND),
@@ -7105,7 +7110,9 @@ parser_prepare(struct parser_params *par https://github.com/ruby/ruby/blob/trunk/parse.y#L7110
 #define IS_END() IS_lex_state(EXPR_END_ANY)
 #define IS_BEG() IS_lex_state(EXPR_BEG_ANY)
 #define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c))
-#define IS_LABEL_POSSIBLE() ((IS_lex_state(EXPR_BEG | EXPR_ENDFN) && !cmd_state) || IS_ARG())
+#define IS_LABEL_POSSIBLE() (\
+	(IS_lex_state(EXPR_LABEL|EXPR_ENDFN) && !cmd_state) || \
+	IS_ARG())
 #define IS_LABEL_SUFFIX(n) (peek_n(':',(n)) && !peek_n(':', (n)+1))
 #define IS_AFTER_OPERATOR() IS_lex_state(EXPR_FNAME | EXPR_DOT)
 
@@ -7781,7 +7788,7 @@ parse_ident(struct parser_params *parser https://github.com/ruby/ruby/blob/trunk/parse.y#L7788
 
     if (IS_LABEL_POSSIBLE()) {
 	if (IS_LABEL_SUFFIX(0)) {
-	    lex_state = EXPR_LABELARG;
+	    lex_state = EXPR_ARG|EXPR_LABELED;
 	    nextc();
 	    set_yylval_name(TOK_INTERN());
 	    return tLABEL;
@@ -7815,11 +7822,11 @@ parse_ident(struct parser_params *parser https://github.com/ruby/ruby/blob/trunk/parse.y#L7822
 		    return keyword_do_block;
 		return keyword_do;
 	    }
-	    if (IS_lex_state_for(state, (EXPR_BEG | EXPR_VALUE | EXPR_LABELARG)))
+	    if (IS_lex_state_for(state, (EXPR_BEG | EXPR_LABELED)))
 		return kw->id[0];
 	    else {
 		if (kw->id[0] != kw->id[1])
-		    lex_state = EXPR_BEG;
+		    lex_state = EXPR_BEG | EXPR_LABEL;
 		return kw->id[1];
 	    }
 	}
@@ -7850,6 +7857,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7857
     register int c;
     int space_seen = 0;
     int cmd_state;
+    int label;
     enum lex_state_e last_state;
 #ifdef RIPPER
     int fallthru = FALSE;
@@ -7876,7 +7884,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7884
 	    if (token == tSTRING_END || token == tREGEXP_END || token == tLABEL_END) {
 		rb_gc_force_recycle((VALUE)lex_strterm);
 		lex_strterm = 0;
-		lex_state = token == tLABEL_END ? EXPR_LABELARG : EXPR_END;
+		lex_state = token == tLABEL_END ? EXPR_BEG|EXPR_LABEL : EXPR_END;
 	    }
 	}
 	return token;
@@ -7926,14 +7934,16 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7934
 #endif
 	/* fall through */
       case '\n':
-	if (IS_lex_state(EXPR_BEG | EXPR_VALUE | EXPR_CLASS | EXPR_FNAME | EXPR_DOT | EXPR_LABELARG)) {
+	c = (IS_lex_state(EXPR_BEG|EXPR_CLASS|EXPR_FNAME|EXPR_DOT) &&
+	     !IS_lex_state(EXPR_LABELED));
+	if (c || IS_lex_state_all(EXPR_ARG|EXPR_LABELED)) {
 #ifdef RIPPER
             if (!fallthru) {
                 ripper_dispatch_scan_event(parser, tIGNORED_NL);
             }
             fallthru = FALSE;
 #endif
-	    if (IS_lex_state(EXPR_LABELARG) && parser->in_kwarg) {
+	    if (!c && parser->in_kwarg) {
 		goto normal_newline;
 	    }
 	    goto retry;
@@ -8147,7 +8157,8 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8157
 	return '>';
 
       case '"':
-	lex_strterm = NEW_STRTERM(str_dquote|STR_FUNC_LABEL, '"', 0);
+	label = (IS_LABEL_POSSIBLE() ? str_label : 0);
+	lex_strterm = NEW_STRTERM(str_dquote | label, '"', 0);
 	return tSTRING_BEG;
 
       case '`':
@@ -8166,7 +8177,8 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8177
 	return tXSTRING_BEG;
 
       case '\'':
-	lex_strterm = NEW_STRTERM(str_squote|STR_FUNC_LABEL, '\'', 0);
+	label = (IS_LABEL_POSSIBLE() ? str_label : 0);
+	lex_strterm = NEW_STRTERM(str_squote | label, '\'', 0);
 	return tSTRING_BEG;
 
       case '?':
@@ -8219,7 +8231,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8231
 	    lex_state = EXPR_BEG;
 	    return tOP_ASGN;
 	}
-	lex_state = IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG;
+	lex_state = IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL;
 	pushback(c);
 	return '|';
 
@@ -8384,7 +8396,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8396
 	return ';';
 
       case ',':
-	lex_state = EXPR_BEG;
+	lex_state = EXPR_BEG|EXPR_LABEL;
 	return ',';
 
       case '~':
@@ -8409,7 +8421,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8421
 	paren_nest++;
 	COND_PUSH(0);
 	CMDARG_PUSH(0);
-	lex_state = EXPR_BEG;
+	lex_state = EXPR_BEG|EXPR_LABEL;
 	return c;
 
       case '[':
@@ -8424,15 +8436,16 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8436
 		return tAREF;
 	    }
 	    pushback(c);
+	    lex_state |= EXPR_LABEL;
 	    return '[';
 	}
 	else if (IS_BEG()) {
 	    c = tLBRACK;
 	}
-	else if (IS_ARG() && space_seen) {
+	else if (IS_ARG() && (space_seen || IS_lex_state(EXPR_LABELED))) {
 	    c = tLBRACK;
 	}
-	lex_state = EXPR_BEG;
+	lex_state = EXPR_BEG|EXPR_LABEL;
 	COND_PUSH(0);
 	CMDARG_PUSH(0);
 	return c;
@@ -8447,7 +8460,9 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8460
 	    CMDARG_PUSH(0);
 	    return tLAMBEG;
 	}
-	if (IS_ARG() || IS_lex_state(EXPR_END | EXPR_ENDFN))
+	if (IS_lex_state(EXPR_LABELED))
+	    c = tLBRACE;      /* hash */
+	else if (IS_lex_state(EXPR_ARG_ANY | EXPR_END | EXPR_ENDFN))
 	    c = '{';          /* block (primary) */
 	else if (IS_lex_state(EXPR_ENDARG))
 	    c = tLBRACE_ARG;  /* block (expr) */
@@ -8456,6 +8471,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L8471
 	COND_PUSH(0);
 	CMDARG_PUSH(0);
 	lex_state = EXPR_BEG;
+	if (c != tLBRACE_ARG) lex_state |= EXPR_LABEL;
 	if (c != tLBRACE) command_start = TRUE;
 	return c;
 
@@ -8942,7 +8958,6 @@ lex_state_name(enum lex_state_e state) https://github.com/ruby/ruby/blob/trunk/parse.y#L8958
     static const char names[][12] = {
 	"EXPR_BEG",    "EXPR_END",    "EXPR_ENDARG", "EXPR_ENDFN",  "EXPR_ARG",
 	"EXPR_CMDARG", "EXPR_MID",    "EXPR_FNAME",  "EXPR_DOT",    "EXPR_CLASS",
-	"EXPR_VALUE",
     };
 
     if ((unsigned)state & ~(~0u << EXPR_MAX_STATE))
Index: test/ruby/test_syntax.rb
===================================================================
--- test/ruby/test_syntax.rb	(revision 51616)
+++ test/ruby/test_syntax.rb	(revision 51617)
@@ -304,6 +304,12 @@ WARN https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L304
     assert_syntax_error("{%q'a': 1}", /unexpected ':'/)
   end
 
+  def test_block_after_cond
+    bug10653 = '[ruby-dev:48790] [Bug #10653]'
+    assert_valid_syntax("false ? raise {} : tap {}", bug10653)
+    assert_valid_syntax("false ? raise do end : tap do end", bug10653)
+  end
+
   def test_duplicated_arg
     assert_syntax_error("def foo(a, a) end", /duplicated argument name/)
     assert_nothing_raised { def foo(_, _) end }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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