Skip to content

Commit cebf598

Browse files
committed
[Bug #17398] Allow private def hello = puts "Hello"
This was a limitation of parse.y that prism intentionally replicated.
1 parent dfd6941 commit cebf598

File tree

10 files changed

+516
-12
lines changed

10 files changed

+516
-12
lines changed

snapshots/endless_methods_command_call.txt

Lines changed: 475 additions & 0 deletions
Large diffs are not rendered by default.

src/prism.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19505,13 +19505,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1950519505
pm_do_loop_stack_push(parser, false);
1950619506
statements = (pm_node_t *) pm_statements_node_create(parser);
1950719507

19508-
// In endless method bodies, we need to handle command calls carefully.
19509-
// We want to allow command calls in assignment context but maintain
19510-
// the same binding power to avoid changing how operators are parsed.
19511-
// Note that we're intentionally NOT allowing code like `private def foo = puts "Hello"`
19512-
// because the original parser, parse.y, can't handle it and we want to maintain the same behavior
19513-
bool allow_command_call = (binding_power == PM_BINDING_POWER_ASSIGNMENT) ||
19514-
(binding_power < PM_BINDING_POWER_COMPOSITION);
19508+
bool allow_command_call;
19509+
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
19510+
allow_command_call = accepts_command_call;
19511+
} else {
19512+
// Allow `def foo = puts "Hello"` but not `private def foo = puts "Hello"`
19513+
allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
19514+
}
1951519515

1951619516
pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
1951719517

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
private :m, def hello = puts "Hello"
2+
^ unexpected string literal, expecting end-of-input
3+

test/prism/errors/private_endless_method.txt

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/prism/errors_test.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ def foo(bar: bar) = 42
100100
end
101101
end
102102

103+
def test_private_endless_method
104+
source = <<~RUBY
105+
private def foo = puts "Hello"
106+
RUBY
107+
108+
assert_predicate Prism.parse(source, version: "3.4"), :failure?
109+
assert_predicate Prism.parse(source), :success?
110+
end
111+
103112
private
104113

105114
def assert_errors(filepath)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
private def foo = puts "Hello"
2+
private def foo = puts "Hello", "World"
3+
private def foo = puts "Hello" do expr end
4+
private def foo() = puts "Hello"
5+
private def foo(x) = puts x
6+
private def obj.foo = puts "Hello"
7+
private def obj.foo() = puts "Hello"
8+
private def obj.foo(x) = puts x

test/prism/lex_test.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class LexTest < TestCase
4242
except << "whitequark/ruby_bug_19281.txt"
4343
end
4444

45+
# https://bugs.ruby-lang.org/issues/17398#note-12
46+
except << "endless_methods_command_call.txt"
47+
4548
Fixture.each(except: except) do |fixture|
4649
define_method(fixture.test_name) { assert_lex(fixture) }
4750
end

test/prism/ruby/parser_test.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class ParserTest < TestCase
6464

6565
# 1.. && 2
6666
"ranges.txt",
67+
68+
# Ruby >= 3.5 specific syntax
69+
"endless_methods_command_call.txt",
6770
]
6871

6972
# These files contain code that is being parsed incorrectly by the parser

test/prism/ruby/ripper_test.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ class RipperTest < TestCase
2626
"whitequark/lvar_injecting_match.txt",
2727

2828
# Ripper fails to understand some structures that span across heredocs.
29-
"spanning_heredoc.txt"
29+
"spanning_heredoc.txt",
30+
31+
# https://bugs.ruby-lang.org/issues/17398#note-12
32+
"endless_methods_command_call.txt",
3033
]
3134

3235
# Skip these tests that we haven't implemented yet.

test/prism/ruby/ruby_parser_test.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ class RubyParserTest < TestCase
7373
"whitequark/ruby_bug_11989.txt",
7474
"whitequark/ruby_bug_18878.txt",
7575
"whitequark/ruby_bug_19281.txt",
76-
"whitequark/slash_newline_in_heredocs.txt"
76+
"whitequark/slash_newline_in_heredocs.txt",
77+
78+
# Ruby >= 3.5 specific syntax
79+
"endless_methods_command_call.txt",
7780
]
7881

7982
Fixture.each(except: failures) do |fixture|

0 commit comments

Comments
 (0)