From 501962cbb6c9c18d9591779d98f2041e960f6677 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:26:30 +0100 Subject: [PATCH] Revert "Reject infix operators on command call on writes" This reverts commit 4e71dbfc7bd93adc1b9e57af927fdebbfd06b6bd. And also add a regression test. Seems like currently prism parses these the same that parse.y does. --- snapshots/write_command_operator.txt | 84 +++++++++++++++++++ src/prism.c | 30 +------ test/prism/errors/command_call_in.txt | 2 - test/prism/errors/write_command.txt | 4 - .../prism/fixtures/write_command_operator.txt | 3 + 5 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 snapshots/write_command_operator.txt delete mode 100644 test/prism/errors/write_command.txt create mode 100644 test/prism/fixtures/write_command_operator.txt diff --git a/snapshots/write_command_operator.txt b/snapshots/write_command_operator.txt new file mode 100644 index 0000000000..f1d92729ed --- /dev/null +++ b/snapshots/write_command_operator.txt @@ -0,0 +1,84 @@ +@ ProgramNode (location: (1,0)-(3,24)) +├── flags: ∅ +├── locals: [:foo] +└── statements: + @ StatementsNode (location: (1,0)-(3,24)) + ├── flags: ∅ + └── body: (length: 2) + ├── @ OrNode (location: (1,0)-(1,27)) + │ ├── flags: newline + │ ├── left: + │ │ @ LocalVariableWriteNode (location: (1,0)-(1,17)) + │ │ ├── flags: ∅ + │ │ ├── name: :foo + │ │ ├── depth: 0 + │ │ ├── name_loc: (1,0)-(1,3) = "foo" + │ │ ├── value: + │ │ │ @ CallNode (location: (1,6)-(1,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── receiver: + │ │ │ │ @ IntegerNode (location: (1,6)-(1,9)) + │ │ │ │ ├── flags: static_literal, decimal + │ │ │ │ └── value: 123 + │ │ │ ├── call_operator_loc: ∅ + │ │ │ ├── name: :| + │ │ │ ├── message_loc: (1,10)-(1,11) = "|" + │ │ │ ├── opening_loc: ∅ + │ │ │ ├── arguments: + │ │ │ │ @ ArgumentsNode (location: (1,12)-(1,17)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ └── arguments: (length: 1) + │ │ │ │ └── @ StringNode (location: (1,12)-(1,17)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (1,12)-(1,13) = "'" + │ │ │ │ ├── content_loc: (1,13)-(1,16) = "456" + │ │ │ │ ├── closing_loc: (1,16)-(1,17) = "'" + │ │ │ │ └── unescaped: "456" + │ │ │ ├── closing_loc: ∅ + │ │ │ ├── equal_loc: ∅ + │ │ │ └── block: ∅ + │ │ └── operator_loc: (1,4)-(1,5) = "=" + │ ├── right: + │ │ @ ReturnNode (location: (1,21)-(1,27)) + │ │ ├── flags: ∅ + │ │ ├── keyword_loc: (1,21)-(1,27) = "return" + │ │ └── arguments: ∅ + │ └── operator_loc: (1,18)-(1,20) = "or" + └── @ MatchPredicateNode (location: (3,0)-(3,24)) + ├── flags: newline + ├── value: + │ @ LocalVariableWriteNode (location: (3,0)-(3,17)) + │ ├── flags: ∅ + │ ├── name: :foo + │ ├── depth: 0 + │ ├── name_loc: (3,0)-(3,3) = "foo" + │ ├── value: + │ │ @ CallNode (location: (3,6)-(3,17)) + │ │ ├── flags: ∅ + │ │ ├── receiver: + │ │ │ @ IntegerNode (location: (3,6)-(3,9)) + │ │ │ ├── flags: static_literal, decimal + │ │ │ └── value: 123 + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :| + │ │ ├── message_loc: (3,10)-(3,11) = "|" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (3,12)-(3,17)) + │ │ │ ├── flags: ∅ + │ │ │ └── arguments: (length: 1) + │ │ │ └── @ StringNode (location: (3,12)-(3,17)) + │ │ │ ├── flags: ∅ + │ │ │ ├── opening_loc: (3,12)-(3,13) = "'" + │ │ │ ├── content_loc: (3,13)-(3,16) = "456" + │ │ │ ├── closing_loc: (3,16)-(3,17) = "'" + │ │ │ └── unescaped: "456" + │ │ ├── closing_loc: ∅ + │ │ ├── equal_loc: ∅ + │ │ └── block: ∅ + │ └── operator_loc: (3,4)-(3,5) = "=" + ├── pattern: + │ @ ConstantReadNode (location: (3,21)-(3,24)) + │ ├── flags: ∅ + │ └── name: :BAR + └── operator_loc: (3,18)-(3,20) = "in" diff --git a/src/prism.c b/src/prism.c index ebd86b01fe..a131f37912 100644 --- a/src/prism.c +++ b/src/prism.c @@ -21619,26 +21619,6 @@ pm_call_node_command_p(const pm_call_node_t *node) { ); } -/** - * Determine if a given write node has a command call as its right-hand side. We - * need this because command calls as the values of writes cannot be extended by - * infix operators. - */ -static inline bool -pm_write_node_command_p(const pm_node_t *node) { - pm_node_t *value; - switch (PM_NODE_TYPE(node)) { - case PM_CLASS_VARIABLE_WRITE_NODE: value = ((pm_class_variable_write_node_t *) node)->value; break; - case PM_CONSTANT_PATH_WRITE_NODE: value = ((pm_constant_path_write_node_t *) node)->value; break; - case PM_CONSTANT_WRITE_NODE: value = ((pm_constant_write_node_t *) node)->value; break; - case PM_GLOBAL_VARIABLE_WRITE_NODE: value = ((pm_global_variable_write_node_t *) node)->value; break; - case PM_INSTANCE_VARIABLE_WRITE_NODE: value = ((pm_instance_variable_write_node_t *) node)->value; break; - case PM_LOCAL_VARIABLE_WRITE_NODE: value = ((pm_local_variable_write_node_t *) node)->value; break; - default: return false; - } - return PM_NODE_TYPE_P(value, PM_CALL_NODE) && pm_call_node_command_p((pm_call_node_t *) value); -} - /** * Parse an expression at the given point of the parser using the given binding * power to parse subsequent chains. If this function finds a syntax error, it @@ -21723,13 +21703,9 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc case PM_INSTANCE_VARIABLE_WRITE_NODE: case PM_LOCAL_VARIABLE_WRITE_NODE: // These expressions are statements, by virtue of the right-hand - // side of their write being an implicit array or a command call. - // This mirrors parse.y's behavior where `lhs = command_call` - // reduces to stmt (not expr), preventing and/or from following. - if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) { - if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) || pm_write_node_command_p(node)) { - return node; - } + // side of their write being an implicit array. + if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) { + return node; } break; case PM_CALL_NODE: diff --git a/test/prism/errors/command_call_in.txt b/test/prism/errors/command_call_in.txt index e9e8e82d3a..2fdcf09738 100644 --- a/test/prism/errors/command_call_in.txt +++ b/test/prism/errors/command_call_in.txt @@ -2,6 +2,4 @@ foo 1 in a ^~ unexpected 'in', expecting end-of-input ^~ unexpected 'in', ignoring it a = foo 2 in b - ^~ unexpected 'in', expecting end-of-input - ^~ unexpected 'in', ignoring it diff --git a/test/prism/errors/write_command.txt b/test/prism/errors/write_command.txt deleted file mode 100644 index 5024f8452a..0000000000 --- a/test/prism/errors/write_command.txt +++ /dev/null @@ -1,4 +0,0 @@ -a = b c and 1 - ^~~ unexpected 'and', expecting end-of-input - ^~~ unexpected 'and', ignoring it - diff --git a/test/prism/fixtures/write_command_operator.txt b/test/prism/fixtures/write_command_operator.txt new file mode 100644 index 0000000000..d719d24f87 --- /dev/null +++ b/test/prism/fixtures/write_command_operator.txt @@ -0,0 +1,3 @@ +foo = 123 | '456' or return + +foo = 123 | '456' in BAR