From ea68bb914a3c806a1c5188993b96791a76ab0849 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 4 Sep 2019 00:07:50 +0900 Subject: [PATCH] Changed numbered parameter prefix --- bootstraptest/test_syntax.rb | 2 +- ext/ripper/eventids2.c | 3 -- parse.y | 81 +++++++++++------------------- test/irb/test_color.rb | 2 - test/ripper/test_lexer.rb | 8 +-- test/ripper/test_parser_events.rb | 10 ++-- test/ripper/test_scanner_events.rb | 7 --- test/ruby/test_syntax.rb | 43 ++++++++-------- 8 files changed, 62 insertions(+), 94 deletions(-) diff --git a/bootstraptest/test_syntax.rb b/bootstraptest/test_syntax.rb index d06ebc9281..a111990a1f 100644 --- a/bootstraptest/test_syntax.rb +++ b/bootstraptest/test_syntax.rb @@ -532,7 +532,7 @@ end assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev:29732]' assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]' assert_syntax_error "syntax error, unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]' -assert_syntax_error "leading zero is not allowed as a numbered parameter", %q{@0..0}, '[ruby-dev:31095]' +assert_syntax_error "`@0' is not allowed as an instance variable name", %q{@0..0}, '[ruby-dev:31095]' assert_syntax_error "identifier $00 is not valid to get", %q{$00..0}, '[ruby-dev:31100]' assert_syntax_error "identifier $00 is not valid to set", %q{0..$00=1} assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]' diff --git a/ext/ripper/eventids2.c b/ext/ripper/eventids2.c index ce4a285783..9b188539cc 100644 --- a/ext/ripper/eventids2.c +++ b/ext/ripper/eventids2.c @@ -51,7 +51,6 @@ typedef struct { ID ripper_id_label_end; ID ripper_id_tlambda; ID ripper_id_tlambeg; - ID ripper_id_tnumparam; ID ripper_id_ignored_nl; ID ripper_id_comment; @@ -114,7 +113,6 @@ ripper_init_eventids2(void) set_id2(label_end); set_id2(tlambda); set_id2(tlambeg); - set_id2(tnumparam); set_id2(ignored_nl); set_id2(comment); @@ -278,7 +276,6 @@ static const struct token_assoc { {tLABEL_END, O(label_end)}, {tLAMBDA, O(tlambda)}, {tLAMBEG, O(tlambeg)}, - {tNUMPARAM, O(tnumparam)}, /* ripper specific tokens */ {tIGNORED_NL, O(ignored_nl)}, diff --git a/parse.y b/parse.y index 3732924272..1a9b110fbf 100644 --- a/parse.y +++ b/parse.y @@ -549,11 +549,8 @@ PRINTF_ARGS(void rb_parser_fatal(struct parser_params *p, const char *fmt, ...), YYLTYPE *rb_parser_set_location_from_strterm_heredoc(struct parser_params *p, rb_strterm_heredoc_t *here, YYLTYPE *yylloc); YYLTYPE *rb_parser_set_location_of_none(struct parser_params *p, YYLTYPE *yylloc); YYLTYPE *rb_parser_set_location(struct parser_params *p, YYLTYPE *yylloc); -ID rb_parser_numparam_id(struct parser_params *p, int num); RUBY_SYMBOL_EXPORT_END -#define numparam_id rb_parser_numparam_id - 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); @@ -1010,7 +1007,6 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in %token tCONSTANT "constant" %token tCVAR "class variable" %token tLABEL -%token tNUMPARAM "numbered parameter" %token tINTEGER "integer literal" %token tFLOAT "float literal" %token tRATIONAL "rational literal" @@ -4584,13 +4580,6 @@ string_dvar : tGVAR /*% %*/ /*% ripper: var_ref!($1) %*/ } - | tNUMPARAM - { - /*%%%*/ - $$ = NEW_DVAR($1, &@1); - /*% %*/ - /*% ripper: var_ref!($1) %*/ - } | backref ; @@ -4646,7 +4635,6 @@ user_variable : tIDENTIFIER | tGVAR | tCONSTANT | tCVAR - | tNUMPARAM ; keyword_variable: keyword_nil {$$ = KWD2EID(nil, $1);} @@ -8480,9 +8468,12 @@ parse_gvar(struct parser_params *p, const enum lex_state_e last_state) return tGVAR; } +#ifndef RIPPER static bool -parser_numbered_param(struct parser_params *p, unsigned long n) +parser_numbered_param(struct parser_params *p, int n) { + if (n < 0) return false; + if (DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev)) { compile_error(p, "implicit parameter outside block"); return false; @@ -8503,10 +8494,22 @@ parser_numbered_param(struct parser_params *p, unsigned long n) return false; } } - set_yylval_name(numparam_id(p, (int)n)); - SET_LEX_STATE(EXPR_ARG); + struct vtable *args = p->lvtbl->args; + if (n == 0) { + p->max_numparam = IMPLICIT_PARAM; + vtable_add(args, idNUMPARAM_0); + } + else { + if (p->max_numparam < n) { + p->max_numparam = n; + } + while (n > args->pos) { + vtable_add(args, NUMPARAM_IDX_TO_ID(args->pos+1)); + } + } return true; } +#endif static enum yytokentype parse_atmark(struct parser_params *p, const enum lex_state_e last_state) @@ -8540,31 +8543,17 @@ parse_atmark(struct parser_params *p, const enum lex_state_e last_state) return result; } else if (ISDIGIT(c)) { - const char *ptr = p->lex.pcur - 1; - size_t len = p->lex.pend - ptr; - int overflow; - unsigned long n = ruby_scan_digits(ptr, len, 10, &len, &overflow); - p->lex.pcur = ptr + len; + pushback(p, c); RUBY_SET_YYLLOC(loc); if (result == tIVAR) { - if (IS_lex_state_for(last_state, EXPR_FNAME)) { - compile_error(p, "`@%c' is not allowed as an instance variable name", c); - } - else if (ptr[0] == '0') { - compile_error(p, "leading zero is not allowed as a numbered parameter"); - } - else if (overflow || n > NUMPARAM_MAX) { - compile_error(p, "too large numbered parameter"); - } - else if (parser_numbered_param(p, n)) { - return tNUMPARAM; - } + compile_error(p, "`@%c' is not allowed as an instance variable name", c); } else { compile_error(p, "`@@%c' is not allowed as a class variable name", c); } parser_show_error_line(p, &loc); set_yylval_noname(); + SET_LEX_STATE(EXPR_END); return result; } @@ -9869,6 +9858,11 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc) node = NEW_LVAR(id, loc); return node; } + if (dyna_in_block(p) && NUMPARAM_ID_P(id) && + parser_numbered_param(p, NUMPARAM_ID_TO_IDX(id))) { + node = NEW_DVAR(id, loc); + return node; + } # if WARN_PAST_SCOPE if (!p->in_defined && RTEST(ruby_verbose) && past_dvar_p(p, id)) { rb_warning1("possible reference to past scope - %"PRIsWARN, rb_id2str(id)); @@ -10073,7 +10067,9 @@ id_is_var(struct parser_params *p, ID id) case ID_INTERNAL: return vtable_included(p->lvtbl->args, id); case ID_LOCAL: - if (dyna_in_block(p) && dvar_defined(p, id)) return 1; + if (dyna_in_block(p)) { + if (NUMPARAM_ID_P(id) || dvar_defined(p, id)) return 1; + } if (local_id(p, id)) return 1; /* method call without arguments */ return 0; @@ -11254,25 +11250,6 @@ args_with_numbered(struct parser_params *p, NODE *args, int max_numparam) return args; } -ID -rb_parser_numparam_id(struct parser_params *p, int idx) -{ - struct vtable *args; - if (idx < 0) return (ID)0; - else if (idx == 0) { - p->max_numparam = IMPLICIT_PARAM; - idx = 1; - } - else if (p->max_numparam < idx) { - p->max_numparam = idx; - } - args = p->lvtbl->args; - while (idx > args->pos) { - vtable_add(args, internal_id(p)); - } - return args->tbl[idx-1]; -} - static NODE* new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc) { diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb index e1057d3144..3ecbee8cd6 100644 --- a/test/irb/test_color.rb +++ b/test/irb/test_color.rb @@ -67,8 +67,6 @@ module TestIRB "4.5.6" => "#{MAGENTA}#{BOLD}4.5#{CLEAR}#{RED}#{REVERSE}.6#{CLEAR}", "\e[0m\n" => "#{RED}#{REVERSE}^[#{CLEAR}[#{BLUE}#{BOLD}0#{CLEAR}#{RED}#{REVERSE}m#{CLEAR}\n", "< "#{RED}< "#{YELLOW}:#{CLEAR}#{RED}#{REVERSE}@1#{CLEAR}", - "@@1" => "#{RED}#{REVERSE}@@1#{CLEAR}", }) end diff --git a/test/ripper/test_lexer.rb b/test/ripper/test_lexer.rb index 060d5f2db9..1794773d89 100644 --- a/test/ripper/test_lexer.rb +++ b/test/ripper/test_lexer.rb @@ -102,15 +102,15 @@ class TestRipper::Lexer < Test::Unit::TestCase def test_state_after_ivar assert_equal [[1,0],:on_ivar,"@a",state(:EXPR_END)], Ripper.lex("@a").last assert_equal [[1,1],:on_ivar,"@a",state(:EXPR_ENDFN)], Ripper.lex(":@a").last - assert_equal [[1,0],:on_ivar,"@1",state(:EXPR_END)], Ripper.lex("@1").last - assert_equal [[1,1],:on_ivar,"@1",state(:EXPR_ENDFN)], Ripper.lex(":@1").last + assert_equal [[1,1],:on_int,"1",state(:EXPR_END)], Ripper.lex("@1").last + assert_equal [[1,2],:on_int,"1",state(:EXPR_END)], Ripper.lex(":@1").last end def test_state_after_cvar assert_equal [[1,0],:on_cvar,"@@a",state(:EXPR_END)], Ripper.lex("@@a").last assert_equal [[1,1],:on_cvar,"@@a",state(:EXPR_ENDFN)], Ripper.lex(":@@a").last - assert_equal [[1,0],:on_cvar,"@@1",state(:EXPR_END)], Ripper.lex("@@1").last - assert_equal [[1,1],:on_cvar,"@@1",state(:EXPR_ENDFN)], Ripper.lex(":@@1").last + assert_equal [[1,2],:on_int,"1",state(:EXPR_END)], Ripper.lex("@@1").last + assert_equal [[1,3],:on_int,"1",state(:EXPR_END)], Ripper.lex(":@@1").last end def test_token_aftr_error_heredoc diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb index 1bae1e31ad..662ab3d7fe 100644 --- a/test/ripper/test_parser_events.rb +++ b/test/ripper/test_parser_events.rb @@ -58,7 +58,10 @@ class TestRipper::ParserEvents < Test::Unit::TestCase assert_equal '[assign(var_field(a),ref(a))]', parse('a=a') assert_equal '[ref(nil)]', parse('nil') assert_equal '[ref(true)]', parse('true') - assert_include parse('proc{@1}'), '[ref(@1)]' + assert_equal '[vcall(_0)]', parse('_0') + assert_equal '[vcall(_1)]', parse('_1') + assert_include parse('proc{_0}'), '[ref(_0)]' + assert_include parse('proc{_1}'), '[ref(_1)]' end def test_vcall @@ -1505,11 +1508,8 @@ class TestRipper::ParserEvents < Test::Unit::TestCase assert_equal("unterminated regexp meets end of file", compile_error('/')) end - def test_invalid_numbered_parameter_name - assert_equal("leading zero is not allowed as a numbered parameter", compile_error('proc{@0}')) - end - def test_invalid_instance_variable_name + assert_equal("`@1' is not allowed as an instance variable name", compile_error('proc{@1}')) assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@%')) assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@')) end diff --git a/test/ripper/test_scanner_events.rb b/test/ripper/test_scanner_events.rb index 75ae29491d..641310b384 100644 --- a/test/ripper/test_scanner_events.rb +++ b/test/ripper/test_scanner_events.rb @@ -360,13 +360,6 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase scan('ivar', 'm(lvar, @ivar, @@cvar, $gvar)') end - def test_tnumparam - assert_equal [], - scan('tnumparam', '') - assert_equal ['@1'], - scan('tnumparam', 'proc {@1}') - end - def test_kw assert_equal [], scan('kw', '') diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 6209bb3a23..31175ebae9 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -1439,26 +1439,29 @@ eom end def test_numbered_parameter - assert_valid_syntax('proc {@1}') - assert_equal(3, eval('[1,2].then {@1+@2}')) - assert_equal("12", eval('[1,2].then {"#@1#@2"}')) - assert_equal(3, eval('->{@1+@2}.call(1,2)')) - assert_equal(4, eval('->(a=->{@1}){a}.call.call(4)')) - assert_equal(5, eval('-> a: ->{@1} {a}.call.call(5)')) - assert_syntax_error('proc {|| @1}', /ordinary parameter is defined/) - assert_syntax_error('proc {|;a| @1}', /ordinary parameter is defined/) - assert_syntax_error("proc {|\n| @1}", /ordinary parameter is defined/) - assert_syntax_error('proc {|x| @1}', /ordinary parameter is defined/) - assert_syntax_error('->(){@1}', /ordinary parameter is defined/) - assert_syntax_error('->(x){@1}', /ordinary parameter is defined/) - assert_syntax_error('->x{@1}', /ordinary parameter is defined/) - assert_syntax_error('->x:@2{}', /ordinary parameter is defined/) - assert_syntax_error('->x=@1{}', /ordinary parameter is defined/) - assert_syntax_error('proc {@1 = nil}', /Can't assign to numbered parameter @1/) - assert_syntax_error('proc {@01}', /leading zero/) - assert_syntax_error('proc {@1_}', /unexpected/) - assert_syntax_error('proc {@9999999999999999}', /too large/) - assert_syntax_error('@1', /outside block/) + assert_valid_syntax('proc {_1}') + assert_equal(3, eval('[1,2].then {_1+_2}')) + assert_equal("12", eval('[1,2].then {"#{_1}#{_2}"}')) + assert_equal([1, 2], eval('[1,2].then {_0}')) + assert_equal(3, eval('->{_1+_2}.call(1,2)')) + assert_equal(4, eval('->(a=->{_1}){a}.call.call(4)')) + assert_equal(5, eval('-> a: ->{_1} {a}.call.call(5)')) + assert_syntax_error('proc {|| _0}', /ordinary parameter is defined/) + assert_syntax_error('proc {|| _1}', /ordinary parameter is defined/) + assert_syntax_error('proc {|;a| _1}', /ordinary parameter is defined/) + assert_syntax_error("proc {|\n| _1}", /ordinary parameter is defined/) + 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('->(){_0}', /ordinary parameter is defined/) + assert_syntax_error('->(){_1}', /ordinary parameter is defined/) + assert_syntax_error('->(x){_1}', /ordinary parameter is defined/) + assert_syntax_error('->x{_1}', /ordinary parameter is defined/) + assert_syntax_error('->x:_2{}', /ordinary parameter is defined/) + 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_warn(/`_1' is used as numbered parameter/) {eval('proc {_1 = nil}')} assert_warn(/`_2' is used as numbered parameter/) {eval('_2=1')} end