From 70413ed4dd96c92bb71f2b82dbe05d164d0d2e68 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 17 Jul 2025 12:29:40 +0100 Subject: [PATCH] Allow command calls in endless method bodies regardless of context Previously, endless method definitions like `x = def f = p 1` would fail to parse because command calls (method calls without parentheses) were only accepted when the surrounding binding power was less than `PM_BINDING_POWER_COMPOSITION` (8). In assignment contexts with binding power 18, this condition was false, causing parse errors. This fix ensures command calls are always accepted in endless method bodies by passing `true` for `accepts_command_call`, making the method body parse consistently regardless of where the method is defined. --- snapshots/endless_methods.txt | 148 +++++++++++++++--------- src/prism.c | 2 +- test/prism/fixtures/endless_methods.txt | 2 + 3 files changed, 97 insertions(+), 55 deletions(-) diff --git a/snapshots/endless_methods.txt b/snapshots/endless_methods.txt index 29f701ed17..512c87d552 100644 --- a/snapshots/endless_methods.txt +++ b/snapshots/endless_methods.txt @@ -1,10 +1,10 @@ -@ ProgramNode (location: (1,0)-(5,22)) +@ ProgramNode (location: (1,0)-(7,15)) ├── flags: ∅ -├── locals: [] +├── locals: [:x] └── statements: - @ StatementsNode (location: (1,0)-(5,22)) + @ StatementsNode (location: (1,0)-(7,15)) ├── flags: ∅ - └── body: (length: 3) + └── body: (length: 4) ├── @ DefNode (location: (1,0)-(1,11)) │ ├── flags: newline │ ├── name: :foo @@ -61,55 +61,95 @@ │ ├── rparen_loc: ∅ │ ├── equal_loc: (3,8)-(3,9) = "=" │ └── end_keyword_loc: ∅ - └── @ DefNode (location: (5,0)-(5,22)) + ├── @ DefNode (location: (5,0)-(5,22)) + │ ├── flags: newline + │ ├── name: :method + │ ├── name_loc: (5,4)-(5,10) = "method" + │ ├── receiver: ∅ + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (5,13)-(5,22)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ CallNode (location: (5,13)-(5,22)) + │ │ ├── flags: ∅ + │ │ ├── receiver: + │ │ │ @ CallNode (location: (5,13)-(5,18)) + │ │ │ ├── flags: ∅ + │ │ │ ├── receiver: + │ │ │ │ @ IntegerNode (location: (5,13)-(5,14)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 1 + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :+ + │ │ │ ├── message_loc: (5,15)-(5,16) = "+" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: + │ │ │ │ @ ArgumentsNode (location: (5,17)-(5,18)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ └── arguments: (length: 1) + │ │ │ │ └── @ IntegerNode (location: (5,17)-(5,18)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 2 + │ │ │ ├── closing_loc: ∅ + │ │ │ └── block: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :+ + │ │ ├── message_loc: (5,19)-(5,20) = "+" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (5,21)-(5,22)) + │ │ │ ├── flags: ∅ + │ │ │ └── arguments: (length: 1) + │ │ │ └── @ IntegerNode (location: (5,21)-(5,22)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 3 + │ │ ├── closing_loc: ∅ + │ │ └── block: ∅ + │ ├── locals: [] + │ ├── def_keyword_loc: (5,0)-(5,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: ∅ + │ ├── rparen_loc: ∅ + │ ├── equal_loc: (5,11)-(5,12) = "=" + │ └── end_keyword_loc: ∅ + └── @ LocalVariableWriteNode (location: (7,0)-(7,15)) ├── flags: newline - ├── name: :method - ├── name_loc: (5,4)-(5,10) = "method" - ├── receiver: ∅ - ├── parameters: ∅ - ├── body: - │ @ StatementsNode (location: (5,13)-(5,22)) + ├── name: :x + ├── depth: 0 + ├── name_loc: (7,0)-(7,1) = "x" + ├── value: + │ @ DefNode (location: (7,4)-(7,15)) │ ├── flags: ∅ - │ └── body: (length: 1) - │ └── @ CallNode (location: (5,13)-(5,22)) - │ ├── flags: ∅ - │ ├── receiver: - │ │ @ CallNode (location: (5,13)-(5,18)) - │ │ ├── flags: ∅ - │ │ ├── receiver: - │ │ │ @ IntegerNode (location: (5,13)-(5,14)) - │ │ │ ├── flags: static_literal, decimal - │ │ │ └── value: 1 - │ │ ├── call_operator_loc: ∅ - │ │ ├── name: :+ - │ │ ├── message_loc: (5,15)-(5,16) = "+" - │ │ ├── opening_loc: ∅ - │ │ ├── arguments: - │ │ │ @ ArgumentsNode (location: (5,17)-(5,18)) - │ │ │ ├── flags: ∅ - │ │ │ └── arguments: (length: 1) - │ │ │ └── @ IntegerNode (location: (5,17)-(5,18)) - │ │ │ ├── flags: static_literal, decimal - │ │ │ └── value: 2 - │ │ ├── closing_loc: ∅ - │ │ └── block: ∅ - │ ├── call_operator_loc: ∅ - │ ├── name: :+ - │ ├── message_loc: (5,19)-(5,20) = "+" - │ ├── opening_loc: ∅ - │ ├── arguments: - │ │ @ ArgumentsNode (location: (5,21)-(5,22)) - │ │ ├── flags: ∅ - │ │ └── arguments: (length: 1) - │ │ └── @ IntegerNode (location: (5,21)-(5,22)) - │ │ ├── flags: static_literal, decimal - │ │ └── value: 3 - │ ├── closing_loc: ∅ - │ └── block: ∅ - ├── locals: [] - ├── def_keyword_loc: (5,0)-(5,3) = "def" - ├── operator_loc: ∅ - ├── lparen_loc: ∅ - ├── rparen_loc: ∅ - ├── equal_loc: (5,11)-(5,12) = "=" - └── end_keyword_loc: ∅ + │ ├── name: :f + │ ├── name_loc: (7,8)-(7,9) = "f" + │ ├── receiver: ∅ + │ ├── parameters: ∅ + │ ├── body: + │ │ @ StatementsNode (location: (7,12)-(7,15)) + │ │ ├── flags: ∅ + │ │ └── body: (length: 1) + │ │ └── @ CallNode (location: (7,12)-(7,15)) + │ │ ├── flags: ignore_visibility + │ │ ├── receiver: ∅ + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :p + │ │ ├── message_loc: (7,12)-(7,13) = "p" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (7,14)-(7,15)) + │ │ │ ├── flags: ∅ + │ │ │ └── arguments: (length: 1) + │ │ │ └── @ IntegerNode (location: (7,14)-(7,15)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 1 + │ │ ├── closing_loc: ∅ + │ │ └── block: ∅ + │ ├── locals: [] + │ ├── def_keyword_loc: (7,4)-(7,7) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: ∅ + │ ├── rparen_loc: ∅ + │ ├── equal_loc: (7,10)-(7,11) = "=" + │ └── end_keyword_loc: ∅ + └── operator_loc: (7,2)-(7,3) = "=" diff --git a/src/prism.c b/src/prism.c index eb7a4f7b81..6022039bea 100644 --- a/src/prism.c +++ b/src/prism.c @@ -19501,7 +19501,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_do_loop_stack_push(parser, false); statements = (pm_node_t *) pm_statements_node_create(parser); - pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, binding_power < PM_BINDING_POWER_COMPOSITION, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1)); + pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, true, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1)); if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) { context_push(parser, PM_CONTEXT_RESCUE_MODIFIER); diff --git a/test/prism/fixtures/endless_methods.txt b/test/prism/fixtures/endless_methods.txt index 8c2f2a30cc..7eb3bf4318 100644 --- a/test/prism/fixtures/endless_methods.txt +++ b/test/prism/fixtures/endless_methods.txt @@ -3,3 +3,5 @@ def foo = 1 def bar = A "" def method = 1 + 2 + 3 + +x = def f = p 1