Make anonymous rest arg (*) and block arg (&) accessible from ARGS node

This commit is contained in:
yui-knk 2022-11-17 23:43:21 +09:00 committed by Yuichiro Kaneko
parent ddd62fadaf
commit f0ce118662
Notes: git 2022-11-18 09:26:01 +00:00
3 changed files with 32 additions and 4 deletions

1
node.h
View file

@ -461,6 +461,7 @@ struct rb_args_info {
NODE *opt_args;
unsigned int no_kwarg: 1;
unsigned int ruby2_keywords: 1;
unsigned int forwarding: 1;
VALUE imemo;
};

11
parse.y
View file

@ -5322,6 +5322,9 @@ args_tail : f_kwarg ',' f_kwrest opt_f_block_arg
{
add_forwarding_args(p);
$$ = new_args_tail(p, Qnone, $1, ID2VAL(idFWD_BLOCK), &@1);
/*%%%*/
($$->nd_ainfo)->forwarding = 1;
/*% %*/
}
;
@ -5688,7 +5691,7 @@ f_rest_arg : restarg_mark tIDENTIFIER
{
arg_var(p, ANON_REST_ID);
/*%%%*/
$$ = internal_id(p);
$$ = ANON_REST_ID;
/*% %*/
/*% ripper: rest_param!(Qnil) %*/
}
@ -5710,7 +5713,7 @@ f_block_arg : blkarg_mark tIDENTIFIER
{
arg_var(p, ANON_BLOCK_ID);
/*%%%*/
$$ = internal_id(p);
$$ = ANON_BLOCK_ID;
/*% %*/
/*% ripper: blockarg!(Qnil) %*/
}
@ -12204,7 +12207,7 @@ 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 (args->forwarding) {
if (rest_arg) {
yyerror1(&tail->nd_loc, "... after rest argument");
return tail;
@ -12223,7 +12226,7 @@ new_args(struct parser_params *p, NODE *pre_args, NODE *opt_args, ID rest_arg, N
args->opt_args = opt_args;
args->ruby2_keywords = rest_arg == idFWD_REST;
args->ruby2_keywords = args->forwarding;
p->ruby_sourceline = saved_line;
nd_set_loc(tail, loc);

View file

@ -461,6 +461,30 @@ class TestAst < Test::Unit::TestCase
assert_not_equal(type1, type2)
end
def test_rest_arg
rest_arg = lambda do |arg_str|
node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end")
node = node.children.last.children.last.children[1].children[-4]
end
assert_equal(nil, rest_arg.call(''))
assert_equal(:r, rest_arg.call('*r'))
assert_equal(:r, rest_arg.call('a, *r'))
assert_equal(:*, rest_arg.call('*'))
assert_equal(:*, rest_arg.call('a, *'))
end
def test_block_arg
block_arg = lambda do |arg_str|
node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end")
node = node.children.last.children.last.children[1].children[-1]
end
assert_equal(nil, block_arg.call(''))
assert_equal(:block, block_arg.call('&block'))
assert_equal(:&, block_arg.call('&'))
end
def test_keyword_rest
kwrest = lambda do |arg_str|
node = RubyVM::AbstractSyntaxTree.parse("def a(#{arg_str}) end")