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

ruby-changes:57883

From: Nobuyoshi <ko1@a...>
Date: Tue, 24 Sep 2019 21:58:11 +0900 (JST)
Subject: [ruby-changes:57883] 0e84eecc17 (master): Make numbered parameters exclusive in a scope

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

From 0e84eecc1764ec6e2a28654b3e66b8c006f73432 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Tue, 24 Sep 2019 18:25:32 +0900
Subject: Make numbered parameters exclusive in a scope


diff --git a/parse.y b/parse.y
index 1a9b110..8adf0fc 100644
--- a/parse.y
+++ b/parse.y
@@ -290,6 +290,10 @@ struct parser_params { https://github.com/ruby/ruby/blob/trunk/parse.y#L290
     VALUE error_buffer;
     VALUE debug_lines;
     const struct rb_block *base_block;
+
+    struct {
+	NODE *outer, *inner, *current;
+    } numparam;
 #else
     /* Ripper only */
 
@@ -576,6 +580,9 @@ static int dvar_curr(struct parser_params*,ID); https://github.com/ruby/ruby/blob/trunk/parse.y#L580
 
 static int lvar_defined(struct parser_params*, ID);
 
+static NODE *numparam_push(struct parser_params *p);
+static void numparam_pop(struct parser_params *p, NODE *prev_inner);
+
 #ifdef RIPPER
 # define METHOD_NOT idNOT
 #else
@@ -3426,6 +3433,9 @@ lambda		:   { https://github.com/ruby/ruby/blob/trunk/parse.y#L3433
 			$<num>$ = p->max_numparam;
 			p->max_numparam = 0;
 		    }
+		    {
+			$<node>$ = numparam_push(p);
+		    }
 		  f_larglist
 		    {
 			CMDARG_PUSH(0);
@@ -3436,16 +3446,17 @@ lambda		:   { https://github.com/ruby/ruby/blob/trunk/parse.y#L3446
 			p->lex.lpar_beg = $<num>2;
 			p->max_numparam = $<num>3;
 			CMDARG_POP();
-			$4 = args_with_numbered(p, $4, max_numparam);
+			$5 = args_with_numbered(p, $5, max_numparam);
 		    /*%%%*/
                         {
-                            YYLTYPE loc = code_loc_gen(&@4, &@6);
-                            $$ = NEW_LAMBDA($4, $6, &loc);
-                            nd_set_line($$->nd_body, @6.end_pos.lineno);
-                            nd_set_line($$, @4.end_pos.lineno);
+                            YYLTYPE loc = code_loc_gen(&@5, &@7);
+                            $$ = NEW_LAMBDA($5, $7, &loc);
+                            nd_set_line($$->nd_body, @7.end_pos.lineno);
+                            nd_set_line($$, @5.end_pos.lineno);
                         }
 		    /*% %*/
-		    /*% ripper: lambda!($4, $6) %*/
+		    /*% ripper: lambda!($5, $7) %*/
+			numparam_pop(p, $<node>4);
 			dyna_pop(p, $<vars>1);
 		    }
 		;
@@ -3624,15 +3635,19 @@ brace_body	: {$<vars>$ = dyna_push(p);} https://github.com/ruby/ruby/blob/trunk/parse.y#L3635
 			$<num>$ = p->max_numparam;
 			p->max_numparam = 0;
 		    }
+		    {
+			$<node>$ = numparam_push(p);
+		    }
 		  opt_block_param compstmt
 		    {
 			int max_numparam = p->max_numparam;
 			p->max_numparam = $<num>2;
-			$3 = args_with_numbered(p, $3, max_numparam);
+			$4 = args_with_numbered(p, $4, max_numparam);
 		    /*%%%*/
-			$$ = NEW_ITER($3, $4, &@$);
+			$$ = NEW_ITER($4, $5, &@$);
 		    /*% %*/
-		    /*% ripper: brace_block!(escape_Qundef($3), $4) %*/
+		    /*% ripper: brace_block!(escape_Qundef($4), $5) %*/
+			numparam_pop(p, $<node>3);
 			dyna_pop(p, $<vars>1);
 		    }
 		;
@@ -3641,18 +3656,22 @@ do_body 	: {$<vars>$ = dyna_push(p);} https://github.com/ruby/ruby/blob/trunk/parse.y#L3656
 		    {
 			$<num>$ = p->max_numparam;
 			p->max_numparam = 0;
+		    }
+		    {
+			$<node>$ = numparam_push(p);
 			CMDARG_PUSH(0);
 		    }
 		  opt_block_param bodystmt
 		    {
 			int max_numparam = p->max_numparam;
 			p->max_numparam = $<num>2;
-			$3 = args_with_numbered(p, $3, max_numparam);
+			$4 = args_with_numbered(p, $4, max_numparam);
 		    /*%%%*/
-			$$ = NEW_ITER($3, $4, &@$);
+			$$ = NEW_ITER($4, $5, &@$);
 		    /*% %*/
-		    /*% ripper: do_block!(escape_Qundef($3), $4) %*/
+		    /*% ripper: do_block!(escape_Qundef($4), $5) %*/
 			CMDARG_POP();
+			numparam_pop(p, $<node>3);
 			dyna_pop(p, $<vars>1);
 		    }
 		;
@@ -9799,6 +9818,24 @@ past_dvar_p(struct parser_params *p, ID id) https://github.com/ruby/ruby/blob/trunk/parse.y#L9818
     } \
 } while (0)
 
