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

ruby-changes:58841

From: Nobuyoshi <ko1@a...>
Date: Tue, 19 Nov 2019 17:23:05 +0900 (JST)
Subject: [ruby-changes:58841] 0b8c73aa65 (master): [ripper] Quoted label without expression must be a local variable

https://git.ruby-lang.org/ruby.git/commit/?id=0b8c73aa65

From 0b8c73aa65add5c57b46b0cfdf4e661508802172 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Tue, 19 Nov 2019 17:17:00 +0900
Subject: [ripper] Quoted label without expression must be a local variable


diff --git a/parse.y b/parse.y
index 9277897..8e02adf 100644
--- a/parse.y
+++ b/parse.y
@@ -497,17 +497,18 @@ static NODE *heredoc_dedent(struct parser_params*,NODE*); https://github.com/ruby/ruby/blob/trunk/parse.y#L497
 
 static void check_literal_when(struct parser_params *p, NODE *args, const YYLTYPE *loc);
 
-static void error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc);
-
 #define get_id(id) (id)
 #define get_value(val) (val)
 #define get_num(num) (num)
 #else  /* RIPPER */
 #define NODE_RIPPER NODE_CDECL
 
+static inline int ripper_is_node_yylval(VALUE n);
+
 static inline VALUE
 ripper_new_yylval(struct parser_params *p, ID a, VALUE b, VALUE c)
 {
+    if (ripper_is_node_yylval(c)) c = RNODE(c)->nd_cval;
     add_mark_object(p, b);
     add_mark_object(p, c);
     return (VALUE)NEW_CDECL(a, b, c, &NULL_LOC);
@@ -566,6 +567,7 @@ YYLTYPE *rb_parser_set_location_of_none(struct parser_params *p, YYLTYPE *yylloc https://github.com/ruby/ruby/blob/trunk/parse.y#L567
 YYLTYPE *rb_parser_set_location(struct parser_params *p, YYLTYPE *yylloc);
 RUBY_SYMBOL_EXPORT_END
 
+static void error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc);
 static void parser_token_value_print(struct parser_params *p, enum yytokentype type, const YYSTYPE *valp);
 static ID formal_argument(struct parser_params*, ID);
 static ID shadowing_lvar(struct parser_params*,ID);
@@ -1080,7 +1082,7 @@ static int looking_at_eol_p(struct parser_params *p); https://github.com/ruby/ruby/blob/trunk/parse.y#L1082
 %type <id>   keyword_variable user_variable sym operation operation2 operation3
 %type <id>   cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
 %type <id>   f_kwrest f_label f_arg_asgn call_op call_op2 reswords relop dot_or_colon
-%type <id>   p_kwrest p_kwnorest
+%type <id>   p_kwrest p_kwnorest p_kw_label
 %type <id>   f_no_kwarg args_forward
 %token END_OF_INPUT 0	"end-of-input"
 %token <id> '.'
@@ -4080,59 +4082,47 @@ p_kwarg 	: p_kw https://github.com/ruby/ruby/blob/trunk/parse.y#L4082
 		    }
 		;
 
-p_kw		: tLABEL p_expr
+p_kw		: p_kw_label p_expr
 		    {
 		    /*%%%*/
 			$$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), $2);
 		    /*% %*/
 		    /*% ripper: rb_ary_new_from_args(1, rb_ary_new_from_args(2, get_value($1), get_value($2))) %*/
 		    }
-		| tLABEL
+		| p_kw_label
 		    {
-			if (!is_local_id(get_id($1))) {
+			if ($1 && !is_local_id(get_id($1))) {
 			    yyerror1(&@1, "key must be valid as local variables");
 			}
+			error_duplicate_pattern_variable(p, get_id($1), &@1);
 		    /*%%%*/
-			error_duplicate_pattern_variable(p, $1, &@1);
 			$$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), assignable(p, $1, 0, &@$));
 		    /*% %*/
 		    /*% ripper: rb_ary_new_from_args(1, rb_ary_new_from_args(2, get_value($1), Qnil)) %*/
 		    }
