Add leading arguments support to arguments forwarding
The idFWD_KWREST sections may be wrong. However, the existing idFWD_KWREST sections for ... without leading arguments are already broken. Implements [Feature #16378]
This commit is contained in:
parent
4178cbd297
commit
f8b4340fa2
Notes:
git
2020-06-07 09:07:38 +09:00
41
parse.y
41
parse.y
@ -2568,6 +2568,32 @@ paren_args : '(' opt_call_args rparen
|
|||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: arg_paren!(escape_Qundef($2)) %*/
|
/*% ripper: arg_paren!(escape_Qundef($2)) %*/
|
||||||
}
|
}
|
||||||
|
| '(' args ',' args_forward rparen
|
||||||
|
{
|
||||||
|
if (!local_id(p, idFWD_REST) ||
|
||||||
|
#if idFWD_KWREST
|
||||||
|
!local_id(p, idFWD_KWREST) ||
|
||||||
|
#endif
|
||||||
|
!local_id(p, idFWD_BLOCK)) {
|
||||||
|
compile_error(p, "unexpected ...");
|
||||||
|
$$ = Qnone;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*%%%*/
|
||||||
|
NODE *splat = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@4), &@4);
|
||||||
|
#if idFWD_KWREST
|
||||||
|
NODE *kwrest = list_append(p, NEW_LIST(0, &@4), NEW_LVAR(idFWD_KWREST, &@4));
|
||||||
|
#endif
|
||||||
|
NODE *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, &@4), &@4);
|
||||||
|
$$ = rest_arg_append(p, $2, splat, &@$);
|
||||||
|
#if idFWD_KWREST
|
||||||
|
$$ = arg_append(p, $$, new_hash(p, kwrest, &@4), &@4);
|
||||||
|
#endif
|
||||||
|
$$ = arg_blk_pass($$, block);
|
||||||
|
/*% %*/
|
||||||
|
/*% ripper: arg_paren!(args_add!($2, $4)) %*/
|
||||||
|
}
|
||||||
|
}
|
||||||
| '(' args_forward rparen
|
| '(' args_forward rparen
|
||||||
{
|
{
|
||||||
if (!local_id(p, idFWD_REST) ||
|
if (!local_id(p, idFWD_REST) ||
|
||||||
@ -4914,6 +4940,21 @@ 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
|
||||||
|
{
|
||||||
|
arg_var(p, idFWD_REST);
|
||||||
|
#if idFWD_KWREST
|
||||||
|
arg_var(p, idFWD_KWREST);
|
||||||
|
#endif
|
||||||
|
arg_var(p, idFWD_BLOCK);
|
||||||
|
/*%%%*/
|
||||||
|
$$ = new_args_tail(p, Qnone, idFWD_KWREST, idFWD_BLOCK, &@4);
|
||||||
|
$$ = new_args(p, $2, Qnone, idFWD_REST, Qnone, $$, &@4);
|
||||||
|
/*% %*/
|
||||||
|
/*% ripper: paren!(params_new($2, Qnone, $4, Qnone, Qnone, Qnone, Qnone)) %*/
|
||||||
|
SET_LEX_STATE(EXPR_BEG);
|
||||||
|
p->command_start = TRUE;
|
||||||
|
}
|
||||||
| '(' args_forward rparen
|
| '(' args_forward rparen
|
||||||
{
|
{
|
||||||
arg_var(p, idFWD_REST);
|
arg_var(p, idFWD_REST);
|
||||||
|
@ -132,9 +132,17 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_args_forward
|
def test_args_forward
|
||||||
thru_args_forward = false
|
[
|
||||||
parse('def m(...) n(...) end', :on_args_forward) {thru_args_forward = true}
|
'def m(...) n(...) end',
|
||||||
assert_equal true, thru_args_forward
|
'def m(...) end',
|
||||||
|
'def m(a, ...) n(1, ...) end',
|
||||||
|
'def m(...) n(1, ...) end',
|
||||||
|
'def m(a, ...) n(...) end'
|
||||||
|
].each do |code|
|
||||||
|
thru_args_forward = false
|
||||||
|
parse(code, :on_args_forward) {thru_args_forward = true}
|
||||||
|
assert_equal true, thru_args_forward, "no args_forward for: #{code}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_arg_paren
|
def test_arg_paren
|
||||||
|
@ -1581,6 +1581,119 @@ eom
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_argument_forwarding_with_leading_arguments
|
||||||
|
obj = Object.new
|
||||||
|
def obj.bar(*args, **kws, &block)
|
||||||
|
if block
|
||||||
|
block.call(args, kws)
|
||||||
|
else
|
||||||
|
[args, kws]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
obj.instance_eval('def foo(_a, ...) bar(...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[], {}], obj.foo(1)
|
||||||
|
assert_equal [[2], {}], obj.foo(1, 2)
|
||||||
|
assert_equal [[2, 3], {}], obj.foo(1, 2, 3)
|
||||||
|
assert_equal [[], {a: 1}], obj.foo(1, a: 1)
|
||||||
|
assert_equal [[2], {a: 1}], obj.foo(1, 2, a: 1)
|
||||||
|
assert_equal [[2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1)
|
||||||
|
assert_equal [[2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1){|args, kws| [args, kws]}
|
||||||
|
|
||||||
|
obj.singleton_class.send(:remove_method, :foo)
|
||||||
|
obj.instance_eval('def foo(...) bar(1, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[1], {}], obj.foo
|
||||||
|
assert_equal [[1, 1], {}], obj.foo(1)
|
||||||
|
assert_equal [[1, 1, 2], {}], obj.foo(1, 2)
|
||||||
|
assert_equal [[1, 1, 2, 3], {}], obj.foo(1, 2, 3)
|
||||||
|
assert_equal [[1], {a: 1}], obj.foo(a: 1)
|
||||||
|
assert_equal [[1, 1], {a: 1}], obj.foo(1, a: 1)
|
||||||
|
assert_equal [[1, 1, 2], {a: 1}], obj.foo(1, 2, a: 1)
|
||||||
|
assert_equal [[1, 1, 2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1)
|
||||||
|
assert_equal [[1, 1, 2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1){|args, kws| [args, kws]}
|
||||||
|
|
||||||
|
obj.singleton_class.send(:remove_method, :foo)
|
||||||
|
obj.instance_eval('def foo(a, ...) bar(a, ...) 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]}
|
||||||
|
|
||||||
|
obj.singleton_class.send(:remove_method, :foo)
|
||||||
|
obj.instance_eval('def foo(_a, ...) bar(1, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[1], {}], obj.foo(4)
|
||||||
|
assert_equal [[1, 2], {}], obj.foo(4, 2)
|
||||||
|
assert_equal [[1, 2, 3], {}], obj.foo(4, 2, 3)
|
||||||
|
assert_equal [[1], {a: 1}], obj.foo(4, a: 1)
|
||||||
|
assert_equal [[1, 2], {a: 1}], obj.foo(4, 2, a: 1)
|
||||||
|
assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
|
||||||
|
assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
|
||||||
|
|
||||||
|
obj.singleton_class.send(:remove_method, :foo)
|
||||||
|
obj.instance_eval('def foo(_a, _b, ...) bar(...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[], {}], obj.foo(4, 5)
|
||||||
|
assert_equal [[2], {}], obj.foo(4, 5, 2)
|
||||||
|
assert_equal [[2, 3], {}], obj.foo(4, 5, 2, 3)
|
||||||
|
assert_equal [[], {a: 1}], obj.foo(4, 5, a: 1)
|
||||||
|
assert_equal [[2], {a: 1}], obj.foo(4, 5, 2, a: 1)
|
||||||
|
assert_equal [[2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
|
||||||
|
assert_equal [[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, _b, ...) bar(1, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[1], {}], obj.foo(4, 5)
|
||||||
|
assert_equal [[1, 2], {}], obj.foo(4, 5, 2)
|
||||||
|
assert_equal [[1, 2, 3], {}], obj.foo(4, 5, 2, 3)
|
||||||
|
assert_equal [[1], {a: 1}], obj.foo(4, 5, a: 1)
|
||||||
|
assert_equal [[1, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
|
||||||
|
assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
|
||||||
|
assert_equal [[1, 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, ...) bar(1, 2, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[1, 2], {}], obj.foo(5)
|
||||||
|
assert_equal [[1, 2, 5], {}], obj.foo(4, 5)
|
||||||
|
assert_equal [[1, 2, 5, 2], {}], obj.foo(4, 5, 2)
|
||||||
|
assert_equal [[1, 2, 5, 2, 3], {}], obj.foo(4, 5, 2, 3)
|
||||||
|
assert_equal [[1, 2, 5], {a: 1}], obj.foo(4, 5, a: 1)
|
||||||
|
assert_equal [[1, 2, 5, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
|
||||||
|
assert_equal [[1, 2, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
|
||||||
|
assert_equal [[1, 2, 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, b, ...) bar(b, a, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[5, 4], {}], obj.foo(4, 5)
|
||||||
|
assert_equal [[5, 4, 2], {}], obj.foo(4, 5, 2)
|
||||||
|
assert_equal [[5, 4, 2, 3], {}], obj.foo(4, 5, 2, 3)
|
||||||
|
assert_equal [[5, 4], {a: 1}], obj.foo(4, 5, a: 1)
|
||||||
|
assert_equal [[5, 4, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
|
||||||
|
assert_equal [[5, 4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
|
||||||
|
assert_equal [[5, 4, 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, _b, ...) bar(a, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[4], {}], obj.foo(4, 5)
|
||||||
|
assert_equal [[4, 2], {}], obj.foo(4, 5, 2)
|
||||||
|
assert_equal [[4, 2, 3], {}], obj.foo(4, 5, 2, 3)
|
||||||
|
assert_equal [[4], {a: 1}], obj.foo(4, 5, a: 1)
|
||||||
|
assert_equal [[4, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
|
||||||
|
assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
|
||||||
|
assert_equal [[4, 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, ...) bar(a, 1, ...) end', __FILE__, __LINE__)
|
||||||
|
assert_equal [[4, 1], {}], obj.foo(4)
|
||||||
|
assert_equal [[4, 1, 5], {}], obj.foo(4, 5)
|
||||||
|
assert_equal [[4, 1, 5, 2], {}], obj.foo(4, 5, 2)
|
||||||
|
assert_equal [[4, 1, 5, 2, 3], {}], obj.foo(4, 5, 2, 3)
|
||||||
|
assert_equal [[4, 1, 5], {a: 1}], obj.foo(4, 5, 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){|args, kws| [args, kws]}
|
||||||
|
end
|
||||||
|
|
||||||
def test_rightward_assign
|
def test_rightward_assign
|
||||||
assert_equal(1, eval("1 => a"))
|
assert_equal(1, eval("1 => a"))
|
||||||
assert_equal([2,3], eval("13.divmod(5) => a,b; [a, b]"))
|
assert_equal([2,3], eval("13.divmod(5) => a,b; [a, b]"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user