From 48b403ea7974927485ae34df6f6900a7660b6b84 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 1 Dec 2025 21:13:25 +0100 Subject: [PATCH] Reject `p(p a, &block => value)` and similar Redo of https://github.com/ruby/prism/pull/3669 with more tests --- snapshots/command_method_call_3.txt | 543 ++++++++++++++++++ src/prism.c | 26 +- test/prism/errors/command_calls_35.txt | 46 ++ test/prism/fixtures/command_method_call_3.txt | 19 + 4 files changed, 633 insertions(+), 1 deletion(-) create mode 100644 snapshots/command_method_call_3.txt create mode 100644 test/prism/errors/command_calls_35.txt create mode 100644 test/prism/fixtures/command_method_call_3.txt diff --git a/snapshots/command_method_call_3.txt b/snapshots/command_method_call_3.txt new file mode 100644 index 0000000000..e004f875de --- /dev/null +++ b/snapshots/command_method_call_3.txt @@ -0,0 +1,543 @@ +@ ProgramNode (location: (1,0)-(19,25)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(19,25)) + ├── flags: ∅ + └── body: (length: 10) + ├── @ CallNode (location: (1,0)-(1,22)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (1,0)-(1,3) = "foo" + │ ├── opening_loc: (1,3)-(1,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (1,4)-(1,21)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ CallNode (location: (1,4)-(1,21)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :bar + │ │ ├── message_loc: (1,4)-(1,7) = "bar" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (1,8)-(1,21)) + │ │ │ ├── flags: contains_keywords + │ │ │ └── arguments: (length: 2) + │ │ │ ├── @ IntegerNode (location: (1,8)-(1,9)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ └── @ KeywordHashNode (location: (1,11)-(1,21)) + │ │ │ ├── flags: ∅ + │ │ │ └── elements: (length: 1) + │ │ │ └── @ AssocNode (location: (1,11)-(1,21)) + │ │ │ ├── flags: ∅ + │ │ │ ├── key: + │ │ │ │ @ CallNode (location: (1,11)-(1,14)) + │ │ │ │ ├── flags: variable_call, ignore_visibility + │ │ │ │ ├── receiver: ∅ + │ │ │ │ ├── call_operator_loc: ∅ + │ │ │ │ ├── name: :key + │ │ │ │ ├── message_loc: (1,11)-(1,14) = "key" + │ │ │ │ ├── opening_loc: ∅ + │ │ │ │ ├── arguments: ∅ + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ ├── equal_loc: ∅ + │ │ │ │ └── block: ∅ + │ │ │ ├── value: + │ │ │ │ @ StringNode (location: (1,18)-(1,21)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (1,18)-(1,19) = "'" + │ │ │ │ ├── content_loc: (1,19)-(1,20) = "2" + │ │ │ │ ├── closing_loc: (1,20)-(1,21) = "'" + │ │ │ │ └── unescaped: "2" + │ │ │ └── operator_loc: (1,15)-(1,17) = "=>" + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: ∅ + │ ├── closing_loc: (1,21)-(1,22) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (3,0)-(3,22)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (3,0)-(3,3) = "foo" + │ ├── opening_loc: (3,3)-(3,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (3,4)-(3,21)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ CallNode (location: (3,4)-(3,21)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :bar + │ │ ├── message_loc: (3,4)-(3,7) = "bar" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (3,8)-(3,21)) + │ │ │ ├── flags: contains_keywords + │ │ │ └── arguments: (length: 2) + │ │ │ ├── @ IntegerNode (location: (3,8)-(3,9)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ └── @ KeywordHashNode (location: (3,11)-(3,21)) + │ │ │ ├── flags: ∅ + │ │ │ └── elements: (length: 1) + │ │ │ └── @ AssocNode (location: (3,11)-(3,21)) + │ │ │ ├── flags: ∅ + │ │ │ ├── key: + │ │ │ │ @ ConstantReadNode (location: (3,11)-(3,14)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ └── name: :KEY + │ │ │ ├── value: + │ │ │ │ @ StringNode (location: (3,18)-(3,21)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (3,18)-(3,19) = "'" + │ │ │ │ ├── content_loc: (3,19)-(3,20) = "2" + │ │ │ │ ├── closing_loc: (3,20)-(3,21) = "'" + │ │ │ │ └── unescaped: "2" + │ │ │ └── operator_loc: (3,15)-(3,17) = "=>" + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: ∅ + │ ├── closing_loc: (3,21)-(3,22) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (5,0)-(5,23)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (5,0)-(5,3) = "foo" + │ ├── opening_loc: (5,3)-(5,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (5,4)-(5,22)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ CallNode (location: (5,4)-(5,22)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :bar + │ │ ├── message_loc: (5,4)-(5,7) = "bar" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (5,8)-(5,22)) + │ │ │ ├── flags: contains_keywords + │ │ │ └── arguments: (length: 2) + │ │ │ ├── @ IntegerNode (location: (5,8)-(5,9)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ └── @ KeywordHashNode (location: (5,11)-(5,22)) + │ │ │ ├── flags: symbol_keys + │ │ │ └── elements: (length: 1) + │ │ │ └── @ AssocNode (location: (5,11)-(5,22)) + │ │ │ ├── flags: ∅ + │ │ │ ├── key: + │ │ │ │ @ SymbolNode (location: (5,11)-(5,15)) + │ │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ │ ├── opening_loc: (5,11)-(5,12) = ":" + │ │ │ │ ├── value_loc: (5,12)-(5,15) = "key" + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ └── unescaped: "key" + │ │ │ ├── value: + │ │ │ │ @ StringNode (location: (5,19)-(5,22)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (5,19)-(5,20) = "'" + │ │ │ │ ├── content_loc: (5,20)-(5,21) = "2" + │ │ │ │ ├── closing_loc: (5,21)-(5,22) = "'" + │ │ │ │ └── unescaped: "2" + │ │ │ └── operator_loc: (5,16)-(5,18) = "=>" + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: ∅ + │ ├── closing_loc: (5,22)-(5,23) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (7,0)-(7,32)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (7,0)-(7,3) = "foo" + │ ├── opening_loc: (7,3)-(7,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (7,4)-(7,31)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ CallNode (location: (7,4)-(7,31)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :bar + │ │ ├── message_loc: (7,4)-(7,7) = "bar" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (7,8)-(7,31)) + │ │ │ ├── flags: contains_keywords + │ │ │ └── arguments: (length: 2) + │ │ │ ├── @ IntegerNode (location: (7,8)-(7,9)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ └── @ KeywordHashNode (location: (7,11)-(7,31)) + │ │ │ ├── flags: ∅ + │ │ │ └── elements: (length: 1) + │ │ │ └── @ AssocNode (location: (7,11)-(7,31)) + │ │ │ ├── flags: ∅ + │ │ │ ├── key: + │ │ │ │ @ HashNode (location: (7,11)-(7,24)) + │ │ │ │ ├── flags: static_literal + │ │ │ │ ├── opening_loc: (7,11)-(7,12) = "{" + │ │ │ │ ├── elements: (length: 1) + │ │ │ │ │ └── @ AssocNode (location: (7,13)-(7,22)) + │ │ │ │ │ ├── flags: static_literal + │ │ │ │ │ ├── key: + │ │ │ │ │ │ @ SymbolNode (location: (7,13)-(7,17)) + │ │ │ │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ │ │ │ ├── opening_loc: ∅ + │ │ │ │ │ │ ├── value_loc: (7,13)-(7,16) = "baz" + │ │ │ │ │ │ ├── closing_loc: (7,16)-(7,17) = ":" + │ │ │ │ │ │ └── unescaped: "baz" + │ │ │ │ │ ├── value: + │ │ │ │ │ │ @ SymbolNode (location: (7,18)-(7,22)) + │ │ │ │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ │ │ │ ├── opening_loc: (7,18)-(7,19) = ":" + │ │ │ │ │ │ ├── value_loc: (7,19)-(7,22) = "bat" + │ │ │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ │ │ └── unescaped: "bat" + │ │ │ │ │ └── operator_loc: ∅ + │ │ │ │ └── closing_loc: (7,23)-(7,24) = "}" + │ │ │ ├── value: + │ │ │ │ @ StringNode (location: (7,28)-(7,31)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (7,28)-(7,29) = "'" + │ │ │ │ ├── content_loc: (7,29)-(7,30) = "2" + │ │ │ │ ├── closing_loc: (7,30)-(7,31) = "'" + │ │ │ │ └── unescaped: "2" + │ │ │ └── operator_loc: (7,25)-(7,27) = "=>" + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: ∅ + │ ├── closing_loc: (7,31)-(7,32) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (9,0)-(9,24)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (9,0)-(9,3) = "foo" + │ ├── opening_loc: ∅ + │ ├── arguments: + │ │ @ ArgumentsNode (location: (9,4)-(9,24)) + │ │ ├── flags: contains_keywords + │ │ └── arguments: (length: 1) + │ │ └── @ KeywordHashNode (location: (9,4)-(9,24)) + │ │ ├── flags: ∅ + │ │ └── elements: (length: 1) + │ │ └── @ AssocNode (location: (9,4)-(9,24)) + │ │ ├── flags: ∅ + │ │ ├── key: + │ │ │ @ CallNode (location: (9,4)-(9,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── receiver: + │ │ │ │ @ CallNode (location: (9,4)-(9,7)) + │ │ │ │ ├── flags: variable_call, ignore_visibility + │ │ │ │ ├── receiver: ∅ + │ │ │ │ ├── call_operator_loc: ∅ + │ │ │ │ ├── name: :bar + │ │ │ │ ├── message_loc: (9,4)-(9,7) = "bar" + │ │ │ │ ├── opening_loc: ∅ + │ │ │ │ ├── arguments: ∅ + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ ├── equal_loc: ∅ + │ │ │ │ └── block: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :- + │ │ │ ├── message_loc: (9,8)-(9,9) = "-" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: + │ │ │ │ @ ArgumentsNode (location: (9,10)-(9,17)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ └── arguments: (length: 1) + │ │ │ │ └── @ ArrayNode (location: (9,10)-(9,17)) + │ │ │ │ ├── flags: static_literal + │ │ │ │ ├── elements: (length: 1) + │ │ │ │ │ └── @ SymbolNode (location: (9,13)-(9,16)) + │ │ │ │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ │ │ │ ├── opening_loc: ∅ + │ │ │ │ │ ├── value_loc: (9,13)-(9,16) = "baz" + │ │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ │ └── unescaped: "baz" + │ │ │ │ ├── opening_loc: (9,10)-(9,13) = "%i[" + │ │ │ │ └── closing_loc: (9,16)-(9,17) = "]" + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── equal_loc: ∅ + │ │ │ └── block: ∅ + │ │ ├── value: + │ │ │ @ StringNode (location: (9,21)-(9,24)) + │ │ │ ├── flags: ∅ + │ │ │ ├── opening_loc: (9,21)-(9,22) = "'" + │ │ │ ├── content_loc: (9,22)-(9,23) = "2" + │ │ │ ├── closing_loc: (9,23)-(9,24) = "'" + │ │ │ └── unescaped: "2" + │ │ └── operator_loc: (9,18)-(9,20) = "=>" + │ ├── closing_loc: ∅ + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (11,0)-(11,18)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (11,0)-(11,3) = "foo" + │ ├── opening_loc: (11,3)-(11,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (11,4)-(11,17)) + │ │ ├── flags: contains_keywords + │ │ └── arguments: (length: 1) + │ │ └── @ KeywordHashNode (location: (11,4)-(11,17)) + │ │ ├── flags: ∅ + │ │ └── elements: (length: 1) + │ │ └── @ AssocNode (location: (11,4)-(11,17)) + │ │ ├── flags: ∅ + │ │ ├── key: + │ │ │ @ CallNode (location: (11,4)-(11,10)) + │ │ │ ├── flags: ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :bar + │ │ │ ├── message_loc: (11,4)-(11,7) = "bar" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── equal_loc: ∅ + │ │ │ └── block: + │ │ │ @ BlockNode (location: (11,8)-(11,10)) + │ │ │ ├── flags: ∅ + │ │ │ ├── locals: [] + │ │ │ ├── parameters: ∅ + │ │ │ ├── body: ∅ + │ │ │ ├── opening_loc: (11,8)-(11,9) = "{" + │ │ │ └── closing_loc: (11,9)-(11,10) = "}" + │ │ ├── value: + │ │ │ @ StringNode (location: (11,14)-(11,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── opening_loc: (11,14)-(11,15) = "'" + │ │ │ ├── content_loc: (11,15)-(11,16) = "2" + │ │ │ ├── closing_loc: (11,16)-(11,17) = "'" + │ │ │ └── unescaped: "2" + │ │ └── operator_loc: (11,11)-(11,13) = "=>" + │ ├── closing_loc: (11,17)-(11,18) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (13,0)-(13,22)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (13,0)-(13,3) = "foo" + │ ├── opening_loc: (13,3)-(13,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (13,4)-(13,21)) + │ │ ├── flags: ∅ + │ │ └── arguments: (length: 1) + │ │ └── @ CallNode (location: (13,4)-(13,21)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :bar + │ │ ├── message_loc: (13,4)-(13,7) = "bar" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (13,8)-(13,21)) + │ │ │ ├── flags: contains_keywords + │ │ │ └── arguments: (length: 1) + │ │ │ └── @ KeywordHashNode (location: (13,8)-(13,21)) + │ │ │ ├── flags: ∅ + │ │ │ └── elements: (length: 1) + │ │ │ └── @ AssocNode (location: (13,8)-(13,21)) + │ │ │ ├── flags: ∅ + │ │ │ ├── key: + │ │ │ │ @ CallNode (location: (13,8)-(13,14)) + │ │ │ │ ├── flags: ignore_visibility + │ │ │ │ ├── receiver: ∅ + │ │ │ │ ├── call_operator_loc: ∅ + │ │ │ │ ├── name: :baz + │ │ │ │ ├── message_loc: (13,8)-(13,11) = "baz" + │ │ │ │ ├── opening_loc: ∅ + │ │ │ │ ├── arguments: ∅ + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ ├── equal_loc: ∅ + │ │ │ │ └── block: + │ │ │ │ @ BlockNode (location: (13,12)-(13,14)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── locals: [] + │ │ │ │ ├── parameters: ∅ + │ │ │ │ ├── body: ∅ + │ │ │ │ ├── opening_loc: (13,12)-(13,13) = "{" + │ │ │ │ └── closing_loc: (13,13)-(13,14) = "}" + │ │ │ ├── value: + │ │ │ │ @ StringNode (location: (13,18)-(13,21)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (13,18)-(13,19) = "'" + │ │ │ │ ├── content_loc: (13,19)-(13,20) = "2" + │ │ │ │ ├── closing_loc: (13,20)-(13,21) = "'" + │ │ │ │ └── unescaped: "2" + │ │ │ └── operator_loc: (13,15)-(13,17) = "=>" + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: ∅ + │ ├── closing_loc: (13,21)-(13,22) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (15,0)-(15,22)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (15,0)-(15,3) = "foo" + │ ├── opening_loc: (15,3)-(15,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (15,4)-(15,21)) + │ │ ├── flags: contains_keywords + │ │ └── arguments: (length: 1) + │ │ └── @ KeywordHashNode (location: (15,4)-(15,21)) + │ │ ├── flags: ∅ + │ │ └── elements: (length: 1) + │ │ └── @ AssocNode (location: (15,4)-(15,21)) + │ │ ├── flags: ∅ + │ │ ├── key: + │ │ │ @ CallNode (location: (15,4)-(15,14)) + │ │ │ ├── flags: ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :bar + │ │ │ ├── message_loc: (15,4)-(15,7) = "bar" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── equal_loc: ∅ + │ │ │ └── block: + │ │ │ @ BlockNode (location: (15,8)-(15,14)) + │ │ │ ├── flags: ∅ + │ │ │ ├── locals: [] + │ │ │ ├── parameters: ∅ + │ │ │ ├── body: ∅ + │ │ │ ├── opening_loc: (15,8)-(15,10) = "do" + │ │ │ └── closing_loc: (15,11)-(15,14) = "end" + │ │ ├── value: + │ │ │ @ StringNode (location: (15,18)-(15,21)) + │ │ │ ├── flags: ∅ + │ │ │ ├── opening_loc: (15,18)-(15,19) = "'" + │ │ │ ├── content_loc: (15,19)-(15,20) = "2" + │ │ │ ├── closing_loc: (15,20)-(15,21) = "'" + │ │ │ └── unescaped: "2" + │ │ └── operator_loc: (15,15)-(15,17) = "=>" + │ ├── closing_loc: (15,21)-(15,22) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + ├── @ CallNode (location: (17,0)-(17,21)) + │ ├── flags: newline, ignore_visibility + │ ├── receiver: ∅ + │ ├── call_operator_loc: ∅ + │ ├── name: :foo + │ ├── message_loc: (17,0)-(17,3) = "foo" + │ ├── opening_loc: (17,3)-(17,4) = "(" + │ ├── arguments: + │ │ @ ArgumentsNode (location: (17,4)-(17,20)) + │ │ ├── flags: contains_keywords + │ │ └── arguments: (length: 2) + │ │ ├── @ IntegerNode (location: (17,4)-(17,5)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ └── @ KeywordHashNode (location: (17,7)-(17,20)) + │ │ ├── flags: ∅ + │ │ └── elements: (length: 1) + │ │ └── @ AssocNode (location: (17,7)-(17,20)) + │ │ ├── flags: ∅ + │ │ ├── key: + │ │ │ @ CallNode (location: (17,7)-(17,13)) + │ │ │ ├── flags: ignore_visibility + │ │ │ ├── receiver: ∅ + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :bar + │ │ │ ├── message_loc: (17,7)-(17,10) = "bar" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: ∅ + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── equal_loc: ∅ + │ │ │ └── block: + │ │ │ @ BlockNode (location: (17,11)-(17,13)) + │ │ │ ├── flags: ∅ + │ │ │ ├── locals: [] + │ │ │ ├── parameters: ∅ + │ │ │ ├── body: ∅ + │ │ │ ├── opening_loc: (17,11)-(17,12) = "{" + │ │ │ └── closing_loc: (17,12)-(17,13) = "}" + │ │ ├── value: + │ │ │ @ StringNode (location: (17,17)-(17,20)) + │ │ │ ├── flags: ∅ + │ │ │ ├── opening_loc: (17,17)-(17,18) = "'" + │ │ │ ├── content_loc: (17,18)-(17,19) = "2" + │ │ │ ├── closing_loc: (17,19)-(17,20) = "'" + │ │ │ └── unescaped: "2" + │ │ └── operator_loc: (17,14)-(17,16) = "=>" + │ ├── closing_loc: (17,20)-(17,21) = ")" + │ ├── equal_loc: ∅ + │ └── block: ∅ + └── @ CallNode (location: (19,0)-(19,25)) + ├── flags: newline, ignore_visibility + ├── receiver: ∅ + ├── call_operator_loc: ∅ + ├── name: :foo + ├── message_loc: (19,0)-(19,3) = "foo" + ├── opening_loc: (19,3)-(19,4) = "(" + ├── arguments: + │ @ ArgumentsNode (location: (19,4)-(19,24)) + │ ├── flags: contains_keywords + │ └── arguments: (length: 2) + │ ├── @ IntegerNode (location: (19,4)-(19,5)) + │ │ ├── flags: static_literal, decimal + │ │ └── value: 1 + │ └── @ KeywordHashNode (location: (19,7)-(19,24)) + │ ├── flags: ∅ + │ └── elements: (length: 1) + │ └── @ AssocNode (location: (19,7)-(19,24)) + │ ├── flags: ∅ + │ ├── key: + │ │ @ CallNode (location: (19,7)-(19,17)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :bar + │ │ ├── message_loc: (19,7)-(19,10) = "bar" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: ∅ + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: + │ │ @ BlockNode (location: (19,11)-(19,17)) + │ │ ├── flags: ∅ + │ │ ├── locals: [] + │ │ ├── parameters: ∅ + │ │ ├── body: ∅ + │ │ ├── opening_loc: (19,11)-(19,13) = "do" + │ │ └── closing_loc: (19,14)-(19,17) = "end" + │ ├── value: + │ │ @ StringNode (location: (19,21)-(19,24)) + │ │ ├── flags: ∅ + │ │ ├── opening_loc: (19,21)-(19,22) = "'" + │ │ ├── content_loc: (19,22)-(19,23) = "2" + │ │ ├── closing_loc: (19,23)-(19,24) = "'" + │ │ └── unescaped: "2" + │ └── operator_loc: (19,18)-(19,20) = "=>" + ├── closing_loc: (19,24)-(19,25) = ")" + ├── equal_loc: ∅ + └── block: ∅ diff --git a/src/prism.c b/src/prism.c index f98032cd73..4c8ab91f0e 100644 --- a/src/prism.c +++ b/src/prism.c @@ -13412,6 +13412,30 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod return contains_keyword_splat; } +static inline bool +argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) { + if (pm_symbol_node_label_p(argument)) { + return true; + } + + switch (PM_NODE_TYPE(argument)) { + case PM_CALL_NODE: { + pm_call_node_t *cast = (pm_call_node_t *) argument; + if (cast->opening_loc.start == NULL && cast->arguments != NULL) { + if (PM_NODE_FLAG_P(cast->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) { + return false; + } + if (cast->block != NULL) { + return false; + } + } + break; + } + default: break; + } + return accept1(parser, PM_TOKEN_EQUAL_GREATER); +} + /** * Append an argument to a list of arguments. */ @@ -13569,7 +13593,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for bool contains_keywords = false; bool contains_keyword_splat = false; - if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) { + if (argument_allowed_for_bare_hash(parser, argument)){ if (parsed_bare_hash) { pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH); } diff --git a/test/prism/errors/command_calls_35.txt b/test/prism/errors/command_calls_35.txt new file mode 100644 index 0000000000..45f569b117 --- /dev/null +++ b/test/prism/errors/command_calls_35.txt @@ -0,0 +1,46 @@ +p(p a, x: b => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, x: => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, &block => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a do end => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, *args => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, **kwargs => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p p 1, &block => 2, &block + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + ^ unexpected ',', expecting end-of-input + ^ unexpected ',', ignoring it + ^ unexpected '&', ignoring it + +p p p 1 => 2 => 3 => 4 + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + +p[p a, x: b => value] + ^ expected a matching `]` + ^ unexpected ']', expecting end-of-input + ^ unexpected ']', ignoring it + diff --git a/test/prism/fixtures/command_method_call_3.txt b/test/prism/fixtures/command_method_call_3.txt new file mode 100644 index 0000000000..6de0446aa9 --- /dev/null +++ b/test/prism/fixtures/command_method_call_3.txt @@ -0,0 +1,19 @@ +foo(bar 1, key => '2') + +foo(bar 1, KEY => '2') + +foo(bar 1, :key => '2') + +foo(bar 1, { baz: :bat } => '2') + +foo bar - %i[baz] => '2' + +foo(bar {} => '2') + +foo(bar baz {} => '2') + +foo(bar do end => '2') + +foo(1, bar {} => '2') + +foo(1, bar do end => '2')