diff options
| author | Benoit Daloze <eregontp@gmail.com> | 2023-08-30 22:22:04 +0200 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2023-09-01 13:18:29 +0000 |
| commit | 4172036bc6ba77aded874f67b15d657bd7ee3241 (patch) | |
| tree | e488c41e52ab92aac9c35e3d748abbffe61689f4 | |
| parent | 7fb56df726d4e661fdec10266a54cf27e52d9892 (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.rb | 63 | ||||
| -rw-r--r-- | test/yarp/desugar_visitor_test.rb | 11 |
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 |
