summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoah Gibbs <the.codefolio.guy@gmail.com>2024-02-07 11:05:01 +0000
committergit <svn-admin@ruby-lang.org>2024-02-07 19:42:13 +0000
commit73d222e1efa64b82bdd23efdb73fa39031fe0b9c (patch)
tree21827eb692d830b27321e89092b9c9c9b4beb033
parentb1310940e36c14bd07dbc2db885fbd6ec8c35bf8 (diff)
[ruby/prism] Support &. calls and calling with blocks, test with fixtures
https://github.com/ruby/prism/commit/e346fa583a
-rw-r--r--lib/prism/ripper_compat.rb47
-rw-r--r--test/prism/ripper_compat_test.rb13
2 files changed, 49 insertions, 11 deletions
diff --git a/lib/prism/ripper_compat.rb b/lib/prism/ripper_compat.rb
index 98dc762f62..764b4f3708 100644
--- a/lib/prism/ripper_compat.rb
+++ b/lib/prism/ripper_compat.rb
@@ -142,31 +142,47 @@ module Prism
raise NotImplementedError, "More than two arguments for operator"
end
elsif node.call_operator_loc.nil?
- # In Ripper a method call like "puts myvar" with no parenthesis is a "command"
+ # In Ripper a method call like "puts myvar" with no parenthesis is a "command".
bounds(node.message_loc)
ident_val = on_ident(node.message)
- args = args_node_to_arguments(node.arguments)
- return on_command(ident_val, args)
+ args = node.arguments.nil? ? nil : args_node_to_arguments(node.arguments)
+
+ # Unless it has a block, and then it's an fcall (e.g. "foo { bar }")
+ if node.block
+ block_val = visit(node.block)
+ # In these calls, even if node.arguments is nil, we still get an :args_new call.
+ method_args_val = on_method_add_arg(on_fcall(ident_val), args_node_to_arguments(node.arguments))
+ return on_method_add_block(method_args_val, on_brace_block(nil, block_val))
+ else
+ return on_command(ident_val, args)
+ end
else
operator = node.call_operator_loc.slice
- if operator == "."
+ if operator == "." || operator == "&."
left_val = visit(node.receiver)
bounds(node.call_operator_loc)
- dot_val = on_period(node.call_operator)
+ operator_val = operator == "." ? on_period(node.call_operator) : on_op(node.call_operator)
bounds(node.message_loc)
right_val = on_ident(node.message)
- return on_call(left_val, dot_val, right_val)
+ call_val = on_call(left_val, operator_val, right_val)
+
+ if node.block
+ block_val = visit(node.block)
+ return on_method_add_block(call_val, on_brace_block(nil, block_val))
+ else
+ return call_val
+ end
else
- raise NotImplementedError, "operator other than dot for call: #{operator.inspect}"
+ raise NotImplementedError, "operator other than . or &. for call: #{operator.inspect}"
end
end
end
# A non-operator method call with parentheses
- args = on_arg_paren(args_node_to_arguments(node.arguments))
+ args = on_arg_paren(node.arguments.nil? ? nil : args_node_to_arguments(node.arguments))
bounds(node.message_loc)
ident_val = on_ident(node.message)
@@ -174,12 +190,23 @@ module Prism
bounds(node.location)
args_call_val = on_method_add_arg(on_fcall(ident_val), args)
if node.block
- raise NotImplementedError, "Method call with a block!"
+ block_val = visit(node.block)
+
+ return on_method_add_block(args_call_val, on_brace_block(nil, block_val))
else
return args_call_val
end
end
+ # Visit a BlockNode
+ def visit_block_node(node)
+ if node.body.nil?
+ on_stmts_add(on_stmts_new, on_void_stmt)
+ else
+ visit(node.body)
+ end
+ end
+
# Visit an AndNode
def visit_and_node(node)
visit_binary_operator(node)
@@ -256,7 +283,7 @@ module Prism
# Ripper generates an interesting format of argument list.
# We'd like to convert an ArgumentsNode to one.
def args_node_to_arguments(args_node)
- return nil if args_node.nil?
+ return on_args_new if args_node.nil?
args = on_args_new
args_node.arguments.each do |arg|
diff --git a/test/prism/ripper_compat_test.rb b/test/prism/ripper_compat_test.rb
index ae611e5e46..8c54f59ef7 100644
--- a/test/prism/ripper_compat_test.rb
+++ b/test/prism/ripper_compat_test.rb
@@ -38,6 +38,10 @@ module Prism
assert_equivalent("foo.🗻")
assert_equivalent("🗻.😮!")
assert_equivalent("🗻 🗻,🗻,🗻")
+ assert_equivalent("foo&.bar")
+ assert_equivalent("foo { bar }")
+ assert_equivalent("foo.bar { 7 }")
+ assert_equivalent("foo(1) { bar }")
end
def test_method_calls_on_immediate_values
@@ -84,7 +88,11 @@ module Prism
class RipperCompatFixturesTest < TestCase
#base = File.join(__dir__, "fixtures")
#relatives = ENV["FOCUS"] ? [ENV["FOCUS"]] : Dir["**/*.txt", base: base]
- relatives = ["arithmetic.txt", "integer_operations.txt"]
+ relatives = [
+ "arithmetic.txt",
+ "comments.txt",
+ "integer_operations.txt",
+ ]
relatives.each do |relative|
define_method "test_ripper_filepath_#{relative}" do
@@ -95,6 +103,9 @@ module Prism
source = File.read(path, binmode: true, external_encoding: Encoding::UTF_8)
expected = Ripper.sexp_raw(source)
+ if expected.nil?
+ puts "Could not parse #{path.inspect}!"
+ end
refute_nil expected
assert_equal expected, RipperCompat.sexp_raw(source)
end