summaryrefslogtreecommitdiff
path: root/lib/prism/desugar_compiler.rb
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-02-15 13:41:40 -0500
committergit <svn-admin@ruby-lang.org>2024-02-15 20:39:50 +0000
commit14a7277da13f4c082850cb30c36f4458b6fd35d1 (patch)
tree1cf18bcdc5748efafaf042b046fbb0f349d669eb /lib/prism/desugar_compiler.rb
parent87cc2fd015fa7f840ae53bb58472354da754b44d (diff)
[ruby/prism] Speed up creating Ruby AST
When creating the Ruby AST, we were previously allocating Location objects for every node and every inner location. Instead, this commit changes it to pack both the start offset and length into a single u64 and pass that into the nodes. Then, when the locations are requested via a reader method, we lazily allocate the Location objects. https://github.com/ruby/prism/commit/de203dca83 Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
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