Skip to content

Commit

Permalink
Fix implementation of [] and []= for ripper translation
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton committed Mar 5, 2024
1 parent 356c97c commit d31cf63
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 27 deletions.
84 changes: 63 additions & 21 deletions lib/prism/translation/ripper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -469,12 +469,71 @@ def visit_break_node(node)
# foo.bar() {}
# ^^^^^^^^^^^^
def visit_call_node(node)
return visit_aref_node(node) if node.name == :[]
return visit_aref_field_node(node) if node.name == :[]=
case node.name
when :[]
if node.opening == "["
receiver = visit(node.receiver)
arguments = node.arguments&.arguments || []
block = node.block

if block.is_a?(BlockArgumentNode)
arguments << block
block = nil
end

if node.variable_call?
raise NoMethodError, __method__ unless node.receiver.nil?
arguments =
if arguments.any?
args = visit_arguments(arguments)

if node.block.is_a?(BlockArgumentNode)
args
else
bounds(arguments.first.location)
on_args_add_block(args, false)
end
end

bounds(node.location)
call = on_aref(receiver, arguments)

if block.nil?
return call
else
block = visit(block)

bounds(node.location)
return on_method_add_block(call, block)
end
end
when :[]=
if node.opening == "["
receiver = visit(node.receiver)

*arguments, last_argument = node.arguments.arguments
arguments << node.block if !node.block.nil?

arguments =
if arguments.any?
args = visit_arguments(arguments)

if !node.block.nil?
args
else
bounds(arguments.first.location)
on_args_add_block(args, false)
end
end

bounds(node.location)
call = on_aref_field(receiver, arguments)

value = visit(last_argument)
bounds(last_argument.location)
return on_assign(call, value)
end
end

if node.variable_call?
bounds(node.message_loc)
return on_vcall(on_ident(node.message))
end
Expand Down Expand Up @@ -2432,23 +2491,6 @@ def visit_no_paren_call(node)
end
end

# In Prism this is a CallNode with :[] as the operator.
# In Ripper it's an :aref.
def visit_aref_node(node)
first_arg_val = visit(node.arguments.arguments[0])
args_val = on_args_add_block(on_args_add(on_args_new, first_arg_val), false)
on_aref(visit(node.receiver), args_val)
end

# In Prism this is a CallNode with :[]= as the operator.
# In Ripper it's an :aref_field.
def visit_aref_field_node(node)
first_arg_val = visit(node.arguments.arguments[0])
args_val = on_args_add_block(on_args_add(on_args_new, first_arg_val), false)
assign_val = visit(node.arguments.arguments[1])
on_assign(on_aref_field(visit(node.receiver), args_val), assign_val)
end

# Ripper has several methods of emitting a symbol literal. Inside an alias
# sometimes it suppresses the [:symbol] wrapper around ident. If the symbol
# is also the name of a keyword (e.g. :if) it will emit a :@kw wrapper, not
Expand Down
6 changes: 0 additions & 6 deletions test/prism/ripper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ class RipperTest < TestCase
seattlerb/heredoc_with_only_carriage_returns.txt
seattlerb/heredoc_with_only_carriage_returns_windows.txt
seattlerb/if_elsif.txt
seattlerb/index_0.txt
seattlerb/interpolated_symbol_array_line_breaks.txt
seattlerb/interpolated_word_array_line_breaks.txt
seattlerb/lambda_do_vs_brace.txt
Expand Down Expand Up @@ -401,18 +400,13 @@ class RipperTest < TestCase
whitequark/ruby_bug_12073.txt
whitequark/ruby_bug_12402.txt
whitequark/ruby_bug_12686.txt
whitequark/ruby_bug_13547.txt
whitequark/ruby_bug_14690.txt
whitequark/ruby_bug_15789.txt
whitequark/send_attr_asgn.txt
whitequark/send_attr_asgn_conditional.txt
whitequark/send_block_chain_cmd.txt
whitequark/send_call.txt
whitequark/send_index.txt
whitequark/send_index_asgn.txt
whitequark/send_index_asgn_legacy.txt
whitequark/send_index_cmd.txt
whitequark/send_index_legacy.txt
whitequark/send_lambda.txt
whitequark/send_lambda_args_noparen.txt
whitequark/send_lambda_legacy.txt
Expand Down

0 comments on commit d31cf63

Please sign in to comment.