summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2023-08-30 22:22:04 +0200
committergit <svn-admin@ruby-lang.org>2023-09-01 13:18:29 +0000
commit4172036bc6ba77aded874f67b15d657bd7ee3241 (patch)
treee488c41e52ab92aac9c35e3d748abbffe61689f4
parent7fb56df726d4e661fdec10266a54cf27e52d9892 (diff)
[ruby/yarp] Do not desugar Foo::Bar {||,&&,+}= baz as it is incorrect without a temporary variable
* See https://github.com/ruby/yarp/pull/1329#discussion_r1310775433 for details. https://github.com/ruby/yarp/commit/f0fdcba0c3
-rw-r--r--lib/yarp/desugar_visitor.rb63
-rw-r--r--test/yarp/desugar_visitor_test.rb11
2 files changed, 8 insertions, 66 deletions
diff --git a/lib/yarp/desugar_visitor.rb b/lib/yarp/desugar_visitor.rb
index 426ecf541f..a988449dc0 100644
--- a/lib/yarp/desugar_visitor.rb
+++ b/lib/yarp/desugar_visitor.rb
@@ -56,69 +56,6 @@ module YARP
desugar_operator_write_node(node, ConstantReadNode, ConstantWriteNode)
end
- # Foo::Bar &&= baz
- #
- # becomes
- #
- # Foo::Bar && Foo::Bar = baz
- def visit_constant_path_and_write_node(node)
- AndNode.new(
- node.target,
- ConstantPathWriteNode.new(node.target, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
- )
- end
-
- # Foo::Bar ||= baz
- #
- # becomes
- #
- # defined?(Foo::Bar) ? Foo::Bar : Foo::Bar = baz
- def visit_constant_path_or_write_node(node)
- IfNode.new(
- node.operator_loc,
- DefinedNode.new(nil, node.target, nil, node.operator_loc, node.target.location),
- StatementsNode.new([node.target], node.location),
- ElseNode.new(
- node.operator_loc,
- StatementsNode.new(
- [ConstantPathWriteNode.new(node.target, node.value, node.operator_loc, node.location)],
- node.location
- ),
- node.operator_loc,
- node.location
- ),
- node.operator_loc,
- node.location
- )
- end
-
- # Foo::Bar += baz
- #
- # becomes
- #
- # Foo::Bar = Foo::Bar + baz
- def visit_constant_path_operator_write_node(node)
- ConstantPathWriteNode.new(
- node.target,
- CallNode.new(
- node.target,
- nil,
- node.operator_loc.copy(length: node.operator_loc.length - 1),
- nil,
- ArgumentsNode.new([node.value], node.value.location),
- nil,
- nil,
- 0,
- node.operator_loc.slice.chomp("="),
- node.location
- ),
- node.operator_loc.copy(start_offset: node.operator_loc.end_offset - 1, length: 1),
- node.location
- )
- end
-
# $foo &&= bar
#
# becomes
diff --git a/test/yarp/desugar_visitor_test.rb b/test/yarp/desugar_visitor_test.rb
index c03b02e67a..1ef2710c8e 100644
--- a/test/yarp/desugar_visitor_test.rb
+++ b/test/yarp/desugar_visitor_test.rb
@@ -6,7 +6,7 @@ module YARP
class DesugarVisitorTest < TestCase
def test_and_write
assert_desugars("(AndNode (ClassVariableReadNode) (ClassVariableWriteNode (CallNode)))", "@@foo &&= bar")
- assert_desugars("(AndNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (ConstantPathWriteNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (CallNode)))", "Foo::Bar &&= baz")
+ assert_not_desugared("Foo::Bar &&= baz", "Desugaring would execute Foo twice or need temporary variables")
assert_desugars("(AndNode (ConstantReadNode) (ConstantWriteNode (CallNode)))", "Foo &&= bar")
assert_desugars("(AndNode (GlobalVariableReadNode) (GlobalVariableWriteNode (CallNode)))", "$foo &&= bar")
assert_desugars("(AndNode (InstanceVariableReadNode) (InstanceVariableWriteNode (CallNode)))", "@foo &&= bar")
@@ -16,7 +16,7 @@ module YARP
def test_or_write
assert_desugars("(IfNode (DefinedNode (ClassVariableReadNode)) (StatementsNode (ClassVariableReadNode)) (ElseNode (StatementsNode (ClassVariableWriteNode (CallNode)))))", "@@foo ||= bar")
- assert_desugars("(IfNode (DefinedNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode))) (StatementsNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode))) (ElseNode (StatementsNode (ConstantPathWriteNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (CallNode)))))", "Foo::Bar ||= baz")
+ assert_not_desugared("Foo::Bar ||= baz", "Desugaring would execute Foo twice or need temporary variables")
assert_desugars("(IfNode (DefinedNode (ConstantReadNode)) (StatementsNode (ConstantReadNode)) (ElseNode (StatementsNode (ConstantWriteNode (CallNode)))))", "Foo ||= bar")
assert_desugars("(IfNode (DefinedNode (GlobalVariableReadNode)) (StatementsNode (GlobalVariableReadNode)) (ElseNode (StatementsNode (GlobalVariableWriteNode (CallNode)))))", "$foo ||= bar")
assert_desugars("(OrNode (InstanceVariableReadNode) (InstanceVariableWriteNode (CallNode)))", "@foo ||= bar")
@@ -26,7 +26,7 @@ module YARP
def test_operator_write
assert_desugars("(ClassVariableWriteNode (CallNode (ClassVariableReadNode) (ArgumentsNode (CallNode))))", "@@foo += bar")
- assert_desugars("(ConstantPathWriteNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (CallNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (ArgumentsNode (CallNode))))", "Foo::Bar += baz")
+ assert_not_desugared("Foo::Bar += baz", "Desugaring would execute Foo twice or need temporary variables")
assert_desugars("(ConstantWriteNode (CallNode (ConstantReadNode) (ArgumentsNode (CallNode))))", "Foo += bar")
assert_desugars("(GlobalVariableWriteNode (CallNode (GlobalVariableReadNode) (ArgumentsNode (CallNode))))", "$foo += bar")
assert_desugars("(InstanceVariableWriteNode (CallNode (InstanceVariableReadNode) (ArgumentsNode (CallNode))))", "@foo += bar")
@@ -55,5 +55,10 @@ module YARP
ast = YARP.parse(source).value.accept(DesugarVisitor.new)
assert_equal expected, ast_inspect(ast.statements.body.last)
end
+
+ def assert_not_desugared(source, reason)
+ ast = YARP.parse(source).value
+ assert_equal_nodes(ast, ast.accept(YARP::DesugarVisitor.new))
+ end
end
end