Skip to content

Commit

Permalink
[ruby/prism] Handle negated numeric in parser translation
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton authored and matzbot committed Feb 26, 2024
1 parent 83e676e commit af3145b
Showing 1 changed file with 37 additions and 2 deletions.
39 changes: 37 additions & 2 deletions lib/prism/translation/parser/compiler.rb
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

0 comments on commit af3145b

Please sign in to comment.