Skip to content

Commit 071c6d1

Browse files
nobukddnewton
authored andcommitted
[PRISM] [Feature #19979] Method definition with &nil
1 parent 116d402 commit 071c6d1

6 files changed

Lines changed: 104 additions & 32 deletions

File tree

lib/prism/node_ext.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,13 @@ def signature
316316
names << [:nokey]
317317
end
318318

319-
names << [:block, block.name || :&] if block
319+
case block
320+
when BlockParameterNode
321+
names << [:block, block.name || :&]
322+
when NoBlockParameterNode
323+
names << [:noblock]
324+
end
325+
320326
names
321327
end
322328
end

prism/config.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3920,6 +3920,18 @@ nodes:
39203920
39213921
nil
39223922
^^^
3923+
- name: NoBlockParameterNode
3924+
fields:
3925+
- name: operator_loc
3926+
type: location
3927+
- name: keyword_loc
3928+
type: location
3929+
comment: |
3930+
Represents the use of `&nil` inside method arguments.
3931+
3932+
def a(&nil)
3933+
^^^^
3934+
end
39233935
- name: NoKeywordsParameterNode
39243936
fields:
39253937
- name: operator_loc
@@ -4066,7 +4078,9 @@ nodes:
40664078
- NoKeywordsParameterNode
40674079
- name: block
40684080
type: node?
4069-
kind: BlockParameterNode
4081+
kind:
4082+
- BlockParameterNode
4083+
- NoBlockParameterNode
40704084
comment: |
40714085
Represents the list of parameters on a method, block, or lambda definition.
40724086

prism/prism.c

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5558,6 +5558,24 @@ pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
55585558
return node;
55595559
}
55605560

5561+
/**
5562+
* Allocate and initialize a new NoKeywordsParameterNode node.
5563+
*/
5564+
static pm_no_block_parameter_node_t *
5565+
pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5566+
assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5567+
assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5568+
pm_no_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_block_parameter_node_t);
5569+
5570+
*node = (pm_no_block_parameter_node_t) {
5571+
.base = PM_NODE_INIT(parser, PM_NO_BLOCK_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, operator, keyword)),
5572+
.operator_loc = TOK2LOC(parser, operator),
5573+
.keyword_loc = TOK2LOC(parser, keyword)
5574+
};
5575+
5576+
return node;
5577+
}
5578+
55615579
/**
55625580
* Allocate and initialize a new NoKeywordsParameterNode node.
55635581
*/
@@ -5787,9 +5805,9 @@ pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *par
57875805
* Set the block parameter on a ParametersNode node.
57885806
*/
57895807
static void
5790-
pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
5808+
pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
57915809
assert(params->block == NULL);
5792-
pm_parameters_node_location_set(params, UP(param));
5810+
pm_parameters_node_location_set(params, param);
57935811
params->block = param;
57945812
}
57955813

@@ -13929,26 +13947,33 @@ parse_parameters(
1392913947
parser_lex(parser);
1393013948

1393113949
pm_token_t operator = parser->previous;
13932-
pm_token_t name = { 0 };
13950+
pm_node_t *param;
1393313951

13934-
bool repeated = false;
13935-
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13936-
name = parser->previous;
13937-
repeated = pm_parser_parameter_name_check(parser, &name);
13938-
pm_parser_local_add_token(parser, &name, 1);
13952+
if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
13953+
param = (pm_node_t *) pm_no_block_parameter_node_create(parser, &operator, &parser->previous);
1393913954
} else {
13940-
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
13941-
}
13955+
pm_token_t name = {0};
1394213956

13943-
pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
13944-
if (repeated) {
13945-
pm_node_flag_set_repeated_parameter(UP(param));
13957+
bool repeated = false;
13958+
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13959+
name = parser->previous;
13960+
repeated = pm_parser_parameter_name_check(parser, &name);
13961+
pm_parser_local_add_token(parser, &name, 1);
13962+
} else {
13963+
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
13964+
}
13965+
13966+
param = (pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
13967+
if (repeated) {
13968+
pm_node_flag_set_repeated_parameter(param);
13969+
}
1394613970
}
13971+
1394713972
if (params->block == NULL) {
1394813973
pm_parameters_node_block_set(params, param);
1394913974
} else {
13950-
pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13951-
pm_parameters_node_posts_append(params, UP(param));
13975+
pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
13976+
pm_parameters_node_posts_append(params, param);
1395213977
}
1395313978

