Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
475 changes: 475 additions & 0 deletions snapshots/endless_methods_command_call.txt

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -19585,13 +19585,13 @@ 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);

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

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

Expand Down
3 changes: 3 additions & 0 deletions test/prism/errors/endless_method_command_call.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
private :m, def hello = puts "Hello"
^ unexpected string literal, expecting end-of-input

3 changes: 0 additions & 3 deletions test/prism/errors/private_endless_method.txt

This file was deleted.

9 changes: 9 additions & 0 deletions test/prism/errors_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ def foo(bar: bar) = 42
end
end

def test_private_endless_method
source = <<~RUBY
private def foo = puts "Hello"
RUBY

assert_predicate Prism.parse(source, version: "3.4"), :failure?
assert_predicate Prism.parse(source), :success?
end

private

def assert_errors(filepath)
Expand Down
8 changes: 8 additions & 0 deletions test/prism/fixtures/endless_methods_command_call.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
private def foo = puts "Hello"
private def foo = puts "Hello", "World"
private def foo = puts "Hello" do expr end
private def foo() = puts "Hello"
private def foo(x) = puts x
private def obj.foo = puts "Hello"
private def obj.foo() = puts "Hello"
private def obj.foo(x) = puts x
5 changes: 4 additions & 1 deletion test/prism/fixtures_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ class FixturesTest < TestCase
except << "whitequark/ruby_bug_19281.txt"
end

except << "leading_logical.txt" if RUBY_VERSION < "3.5.0"
if RUBY_VERSION < "3.5.0"
except << "leading_logical.txt"
except << "endless_methods_command_call.txt"
end

Fixture.each(except: except) do |fixture|
define_method(fixture.test_name) { assert_valid_syntax(fixture.read) }
Expand Down
3 changes: 3 additions & 0 deletions test/prism/lex_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class LexTest < TestCase
# https://bugs.ruby-lang.org/issues/20925
except << "leading_logical.txt"

# https://bugs.ruby-lang.org/issues/17398#note-12
except << "endless_methods_command_call.txt"

Fixture.each(except: except) do |fixture|
define_method(fixture.test_name) { assert_lex(fixture) }
end
Expand Down
3 changes: 3 additions & 0 deletions test/prism/ruby/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ParserTest < TestCase

# Cannot yet handling leading logical operators.
"leading_logical.txt",

# Ruby >= 3.5 specific syntax
"endless_methods_command_call.txt",
]

# These files contain code that is being parsed incorrectly by the parser
Expand Down
5 changes: 4 additions & 1 deletion test/prism/ruby/ripper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ class RipperTest < TestCase
"whitequark/lvar_injecting_match.txt",

# Ripper fails to understand some structures that span across heredocs.
"spanning_heredoc.txt"
"spanning_heredoc.txt",

# https://bugs.ruby-lang.org/issues/17398#note-12
"endless_methods_command_call.txt",
]

# Skip these tests that we haven't implemented yet.
Expand Down
5 changes: 4 additions & 1 deletion test/prism/ruby/ruby_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ class RubyParserTest < TestCase
"whitequark/ruby_bug_11989.txt",
"whitequark/ruby_bug_18878.txt",
"whitequark/ruby_bug_19281.txt",
"whitequark/slash_newline_in_heredocs.txt"
"whitequark/slash_newline_in_heredocs.txt",

# Ruby >= 3.5 specific syntax
"endless_methods_command_call.txt",
]

Fixture.each(except: failures) do |fixture|
Expand Down
Loading