Skip to content
Merged
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
39 changes: 37 additions & 2 deletions lib/prism/translation/parser/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@ def visit_call_node(node)

if node.call_operator_loc.nil?
case name
when :-@
case (receiver = node.receiver).type
when :integer_node, :float_node, :rational_node, :imaginary_node
return visit(numeric_negate(node.message_loc, receiver))
end
when :!
return visit_block(builder.not_op(token(node.message_loc), token(node.opening_loc), visit(node.receiver), token(node.closing_loc)), block)
when :[]
Expand Down Expand Up @@ -792,7 +797,7 @@ def visit_if_node(node)

# 1i
def visit_imaginary_node(node)
visit_numeric(node, builder.complex([node.value, srange(node.location)]))
visit_numeric(node, builder.complex([imaginary_value(node), srange(node.location)]))
end

# { foo: }
Expand Down Expand Up @@ -1325,7 +1330,7 @@ def visit_range_node(node)
# 1r
# ^^
def visit_rational_node(node)
visit_numeric(node, builder.rational([node.value, srange(node.location)]))
visit_numeric(node, builder.rational([rational_value(node), srange(node.location)]))
end

# redo
Expand Down Expand Up @@ -1690,6 +1695,26 @@ def find_forwarding(node)
forwarding
end

# Because we have mutated the AST to allow for newlines in the middle of
# a rational, we need to manually handle the value here.
def imaginary_value(node)
Complex(0, node.numeric.is_a?(RationalNode) ? rational_value(node.numeric) : node.numeric.value)
end

# Negate the value of a numeric node. This is a special case where you
# have a negative sign on one line and then a number on the next line.
# In normal Ruby, this will always be a method call. The parser gem,
# however, marks this as a numeric literal. We have to massage the tree
# here to get it into the correct form.
def numeric_negate(message_loc, receiver)
case receiver.type
when :integer_node, :float_node
receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
when :rational_node, :imaginary_node
receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
end
end

# Blocks can have a special set of parameters that automatically expand
# when given arrays if they have a single required parameter and no
# other parameters.
Expand All @@ -1704,6 +1729,16 @@ def procarg0?(parameters)
parameters.block.nil?
end

# Because we have mutated the AST to allow for newlines in the middle of
# a rational, we need to manually handle the value here.
def rational_value(node)
if node.numeric.is_a?(IntegerNode)
Rational(node.numeric.value)
else
Rational(node.slice.gsub(/\s/, "").chomp("r"))
end
end

# Locations in the parser gem AST are generated using this class. We
# store a reference to its constant to make it slightly faster to look
# up.
Expand Down