-		| tSTRING_BEG string_contents tLABEL_END p_expr
-		    {
-		    /*%%%*/
-			YYLTYPE loc = code_loc_gen(&@1, &@3);
-			NODE *node = dsym_node(p, $2, &loc);
-			if (nd_type(node) == NODE_LIT) {
-			    $$ = list_append(p, NEW_LIST(node, &loc), $4);
-			}
-			else {
-			    yyerror1(&loc, "symbol literal with interpolation is not allowed");
-			    $$ = 0;
-			}
-		    /*% %*/
-		    /*% ripper: rb_ary_new_from_args(1, rb_ary_new_from_args(2, $2, get_value($4))) %*/
-		    }
+		;
+
+p_kw_label	: tLABEL
 		| tSTRING_BEG string_contents tLABEL_END
 		    {
-		    /*%%%*/
 			YYLTYPE loc = code_loc_gen(&@1, &@3);
-			NODE *node = dsym_node(p, $2, &loc);
-			ID id;
-			if (nd_type(node) == NODE_LIT) {
-			    id = SYM2ID(node->nd_lit);
-			    if (!is_local_id(id)) {
-				yyerror1(&loc, "key must be valid as local variables");
-			    }
-			    error_duplicate_pattern_variable(p, id, &loc);
-			    $$ = list_append(p, NEW_LIST(node, &loc), assignable(p, id, 0, &@$));
+		    /*%%%*/
+			if (!$2 || nd_type($2) == NODE_STR) {
+			    NODE *node = dsym_node(p, $2, &loc);
+			    $$ = SYM2ID(node->nd_lit);
 			}
+		    /*%
+			if (ripper_is_node_yylval($2) && RNODE($2)->nd_cval) {
+			    VALUE label = RNODE($2)->nd_cval;
+			    VALUE rval = RNODE($2)->nd_rval;
+			    $$ = ripper_new_yylval(p, rb_intern_str(label), rval, label);
+			    RNODE($$)->nd_loc = loc;
+			}
+		    %*/
 			else {
 			    yyerror1(&loc, "symbol literal with interpolation is not allowed");
 			    $$ = 0;
 			}
-		    /*% %*/
-		    /*% ripper: rb_ary_new_from_args(1, rb_ary_new_from_args(2, $2, Qnil)) %*/
 		    }
 		;
 
@@ -4521,6 +4511,10 @@ string_contents : /* none */ https://github.com/ruby/ruby/blob/trunk/parse.y#L4511
 			$$ = 0;
 		    /*% %*/
 		    /*% ripper: string_content! %*/
+		    /*%%%*/
+		    /*%
+			$$ = ripper_new_yylval(p, 0, $$, 0);
+		    %*/
 		    }
 		| string_contents string_content
 		    {
@@ -4528,6 +4522,15 @@ string_contents : /* none */ https://github.com/ruby/ruby/blob/trunk/parse.y#L4522
 			$$ = literal_concat(p, $1, $2, &@$);
 		    /*% %*/
 		    /*% ripper: string_add!($1, $2) %*/
+		    /*%%%*/
+		    /*%
+			if (ripper_is_node_yylval($1) && ripper_is_node_yylval($2) &&
+			    !RNODE($1)->nd_cval) {
+			    RNODE($1)->nd_cval = RNODE($2)->nd_cval;
+			    RNODE($1)->nd_rval = $$;
+			    $$ = $1;
+			}
+		    %*/
 		    }
 		;
 
@@ -4600,6 +4603,7 @@ regexp_contents: /* none */ https://github.com/ruby/ruby/blob/trunk/parse.y#L4603
 		;
 
 string_content	: tSTRING_CONTENT
