Skip to content

Commit 2870b7d

Browse files
Earlopainmatzbot
authored andcommitted
[ruby/prism] Reject p(p a, &block => value) and similar
They were being parsed as `p((p a, &block) => value)`. When we get to this point, we must not just have parsed a command call, always consuming the `=>` is not correct. Closes [Bug #21622] ruby/prism@796ab0edf4
1 parent 190b017 commit 2870b7d

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

prism/prism.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14232,6 +14232,25 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
1423214232
return contains_keyword_splat;
1423314233
}
1423414234

14235+
static inline bool
14236+
argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) {
14237+
if (pm_symbol_node_label_p(argument)) {
14238+
return true;
14239+
}
14240+
14241+
switch (PM_NODE_TYPE(argument)) {
14242+
case PM_CALL_NODE: {
14243+
pm_call_node_t *cast = (pm_call_node_t *) argument;
14244+
if (cast->opening_loc.start == NULL && cast->arguments != NULL) {
14245+
return false;
14246+
}
14247+
break;
14248+
}
14249+
default: break;
14250+
}
14251+
return accept1(parser, PM_TOKEN_EQUAL_GREATER);
14252+
}
14253+
1423514254
/**
1423614255
* Append an argument to a list of arguments.
1423714256
*/
@@ -14389,7 +14408,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
1438914408
bool contains_keywords = false;
1439014409
bool contains_keyword_splat = false;
1439114410

14392-
if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14411+
if (argument_allowed_for_bare_hash(parser, argument)){
1439314412
if (parsed_bare_hash) {
1439414413
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
1439514414
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
p(p a, x: b => value)
2+
^~ unexpected '=>'; expected a `)` to close the arguments
3+
^ unexpected ')', expecting end-of-input
4+
^ unexpected ')', ignoring it
5+
6+
p(p a, x: => value)
7+
^~ unexpected '=>'; expected a `)` to close the arguments
8+
^ unexpected ')', expecting end-of-input
9+
^ unexpected ')', ignoring it
10+
11+
p(p a, &block => value)
12+
^~ unexpected '=>'; expected a `)` to close the arguments
13+
^ unexpected ')', expecting end-of-input
14+
^ unexpected ')', ignoring it
15+
16+
p(p a, *args => value)
17+
^~ unexpected '=>'; expected a `)` to close the arguments
18+
^ unexpected ')', expecting end-of-input
19+
^ unexpected ')', ignoring it
20+
21+
p(p a, **kwargs => value)
22+
^~ unexpected '=>'; expected a `)` to close the arguments
23+
^ unexpected ')', expecting end-of-input
24+
^ unexpected ')', ignoring it
25+
26+
p p 1, &block => 2, &block
27+
^~ unexpected '=>', expecting end-of-input
28+
^~ unexpected '=>', ignoring it
29+
^ unexpected ',', expecting end-of-input
30+
^ unexpected ',', ignoring it
31+
^ unexpected '&', ignoring it
32+
33+
p p p 1 => 2 => 3 => 4
34+
^~ unexpected '=>', expecting end-of-input
35+
^~ unexpected '=>', ignoring it
36+
37+
p[p a, x: b => value]
38+
^ expected a matching `]`
39+
^ unexpected ']', expecting end-of-input
40+
^ unexpected ']', ignoring it
41+

test/prism/fixtures/command_method_call.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ def foo = bar 1
3939
!foo 1 or !bar 2
4040

4141
not !foo 1
42+
43+
foo(bar baz, key => value)
44+
45+
foo(bar baz, KEY => value)
46+
47+
foo(bar baz, :key => value)

0 commit comments

Comments
 (0)