Skip to content

Commit 5877a95

Browse files
committed
Handle negated numeric in parser translation
1 parent 27cb352 commit 5877a95

File tree

1 file changed

+37
-2
lines changed

1 file changed

+37
-2
lines changed

lib/prism/translation/parser/compiler.rb

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ def visit_call_node(node)
247247

248248
if node.call_operator_loc.nil?
249249
case name
250+
when :-@
251+
case (receiver = node.receiver).type
252+
when :integer_node, :float_node, :rational_node, :imaginary_node
253+
return visit(numeric_negate(node.message_loc, receiver))
254+
end
250255
when :!
251256
return visit_block(builder.not_op(token(node.message_loc), token(node.opening_loc), visit(node.receiver), token(node.closing_loc)), block)
252257
when :[]
@@ -792,7 +797,7 @@ def visit_if_node(node)
792797

793798
# 1i
794799
def visit_imaginary_node(node)
795-
visit_numeric(node, builder.complex([node.value, srange(node.location)]))
800+
visit_numeric(node, builder.complex([imaginary_value(node), srange(node.location)]))
796801
end
797802

798803
# { foo: }
@@ -1325,7 +1330,7 @@ def visit_range_node(node)
13251330
# 1r
13261331
# ^^
13271332
def visit_rational_node(node)
1328-
visit_numeric(node, builder.rational([node.value, srange(node.location)]))
1333+
visit_numeric(node, builder.rational([rational_value(node), srange(node.location)]))
13291334
end
13301335

13311336
# redo
@@ -1690,6 +1695,26 @@ def find_forwarding(node)
16901695
forwarding
16911696
end
16921697

1698+
# Because we have mutated the AST to allow for newlines in the middle of
1699+
# a rational, we need to manually handle the value here.
1700+
def imaginary_value(node)
1701+
Complex(0, node.numeric.is_a?(RationalNode) ? rational_value(node.numeric) : node.numeric.value)
1702+
end
1703+
1704+
# Negate the value of a numeric node. This is a special case where you
1705+
# have a negative sign on one line and then a number on the next line.
1706+
# In normal Ruby, this will always be a method call. The parser gem,
1707+
# however, marks this as a numeric literal. We have to massage the tree
1708+
# here to get it into the correct form.
1709+
def numeric_negate(message_loc, receiver)
1710+
case receiver.type
1711+
when :integer_node, :float_node
1712+
receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
1713+
when :rational_node, :imaginary_node
1714+
receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
1715+
end
1716+
end
1717+
16931718
# Blocks can have a special set of parameters that automatically expand
16941719
# when given arrays if they have a single required parameter and no
16951720
# other parameters.
@@ -1704,6 +1729,16 @@ def procarg0?(parameters)
17041729
parameters.block.nil?
17051730
end
17061731

1732+
# Because we have mutated the AST to allow for newlines in the middle of
1733+
# a rational, we need to manually handle the value here.
1734+
def rational_value(node)
1735+
if node.numeric.is_a?(IntegerNode)
1736+
Rational(node.numeric.value)
1737+
else
1738+
Rational(node.slice.gsub(/\s/, "").chomp("r"))
1739+
end
1740+
end
1741+
17071742
# Locations in the parser gem AST are generated using this class. We
17081743
# store a reference to its constant to make it slightly faster to look
17091744
# up.

0 commit comments

Comments
 (0)