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/