8000 Disallow keywords and blocks in index expressions · ruby/prism@e950dc1 · GitHub
[go: up one dir, main page]

Skip to content

Commit e950dc1

Browse files
committed
Disallow keywords and blocks in index expressions
1 parent 14d9b43 commit e950dc1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+163
-116
lines changed

config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ errors:
250250
- UNARY_RECEIVER
251251
- UNDEF_ARGUMENT
252252
- UNEXPECTED_BLOCK_ARGUMENT
253+
- UNEXPECTED_INDEX_BLOCK
254+
- UNEXPECTED_INDEX_KEYWORDS
253255
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
254256
- UNEXPECTED_TOKEN_IGNORE
255257
- UNTIL_TERM
@@ -620,6 +622,8 @@ tokens:
620622
flags:
621623
- name: ArgumentsNodeFlags
622624
values:
625+
- name: CONTAINS_KEYWORDS
626+
comment: "if arguments contain keywords"
623627
- name: CONTAINS_KEYWORD_SPLAT
624628
comment: "if arguments contain keyword splat"
625629
comment: Flags for arguments nodes.

src/prism.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2943,6 +2943,29 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
29432943
return node;
29442944
}
29452945

2946+
/**
2947+
* Validate that index expressions do not have keywords or blocks if we are
2948+
* parsing as Ruby 3.4+.
2949+
*/
2950+
static void
2951+
pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2952+
if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
2953+
if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2954+
pm_node_t *node;
2955+
PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2956+
if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2957+
pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2958+
break;
2959+
}
2960+
}
2961+
}
2962+
2963+
if (block != NULL) {
2964+
pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2965+
}
2966+
}
2967+
}
2968+
29462969
/**
29472970
* Allocate and initialize a new IndexAndWriteNode node.
29482971
*/
@@ -2951,6 +2974,8 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons
29512974
assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
29522975
pm_index_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_and_write_node_t);
29532976

