diff --git a/src/prism.c b/src/prism.c index efe21c5e7e..2e2d6bcbd4 100644 --- a/src/prism.c +++ b/src/prism.c @@ -21621,7 +21621,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc return node; } break; - case PM_CALL_NODE: + case PM_CALL_NODE: { // A do-block can attach to a command-style call // produced by infix operators (e.g., dot-calls like // `obj.method args do end`). @@ -21635,7 +21635,22 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) { return node; } + + // Command-style calls (calls with arguments but without + // parentheses) only accept composition (and/or) and modifier + // (if/unless/etc.) operators. We need to exclude operator calls + // (e.g., a + b) which also satisfy pm_call_node_command_p but + // are not commands. + const pm_call_node_t *cast = (const pm_call_node_t *) node; + if ( + (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_COMPOSITION) && + (cast->receiver == NULL || cast->call_operator_loc.length > 0) && + pm_call_node_command_p(cast) + ) { + return node; + } break; + } case PM_RESCUE_MODIFIER_NODE: // A rescue modifier whose handler is a one-liner pattern match // (=> or in) produces a statement. That means it cannot be diff --git a/test/prism/errors/command_call_in_2.txt b/test/prism/errors/command_call_in_2.txt new file mode 100644 index 0000000000..6676b1acba --- /dev/null +++ b/test/prism/errors/command_call_in_2.txt @@ -0,0 +1,4 @@ +a.b x in pattern + ^~ unexpected 'in', expecting end-of-input + ^~ unexpected 'in', ignoring it + diff --git a/test/prism/errors/command_call_in_3.txt b/test/prism/errors/command_call_in_3.txt new file mode 100644 index 0000000000..6fe026d7d3 --- /dev/null +++ b/test/prism/errors/command_call_in_3.txt @@ -0,0 +1,4 @@ +a.b x: in pattern + ^~ unexpected 'in', expecting end-of-input + ^~ unexpected 'in', ignoring it + diff --git a/test/prism/errors/command_call_in_4.txt b/test/prism/errors/command_call_in_4.txt new file mode 100644 index 0000000000..045afe6498 --- /dev/null +++ b/test/prism/errors/command_call_in_4.txt @@ -0,0 +1,4 @@ +a.b &x in pattern + ^~ unexpected 'in', expecting end-of-input + ^~ unexpected 'in', ignoring it + diff --git a/test/prism/errors/command_call_in_5.txt b/test/prism/errors/command_call_in_5.txt new file mode 100644 index 0000000000..be07287f81 --- /dev/null +++ b/test/prism/errors/command_call_in_5.txt @@ -0,0 +1,4 @@ +a.b *x => pattern + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + diff --git a/test/prism/errors/command_call_in_6.txt b/test/prism/errors/command_call_in_6.txt new file mode 100644 index 0000000000..470f323872 --- /dev/null +++ b/test/prism/errors/command_call_in_6.txt @@ -0,0 +1,4 @@ +a.b x: => pattern + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + diff --git a/test/prism/errors/command_call_in_7.txt b/test/prism/errors/command_call_in_7.txt new file mode 100644 index 0000000000..a8bea912b5 --- /dev/null +++ b/test/prism/errors/command_call_in_7.txt @@ -0,0 +1,4 @@ +a.b &x => pattern + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index 898f4afb45..c3362eaaf5 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -60,10 +60,6 @@ def test_unterminated_empty_string_closing assert_nil statement.closing end - def test_invalid_message_name - assert_equal :"", Prism.parse_statement("+.@foo,+=foo").write_name - end - def test_regexp_encoding_option_mismatch_error # UTF-8 char with ASCII-8BIT modifier result = Prism.parse('/Ȃ/n')