+		    /*% ripper[brace]: ripper_new_yylval(p, 0, get_value($1), $1) %*/
 		| tSTRING_DVAR
 		    {
 			/* need to backup p->lex.strterm so that a string literal `%&foo,#$&,bar&` can be parsed */
@@ -5753,8 +5757,21 @@ ruby_show_error_line(VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str) https://github.com/ruby/ruby/blob/trunk/parse.y#L5757
 static int
 parser_yyerror(struct parser_params *p, const YYLTYPE *yylloc, const char *msg)
 {
+    const char *pcur = 0, *ptok = 0;
+    if (yylloc &&
+	p->ruby_sourceline == yylloc->beg_pos.lineno &&
+	p->ruby_sourceline == yylloc->end_pos.lineno) {
+	pcur = p->lex.pcur;
+	ptok = p->lex.ptok;
+	p->lex.ptok = p->lex.pbeg + yylloc->beg_pos.column;
+	p->lex.pcur = p->lex.pbeg + yylloc->end_pos.column;
+    }
     dispatch1(parse_error, STR_NEW2(msg));
     ripper_error(p);
+    if (pcur) {
+	p->lex.ptok = ptok;
+	p->lex.pcur = pcur;
+    }
     return 0;
 }
 
@@ -8342,6 +8359,7 @@ static enum yytokentype https://github.com/ruby/ruby/blob/trunk/parse.y#L8359
 parse_percent(struct parser_params *p, const int space_seen, const enum lex_state_e last_state)
 {
     register int c;
+    const char *ptok = p->lex.pcur;
 
     if (IS_BEG()) {
 	int term;
@@ -8371,6 +8389,7 @@ parse_percent(struct parser_params *p, const int space_seen, const enum lex_stat https://github.com/ruby/ruby/blob/trunk/parse.y#L8389
 	else if (term == '<') term = '>';
 	else paren = 0;
 
+	p->lex.ptok = ptok-1;
 	switch (c) {
 	  case 'Q':
 	    p->lex.strterm = NEW_STRTERM(str_dquote, term, paren);
@@ -9035,6 +9054,7 @@ parser_yylex(struct parser_params *p) https://github.com/ruby/ruby/blob/trunk/parse.y#L9054
       case '"':
 	label = (IS_LABEL_POSSIBLE() ? str_label : 0);
 	p->lex.strterm = NEW_STRTERM(str_dquote | label, '"', 0);
+	p->lex.ptok = p->lex.pcur-1;
 	return tSTRING_BEG;
 
       case '`':
@@ -9055,6 +9075,7 @@ parser_yylex(struct parser_params *p) https://github.com/ruby/ruby/blob/trunk/parse.y#L9075
       case '\'':
 	label = (IS_LABEL_POSSIBLE() ? str_label : 0);
 	p->lex.strterm = NEW_STRTERM(str_squote | label, '\'', 0);
+	p->lex.ptok = p->lex.pcur-1;
 	return tSTRING_BEG;
 
       case '?':
@@ -11499,6 +11520,7 @@ new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc) https://github.com/ruby/ruby/blob/trunk/parse.y#L11520
     if (hash) hash = remove_duplicate_keys(p, hash);
     return NEW_HASH(hash, loc);
 }
+#endif
 
 static void
 error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc)
@@ -11514,6 +11536,7 @@ error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE * https://github.com/ruby/ruby/blob/trunk/parse.y#L11536
     }
 }
 
+#ifndef RIPPER
 static void
 error_duplicate_keys(struct parser_params *p, NODE *hash)
 {
@@ -12155,6 +12178,7 @@ parser_reg_compile(struct parser_params* p, VALUE str, int options, VALUE *errms https://github.com/ruby/ruby/blob/trunk/parse.y#L12178
 {
     VALUE err = rb_errinfo();
     VALUE re;
+    str = ripper_is_node_yylval(str) ? RNODE(str)->nd_cval : str;
     int c = rb_reg_fragment_setenc(p, str, options);
     if (c) reg_fragment_enc_error(p, str, c);
     re = rb_parser_reg_compile(p, str, options);
diff --git a/test/ripper/test_sexp.rb b/test/ripper/test_sexp.rb
index d6c7d60..9b3a99e 100644
--- a/test/ripper/test_sexp.rb
+++ b/test/ripper/test_sexp.rb
@@ -435,6 +435,9 @@ eot https://github.com/ruby/ruby/blob/trunk/test/ripper/test_sexp.rb#L435
 
     [__LINE__, %q{ case 0; in a?:; end }] =>
     nil,
+
+    [__LINE__, %q{ case 0; in "A":; end }] =>
+    nil,
   }
   pattern_matching_data.each do |(i, src), expected|
     define_method(:"test_pattern_matching_#{i}") do
-- 
cgit v0.10.2


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

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