Argument forwarding definition without parentheses [Bug #18267]
This commit is contained in:
parent
7da6e9b3ec
commit
13a9597c7c
Notes:
git
2021-10-31 18:28:22 +09:00
49
parse.y
49
parse.y
@ -675,7 +675,6 @@ static int local_id_ref(struct parser_params*, ID, ID **);
|
|||||||
#ifndef RIPPER
|
#ifndef RIPPER
|
||||||
static ID internal_id(struct parser_params*);
|
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_call(struct parser_params*, NODE*, const YYLTYPE*, const YYLTYPE*);
|
||||||
static NODE *new_args_forward_def(struct parser_params*, NODE*, const YYLTYPE*);
|
|
||||||
#endif
|
#endif
|
||||||
static int check_forwarding_args(struct parser_params*);
|
static int check_forwarding_args(struct parser_params*);
|
||||||
static void add_forwarding_args(struct parser_params *p);
|
static void add_forwarding_args(struct parser_params *p);
|
||||||
@ -5128,26 +5127,6 @@ f_paren_args : '(' f_args rparen
|
|||||||
SET_LEX_STATE(EXPR_BEG);
|
SET_LEX_STATE(EXPR_BEG);
|
||||||
p->command_start = TRUE;
|
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
|
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);
|
$$ = 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
|
opt_args_tail : ',' args_tail
|
||||||
@ -5259,7 +5243,7 @@ f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
|
|||||||
args_forward : tBDOT3
|
args_forward : tBDOT3
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = idDot3;
|
$$ = idFWD_KWREST;
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: args_forward! %*/
|
/*% ripper: args_forward! %*/
|
||||||
}
|
}
|
||||||
@ -9653,6 +9637,12 @@ parser_yylex(struct parser_params *p)
|
|||||||
if ((c = nextc(p)) == '.') {
|
if ((c = nextc(p)) == '.') {
|
||||||
if ((c = nextc(p)) == '.') {
|
if ((c = nextc(p)) == '.') {
|
||||||
if (p->lex.paren_nest == 0 && looking_at_eol_p(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?");
|
rb_warn0("... at EOL, should be parenthesized?");
|
||||||
}
|
}
|
||||||
else if (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest) {
|
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;
|
int saved_line = p->ruby_sourceline;
|
||||||
struct rb_args_info *args = tail->nd_ainfo;
|
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_args_num = pre_args ? rb_long2int(pre_args->nd_plen) : 0;
|
||||||
args->pre_init = pre_args ? pre_args->nd_next : 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
|
#endif
|
||||||
return arg_blk_pass(args, block);
|
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
|
#endif
|
||||||
|
|
||||||
static NODE *
|
static NODE *
|
||||||
|
@ -1575,6 +1575,7 @@ eom
|
|||||||
def test_argument_forwarding
|
def test_argument_forwarding
|
||||||
assert_valid_syntax('def foo(...) bar(...) end')
|
assert_valid_syntax('def foo(...) bar(...) end')
|
||||||
assert_valid_syntax('def foo(...) 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 [](...) end')
|
assert_valid_syntax('def [](...) end')
|
||||||
assert_valid_syntax('def nil(...) end')
|
assert_valid_syntax('def nil(...) end')
|
||||||
@ -1604,7 +1605,9 @@ eom
|
|||||||
[args, kws]
|
[args, kws]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
obj4 = obj1.clone
|
||||||
obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
|
obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
|
||||||
|
obj4.instance_eval("def foo ...\n bar(...)\n""end", __FILE__, __LINE__)
|
||||||
|
|
||||||
klass = Class.new {
|
klass = Class.new {
|
||||||
def foo(*args, **kws, &block)
|
def foo(*args, **kws, &block)
|
||||||
@ -1633,7 +1636,7 @@ eom
|
|||||||
end
|
end
|
||||||
obj3.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
|
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_warning('') {
|
||||||
assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5) {|*x| x})
|
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], {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)
|
||||||
assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
|
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
|
end
|
||||||
|
|
||||||
def test_cdhash
|
def test_cdhash
|
||||||
|
Loading…
x
Reference in New Issue
Block a user