2977+
pm_index_arguments_check(parser, target->arguments, target->block);
2978+
29542979
*node = (pm_index_and_write_node_t) {
29552980
{
29562981
.type = PM_INDEX_AND_WRITE_NODE,
@@ -3022,6 +3047,8 @@ static pm_index_operator_write_node_t *
30223047
pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
30233048
pm_index_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_operator_write_node_t);
30243049

3050+
pm_index_arguments_check(parser, target->arguments, target->block);
3051+
30253052
*node = (pm_index_operator_write_node_t) {
30263053
{
30273054
.type = PM_INDEX_OPERATOR_WRITE_NODE,
@@ -3095,6 +3122,8 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
30953122
assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
30963123
pm_index_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_or_write_node_t);
30973124

3125+
pm_index_arguments_check(parser, target->arguments, target->block);
3126+
30983127
*node = (pm_index_or_write_node_t) {
30993128
{
31003129
.type = PM_INDEX_OR_WRITE_NODE,
@@ -3159,6 +3188,8 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
31593188
pm_index_target_node_t *node = PM_ALLOC_NODE(parser, pm_index_target_node_t);
31603189
pm_node_flags_t flags = target->base.flags;
31613190

3191+
pm_index_arguments_check(parser, target->arguments, target->block);
3192+
31623193
*node = (pm_index_target_node_t) {
31633194
{
31643195
.type = PM_INDEX_TARGET_NODE,
@@ -13733,9 +13764,10 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
1373313764
bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash);
1373413765

1373513766
parse_arguments_append(parser, arguments, argument);
13736-
if (contains_keyword_splat) {
13737-
pm_node_flag_set((pm_node_t *) arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
13738-
}
13767+
13768+
pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13769+
if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13770+
pm_node_flag_set((pm_node_t *) arguments->arguments, flags);
1373913771

1374013772
pm_static_literals_free(&hash_keys);
1374113773
parsed_bare_hash = true;
@@ -13813,7 +13845,9 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
1381313845
argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, PM_ERR_EXPECT_ARGUMENT);
1381413846
}
1381513847

13848+
bool contains_keywords = false;
1381613849
bool contains_keyword_splat = false;
13850+
1381713851
if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
1381813852
if (parsed_bare_hash) {
1381913853
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
@@ -13827,6 +13861,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
1382713861
}
1382813862

1382913863
pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
13864+
contains_keywords = true;
1383013865

1383113866
// Create the set of static literals for this hash.
1383213867
pm_static_literals_t hash_keys = { 0 };
@@ -13855,9 +13890,12 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
1385513890
}
1385613891

1385713892
parse_arguments_append(parser, arguments, argument);
13858-
if (contains_keyword_splat) {
13859-
pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
13860-
}
13893+
13894+
pm_node_flags_t flags = 0;
13895+
if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13896+
if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13897+
pm_node_flag_set((pm_node_t *) arguments->arguments, flags);
13898+
1386113899
break;
1386213900
}
1386313901
}

templates/src/diagnostic.c.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
332332
[PM_ERR_UNDEF_ARGUMENT] = { "invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", PM_ERROR_LEVEL_SYNTAX },
333333
[PM_ERR_UNARY_RECEIVER] = { "unexpected %s, expected a receiver for unary `%c`", PM_ERROR_LEVEL_SYNTAX },
334334
[PM_ERR_UNEXPECTED_BLOCK_ARGUMENT] = { "block argument should not be given", PM_ERROR_LEVEL_SYNTAX },
335+
[PM_ERR_UNEXPECTED_INDEX_BLOCK] = { "unexpected block arg given in index; blocks are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
336+
[PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index; keywords are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
335337
[PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
336338
[PM_ERR_UNEXPECTED_TOKEN_IGNORE] = { "unexpected %s, ignoring it", PM_ERROR_LEVEL_SYNTAX },
337339
[PM_ERR_UNTIL_TERM] = { "expected an `end` to close the `until` statement", PM_ERROR_LEVEL_SYNTAX },

test/prism/errors_test.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,13 @@ def test_double_splat_followed_by_splat_argument
378378
:a,
379379
Location(),
380380
Location(),
381-
ArgumentsNode(1, [
382-
KeywordHashNode(0, [AssocSplatNode(expression("kwargs"), Location())]),
383-
SplatNode(Location(), expression("args"))
384-
]),
381+
ArgumentsNode(
382+
ArgumentsNodeFlags::CONTAINS_KEYWORDS | ArgumentsNodeFlags::CONTAINS_KEYWORD_SPLAT,
383+
[
384+
KeywordHashNode(0, [AssocSplatNode(expression("kwargs"), Location())]),
385+
SplatNode(Location(), expression("args"))
386+
]
387+
),
385388
Location(),
386389
nil
387390
)
@@ -425,7 +428,7 @@ def test_splat_argument_after_keyword_argument
425428
:a,
426429
Location(),
427430
Location(),
428-
ArgumentsNode(0, [
431+
ArgumentsNode(ArgumentsNodeFlags::CONTAINS_KEYWORDS, [
429432
KeywordHashNode(1, [
430433
AssocNode(
431434
SymbolNode(SymbolFlags::FORCED_US_ASCII_ENCODING, nil, Location(), Location(), "foo"),

test/prism/index_write_test.rb

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,41 @@ def foo(&)
4040
RUBY
4141
end
4242

43-
# def test_keywords_latest
44-
# assert_parse_failure(<<~RUBY)
45-
# foo[bar: 1] = 1
46-
# foo[bar: 1] &&= 1
47-
# foo[bar: 1] ||= 1
48-
# foo[bar: 1] += 1
49-
# RUBY
43+
def test_keywords_latest
44+
assert_parse_failure(<<~RUBY)
45+
foo[bar: 1] = 1
46+
foo[bar: 1] &&= 1
47+
foo[bar: 1] ||= 1
48+
foo[bar: 1] += 1
49+
RUBY
5050

51-
# assert_parse_failure(<<~RUBY)
52-
# def foo(**)
53-
# bar[**] = 1
54-
# bar[**] &&= 1
55-
# bar[**] ||= 1
56-
# bar[**] += 1
57-
# end
58-
# RUBY
59-
# end
51+
assert_parse_failure(<<~RUBY)
52+
def foo(**)
53+
bar[**] = 1
54+
bar[**] &&= 1
55+
bar[**] ||= 1
56+
bar[**] += 1
57+
end
58+
RUBY
59+
end
6060

61-
# def test_block_latest
62-
# assert_parse_failure(<<~RUBY)
63-
# foo[&bar] = 1
64-
# foo[&bar] &&= 1
65-
# foo[&bar] ||= 1
66-
# foo[&bar] += 1
67-
# RUBY
61+
def test_block_latest
62+
assert_parse_failure(<<~RUBY)
63+
foo[&bar] = 1
64+
foo[&bar] &&= 1
65+
foo[&bar] ||= 1
66+
foo[&bar] += 1
67+
RUBY
6868

69-
# assert_parse_failure(<<~RUBY)
70-
# def foo(&)
71-
# bar[&] = 1
72-
# bar[&] &&= 1
73-
# bar[&] ||= 1
74-
# bar[&] += 1
75-
# end
76-
# RUBY
77-
# end
69+
assert_parse_failure(<<~RUBY)
70+
def foo(&)
71+
bar[&] = 1
72+
bar[&] &&= 1
73+
bar[&] ||= 1
74+
bar[&] += 1
75+
end
76+
RUBY
77+
end
7878

7979
private
8080

test/prism/location_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ def test_IndexOrWriteNode
477477
end
478478

479479
def test_IndexTargetNode
480-
assert_location(IndexTargetNode, "foo[bar, &baz], = qux", 0...14) do |node|
480+
assert_location(IndexTargetNode, "foo[bar], = qux", 0...8) do |node|
481481
node.lefts.first
482482
end
48 6EEB 3483
end

test/prism/snapshots/constants.txt

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/prism/snapshots/if.txt

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0