diff options
-rw-r--r-- | parse.y | 49 | ||||
-rw-r--r-- | test/ruby/test_syntax.rb | 15 |
2 files changed, 34 insertions, 30 deletions
@@ -675,7 +675,6 @@ static int local_id_ref(struct parser_params*, ID, ID **); #ifndef RIPPER static ID internal_id(struct parser_params*); static NODE *new_args_forward_call(struct parser_params*, NODE*, const YYLTYPE*, const YYLTYPE*); -static NODE *new_args_forward_def(struct parser_params*, NODE*, const YYLTYPE*); #endif static int check_forwarding_args(struct parser_params*); static void add_forwarding_args(struct parser_params *p); @@ -5128,26 +5127,6 @@ f_paren_args : '(' f_args rparen SET_LEX_STATE(EXPR_BEG); p->command_start = TRUE; } - | '(' f_arg ',' args_forward rparen - { - add_forwarding_args(p); - /*%%%*/ - $$ = new_args_forward_def(p, $2, &@$); - /*% %*/ - /*% ripper: paren!(params!($2, Qnone, $4, Qnone, Qnone, Qnone, Qnone)) %*/ - SET_LEX_STATE(EXPR_BEG); - p->command_start = TRUE; - } - | '(' args_forward rparen - { - add_forwarding_args(p); - /*%%%*/ - $$ = new_args_forward_def(p, 0, &@$); - /*% %*/ - /*% ripper: paren!(params!(Qnone, Qnone, $2, Qnone, Qnone, Qnone, Qnone)) %*/ - SET_LEX_STATE(EXPR_BEG); - p->command_start = TRUE; - } ; f_arglist : f_paren_args @@ -5181,6 +5160,11 @@ args_tail : f_kwarg ',' f_kwrest opt_f_block_arg { $$ = new_args_tail(p, Qnone, Qnone, $1, &@1); } + | args_forward + { + add_forwarding_args(p); + $$ = new_args_tail(p, Qnone, $1, ID2VAL(idFWD_BLOCK), &@1); + } ; opt_args_tail : ',' args_tail @@ -5259,7 +5243,7 @@ f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail args_forward : tBDOT3 { /*%%%*/ - $$ = idDot3; + $$ = idFWD_KWREST; /*% %*/ /*% ripper: args_forward! %*/ } @@ -9653,6 +9637,12 @@ parser_yylex(struct parser_params *p) if ((c = nextc(p)) == '.') { if ((c = nextc(p)) == '.') { if (p->lex.paren_nest == 0 && looking_at_eol_p(p)) { + if (p->ctxt.in_argdef || /* def foo a, ... */ + IS_lex_state_for(last_state, EXPR_ENDFN) || /* def foo ... */ + 0) { + SET_LEX_STATE(EXPR_ENDARG); + return tBDOT3; + } rb_warn0("... at EOL, should be parenthesized?"); } else if (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest) { @@ -11967,6 +11957,14 @@ new_args(struct parser_params *p, NODE *pre_args, NODE *opt_args, ID rest_arg, N int saved_line = p->ruby_sourceline; struct rb_args_info *args = tail->nd_ainfo; + if (args->block_arg == idFWD_BLOCK) { + if (rest_arg) { + yyerror1(&tail->nd_loc, "... after rest argument"); + return tail; + } + rest_arg = idFWD_REST; + } + args->pre_args_num = pre_args ? rb_long2int(pre_args->nd_plen) : 0; args->pre_init = pre_args ? pre_args->nd_next : 0; @@ -12697,13 +12695,6 @@ new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc #endif return arg_blk_pass(args, block); } - -static NODE * -new_args_forward_def(struct parser_params *p, NODE *leading, const YYLTYPE *loc) -{ - NODE *n = new_args_tail(p, Qnone, idFWD_KWREST, idFWD_BLOCK, loc); - return new_args(p, leading, Qnone, idFWD_REST, Qnone, n, loc); -} #endif static NODE * diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index fc40a7f21a..11953ab563 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -1575,6 +1575,7 @@ eom def test_argument_forwarding assert_valid_syntax('def foo(...) bar(...) end') assert_valid_syntax('def foo(...) end') + assert_valid_syntax("def foo ...\n bar(...)\nend") assert_valid_syntax('def ==(...) end') assert_valid_syntax('def [](...) end') assert_valid_syntax('def nil(...) end') @@ -1604,7 +1605,9 @@ eom [args, kws] end end + obj4 = obj1.clone obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__) + obj4.instance_eval("def foo ...\n bar(...)\n""end", __FILE__, __LINE__) klass = Class.new { def foo(*args, **kws, &block) @@ -1633,7 +1636,7 @@ eom end obj3.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__) - [obj1, obj2, obj3].each do |obj| + [obj1, obj2, obj3, obj4].each do |obj| assert_warning('') { assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5) {|*x| x}) } @@ -1766,6 +1769,16 @@ eom assert_equal [[4, 1, 5, 2], {a: 1}], obj.foo(4, 5, 2, a: 1) assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1) assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]} + + obj.singleton_class.send(:remove_method, :foo) + obj.instance_eval("def foo a, ...\n bar(a, ...)\n"" end", __FILE__, __LINE__) + assert_equal [[4], {}], obj.foo(4) + assert_equal [[4, 2], {}], obj.foo(4, 2) + assert_equal [[4, 2, 3], {}], obj.foo(4, 2, 3) + assert_equal [[4], {a: 1}], obj.foo(4, a: 1) + assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1) + assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1) + assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]} end def test_cdhash |