+static int
+numparam_nested_p(struct parser_params *p)
+{
+    NODE *outer = p->numparam.outer;
+    NODE *inner = p->numparam.inner;
+    if (outer || inner) {
+	NODE *used = outer ? outer : inner;
+	compile_error(p, "%s parameter is already used in\n"
+		      "%s:%d: %s block here",
+		      used->nd_vid == idNUMPARAM_0 ? "implicit" : "numbered",
+		      p->ruby_sourcefile, nd_line(used),
+		      outer ? "outer" : "inner");
+	parser_show_error_line(p, &used->nd_loc);
+	return 1;
+    }
+    return 0;
+}
+
 static NODE*
 gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
 {
@@ -9843,6 +9880,7 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc) https://github.com/ruby/ruby/blob/trunk/parse.y#L9880
 	break;
       case ID_LOCAL:
 	if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
+	    if (NUMPARAM_ID_P(id) && numparam_nested_p(p)) return 0;
 	    if (id == p->cur_arg) {
 		rb_warn1("circular argument reference - %"PRIsWARN, rb_id2str(id));
 	    }
@@ -9860,7 +9898,9 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc) https://github.com/ruby/ruby/blob/trunk/parse.y#L9898
 	}
 	if (dyna_in_block(p) && NUMPARAM_ID_P(id) &&
 	    parser_numbered_param(p, NUMPARAM_ID_TO_IDX(id))) {
+	    if (numparam_nested_p(p)) return 0;
 	    node = NEW_DVAR(id, loc);
+	    if (!p->numparam.current) p->numparam.current = node;
 	    return node;
 	}
 # if WARN_PAST_SCOPE
@@ -11654,6 +11694,11 @@ local_pop(struct parser_params *p) https://github.com/ruby/ruby/blob/trunk/parse.y#L11694
     COND_POP();
     ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
     p->lvtbl = local;
+# ifndef RIPPER
+    p->numparam.outer = 0;
+    p->numparam.inner = 0;
+    p->numparam.current = 0;
+# endif
 }
 
 #ifndef RIPPER
@@ -11754,6 +11799,46 @@ local_id(struct parser_params *p, ID id) https://github.com/ruby/ruby/blob/trunk/parse.y#L11799
     return local_id_ref(p, id, NULL);
 }
 
+static NODE *
+numparam_push(struct parser_params *p)
+{
+#ifndef RIPPER
+    NODE *inner = p->numparam.inner;
+    if (!p->numparam.outer) {
+	p->numparam.outer = p->numparam.current;
+    }
+    p->numparam.inner = 0;
+    p->numparam.current = 0;
+    return inner;
+#else
+    return 0;
+#endif
+}
+
+static void
+numparam_pop(struct parser_params *p, NODE *prev_inner)
+{
+#ifndef RIPPER
+    if (prev_inner) {
+	/* prefer first one */
+	p->numparam.inner = prev_inner;
+    }
+    else if (p->numparam.current) {
+	/* current and inner are exclusive */
+	p->numparam.inner = p->numparam.current;
+    }
+    if (p->max_numparam > NO_PARAM || p->max_numparam == IMPLICIT_PARAM) {
+	/* current and outer are exclusive */
+	p->numparam.current = p->numparam.outer;
+	p->numparam.outer = 0;
+    }
+    else {
+	/* no numbered parameter */
+	p->numparam.current = 0;
+    }
+#endif
+}
+
 static const struct vtable *
 dyna_push(struct parser_params *p)
 {
@@ -13008,3 +13093,10 @@ InitVM_ripper(void) https://github.com/ruby/ruby/blob/trunk/parse.y#L13093
 
 }
 #endif /* RIPPER */
+
+/*
+ * Local variables:
+ * mode: c
+ * c-file-style: ruby
+ * End:
+ */
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 31175eb..61bee81 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -1453,6 +1453,10 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1453
     assert_syntax_error('proc {|x| _1}', /ordinary parameter is defined/)
     assert_syntax_error('proc {_0+_1}', /implicit parameter is used/)
     assert_syntax_error('proc {_1+_0}', /numbered parameter is used/)
+    assert_syntax_error('proc {_1; proc {_2}}', /numbered parameter is already used/)
+    assert_syntax_error('proc {proc {_1}; _2}', /numbered parameter is already used/)
+    assert_syntax_error('proc {_0; proc {_1}}', /implicit parameter is already used/)
+    assert_syntax_error('proc {proc {_0}; _1}', /implicit parameter is already used/)
     assert_syntax_error('->(){_0}', /ordinary parameter is defined/)
     assert_syntax_error('->(){_1}', /ordinary parameter is defined/)
     assert_syntax_error('->(x){_1}', /ordinary parameter is defined/)
@@ -1461,6 +1465,10 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1465
     assert_syntax_error('->x=_1{}', /ordinary parameter is defined/)
     assert_syntax_error('-> {_0+_1}', /implicit parameter is used/)
     assert_syntax_error('-> {_1+_0}', /numbered parameter is used/)
+    assert_syntax_error('-> {_1; -> {_2}}', /numbered parameter is already used/)
+    assert_syntax_error('-> {-> {_1}; _2}', /numbered parameter is already used/)
+    assert_syntax_error('-> {_0; -> {_1}}', /implicit parameter is already used/)
+    assert_syntax_error('-> {-> {_0}; _1}', /implicit parameter is already used/)
     assert_warn(/`_1' is used as numbered parameter/) {eval('proc {_1 = nil}')}
     assert_warn(/`_2' is used as numbered parameter/) {eval('_2=1')}
   end
-- 
cgit v0.10.2


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

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