Skip to content

Commit b1b9bbd

Browse files
nobuparacycle
authored andcommitted
[PRISM] [Feature #19979] Method definition with &nil
1 parent 3a85dc8 commit b1b9bbd

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
@@ -3919,6 +3919,18 @@ nodes:
39193919
39203920
nil
39213921
^^^
3922+
- name: NoBlockParameterNode
3923+
fields:
3924+
- name: operator_loc
3925+
type: location
3926+
- name: keyword_loc
3927+
type: location
3928+
comment: |
3929+
Represents the use of `&nil` inside method arguments.
3930+
3931+
def a(&nil)
3932+
^^^^
3933+
end
39223934
- name: NoKeywordsParameterNode
39233935
fields:
39243936
- name: operator_loc
@@ -4065,7 +4077,9 @@ nodes:
40654077
- NoKeywordsParameterNode
40664078
- name: block
40674079
type: node?
4068-
kind: BlockParameterNode
4080+
kind:
4081+
- BlockParameterNode
4082+
- NoBlockParameterNode
40694083
comment: |
40704084
Represents the list of parameters on a method, block, or lambda definition.
40714085

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

@@ -13915,26 +13933,33 @@ parse_parameters(
1391513933
parser_lex(parser);
1391613934

1391713935
pm_token_t operator = parser->previous;
13918-
pm_token_t name = { 0 };
13936+
pm_node_t *param;
1391913937

13920-
bool repeated = false;
13921-
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13922-
name = parser->previous;
13923-
repeated = pm_parser_parameter_name_check(parser, &name);
13924-
pm_parser_local_add_token(parser, &name, 1);
13938+
if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
13939+
param = (pm_node_t *) pm_no_block_parameter_node_create(parser, &operator, &parser->previous);
1392513940
} else {
13926-
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
13927-
}
13941+
pm_token_t name = {0};
1392813942

13929-
pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
13930-
if (repeated) {
13931-
pm_node_flag_set_repeated_parameter(UP(param));
13943+
bool repeated = false;
13944+
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13945+
name = parser->previous;
13946+
repeated = pm_parser_parameter_name_check(parser, &name);
13947+
pm_parser_local_add_token(parser, &name, 1);
13948+
} else {
13949+
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
13950+
}
13951+
13952+
param = (pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
13953+
if (repeated) {
13954+
pm_node_flag_set_repeated_parameter(param);
13955+
}
1393213956
}
13957+
1393313958
if (params->block == NULL) {
1393413959
pm_parameters_node_block_set(params, param);
1393513960
} else {
13936-
pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13937-
pm_parameters_node_posts_append(params, UP(param));
13961+
pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
13962+
pm_parameters_node_posts_append(params, param);
1393813963
}
1393913964

1394013965
break;

prism_compile.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4521,6 +4521,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
45214521
case PM_PARAMETERS_NODE:
45224522
case PM_KEYWORD_REST_PARAMETER_NODE:
45234523
case PM_NO_KEYWORDS_PARAMETER_NODE:
4524+
case PM_NO_BLOCK_PARAMETER_NODE:
45244525
case PM_NUMBERED_PARAMETERS_NODE:
45254526
case PM_OPTIONAL_KEYWORD_PARAMETER_NODE:
45264527
case PM_OPTIONAL_PARAMETER_NODE:
@@ -6337,7 +6338,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
63376338
}
63386339
}
63396340

6340-
if (parameters_node && parameters_node->block) {
6341+
if (parameters_node && parameters_node->block && PM_NODE_TYPE_P(parameters_node->block, PM_BLOCK_PARAMETER_NODE)) {
63416342
const pm_block_parameter_node_t *block_node = (const pm_block_parameter_node_t *) parameters_node->block;
63426343

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

6690-
pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
6692+
iseq_set_use_block(iseq);
66916693

6692-
if (name) {
6693-
if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
6694-
ID local = pm_constant_id_lookup(scope_node, name);
6695-
local_table_for_iseq->ids[local_index] = local;
6694+
pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
6695+
6696+
if (name) {
6697+
if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
6698+
ID local = pm_constant_id_lookup(scope_node, name);
6699+
local_table_for_iseq->ids[local_index] = local;
6700+
}
6701+
else {
6702+
pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
6703+
}
66966704
}
66976705
else {
6698-
pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
6706+
pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
66996707
}
6700-
}
6701-
else {
6702-
pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
6703-
}
67046708

6705-
local_index++;
6709+
local_index++;
6710+
break;
6711+
}
6712+
case PM_NO_BLOCK_PARAMETER_NODE: {
6713+
body->param.flags.accepts_no_block = true;
6714+
break;
6715+
}
6716+
default:
6717+
rb_bug("node type %s not expected as block parameter", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->block)));
6718+
}
67066719
}
67076720
}
67086721

@@ -9952,6 +9965,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
99529965

99539966
return;
99549967
}
9968+
case PM_NO_BLOCK_PARAMETER_NODE: {
9969+
// def foo(&nil); end
9970+
// ^^^^
9971+
ISEQ_BODY(iseq)->param.flags.accepts_no_block = TRUE;
9972+
return;
9973+
}
99559974
case PM_NO_KEYWORDS_PARAMETER_NODE: {
99569975
// def foo(**nil); end
99579976
// ^^^^^

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)