summaryrefslogtreecommitdiff
path: root/lib/prism/desugar_compiler.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/prism/desugar_compiler.rb')
-rw-r--r--lib/prism/desugar_compiler.rb305
1 files changed, 225 insertions, 80 deletions
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
index daca02f35e..00b3097f9f 100644
--- a/lib/prism/desugar_compiler.rb
+++ b/lib/prism/desugar_compiler.rb
@@ -1,6 +1,216 @@
# frozen_string_literal: true
module Prism
+ class DesugarAndWriteNode # :nodoc:
+ attr_reader :node, :source, :read_class, :write_class, :arguments
+
+ def initialize(node, source, read_class, write_class, *arguments)
+ @node = node
+ @source = source
+ @read_class = read_class
+ @write_class = write_class
+ @arguments = arguments
+ end
+
+ # Desugar `x &&= y` to `x && x = y`
+ def compile
+ AndNode.new(
+ source,
+ read_class.new(source, *arguments, node.name_loc),
+ write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location),
+ node.operator_loc,
+ node.location
+ )
+ end
+ end
+
+ class DesugarOrWriteDefinedNode # :nodoc:
+ attr_reader :node, :source, :read_class, :write_class, :arguments
+
+ def initialize(node, source, read_class, write_class, *arguments)
+ @node = node
+ @source = source
+ @read_class = read_class
+ @write_class = write_class
+ @arguments = arguments
+ end
+
+ # Desugar `x ||= y` to `defined?(x) ? x : x = y`
+ def compile
+ IfNode.new(
+ source,
+ node.operator_loc,
+ DefinedNode.new(source, nil, read_class.new(source, *arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
+ node.operator_loc,
+ StatementsNode.new(source, [read_class.new(source, *arguments, node.name_loc)], node.location),
+ ElseNode.new(
+ source,
+ node.operator_loc,
+ StatementsNode.new(
+ source,
+ [write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location)],
+ node.location
+ ),
+ node.operator_loc,
+ node.location
+ ),
+ node.operator_loc,
+ node.location
+ )
+ end
+ end
+
+ class DesugarOperatorWriteNode # :nodoc:
+ attr_reader :node, :source, :read_class, :write_class, :arguments
+
+ def initialize(node, source, read_class, write_class, *arguments)
+ @node = node
+ @source = source
+ @read_class = read_class
+ @write_class = write_class
+ @arguments = arguments
+ end
+
+ # Desugar `x += y` to `x = x + y`
+ def compile
+ write_class.new(
+ source,
+ *arguments,
+ node.name_loc,
+ CallNode.new(
+ source,
+ 0,
+ read_class.new(source, *arguments, node.name_loc),
+ nil,
+ node.operator_loc.slice.chomp("="),
+ node.operator_loc.copy(length: node.operator_loc.length - 1),
+ nil,
+ ArgumentsNode.new(source, 0, [node.value], node.value.location),
+ nil,
+ nil,
+ node.location
+ ),
+ node.operator_loc.copy(start_offset: node.operator_loc.end_offset - 1, length: 1),
+ node.location
+ )
+ end
+ end
+
+ class DesugarOrWriteNode # :nodoc:
+ attr_reader :node, :source, :read_class, :write_class, :arguments
+
+ def initialize(node, source, read_class, write_class, *arguments)
+ @node = node
+ @source = source
+ @read_class = read_class
+ @write_class = write_class
+ @arguments = arguments
+ end
+
+ # Desugar `x ||= y` to `x || x = y`
+ def compile
+ OrNode.new(
+ source,
+ read_class.new(source, *arguments, node.name_loc),
+ write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location),
+ node.operator_loc,
+ node.location
+ )
+ end
+ end
+
+ private_constant :DesugarAndWriteNode, :DesugarOrWriteNode, :DesugarOrWriteDefinedNode, :DesugarOperatorWriteNode
+
+ class ClassVariableAndWriteNode
+ def desugar # :nodoc:
+ DesugarAndWriteNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
+ end
+ end
+
+ class ClassVariableOrWriteNode
+ def desugar # :nodoc:
+ DesugarOrWriteDefinedNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
+ end
+ end
+
+ class ClassVariableOperatorWriteNode
+ def desugar # :nodoc:
+ DesugarOperatorWriteNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
+ end
+ end
+
+ class ConstantAndWriteNode
+ def desugar # :nodoc:
+ DesugarAndWriteNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
+ end
+ end
+
+ class ConstantOrWriteNode
+ def desugar # :nodoc:
+ DesugarOrWriteDefinedNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
+ end
+ end
+
+ class ConstantOperatorWriteNode
+ def desugar # :nodoc:
+ DesugarOperatorWriteNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
+ end
+ end
+
+ class GlobalVariableAndWriteNode
+ def desugar # :nodoc:
+ DesugarAndWriteNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
+ end
+ end
+
+ class GlobalVariableOrWriteNode
+ def desugar # :nodoc:
+ DesugarOrWriteDefinedNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
+ end
+ end
+
+ class GlobalVariableOperatorWriteNode
+ def desugar # :nodoc:
+ DesugarOperatorWriteNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
+ end
+ end
+
+ class InstanceVariableAndWriteNode
+ def desugar # :nodoc:
+ DesugarAndWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
+ end
+ end
+
+ class InstanceVariableOrWriteNode
+ def desugar # :nodoc:
+ DesugarOrWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
+ end
+ end
+
+ class InstanceVariableOperatorWriteNode
+ def desugar # :nodoc:
+ DesugarOperatorWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
+ end
+ end
+
+ class LocalVariableAndWriteNode
+ def desugar # :nodoc:
+ DesugarAndWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
+ end
+ end
+
+ class LocalVariableOrWriteNode
+ def desugar # :nodoc:
+ DesugarOrWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
+ end
+ end
+
+ class LocalVariableOperatorWriteNode
+ def desugar # :nodoc:
+ DesugarOperatorWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
+ end
+ end
+
# DesugarCompiler is a compiler that desugars Ruby code into a more primitive
# form. This is useful for consumers that want to deal with fewer node types.
class DesugarCompiler < MutationCompiler
@@ -10,7 +220,7 @@ module Prism
#
# @@foo && @@foo = bar
def visit_class_variable_and_write_node(node)
- desugar_and_write_node(node, ClassVariableReadNode, ClassVariableWriteNode, node.name)
+ node.desugar
end
# @@foo ||= bar
@@ -19,7 +229,7 @@ module Prism
#
# defined?(@@foo) ? @@foo : @@foo = bar
def visit_class_variable_or_write_node(node)
- desugar_or_write_defined_node(node, ClassVariableReadNode, ClassVariableWriteNode, node.name)
+ node.desugar
end
# @@foo += bar
@@ -28,7 +238,7 @@ module Prism
#
# @@foo = @@foo + bar
def visit_class_variable_operator_write_node(node)
- desugar_operator_write_node(node, ClassVariableReadNode, ClassVariableWriteNode, node.name)
+ node.desugar
end
# Foo &&= bar
@@ -37,7 +247,7 @@ module Prism
#
# Foo && Foo = bar
def visit_constant_and_write_node(node)
- desugar_and_write_node(node, ConstantReadNode, ConstantWriteNode, node.name)
+ node.desugar
end
# Foo ||= bar
@@ -46,7 +256,7 @@ module Prism
#
# defined?(Foo) ? Foo : Foo = bar
def visit_constant_or_write_node(node)
- desugar_or_write_defined_node(node, ConstantReadNode, ConstantWriteNode, node.name)
+ node.desugar
end
# Foo += bar
@@ -55,7 +265,7 @@ module Prism
#
# Foo = Foo + bar
def visit_constant_operator_write_node(node)
- desugar_operator_write_node(node, ConstantReadNode, ConstantWriteNode, node.name)
+ node.desugar
end
# $foo &&= bar
@@ -64,7 +274,7 @@ module Prism
#
# $foo && $foo = bar
def visit_global_variable_and_write_node(node)
- desugar_and_write_node(node, GlobalVariableReadNode, GlobalVariableWriteNode, node.name)
+ node.desugar
end
# $foo ||= bar
@@ -73,7 +283,7 @@ module Prism
#
# defined?($foo) ? $foo : $foo = bar
def visit_global_variable_or_write_node(node)
- desugar_or_write_defined_node(node, GlobalVariableReadNode, GlobalVariableWriteNode, node.name)
+ node.desugar
end
# $foo += bar
@@ -82,7 +292,7 @@ module Prism
#
# $foo = $foo + bar
def visit_global_variable_operator_write_node(node)
- desugar_operator_write_node(node, GlobalVariableReadNode, GlobalVariableWriteNode, node.name)
+ node.desugar
end
# @foo &&= bar
@@ -91,7 +301,7 @@ module Prism
#
# @foo && @foo = bar
def visit_instance_variable_and_write_node(node)
- desugar_and_write_node(node, InstanceVariableReadNode, InstanceVariableWriteNode, node.name)
+ node.desugar
end
# @foo ||= bar
@@ -100,7 +310,7 @@ module Prism
#
# @foo || @foo = bar
def visit_instance_variable_or_write_node(node)
- desugar_or_write_node(node, InstanceVariableReadNode, InstanceVariableWriteNode, node.name)
+ node.desugar
end
# @foo += bar
@@ -109,7 +319,7 @@ module Prism
#
# @foo = @foo + bar
def visit_instance_variable_operator_write_node(node)
- desugar_operator_write_node(node, InstanceVariableReadNode, InstanceVariableWriteNode, node.name)
+ node.desugar
end
# foo &&= bar
@@ -118,7 +328,7 @@ module Prism
#
# foo && foo = bar
def visit_local_variable_and_write_node(node)
- desugar_and_write_node(node, LocalVariableReadNode, LocalVariableWriteNode, node.name, node.depth)
+ node.desugar
end
# foo ||= bar
@@ -127,7 +337,7 @@ module Prism
#
# foo || foo = bar
def visit_local_variable_or_write_node(node)
- desugar_or_write_node(node, LocalVariableReadNode, LocalVariableWriteNode, node.name, node.depth)
+ node.desugar
end
# foo += bar
@@ -136,72 +346,7 @@ module Prism
#
# foo = foo + bar
def visit_local_variable_operator_write_node(node)
- desugar_operator_write_node(node, LocalVariableReadNode, LocalVariableWriteNode, node.name, node.depth)
- end
-
- private
-
- # Desugar `x &&= y` to `x && x = y`
- def desugar_and_write_node(node, read_class, write_class, *arguments)
- AndNode.new(
- read_class.new(*arguments, node.name_loc),
- write_class.new(*arguments, node.name_loc, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
- )
- end
-
- # Desugar `x += y` to `x = x + y`
- def desugar_operator_write_node(node, read_class, write_class, *arguments)
- write_class.new(
- *arguments,
- node.name_loc,
- CallNode.new(
- 0,
- read_class.new(*arguments, node.name_loc),
- nil,
- node.operator_loc.slice.chomp("="),
- node.operator_loc.copy(length: node.operator_loc.length - 1),
- nil,
- ArgumentsNode.new(0, [node.value], node.value.location),
- nil,
- nil,
- node.location
- ),
- node.operator_loc.copy(start_offset: node.operator_loc.end_offset - 1, length: 1),
- node.location
- )
- end
-
- # Desugar `x ||= y` to `x || x = y`
- def desugar_or_write_node(node, read_class, write_class, *arguments)
- OrNode.new(
- read_class.new(*arguments, node.name_loc),
- write_class.new(*arguments, node.name_loc, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
- )
- end
-
- # Desugar `x ||= y` to `defined?(x) ? x : x = y`
- def desugar_or_write_defined_node(node, read_class, write_class, *arguments)
- IfNode.new(
- node.operator_loc,
- DefinedNode.new(nil, read_class.new(*arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
- node.operator_loc,
- StatementsNode.new([read_class.new(*arguments, node.name_loc)], node.location),
- ElseNode.new(
- node.operator_loc,
- StatementsNode.new(
- [write_class.new(*arguments, node.name_loc, node.value, node.operator_loc, node.location)],
- node.location
- ),
- node.operator_loc,
- node.location
- ),
- node.operator_loc,
- node.location
- )
+ node.desugar
end
end
end