summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2026-01-20 21:20:06 +0100
committergit <svn-admin@ruby-lang.org>2026-01-21 13:21:37 +0000
commit913ffcd1ddb854d2fdbf73a6ddf1930b8a472322 (patch)
tree54e80d41045ee84c3e33a12452cfcbc3bfc91480
parent519a4bdbc19693be9020419eb4dea9e66a256a41 (diff)
[ruby/prism] Check using Prism nodes if a command call has any arguments in Ripper translator
* We don't know what `on_*` events might return so we cannot assume it's an Array. * See https://github.com/ruby/prism/issues/3838#issuecomment-3774702396 https://github.com/ruby/prism/commit/bed4271ce2
-rw-r--r--lib/prism/translation/ripper.rb18
-rw-r--r--test/prism/ruby/ripper_test.rb12
2 files changed, 25 insertions, 5 deletions
diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb
index afe30bb5db..41dd699438 100644
--- a/lib/prism/translation/ripper.rb
+++ b/lib/prism/translation/ripper.rb
@@ -1112,7 +1112,7 @@ module Prism
else
arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
call =
- if node.opening_loc.nil? && arguments&.any?
+ if node.opening_loc.nil? && get_arguments_and_block(node.arguments, node.block).first.any?
bounds(node.location)
on_command(message, arguments)
elsif !node.opening_loc.nil?
@@ -1179,17 +1179,25 @@ module Prism
end
end
- # Visit the arguments and block of a call node and return the arguments
- # and block as they should be used.
- private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
+ # Extract the arguments and block Ripper-style, which means if the block
+ # is like `&b` then it's moved to arguments.
+ private def get_arguments_and_block(arguments_node, block_node)
arguments = arguments_node&.arguments || []
block = block_node
if block.is_a?(BlockArgumentNode)
- arguments << block
+ arguments += [block]
block = nil
end
+ [arguments, block]
+ end
+
+ # Visit the arguments and block of a call node and return the arguments
+ # and block as they should be used.
+ private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
+ arguments, block = get_arguments_and_block(arguments_node, block_node)
+
[
if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
visit(arguments.first)
diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb
index 174c90cbca..8848c6a8c0 100644
--- a/test/prism/ruby/ripper_test.rb
+++ b/test/prism/ruby/ripper_test.rb
@@ -110,6 +110,14 @@ module Prism
include Events
end
+ class ObjectEvents < Translation::Ripper
+ Prism::Translation::Ripper::PARSER_EVENTS.each do |event|
+ define_method(:"on_#{event}") do |*args|
+ Object.new
+ end
+ end
+ end
+
def test_events
source = "1 rescue 2"
ripper = RipperEvents.new(source)
@@ -152,6 +160,10 @@ module Prism
def assert_ripper_sexp_raw(source)
assert_equal Ripper.sexp_raw(source), Prism::Translation::Ripper.sexp_raw(source)
+
+ # Similar to test/ripper/assert_parse_files.rb in CRuby
+ object_events = ObjectEvents.new(source)
+ assert_nothing_raised { object_events.parse }
end
def assert_ripper_lex(source)