summaryrefslogtreecommitdiff
path: root/lib/prism/translation/parser
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-02-26 09:18:17 -0500
committergit <svn-admin@ruby-lang.org>2024-02-26 14:26:53 +0000
commitaf3145bb2446f27f895e78cfab49eea23fad8865 (patch)
tree877621ce6d0774a511cd76f89521a0482c099fa6 /lib/prism/translation/parser
parent83e676e5f9049168047c36d1bbd75ac342e6fed6 (diff)
[ruby/prism] Handle negated numeric in parser translation
https://github.com/ruby/prism/commit/5877a95be4
Diffstat (limited to 'lib/prism/translation/parser')
-rw-r--r--lib/prism/translation/parser/compiler.rb39
1 files changed, 37 insertions, 2 deletions
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index 423df8fb8c..c8ab3740bd 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -247,6 +247,11 @@ module Prism
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 :[]
@@ -792,7 +797,7 @@ module Prism
# 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: }
@@ -1325,7 +1330,7 @@ module Prism
# 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
@@ -1690,6 +1695,26 @@ module Prism
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.
@@ -1704,6 +1729,16 @@ module Prism
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.