1395413979
break;

prism_compile.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4524,6 +4524,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
45244524
case PM_PARAMETERS_NODE:
45254525
case PM_KEYWORD_REST_PARAMETER_NODE:
45264526
case PM_NO_KEYWORDS_PARAMETER_NODE:
4527+
case PM_NO_BLOCK_PARAMETER_NODE:
45274528
case PM_NUMBERED_PARAMETERS_NODE:
45284529
case PM_OPTIONAL_KEYWORD_PARAMETER_NODE:
45294530
case PM_OPTIONAL_PARAMETER_NODE:
@@ -6340,7 +6341,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
63406341
}
63416342
}
63426343

6343-
if (parameters_node && parameters_node->block) {
6344+
if (parameters_node && parameters_node->block && PM_NODE_TYPE_P(parameters_node->block, PM_BLOCK_PARAMETER_NODE)) {
63446345
const pm_block_parameter_node_t *block_node = (const pm_block_parameter_node_t *) parameters_node->block;
63456346

63466347
if (PM_NODE_FLAG_P(block_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER) || !block_node->name) {
@@ -6686,26 +6687,38 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
66866687
// def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
66876688
// ^^
66886689
if (parameters_node->block) {
6689-
body->param.block_start = local_index;
6690-
body->param.flags.has_block = true;
6691-
iseq_set_use_block(iseq);
6690+
switch (PM_NODE_TYPE(parameters_node->block)) {
6691+
case PM_BLOCK_PARAMETER_NODE: {
6692+
body->param.block_start = local_index;
6693+
body->param.flags.has_block = true;
66926694

6693-
pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
6695+
iseq_set_use_block(iseq);
66946696

6695-
if (name) {
6696-
if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
6697-
ID local = pm_constant_id_lookup(scope_node, name);
6698-
local_table_for_iseq->ids[local_index] = local;
6697+
pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
6698+
6699+
if (name) {
6700+
if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
6701+
ID local = pm_constant_id_lookup(scope_node, name);
6702+
local_table_for_iseq->ids[local_index] = local;
6703+
}
6704+
else {
6705+
pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
6706+
}
66996707
}
67006708
else {
6701-
pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
6709+
pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
67026710
}
6703-
}
6704-
else {
6705-
pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
6706-
}
67076711

6708-
local_index++;
6712+
local_index++;
6713+
break;
6714+
}
6715+
case PM_NO_BLOCK_PARAMETER_NODE: {
6716+
body->param.flags.accepts_no_block = true;
6717+
break;
6718+
}
6719+
default:
6720+
rb_bug("node type %s not expected as block parameter", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->block)));
6721+
}
67096722
}
67106723
}
67116724

@@ -9955,6 +9968,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
99559968

99569969
return;
99579970
}
9971+
case PM_NO_BLOCK_PARAMETER_NODE: {
9972+
// def foo(&nil); end
9973+
// ^^^^
9974+
ISEQ_BODY(iseq)->param.flags.accepts_no_block = TRUE;
9975+
return;
9976+
}
99589977
case PM_NO_KEYWORDS_PARAMETER_NODE: {
99599978
// def foo(**nil); end
99609979
// ^^^^^

test/prism/result/source_location_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,10 @@ def test_NilNode
650650
assert_location(NilNode, "nil")
651651
end
652652

653+
def test_NoBlockParameterNode
654+
assert_location(NoBlockParameterNode, "def foo(&nil); end", 8...12) { |node| node.parameters.block }
655+
end
656+
653657
def test_NoKeywordsParameterNode
654658
assert_location(NoKeywordsParameterNode, "def foo(**nil); end", 8...13) { |node| node.parameters.keyword_rest }
655659
end

test/prism/ruby/parameters_signature_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ def test_nokey
5050
assert_parameters([[:nokey]], "**nil")
5151
end
5252

53+
def test_noblock
54+
assert_parameters([[:noblock]], "&nil")
55+
end
56+
5357
def test_keyrest_anonymous
5458
assert_parameters([[:keyrest, :**]], "**")
5559
end

0 commit comments

Comments
 (0)