# frozen_string_literal: true
# :markup: markdown

=begin
--
This file is generated by the templates/template.rb script and should not be
modified manually. See templates/lib/prism/node.rb.erb
if you are looking to modify the template
++
=end

#--
# rbs_inline: enabled

module Prism
  # @rbs!
  #    interface _Repository
  #      def enter: (Integer node_id, Symbol field_name) -> Relocation::Entry
  #    end
  #
  #    interface _Node
  #      def deconstruct: () -> Array[Prism::node?]
  #      def inspect: () -> String
  #    end
  #
  #    type node = Node & _Node

  # This represents a node in the tree. It is the parent class of all of the
  # various node types.
  class Node
    # A pointer to the source that this node was created from.
    # :stopdoc:
    attr_reader :source #: Source
    private :source
    # :startdoc:

    # A unique identifier for this node. This is used in a very specific
    # use case where you want to keep around a reference to a node without
    # having to keep around the syntax tree in memory. This unique identifier
    # will be consistent across multiple parses of the same source code.
    attr_reader :node_id #: Integer

    # The location associated with this node. For lazily loading Location
    # objects, we keep it as a packed integer until it is accessed.
    # @rbs @location: Location | Integer

    # Save this node using a saved source so that it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save(repository)
      repository.enter(node_id, :itself)
    end

    # A Location instance that represents the location of this node in the
    # source.
    #--
    #: () -> Location
    def location
      location = @location
      return location if location.is_a?(Location)
      @location = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # Save the location using a saved source so that it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_location(repository)
      repository.enter(node_id, :location)
    end

    # --------------------------------------------------------------------------
    # :section: Location Delegators
    # These methods provide convenient access to the underlying Location object.
    # --------------------------------------------------------------------------

    # Delegates to [`start_line`](rdoc-ref:Location#start_line) of the associated location object.
    #--
    #: () -> Integer
    def start_line
      location.start_line
    end

    # Delegates to [`end_line`](rdoc-ref:Location#end_line) of the associated location object.
    #--
    #: () -> Integer
    def end_line
      location.end_line
    end

    # Delegates to [`start_offset`](rdoc-ref:Location#start_offset) of the associated location object.
    #--
    #: () -> Integer
    def start_offset
      location = @location
      location.is_a?(Location) ? location.start_offset : location >> 32
    end

    # Delegates to [`end_offset`](rdoc-ref:Location#end_offset) of the associated location object.
    #--
    #: () -> Integer
    def end_offset
      location = @location
      location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
    end

    # Delegates to [`start_character_offset`](rdoc-ref:Location#start_character_offset)
    # of the associated location object.
    #--
    #: () -> Integer
    def start_character_offset
      location.start_character_offset
    end

    # Delegates to [`end_character_offset`](rdoc-ref:Location#end_character_offset)
    # of the associated location object.
    #--
    #: () -> Integer
    def end_character_offset
      location.end_character_offset
    end

    # Delegates to [`cached_start_code_units_offset`](rdoc-ref:Location#cached_start_code_units_offset)
    # of the associated location object.
    #--
    #: (_CodeUnitsCache cache) -> Integer
    def cached_start_code_units_offset(cache)
      location.cached_start_code_units_offset(cache)
    end

    # Delegates to [`cached_end_code_units_offset`](rdoc-ref:Location#cached_end_code_units_offset)
    # of the associated location object.
    #--
    #: (_CodeUnitsCache cache) -> Integer
    def cached_end_code_units_offset(cache)
      location.cached_end_code_units_offset(cache)
    end

    # Delegates to [`start_column`](rdoc-ref:Location#start_column) of the associated location object.
    #--
    #: () -> Integer
    def start_column
      location.start_column
    end

    # Delegates to [`end_column`](rdoc-ref:Location#end_column) of the associated location object.
    #--
    #: () -> Integer
    def end_column
      location.end_column
    end

    # Delegates to [`start_character_column`](rdoc-ref:Location#start_character_column)
    # of the associated location object.
    #--
    #: () -> Integer
    def start_character_column
      location.start_character_column
    end

    # Delegates to [`end_character_column`](rdoc-ref:Location#end_character_column)
    # of the associated location object.
    #--
    #: () -> Integer
    def end_character_column
      location.end_character_column
    end

    # Delegates to [`cached_start_code_units_column`](rdoc-ref:Location#cached_start_code_units_column)
    # of the associated location object.
    #--
    #: (_CodeUnitsCache cache) -> Integer
    def cached_start_code_units_column(cache)
      location.cached_start_code_units_column(cache)
    end

    # Delegates to [`cached_end_code_units_column`](rdoc-ref:Location#cached_end_code_units_column)
    # of the associated location object.
    #--
    #: (_CodeUnitsCache cache) -> Integer
    def cached_end_code_units_column(cache)
      location.cached_end_code_units_column(cache)
    end

    # Delegates to [`leading_comments`](rdoc-ref:Location#leading_comments) of the associated location object.
    #--
    #: () -> Array[Comment]
    def leading_comments
      location.leading_comments
    end

    # Delegates to [`trailing_comments`](rdoc-ref:Location#trailing_comments) of the associated location object.
    #--
    #: () -> Array[Comment]
    def trailing_comments
      location.trailing_comments
    end

    # Delegates to [`comments`](rdoc-ref:Location#comments) of the associated location object.
    #--
    #: () -> Array[Comment]
    def comments
      location.comments
    end

    # :section:

    # Returns all of the lines of the source code associated with this node.
    #--
    #: () -> Array[String]
    def source_lines
      location.source_lines
    end

    # An alias for source_lines, used to mimic the API from
    # RubyVM::AbstractSyntaxTree to make it easier to migrate.
    alias script_lines source_lines

    # Slice the location of the node from the source.
    #--
    #: () -> String
    def slice
      location.slice
    end

    # Slice the location of the node from the source, starting at the beginning
    # of the line that the location starts on, ending at the end of the line
    # that the location ends on.
    #--
    #: () -> String
    def slice_lines
      location.slice_lines
    end

    # An bitset of flags for this node. There are certain flags that are common
    # for all nodes, and then some nodes have specific flags.
    # :stopdoc:
    attr_reader :flags #: Integer
    protected :flags
    # :startdoc:

    # Returns true if the node has the newline flag set.
    #--
    #: () -> bool
    def newline?
      flags.anybits?(NodeFlags::NEWLINE)
    end

    # Returns true if the node has the static literal flag set.
    #--
    #: () -> bool
    def static_literal?
      flags.anybits?(NodeFlags::STATIC_LITERAL)
    end

    # Similar to inspect, but respects the current level of indentation given by
    # the pretty print object.
    #--
    #: (PP q) -> void
    def pretty_print(q) # :nodoc:
      q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
        q.text(line.chomp)
      end
      q.current_group.break
    end

    # Convert this node into a graphviz dot graph string.
    #--
    #: () -> String
    def to_dot
      # @type self: node
      DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
    end

    # Returns a list of nodes that are descendants of this node that contain the
    # given line and column. This is useful for locating a node that is selected
    # based on the line and column of the source code.
    #
    # Important to note is that the column given to this method should be in
    # bytes, as opposed to characters or code units.
    #--
    #: (Integer line, Integer column) -> Array[node]
    def tunnel(line, column)
      queue = [self] #: Array[node]
      result = [] #: Array[node]
      offset = source.byte_offset(line, column)

      while (node = queue.shift)
        result << node

        node.each_child_node do |child_node|
          if child_node.start_offset <= offset && offset < child_node.end_offset
            queue << child_node
            break
          end
        end
      end

      result
    end

    # Returns the first node that matches the given block when visited in a
    # breadth-first search. This is useful for finding a node that matches a
    # particular condition.
    #
    #     node.breadth_first_search { |node| node.node_id == node_id }
    #--
    #: () { (node) -> bool } -> node?
    def breadth_first_search(&blk)
      queue = [self] #: Array[node]

      while (node = queue.shift)
        return node if yield node
        queue.concat(node.compact_child_nodes)
      end

      nil
    end
    alias find breadth_first_search

    # Returns all of the nodes that match the given block when visited in a
    # breadth-first search. This is useful for finding all nodes that match a
    # particular condition.
    #
    #     node.breadth_first_search_all { |node| node.is_a?(Prism::CallNode) }
    #--
    #: () { (node) -> bool } -> Array[node]
    def breadth_first_search_all(&blk)
      queue = [self] #: Array[Prism::node]
      results = [] #: Array[Prism::node]

      while (node = queue.shift)
        results << node if yield node
        queue.concat(node.compact_child_nodes)
      end

      results
    end
    alias find_all breadth_first_search_all

    # Returns a list of the fields that exist for this node class. Fields
    # describe the structure of the node. This kind of reflection is useful for
    # things like recursively visiting each node _and_ field in the tree.
    #--
    #: () -> Array[Reflection::Field]
    def self.fields
      # This method should only be called on subclasses of Node, not Node
      # itself.
      raise NoMethodError, "undefined method `fields' for #{inspect}" if self == Node

      Reflection.fields_for(self)
    end

    # --------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are effectively abstract methods that are implemented by
    # the various subclasses of Node.
    # --------------------------------------------------------------------------

    # Accepts a visitor and calls back into the specialized visit function.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      raise NoMethodError, "undefined method `accept' for #{inspect}"
    end

    # Returns an array of child nodes, including `nil`s in the place of optional
    # nodes that were not present.
    #--
    #: () -> Array[node?]
    def child_nodes
      raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
    end

    alias deconstruct child_nodes

    # With a block given, yields each child node. Without a block, returns
    # an enumerator that contains each child node. Excludes any `nil`s in
    # the place of optional nodes that were not present.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      raise NoMethodError, "undefined method `each_child_node' for #{inspect}"
    end

    # Returns an array of child nodes, excluding any `nil`s in the place of
    # optional nodes that were not present.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
    end

    # Returns an array of child nodes and locations that could potentially have
    # comments attached to them.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
    end

    # Returns a string representation of the node.
    #--
    #: () -> String
    def inspect
      raise NoMethodError, "undefined method `inspect' for #{inspect}"
    end

    # Sometimes you want to check an instance of a node against a list of
    # classes to see what kind of behavior to perform. Usually this is done by
    # calling `[cls1, cls2].include?(node.class)` or putting the node into a
    # case statement and doing `case node; when cls1; when cls2; end`. Both of
    # these approaches are relatively slow because of the constant lookups,
    # method calls, and/or array allocations.
    #
    # Instead, you can call #type, which will return to you a symbol that you
    # can use for comparison. This is faster than the other approaches because
    # it uses a single integer comparison, but also because if you're on CRuby
    # you can take advantage of the fact that case statements with all symbol
    # keys will use a jump table.
    #--
    #: () -> Symbol
    def type
      raise NoMethodError, "undefined method `type' for #{inspect}"
    end

    # Similar to #type, this method returns a symbol that you can use for
    # splitting on the type of the node without having to do a long === chain.
    # Note that like #type, it will still be slower than using == for a single
    # class, but should be faster in a case statement or an array comparison.
    #--
    #: () -> Symbol
    def self.type
      raise NoMethodError, "undefined method `type' for #{inspect}"
    end
  end

  # Represents the use of the `alias` keyword to alias a global variable.
  #
  #     alias $foo $bar
  #     ^^^^^^^^^^^^^^^
  class AliasGlobalVariableNode < Node
    # @rbs @new_name: (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)
    # @rbs @old_name: (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)
    # @rbs @keyword_loc: Location

    # Initialize a new AliasGlobalVariableNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode) new_name, (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode) old_name, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, new_name, old_name, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @new_name = new_name
      @old_name = old_name
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_alias_global_variable_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [new_name, old_name]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield new_name
      yield old_name
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [new_name, old_name]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [new_name, old_name, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> AliasGlobalVariableNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?new_name: (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode), ?old_name: (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode), ?keyword_loc: Location) -> AliasGlobalVariableNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, new_name: self.new_name, old_name: self.old_name, keyword_loc: self.keyword_loc)
      AliasGlobalVariableNode.new(source, node_id, location, flags, new_name, old_name, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location new_name old_name keyword_loc keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :new_name                then deconstructed[:new_name] = self.new_name
        when :old_name                then deconstructed[:old_name] = self.old_name
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :alias_global_variable_node
    def type
      :alias_global_variable_node
    end

    # See `Node.type`.
    #--
    #: () -> :alias_global_variable_node
    def self.type
      :alias_global_variable_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   new_name -> GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode
    #
    # Represents the new name of the global variable that can be used after aliasing.
    #
    #     alias $foo $bar
    #           ^^^^
    #--
    #: () -> (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)
    def new_name
      @new_name
    end

    # :call-seq:
    #   old_name -> GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode
    #
    # Represents the old name of the global variable that can be used before aliasing.
    #
    #     alias $foo $bar
    #                ^^^^
    #--
    #: () -> (GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)
    def old_name
      @old_name
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # The Location of the `alias` keyword.
    #
    #     alias $foo $bar
    #     ^^^^^
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(AliasGlobalVariableNode) &&
        (new_name === other.new_name) &&
        (old_name === other.old_name) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents the use of the `alias` keyword to alias a method.
  #
  #     alias foo bar
  #     ^^^^^^^^^^^^^
  class AliasMethodNode < Node
    # @rbs @new_name: (SymbolNode | InterpolatedSymbolNode)
    # @rbs @old_name: (SymbolNode | InterpolatedSymbolNode)
    # @rbs @keyword_loc: Location

    # Initialize a new AliasMethodNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (SymbolNode | InterpolatedSymbolNode) new_name, (SymbolNode | InterpolatedSymbolNode) old_name, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, new_name, old_name, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @new_name = new_name
      @old_name = old_name
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_alias_method_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [new_name, old_name]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield new_name
      yield old_name
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [new_name, old_name]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [new_name, old_name, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> AliasMethodNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?new_name: (SymbolNode | InterpolatedSymbolNode), ?old_name: (SymbolNode | InterpolatedSymbolNode), ?keyword_loc: Location) -> AliasMethodNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, new_name: self.new_name, old_name: self.old_name, keyword_loc: self.keyword_loc)
      AliasMethodNode.new(source, node_id, location, flags, new_name, old_name, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location new_name old_name keyword_loc keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :new_name                then deconstructed[:new_name] = self.new_name
        when :old_name                then deconstructed[:old_name] = self.old_name
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :alias_method_node
    def type
      :alias_method_node
    end

    # See `Node.type`.
    #--
    #: () -> :alias_method_node
    def self.type
      :alias_method_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   new_name -> SymbolNode | InterpolatedSymbolNode
    #
    # Represents the new name of the method that will be aliased.
    #
    #     alias foo bar
    #           ^^^
    #
    #     alias :foo :bar
    #           ^^^^
    #
    #     alias :"#{foo}" :"#{bar}"
    #           ^^^^^^^^^
    #--
    #: () -> (SymbolNode | InterpolatedSymbolNode)
    def new_name
      @new_name
    end

    # :call-seq:
    #   old_name -> SymbolNode | InterpolatedSymbolNode
    #
    # Represents the old name of the method that will be aliased.
    #
    #     alias foo bar
    #               ^^^
    #
    #     alias :foo :bar
    #                ^^^^
    #
    #     alias :"#{foo}" :"#{bar}"
    #                     ^^^^^^^^^
    #--
    #: () -> (SymbolNode | InterpolatedSymbolNode)
    def old_name
      @old_name
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Represents the Location of the `alias` keyword.
    #
    #     alias foo bar
    #     ^^^^^
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(AliasMethodNode) &&
        (new_name === other.new_name) &&
        (old_name === other.old_name) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents an alternation pattern in pattern matching.
  #
  #     foo => bar | baz
  #            ^^^^^^^^^
  class AlternationPatternNode < Node
    # @rbs @left: Prism::node
    # @rbs @right: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new AlternationPatternNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node left, Prism::node right, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, left, right, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_alternation_pattern_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [left, right]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield left
      yield right
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [left, right]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [left, right, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> AlternationPatternNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?left: Prism::node, ?right: Prism::node, ?operator_loc: Location) -> AlternationPatternNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, left: self.left, right: self.right, operator_loc: self.operator_loc)
      AlternationPatternNode.new(source, node_id, location, flags, left, right, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location left right operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :left                    then deconstructed[:left] = self.left
        when :right                   then deconstructed[:right] = self.right
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :alternation_pattern_node
    def type
      :alternation_pattern_node
    end

    # See `Node.type`.
    #--
    #: () -> :alternation_pattern_node
    def self.type
      :alternation_pattern_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   left -> Node
    #
    # Represents the left side of the expression.
    #
    #     foo => bar | baz
    #            ^^^
    #--
    #: () -> Prism::node
    def left
      @left
    end

    # :call-seq:
    #   right -> Node
    #
    # Represents the right side of the expression.
    #
    #     foo => bar | baz
    #                  ^^^
    #--
    #: () -> Prism::node
    def right
      @right
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the alternation operator Location.
    #
    #     foo => bar | baz
    #                ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(AlternationPatternNode) &&
        (left === other.left) &&
        (right === other.right) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents the use of the `&&` operator or the `and` keyword.
  #
  #     left and right
  #     ^^^^^^^^^^^^^^
  class AndNode < Node
    # @rbs @left: Prism::node
    # @rbs @right: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new AndNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node left, Prism::node right, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, left, right, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_and_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [left, right]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield left
      yield right
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [left, right]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [left, right, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> AndNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?left: Prism::node, ?right: Prism::node, ?operator_loc: Location) -> AndNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, left: self.left, right: self.right, operator_loc: self.operator_loc)
      AndNode.new(source, node_id, location, flags, left, right, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location left right operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :left                    then deconstructed[:left] = self.left
        when :right                   then deconstructed[:right] = self.right
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :and_node
    def type
      :and_node
    end

    # See `Node.type`.
    #--
    #: () -> :and_node
    def self.type
      :and_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   left -> Node
    #
    # Represents the left side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     left and right
    #     ^^^^
    #
    #     1 && 2
    #     ^
    #--
    #: () -> Prism::node
    def left
      @left
    end

    # :call-seq:
    #   right -> Node
    #
    # Represents the right side of the expression.
    #
    #     left && right
    #             ^^^^^
    #
    #     1 and 2
    #           ^
    #--
    #: () -> Prism::node
    def right
      @right
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `and` keyword or the `&&` operator.
    #
    #     left and right
    #          ^^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(AndNode) &&
        (left === other.left) &&
        (right === other.right) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a set of arguments to a method or a keyword.
  #
  #     return foo, bar, baz
  #            ^^^^^^^^^^^^^
  class ArgumentsNode < Node
    # @rbs @arguments: Array[Prism::node]

    # Initialize a new ArgumentsNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Prism::node] arguments) -> void
    def initialize(source, node_id, location, flags, arguments)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @arguments = arguments
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_arguments_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*arguments]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      arguments.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*arguments]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*arguments] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ArgumentsNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?arguments: Array[Prism::node]) -> ArgumentsNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, arguments: self.arguments)
      ArgumentsNode.new(source, node_id, location, flags, arguments)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location arguments]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :arguments               then deconstructed[:arguments] = self.arguments
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :arguments_node
    def type
      :arguments_node
    end

    # See `Node.type`.
    #--
    #: () -> :arguments_node
    def self.type
      :arguments_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # if the arguments contain forwarding
    #--
    #: () -> bool
    def contains_forwarding?
      flags.anybits?(ArgumentsNodeFlags::CONTAINS_FORWARDING)
    end

    # :category: Flags
    # if the arguments contain keywords
    #--
    #: () -> bool
    def contains_keywords?
      flags.anybits?(ArgumentsNodeFlags::CONTAINS_KEYWORDS)
    end

    # :category: Flags
    # if the arguments contain a keyword splat
    #--
    #: () -> bool
    def contains_keyword_splat?
      flags.anybits?(ArgumentsNodeFlags::CONTAINS_KEYWORD_SPLAT)
    end

    # :category: Flags
    # if the arguments contain a splat
    #--
    #: () -> bool
    def contains_splat?
      flags.anybits?(ArgumentsNodeFlags::CONTAINS_SPLAT)
    end

    # :category: Flags
    # if the arguments contain multiple splats
    #--
    #: () -> bool
    def contains_multiple_splats?
      flags.anybits?(ArgumentsNodeFlags::CONTAINS_MULTIPLE_SPLATS)
    end

    # :call-seq:
    #   arguments -> Array[Node]
    #
    # The list of arguments, if present. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo(bar, baz)
    #         ^^^^^^^^
    #--
    #: () -> Array[Prism::node]
    def arguments
      @arguments
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ArgumentsNode) &&
        (flags === other.flags) &&
        (arguments.length == other.arguments.length) &&
        arguments.zip(other.arguments).all? { |left, right| left === right }
    end
  end

  # Represents an array literal. This can be a regular array using brackets or a special array using % like %w or %i.
  #
  #     [1, 2, 3]
  #     ^^^^^^^^^
  class ArrayNode < Node
    # @rbs @elements: Array[Prism::node]
    # @rbs @opening_loc: Location?
    # @rbs @closing_loc: Location?

    # Initialize a new ArrayNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Prism::node] elements, Location? opening_loc, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, elements, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @elements = elements
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_array_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*elements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      elements.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*elements]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*elements, *opening_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ArrayNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?elements: Array[Prism::node], ?opening_loc: Location?, ?closing_loc: Location?) -> ArrayNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, elements: self.elements, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      ArrayNode.new(source, node_id, location, flags, elements, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location elements opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :elements                then deconstructed[:elements] = self.elements
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :array_node
    def type
      :array_node
    end

    # See `Node.type`.
    #--
    #: () -> :array_node
    def self.type
      :array_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # if array contains splat nodes
    #--
    #: () -> bool
    def contains_splat?
      flags.anybits?(ArrayNodeFlags::CONTAINS_SPLAT)
    end

    # :call-seq:
    #   elements -> Array[Node]
    #
    # Represent the list of zero or more [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression) within the array.
    #--
    #: () -> Array[Prism::node]
    def elements
      @elements
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Represents the optional source Location for the opening token.
    #
    #     [1,2,3]                 # "["
    #     %w[foo bar baz]         # "%w["
    #     %I(apple orange banana) # "%I("
    #     foo = 1, 2, 3           # nil
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Represents the optional source Location for the closing token.
    #
    #     [1,2,3]                 # "]"
    #     %w[foo bar baz]         # "]"
    #     %I(apple orange banana) # ")"
    #     foo = 1, 2, 3           # nil
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ArrayNode) &&
        (flags === other.flags) &&
        (elements.length == other.elements.length) &&
        elements.zip(other.elements).all? { |left, right| left === right } &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents an array pattern in pattern matching.
  #
  #     foo in 1, 2
  #            ^^^^
  #
  #     foo in [1, 2]
  #            ^^^^^^
  #
  #     foo in *bar
  #            ^^^^
  #
  #     foo in Bar[]
  #            ^^^^^
  #
  #     foo in Bar[1, 2, 3]
  #            ^^^^^^^^^^^^
  class ArrayPatternNode < Node
    # @rbs @constant: (ConstantPathNode | ConstantReadNode)?
    # @rbs @requireds: Array[Prism::node]
    # @rbs @rest: (ImplicitRestNode | SplatNode)?
    # @rbs @posts: Array[Prism::node]
    # @rbs @opening_loc: Location?
    # @rbs @closing_loc: Location?

    # Initialize a new ArrayPatternNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (ConstantPathNode | ConstantReadNode)? constant, Array[Prism::node] requireds, (ImplicitRestNode | SplatNode)? rest, Array[Prism::node] posts, Location? opening_loc, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, constant, requireds, rest, posts, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @constant = constant
      @requireds = requireds
      @rest = rest
      @posts = posts
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_array_pattern_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [constant, *requireds, rest, *posts]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (constant = self.constant); yield constant; end
      requireds.each { |node| yield node }
      if (rest = self.rest); yield rest; end
      posts.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (constant = self.constant); compact << constant; end
      compact.concat(requireds)
      if (rest = self.rest); compact << rest; end
      compact.concat(posts)
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*constant, *requireds, *rest, *posts, *opening_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ArrayPatternNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?constant: (ConstantPathNode | ConstantReadNode)?, ?requireds: Array[Prism::node], ?rest: (ImplicitRestNode | SplatNode)?, ?posts: Array[Prism::node], ?opening_loc: Location?, ?closing_loc: Location?) -> ArrayPatternNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, constant: self.constant, requireds: self.requireds, rest: self.rest, posts: self.posts, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      ArrayPatternNode.new(source, node_id, location, flags, constant, requireds, rest, posts, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location constant requireds rest posts opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :constant                then deconstructed[:constant] = self.constant
        when :requireds               then deconstructed[:requireds] = self.requireds
        when :rest                    then deconstructed[:rest] = self.rest
        when :posts                   then deconstructed[:posts] = self.posts
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :array_pattern_node
    def type
      :array_pattern_node
    end

    # See `Node.type`.
    #--
    #: () -> :array_pattern_node
    def self.type
      :array_pattern_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   constant -> ConstantPathNode | ConstantReadNode | nil
    #
    # Represents the optional constant preceding the Array
    #
    #     foo in Bar[]
    #            ^^^
    #
    #     foo in Bar[1, 2, 3]
    #            ^^^
    #
    #     foo in Bar::Baz[1, 2, 3]
    #            ^^^^^^^^
    #--
    #: () -> (ConstantPathNode | ConstantReadNode)?
    def constant
      @constant
    end

    # :call-seq:
    #   requireds -> Array[Node]
    #
    # Represents the required elements of the array pattern.
    #
    #     foo in [1, 2]
    #             ^  ^
    #--
    #: () -> Array[Prism::node]
    def requireds
      @requireds
    end

    # :call-seq:
    #   rest -> ImplicitRestNode | SplatNode | nil
    #
    # Represents the rest element of the array pattern.
    #
    #     foo in *bar
    #            ^^^^
    #--
    #: () -> (ImplicitRestNode | SplatNode)?
    def rest
      @rest
    end

    # :call-seq:
    #   posts -> Array[Node]
    #
    # Represents the elements after the rest element of the array pattern.
    #
    #     foo in *bar, baz
    #                  ^^^
    #--
    #: () -> Array[Prism::node]
    def posts
      @posts
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Represents the opening Location of the array pattern.
    #
    #     foo in [1, 2]
    #            ^
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Represents the closing Location of the array pattern.
    #
    #     foo in [1, 2]
    #                 ^
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ArrayPatternNode) &&
        (constant === other.constant) &&
        (requireds.length == other.requireds.length) &&
        requireds.zip(other.requireds).all? { |left, right| left === right } &&
        (rest === other.rest) &&
        (posts.length == other.posts.length) &&
        posts.zip(other.posts).all? { |left, right| left === right } &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents a hash key/value pair.
  #
  #     { a => b }
  #       ^^^^^^
  class AssocNode < Node
    # @rbs @key: Prism::node
    # @rbs @value: Prism::node
    # @rbs @operator_loc: Location?

    # Initialize a new AssocNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node key, Prism::node value, Location? operator_loc) -> void
    def initialize(source, node_id, location, flags, key, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @key = key
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_assoc_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [key, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield key
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [key, value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [key, value, *operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> AssocNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?key: Prism::node, ?value: Prism::node, ?operator_loc: Location?) -> AssocNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, key: self.key, value: self.value, operator_loc: self.operator_loc)
      AssocNode.new(source, node_id, location, flags, key, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location key value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :key                     then deconstructed[:key] = self.key
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :assoc_node
    def type
      :assoc_node
    end

    # See `Node.type`.
    #--
    #: () -> :assoc_node
    def self.type
      :assoc_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   key -> Node
    #
    # The key of the association. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     { a: b }
    #       ^
    #
    #     { foo => bar }
    #       ^^^
    #
    #     { def a; end => 1 }
    #       ^^^^^^^^^^
    #--
    #: () -> Prism::node
    def key
      @key
    end

    # :call-seq:
    #   value -> Node
    #
    # The value of the association, if present. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     { foo => bar }
    #              ^^^
    #
    #     { x: 1 }
    #          ^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location | nil
    #
    # The Location of the `=>` operator, if present.
    #
    #     { foo => bar }
    #           ^^
    #--
    #: () -> Location?
    def operator_loc
      location = @operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc) unless @operator_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   operator -> String | nil
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String?
    def operator
      operator_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(AssocNode) &&
        (key === other.key) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a splat in a hash literal.
  #
  #     { **foo }
  #       ^^^^^
  class AssocSplatNode < Node
    # @rbs @value: Prism::node?
    # @rbs @operator_loc: Location

    # Initialize a new AssocSplatNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? value, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_assoc_splat_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (value = self.value); yield value; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (value = self.value); compact << value; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*value, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> AssocSplatNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: Prism::node?, ?operator_loc: Location) -> AssocSplatNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value, operator_loc: self.operator_loc)
      AssocSplatNode.new(source, node_id, location, flags, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :assoc_splat_node
    def type
      :assoc_splat_node
    end

    # See `Node.type`.
    #--
    #: () -> :assoc_splat_node
    def self.type
      :assoc_splat_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   value -> Node | nil
    #
    # The value to be splatted, if present. Will be missing when keyword rest argument forwarding is used.
    #
    #     { **foo }
    #         ^^^
    #--
    #: () -> Prism::node?
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `**` operator.
    #
    #     { **x }
    #       ^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(AssocSplatNode) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents reading a reference to a field in the previous match.
  #
  #     $'
  #     ^^
  class BackReferenceReadNode < Node
    # @rbs @name: Symbol

    # Initialize a new BackReferenceReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_back_reference_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BackReferenceReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> BackReferenceReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      BackReferenceReadNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :back_reference_read_node
    def type
      :back_reference_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :back_reference_read_node
    def self.type
      :back_reference_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the back-reference variable, including the leading `$`.
    #
    #     $& # name `:$&`
    #
    #     $+ # name `:$+`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BackReferenceReadNode) &&
        (name === other.name)
    end
  end

  # Represents a begin statement.
  #
  #     begin
  #       foo
  #     end
  #     ^^^^^
  class BeginNode < Node
    # @rbs @begin_keyword_loc: Location?
    # @rbs @statements: StatementsNode?
    # @rbs @rescue_clause: RescueNode?
    # @rbs @else_clause: ElseNode?
    # @rbs @ensure_clause: EnsureNode?
    # @rbs @end_keyword_loc: Location?

    # Initialize a new BeginNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? begin_keyword_loc, StatementsNode? statements, RescueNode? rescue_clause, ElseNode? else_clause, EnsureNode? ensure_clause, Location? end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @begin_keyword_loc = begin_keyword_loc
      @statements = statements
      @rescue_clause = rescue_clause
      @else_clause = else_clause
      @ensure_clause = ensure_clause
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_begin_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements, rescue_clause, else_clause, ensure_clause]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (statements = self.statements); yield statements; end
      if (rescue_clause = self.rescue_clause); yield rescue_clause; end
      if (else_clause = self.else_clause); yield else_clause; end
      if (ensure_clause = self.ensure_clause); yield ensure_clause; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (statements = self.statements); compact << statements; end
      if (rescue_clause = self.rescue_clause); compact << rescue_clause; end
      if (else_clause = self.else_clause); compact << else_clause; end
      if (ensure_clause = self.ensure_clause); compact << ensure_clause; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*begin_keyword_loc, *statements, *rescue_clause, *else_clause, *ensure_clause, *end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BeginNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?begin_keyword_loc: Location?, ?statements: StatementsNode?, ?rescue_clause: RescueNode?, ?else_clause: ElseNode?, ?ensure_clause: EnsureNode?, ?end_keyword_loc: Location?) -> BeginNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, begin_keyword_loc: self.begin_keyword_loc, statements: self.statements, rescue_clause: self.rescue_clause, else_clause: self.else_clause, ensure_clause: self.ensure_clause, end_keyword_loc: self.end_keyword_loc)
      BeginNode.new(source, node_id, location, flags, begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location begin_keyword_loc statements rescue_clause else_clause ensure_clause end_keyword_loc begin_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :begin_keyword_loc       then deconstructed[:begin_keyword_loc] = self.begin_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :rescue_clause           then deconstructed[:rescue_clause] = self.rescue_clause
        when :else_clause             then deconstructed[:else_clause] = self.else_clause
        when :ensure_clause           then deconstructed[:ensure_clause] = self.ensure_clause
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :begin_keyword           then deconstructed[:begin_keyword] = self.begin_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :begin_node
    def type
      :begin_node
    end

    # See `Node.type`.
    #--
    #: () -> :begin_node
    def self.type
      :begin_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   begin_keyword_loc -> Location | nil
    #
    # Represents the Location of the `begin` keyword.
    #
    #     begin x end
    #     ^^^^^
    #--
    #: () -> Location?
    def begin_keyword_loc
      location = @begin_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @begin_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the begin_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_begin_keyword_loc(repository)
      repository.enter(node_id, :begin_keyword_loc) unless @begin_keyword_loc.nil?
    end
    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Represents the statements within the begin block.
    #
    #     begin x end
    #           ^
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :call-seq:
    #   rescue_clause -> RescueNode | nil
    #
    # Represents the rescue clause within the begin block.
    #
    #     begin x; rescue y; end
    #              ^^^^^^^^
    #--
    #: () -> RescueNode?
    def rescue_clause
      @rescue_clause
    end

    # :call-seq:
    #   else_clause -> ElseNode | nil
    #
    # Represents the else clause within the begin block.
    #
    #     begin x; rescue y; else z; end
    #                        ^^^^^^^^^^^
    #--
    #: () -> ElseNode?
    def else_clause
      @else_clause
    end

    # :call-seq:
    #   ensure_clause -> EnsureNode | nil
    #
    # Represents the ensure clause within the begin block.
    #
    #     begin x; ensure y; end
    #              ^^^^^^^^
    #--
    #: () -> EnsureNode?
    def ensure_clause
      @ensure_clause
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # Represents the Location of the `end` keyword.
    #
    #     begin x end
    #             ^^^
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   begin_keyword -> String | nil
    #
    # Slice the location of begin_keyword_loc from the source.
    #--
    #: () -> String?
    def begin_keyword
      begin_keyword_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BeginNode) &&
        (begin_keyword_loc.nil? == other.begin_keyword_loc.nil?) &&
        (statements === other.statements) &&
        (rescue_clause === other.rescue_clause) &&
        (else_clause === other.else_clause) &&
        (ensure_clause === other.ensure_clause) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents a block argument using `&`.
  #
  #     bar(&args)
  #         ^^^^^
  class BlockArgumentNode < Node
    # @rbs @expression: Prism::node?
    # @rbs @operator_loc: Location

    # Initialize a new BlockArgumentNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? expression, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, expression, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @expression = expression
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_block_argument_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [expression]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (expression = self.expression); yield expression; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (expression = self.expression); compact << expression; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*expression, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BlockArgumentNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?expression: Prism::node?, ?operator_loc: Location) -> BlockArgumentNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, expression: self.expression, operator_loc: self.operator_loc)
      BlockArgumentNode.new(source, node_id, location, flags, expression, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location expression operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :expression              then deconstructed[:expression] = self.expression
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :block_argument_node
    def type
      :block_argument_node
    end

    # See `Node.type`.
    #--
    #: () -> :block_argument_node
    def self.type
      :block_argument_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   expression -> Node | nil
    #
    # The expression that is being passed as a block argument. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo(&args)
    #          ^^^^
    #--
    #: () -> Prism::node?
    def expression
      @expression
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the Location of the `&` operator.
    #
    #     foo(&args)
    #         ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BlockArgumentNode) &&
        (expression === other.expression) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a block local variable.
  #
  #     a { |; b| }
  #            ^
  class BlockLocalVariableNode < Node
    # @rbs @name: Symbol

    # Initialize a new BlockLocalVariableNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_block_local_variable_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BlockLocalVariableNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> BlockLocalVariableNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      BlockLocalVariableNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :block_local_variable_node
    def type
      :block_local_variable_node
    end

    # See `Node.type`.
    #--
    #: () -> :block_local_variable_node
    def self.type
      :block_local_variable_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the block local variable.
    #
    #     a { |; b| } # name `:b`
    #            ^
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BlockLocalVariableNode) &&
        (flags === other.flags) &&
        (name === other.name)
    end
  end

  # Represents a block of ruby code.
  #
  #     [1, 2, 3].each { |i| puts x }
  #                    ^^^^^^^^^^^^^^
  class BlockNode < Node
    # @rbs @locals: Array[Symbol]
    # @rbs @parameters: (BlockParametersNode | NumberedParametersNode | ItParametersNode)?
    # @rbs @body: (StatementsNode | BeginNode)?
    # @rbs @opening_loc: Location
    # @rbs @closing_loc: Location

    # Initialize a new BlockNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Symbol] locals, (BlockParametersNode | NumberedParametersNode | ItParametersNode)? parameters, (StatementsNode | BeginNode)? body, Location opening_loc, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, locals, parameters, body, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @locals = locals
      @parameters = parameters
      @body = body
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_block_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [parameters, body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (parameters = self.parameters); yield parameters; end
      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (parameters = self.parameters); compact << parameters; end
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*parameters, *body, opening_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BlockNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?locals: Array[Symbol], ?parameters: (BlockParametersNode | NumberedParametersNode | ItParametersNode)?, ?body: (StatementsNode | BeginNode)?, ?opening_loc: Location, ?closing_loc: Location) -> BlockNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, locals: self.locals, parameters: self.parameters, body: self.body, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      BlockNode.new(source, node_id, location, flags, locals, parameters, body, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location locals parameters body opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :locals                  then deconstructed[:locals] = self.locals
        when :parameters              then deconstructed[:parameters] = self.parameters
        when :body                    then deconstructed[:body] = self.body
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :block_node
    def type
      :block_node
    end

    # See `Node.type`.
    #--
    #: () -> :block_node
    def self.type
      :block_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # The local variables declared in the block.
    #
    #     [1, 2, 3].each { |i| puts x } # locals: [:i]
    #                       ^
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :call-seq:
    #   parameters -> BlockParametersNode | NumberedParametersNode | ItParametersNode | nil
    #
    # The parameters of the block.
    #
    #     [1, 2, 3].each { |i| puts x }
    #                      ^^^
    #     [1, 2, 3].each { puts _1 }
    #                    ^^^^^^^^^^^
    #     [1, 2, 3].each { puts it }
    #                    ^^^^^^^^^^^
    #--
    #: () -> (BlockParametersNode | NumberedParametersNode | ItParametersNode)?
    def parameters
      @parameters
    end

    # :call-seq:
    #   body -> StatementsNode | BeginNode | nil
    #
    # The body of the block.
    #
    #     [1, 2, 3].each { |i| puts x }
    #                          ^^^^^^
    #--
    #: () -> (StatementsNode | BeginNode)?
    def body
      @body
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Represents the Location of the opening `{` or `do`.
    #
    #     [1, 2, 3].each { |i| puts x }
    #                    ^
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Represents the Location of the closing `}` or `end`.
    #
    #     [1, 2, 3].each { |i| puts x }
    #                                 ^
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BlockNode) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (parameters === other.parameters) &&
        (body === other.body) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents a block parameter of a method, block, or lambda definition.
  #
  #     def a(&b)
  #           ^^
  #     end
  class BlockParameterNode < Node
    # @rbs @name: Symbol?
    # @rbs @name_loc: Location?
    # @rbs @operator_loc: Location

    # Initialize a new BlockParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol? name, Location? name_loc, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_block_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*name_loc, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BlockParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol?, ?name_loc: Location?, ?operator_loc: Location) -> BlockParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc)
      BlockParameterNode.new(source, node_id, location, flags, name, name_loc, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :block_parameter_node
    def type
      :block_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :block_parameter_node
    def self.type
      :block_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol | nil
    #
    # The name of the block parameter.
    #
    #     def a(&b) # name `:b`
    #            ^
    #     end
    #--
    #: () -> Symbol?
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location | nil
    #
    # Represents the Location of the block parameter name.
    #
    #     def a(&b)
    #            ^
    #--
    #: () -> Location?
    def name_loc
      location = @name_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc) unless @name_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the Location of the `&` operator.
    #
    #     def a(&b)
    #           ^
    #     end
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BlockParameterNode) &&
        (flags === other.flags) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a block's parameters declaration.
  #
  #     -> (a, b = 1; local) { }
  #        ^^^^^^^^^^^^^^^^^
  #
  #     foo do |a, b = 1; local|
  #            ^^^^^^^^^^^^^^^^^
  #     end
  class BlockParametersNode < Node
    # @rbs @parameters: ParametersNode?
    # @rbs @locals: Array[BlockLocalVariableNode]
    # @rbs @opening_loc: Location?
    # @rbs @closing_loc: Location?

    # Initialize a new BlockParametersNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ParametersNode? parameters, Array[BlockLocalVariableNode] locals, Location? opening_loc, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, parameters, locals, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @parameters = parameters
      @locals = locals
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_block_parameters_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [parameters, *locals]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (parameters = self.parameters); yield parameters; end
      locals.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (parameters = self.parameters); compact << parameters; end
      compact.concat(locals)
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*parameters, *locals, *opening_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BlockParametersNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?parameters: ParametersNode?, ?locals: Array[BlockLocalVariableNode], ?opening_loc: Location?, ?closing_loc: Location?) -> BlockParametersNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, parameters: self.parameters, locals: self.locals, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      BlockParametersNode.new(source, node_id, location, flags, parameters, locals, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location parameters locals opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :parameters              then deconstructed[:parameters] = self.parameters
        when :locals                  then deconstructed[:locals] = self.locals
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :block_parameters_node
    def type
      :block_parameters_node
    end

    # See `Node.type`.
    #--
    #: () -> :block_parameters_node
    def self.type
      :block_parameters_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   parameters -> ParametersNode | nil
    #
    # Represents the parameters of the block.
    #
    #     -> (a, b = 1; local) { }
    #         ^^^^^^^^
    #
    #     foo do |a, b = 1; local|
    #             ^^^^^^^^
    #     end
    #--
    #: () -> ParametersNode?
    def parameters
      @parameters
    end

    # :call-seq:
    #   locals -> Array[BlockLocalVariableNode]
    #
    # Represents the local variables of the block.
    #
    #     -> (a, b = 1; local) { }
    #                   ^^^^^
    #
    #     foo do |a, b = 1; local|
    #                       ^^^^^
    #     end
    #--
    #: () -> Array[BlockLocalVariableNode]
    def locals
      @locals
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Represents the opening Location of the block parameters.
    #
    #     -> (a, b = 1; local) { }
    #        ^
    #
    #     foo do |a, b = 1; local|
    #            ^
    #     end
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Represents the closing Location of the block parameters.
    #
    #     -> (a, b = 1; local) { }
    #                        ^
    #
    #     foo do |a, b = 1; local|
    #                            ^
    #     end
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BlockParametersNode) &&
        (parameters === other.parameters) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents the use of the `break` keyword.
  #
  #     break foo
  #     ^^^^^^^^^
  class BreakNode < Node
    # @rbs @arguments: ArgumentsNode?
    # @rbs @keyword_loc: Location

    # Initialize a new BreakNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ArgumentsNode? arguments, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, arguments, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @arguments = arguments
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_break_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [arguments]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (arguments = self.arguments); yield arguments; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (arguments = self.arguments); compact << arguments; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*arguments, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> BreakNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?arguments: ArgumentsNode?, ?keyword_loc: Location) -> BreakNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, arguments: self.arguments, keyword_loc: self.keyword_loc)
      BreakNode.new(source, node_id, location, flags, arguments, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location arguments keyword_loc keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :break_node
    def type
      :break_node
    end

    # See `Node.type`.
    #--
    #: () -> :break_node
    def self.type
      :break_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # The arguments to the break statement, if present. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     break foo
    #           ^^^
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # The Location of the `break` keyword.
    #
    #     break foo
    #     ^^^^^
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(BreakNode) &&
        (arguments === other.arguments) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents the use of the `&&=` operator on a call.
  #
  #     foo.bar &&= value
  #     ^^^^^^^^^^^^^^^^^
  class CallAndWriteNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @message_loc: Location?
    # @rbs @read_name: Symbol
    # @rbs @write_name: Symbol
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new CallAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Location? message_loc, Symbol read_name, Symbol write_name, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @message_loc = message_loc
      @read_name = read_name
      @write_name = write_name
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_call_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, *message_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CallAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?message_loc: Location?, ?read_name: Symbol, ?write_name: Symbol, ?operator_loc: Location, ?value: Prism::node) -> CallAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, message_loc: self.message_loc, read_name: self.read_name, write_name: self.write_name, operator_loc: self.operator_loc, value: self.value)
      CallAndWriteNode.new(source, node_id, location, flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc message_loc read_name write_name operator_loc value call_operator message operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :message_loc             then deconstructed[:message_loc] = self.message_loc
        when :read_name               then deconstructed[:read_name] = self.read_name
        when :write_name              then deconstructed[:write_name] = self.write_name
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :message                 then deconstructed[:message] = self.message
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :call_and_write_node
    def type
      :call_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :call_and_write_node
    def self.type
      :call_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # The object that the method is being called on. This can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo.bar &&= value
    #     ^^^
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Represents the Location of the call operator.
    #
    #     foo.bar &&= value
    #        ^
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   message_loc -> Location | nil
    #
    # Represents the Location of the message.
    #
    #     foo.bar &&= value
    #         ^^^
    #--
    #: () -> Location?
    def message_loc
      location = @message_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @message_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the message_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_message_loc(repository)
      repository.enter(node_id, :message_loc) unless @message_loc.nil?
    end
    # :call-seq:
    #   read_name -> Symbol
    #
    # Represents the name of the method being called.
    #
    #     foo.bar &&= value # read_name `:bar`
    #         ^^^
    #--
    #: () -> Symbol
    def read_name
      @read_name
    end

    # :call-seq:
    #   write_name -> Symbol
    #
    # Represents the name of the method being written to.
    #
    #     foo.bar &&= value # write_name `:bar=`
    #         ^^^
    #--
    #: () -> Symbol
    def write_name
      @write_name
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the Location of the operator.
    #
    #     foo.bar &&= value
    #             ^^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Represents the value being assigned.
    #
    #     foo.bar &&= value
    #                 ^^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   message -> String | nil
    #
    # Slice the location of message_loc from the source.
    #--
    #: () -> String?
    def message
      message_loc&.slice
    end

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CallAndWriteNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (message_loc.nil? == other.message_loc.nil?) &&
        (read_name === other.read_name) &&
        (write_name === other.write_name) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents a method call, in all of the various forms that can take.
  #
  #     foo
  #     ^^^
  #
  #     foo()
  #     ^^^^^
  #
  #     +foo
  #     ^^^^
  #
  #     foo + bar
  #     ^^^^^^^^^
  #
  #     foo.bar
  #     ^^^^^^^
  #
  #     foo&.bar
  #     ^^^^^^^^
  class CallNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @name: Symbol
    # @rbs @message_loc: Location?
    # @rbs @opening_loc: Location?
    # @rbs @arguments: ArgumentsNode?
    # @rbs @closing_loc: Location?
    # @rbs @equal_loc: Location?
    # @rbs @block: (BlockNode | BlockArgumentNode)?

    # Initialize a new CallNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Symbol name, Location? message_loc, Location? opening_loc, ArgumentsNode? arguments, Location? closing_loc, Location? equal_loc, (BlockNode | BlockArgumentNode)? block) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, name, message_loc, opening_loc, arguments, closing_loc, equal_loc, block)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @name = name
      @message_loc = message_loc
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @equal_loc = equal_loc
      @block = block
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_call_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, arguments, block]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      if (arguments = self.arguments); yield arguments; end
      if (block = self.block); yield block; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      if (arguments = self.arguments); compact << arguments; end
      if (block = self.block); compact << block; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, *message_loc, *opening_loc, *arguments, *closing_loc, *equal_loc, *block] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CallNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?name: Symbol, ?message_loc: Location?, ?opening_loc: Location?, ?arguments: ArgumentsNode?, ?closing_loc: Location?, ?equal_loc: Location?, ?block: (BlockNode | BlockArgumentNode)?) -> CallNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, name: self.name, message_loc: self.message_loc, opening_loc: self.opening_loc, arguments: self.arguments, closing_loc: self.closing_loc, equal_loc: self.equal_loc, block: self.block)
      CallNode.new(source, node_id, location, flags, receiver, call_operator_loc, name, message_loc, opening_loc, arguments, closing_loc, equal_loc, block)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc name message_loc opening_loc arguments closing_loc equal_loc block call_operator message opening closing equal]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :name                    then deconstructed[:name] = self.name
        when :message_loc             then deconstructed[:message_loc] = self.message_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :equal_loc               then deconstructed[:equal_loc] = self.equal_loc
        when :block                   then deconstructed[:block] = self.block
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :message                 then deconstructed[:message] = self.message
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        when :equal                   then deconstructed[:equal] = self.equal
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :call_node
    def type
      :call_node
    end

    # See `Node.type`.
    #--
    #: () -> :call_node
    def self.type
      :call_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # The object that the method is being called on. This can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo.bar
    #     ^^^
    #
    #     +foo
    #      ^^^
    #
    #     foo + bar
    #     ^^^
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Represents the Location of the call operator.
    #
    #     foo.bar
    #        ^
    #
    #     foo&.bar
    #        ^^
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :call-seq:
    #   name -> Symbol
    #
    # Represents the name of the method being called.
    #
    #     foo.bar # name `:foo`
    #     ^^^
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   message_loc -> Location | nil
    #
    # Represents the Location of the message.
    #
    #     foo.bar
    #         ^^^
    #--
    #: () -> Location?
    def message_loc
      location = @message_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @message_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the message_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_message_loc(repository)
      repository.enter(node_id, :message_loc) unless @message_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Represents the Location of the left parenthesis.
    #
    #     foo(bar)
    #        ^
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Represents the arguments to the method call. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo(bar)
    #         ^^^
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Represents the Location of the right parenthesis.
    #
    #     foo(bar)
    #            ^
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   equal_loc -> Location | nil
    #
    # Represents the Location of the equal sign, in the case that this is an attribute write.
    #
    #     foo.bar = value
    #             ^
    #
    #     foo[bar] = value
    #              ^
    #--
    #: () -> Location?
    def equal_loc
      location = @equal_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @equal_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the equal_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_equal_loc(repository)
      repository.enter(node_id, :equal_loc) unless @equal_loc.nil?
    end
    # :call-seq:
    #   block -> BlockNode | BlockArgumentNode | nil
    #
    # Represents the block that is being passed to the method.
    #
    #     foo { |a| a }
    #         ^^^^^^^^^
    #--
    #: () -> (BlockNode | BlockArgumentNode)?
    def block
      @block
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   message -> String | nil
    #
    # Slice the location of message_loc from the source.
    #--
    #: () -> String?
    def message
      message_loc&.slice
    end

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :call-seq:
    #   equal -> String | nil
    #
    # Slice the location of equal_loc from the source.
    #--
    #: () -> String?
    def equal
      equal_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CallNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (name === other.name) &&
        (message_loc.nil? == other.message_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (arguments === other.arguments) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (equal_loc.nil? == other.equal_loc.nil?) &&
        (block === other.block)
    end
  end

  # Represents the use of an assignment operator on a call.
  #
  #     foo.bar += baz
  #     ^^^^^^^^^^^^^^
  class CallOperatorWriteNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @message_loc: Location?
    # @rbs @read_name: Symbol
    # @rbs @write_name: Symbol
    # @rbs @binary_operator: Symbol
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new CallOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Location? message_loc, Symbol read_name, Symbol write_name, Symbol binary_operator, Location binary_operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, message_loc, read_name, write_name, binary_operator, binary_operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @message_loc = message_loc
      @read_name = read_name
      @write_name = write_name
      @binary_operator = binary_operator
      @binary_operator_loc = binary_operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_call_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, *message_loc, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CallOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?message_loc: Location?, ?read_name: Symbol, ?write_name: Symbol, ?binary_operator: Symbol, ?binary_operator_loc: Location, ?value: Prism::node) -> CallOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, message_loc: self.message_loc, read_name: self.read_name, write_name: self.write_name, binary_operator: self.binary_operator, binary_operator_loc: self.binary_operator_loc, value: self.value)
      CallOperatorWriteNode.new(source, node_id, location, flags, receiver, call_operator_loc, message_loc, read_name, write_name, binary_operator, binary_operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc message_loc read_name write_name binary_operator binary_operator_loc value call_operator message]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :message_loc             then deconstructed[:message_loc] = self.message_loc
        when :read_name               then deconstructed[:read_name] = self.read_name
        when :write_name              then deconstructed[:write_name] = self.write_name
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :message                 then deconstructed[:message] = self.message
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :call_operator_write_node
    def type
      :call_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :call_operator_write_node
    def self.type
      :call_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # The object that the method is being called on. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo.bar += value
    #     ^^^
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Represents the Location of the call operator.
    #
    #     foo.bar += value
    #        ^
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   message_loc -> Location | nil
    #
    # Represents the Location of the message.
    #
    #     foo.bar += value
    #         ^^^
    #--
    #: () -> Location?
    def message_loc
      location = @message_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @message_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the message_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_message_loc(repository)
      repository.enter(node_id, :message_loc) unless @message_loc.nil?
    end
    # :call-seq:
    #   read_name -> Symbol
    #
    # Represents the name of the method being called.
    #
    #     foo.bar += value # read_name `:bar`
    #         ^^^
    #--
    #: () -> Symbol
    def read_name
      @read_name
    end

    # :call-seq:
    #   write_name -> Symbol
    #
    # Represents the name of the method being written to.
    #
    #     foo.bar += value # write_name `:bar=`
    #         ^^^
    #--
    #: () -> Symbol
    def write_name
      @write_name
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Represents the binary operator being used.
    #
    #     foo.bar += value # binary_operator `:+`
    #             ^
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Represents the Location of the binary operator.
    #
    #     foo.bar += value
    #             ^^
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Represents the value being assigned.
    #
    #     foo.bar += value
    #                ^^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   message -> String | nil
    #
    # Slice the location of message_loc from the source.
    #--
    #: () -> String?
    def message
      message_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CallOperatorWriteNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (message_loc.nil? == other.message_loc.nil?) &&
        (read_name === other.read_name) &&
        (write_name === other.write_name) &&
        (binary_operator === other.binary_operator) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents the use of the `||=` operator on a call.
  #
  #     foo.bar ||= value
  #     ^^^^^^^^^^^^^^^^^
  class CallOrWriteNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @message_loc: Location?
    # @rbs @read_name: Symbol
    # @rbs @write_name: Symbol
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new CallOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Location? message_loc, Symbol read_name, Symbol write_name, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @message_loc = message_loc
      @read_name = read_name
      @write_name = write_name
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_call_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, *message_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CallOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?message_loc: Location?, ?read_name: Symbol, ?write_name: Symbol, ?operator_loc: Location, ?value: Prism::node) -> CallOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, message_loc: self.message_loc, read_name: self.read_name, write_name: self.write_name, operator_loc: self.operator_loc, value: self.value)
      CallOrWriteNode.new(source, node_id, location, flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc message_loc read_name write_name operator_loc value call_operator message operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :message_loc             then deconstructed[:message_loc] = self.message_loc
        when :read_name               then deconstructed[:read_name] = self.read_name
        when :write_name              then deconstructed[:write_name] = self.write_name
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :message                 then deconstructed[:message] = self.message
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :call_or_write_node
    def type
      :call_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :call_or_write_node
    def self.type
      :call_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # The object that the method is being called on. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo.bar ||= value
    #     ^^^
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Represents the Location of the call operator.
    #
    #     foo.bar ||= value
    #        ^
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   message_loc -> Location | nil
    #
    # Represents the Location of the message.
    #
    #     foo.bar ||= value
    #         ^^^
    #--
    #: () -> Location?
    def message_loc
      location = @message_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @message_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the message_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_message_loc(repository)
      repository.enter(node_id, :message_loc) unless @message_loc.nil?
    end
    # :call-seq:
    #   read_name -> Symbol
    #
    # Represents the name of the method being called.
    #
    #     foo.bar ||= value # read_name `:bar`
    #         ^^^
    #--
    #: () -> Symbol
    def read_name
      @read_name
    end

    # :call-seq:
    #   write_name -> Symbol
    #
    # Represents the name of the method being written to.
    #
    #     foo.bar ||= value # write_name `:bar=`
    #         ^^^
    #--
    #: () -> Symbol
    def write_name
      @write_name
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the Location of the operator.
    #
    #     foo.bar ||= value
    #             ^^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Represents the value being assigned.
    #
    #     foo.bar ||= value
    #                 ^^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   message -> String | nil
    #
    # Slice the location of message_loc from the source.
    #--
    #: () -> String?
    def message
      message_loc&.slice
    end

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CallOrWriteNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (message_loc.nil? == other.message_loc.nil?) &&
        (read_name === other.read_name) &&
        (write_name === other.write_name) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents assigning to a method call.
  #
  #     foo.bar, = 1
  #     ^^^^^^^
  #
  #     begin
  #     rescue => foo.bar
  #               ^^^^^^^
  #     end
  #
  #     for foo.bar in baz do end
  #         ^^^^^^^
  class CallTargetNode < Node
    # @rbs @receiver: Prism::node
    # @rbs @call_operator_loc: Location
    # @rbs @name: Symbol
    # @rbs @message_loc: Location

    # Initialize a new CallTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node receiver, Location call_operator_loc, Symbol name, Location message_loc) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, name, message_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @name = name
      @message_loc = message_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_call_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield receiver
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [receiver]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [receiver, call_operator_loc, message_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CallTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node, ?call_operator_loc: Location, ?name: Symbol, ?message_loc: Location) -> CallTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, name: self.name, message_loc: self.message_loc)
      CallTargetNode.new(source, node_id, location, flags, receiver, call_operator_loc, name, message_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc name message_loc call_operator message]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :name                    then deconstructed[:name] = self.name
        when :message_loc             then deconstructed[:message_loc] = self.message_loc
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :message                 then deconstructed[:message] = self.message
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :call_target_node
    def type
      :call_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :call_target_node
    def self.type
      :call_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node
    #
    # The object that the method is being called on. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo.bar = 1
    #     ^^^
    #--
    #: () -> Prism::node
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location
    #
    # Represents the Location of the call operator.
    #
    #     foo.bar = 1
    #        ^
    #--
    #: () -> Location
    def call_operator_loc
      location = @call_operator_loc
      return location if location.is_a?(Location)
      @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Represents the name of the method being called.
    #
    #     foo.bar = 1 # name `:foo`
    #     ^^^
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   message_loc -> Location
    #
    # Represents the Location of the message.
    #
    #     foo.bar = 1
    #         ^^^
    #--
    #: () -> Location
    def message_loc
      location = @message_loc
      return location if location.is_a?(Location)
      @message_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the message_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_message_loc(repository)
      repository.enter(node_id, :message_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String
    def call_operator
      call_operator_loc.slice
    end

    # :call-seq:
    #   message -> String
    #
    # Slice the location of message_loc from the source.
    #--
    #: () -> String
    def message
      message_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CallTargetNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (name === other.name) &&
        (message_loc.nil? == other.message_loc.nil?)
    end
  end

  # Represents assigning to a local variable in pattern matching.
  #
  #     foo => [bar => baz]
  #             ^^^^^^^^^^
  class CapturePatternNode < Node
    # @rbs @value: Prism::node
    # @rbs @target: LocalVariableTargetNode
    # @rbs @operator_loc: Location

    # Initialize a new CapturePatternNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node value, LocalVariableTargetNode target, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, value, target, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
      @target = target
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_capture_pattern_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value, target]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
      yield target
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value, target]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [value, target, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CapturePatternNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: Prism::node, ?target: LocalVariableTargetNode, ?operator_loc: Location) -> CapturePatternNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value, target: self.target, operator_loc: self.operator_loc)
      CapturePatternNode.new(source, node_id, location, flags, value, target, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value target operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        when :target                  then deconstructed[:target] = self.target
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :capture_pattern_node
    def type
      :capture_pattern_node
    end

    # See `Node.type`.
    #--
    #: () -> :capture_pattern_node
    def self.type
      :capture_pattern_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   value -> Node
    #
    # Represents the value to capture.
    #
    #     foo => bar
    #            ^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   target -> LocalVariableTargetNode
    #
    # Represents the target of the capture.
    #
    #     foo => bar
    #     ^^^
    #--
    #: () -> LocalVariableTargetNode
    def target
      @target
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the Location of the `=>` operator.
    #
    #     foo => bar
    #         ^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CapturePatternNode) &&
        (value === other.value) &&
        (target === other.target) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents the use of a case statement for pattern matching.
  #
  #     case true
  #     in false
  #     end
  #     ^^^^^^^^^
  class CaseMatchNode < Node
    # @rbs @predicate: Prism::node?
    # @rbs @conditions: Array[InNode]
    # @rbs @else_clause: ElseNode?
    # @rbs @case_keyword_loc: Location
    # @rbs @end_keyword_loc: Location

    # Initialize a new CaseMatchNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? predicate, Array[InNode] conditions, ElseNode? else_clause, Location case_keyword_loc, Location end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, predicate, conditions, else_clause, case_keyword_loc, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @predicate = predicate
      @conditions = conditions
      @else_clause = else_clause
      @case_keyword_loc = case_keyword_loc
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_case_match_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [predicate, *conditions, else_clause]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (predicate = self.predicate); yield predicate; end
      conditions.each { |node| yield node }
      if (else_clause = self.else_clause); yield else_clause; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (predicate = self.predicate); compact << predicate; end
      compact.concat(conditions)
      if (else_clause = self.else_clause); compact << else_clause; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*predicate, *conditions, *else_clause, case_keyword_loc, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CaseMatchNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?predicate: Prism::node?, ?conditions: Array[InNode], ?else_clause: ElseNode?, ?case_keyword_loc: Location, ?end_keyword_loc: Location) -> CaseMatchNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, predicate: self.predicate, conditions: self.conditions, else_clause: self.else_clause, case_keyword_loc: self.case_keyword_loc, end_keyword_loc: self.end_keyword_loc)
      CaseMatchNode.new(source, node_id, location, flags, predicate, conditions, else_clause, case_keyword_loc, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location predicate conditions else_clause case_keyword_loc end_keyword_loc case_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :predicate               then deconstructed[:predicate] = self.predicate
        when :conditions              then deconstructed[:conditions] = self.conditions
        when :else_clause             then deconstructed[:else_clause] = self.else_clause
        when :case_keyword_loc        then deconstructed[:case_keyword_loc] = self.case_keyword_loc
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :case_keyword            then deconstructed[:case_keyword] = self.case_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :case_match_node
    def type
      :case_match_node
    end

    # See `Node.type`.
    #--
    #: () -> :case_match_node
    def self.type
      :case_match_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   predicate -> Node | nil
    #
    # Represents the predicate of the case match. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     case true; in false; end
    #          ^^^^
    #--
    #: () -> Prism::node?
    def predicate
      @predicate
    end

    # :call-seq:
    #   conditions -> Array[InNode]
    #
    # Represents the conditions of the case match.
    #
    #     case true; in false; end
    #                ^^^^^^^^
    #--
    #: () -> Array[InNode]
    def conditions
      @conditions
    end

    # :call-seq:
    #   else_clause -> ElseNode | nil
    #
    # Represents the else clause of the case match.
    #
    #     case true; in false; else; end
    #                          ^^^^^^^^^
    #--
    #: () -> ElseNode?
    def else_clause
      @else_clause
    end

    # :category: Locations
    # :call-seq:
    #   case_keyword_loc -> Location
    #
    # Represents the Location of the `case` keyword.
    #
    #     case true; in false; end
    #     ^^^^
    #--
    #: () -> Location
    def case_keyword_loc
      location = @case_keyword_loc
      return location if location.is_a?(Location)
      @case_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the case_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_case_keyword_loc(repository)
      repository.enter(node_id, :case_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # Represents the Location of the `end` keyword.
    #
    #     case true; in false; end
    #                          ^^^
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   case_keyword -> String
    #
    # Slice the location of case_keyword_loc from the source.
    #--
    #: () -> String
    def case_keyword
      case_keyword_loc.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CaseMatchNode) &&
        (predicate === other.predicate) &&
        (conditions.length == other.conditions.length) &&
        conditions.zip(other.conditions).all? { |left, right| left === right } &&
        (else_clause === other.else_clause) &&
        (case_keyword_loc.nil? == other.case_keyword_loc.nil?) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents the use of a case statement.
  #
  #     case true
  #     when false
  #     end
  #     ^^^^^^^^^^
  class CaseNode < Node
    # @rbs @predicate: Prism::node?
    # @rbs @conditions: Array[WhenNode]
    # @rbs @else_clause: ElseNode?
    # @rbs @case_keyword_loc: Location
    # @rbs @end_keyword_loc: Location

    # Initialize a new CaseNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? predicate, Array[WhenNode] conditions, ElseNode? else_clause, Location case_keyword_loc, Location end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, predicate, conditions, else_clause, case_keyword_loc, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @predicate = predicate
      @conditions = conditions
      @else_clause = else_clause
      @case_keyword_loc = case_keyword_loc
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_case_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [predicate, *conditions, else_clause]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (predicate = self.predicate); yield predicate; end
      conditions.each { |node| yield node }
      if (else_clause = self.else_clause); yield else_clause; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (predicate = self.predicate); compact << predicate; end
      compact.concat(conditions)
      if (else_clause = self.else_clause); compact << else_clause; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*predicate, *conditions, *else_clause, case_keyword_loc, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> CaseNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?predicate: Prism::node?, ?conditions: Array[WhenNode], ?else_clause: ElseNode?, ?case_keyword_loc: Location, ?end_keyword_loc: Location) -> CaseNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, predicate: self.predicate, conditions: self.conditions, else_clause: self.else_clause, case_keyword_loc: self.case_keyword_loc, end_keyword_loc: self.end_keyword_loc)
      CaseNode.new(source, node_id, location, flags, predicate, conditions, else_clause, case_keyword_loc, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location predicate conditions else_clause case_keyword_loc end_keyword_loc case_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :predicate               then deconstructed[:predicate] = self.predicate
        when :conditions              then deconstructed[:conditions] = self.conditions
        when :else_clause             then deconstructed[:else_clause] = self.else_clause
        when :case_keyword_loc        then deconstructed[:case_keyword_loc] = self.case_keyword_loc
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :case_keyword            then deconstructed[:case_keyword] = self.case_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :case_node
    def type
      :case_node
    end

    # See `Node.type`.
    #--
    #: () -> :case_node
    def self.type
      :case_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   predicate -> Node | nil
    #
    # Represents the predicate of the case statement. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     case true; when false; end
    #          ^^^^
    #--
    #: () -> Prism::node?
    def predicate
      @predicate
    end

    # :call-seq:
    #   conditions -> Array[WhenNode]
    #
    # Represents the conditions of the case statement.
    #
    #     case true; when false; end
    #                ^^^^^^^^^^
    #--
    #: () -> Array[WhenNode]
    def conditions
      @conditions
    end

    # :call-seq:
    #   else_clause -> ElseNode | nil
    #
    # Represents the else clause of the case statement.
    #
    #     case true; when false; else; end
    #                            ^^^^^^^^^
    #--
    #: () -> ElseNode?
    def else_clause
      @else_clause
    end

    # :category: Locations
    # :call-seq:
    #   case_keyword_loc -> Location
    #
    # Represents the Location of the `case` keyword.
    #
    #     case true; when false; end
    #     ^^^^
    #--
    #: () -> Location
    def case_keyword_loc
      location = @case_keyword_loc
      return location if location.is_a?(Location)
      @case_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the case_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_case_keyword_loc(repository)
      repository.enter(node_id, :case_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # Represents the Location of the `end` keyword.
    #
    #     case true; when false; end
    #                            ^^^
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   case_keyword -> String
    #
    # Slice the location of case_keyword_loc from the source.
    #--
    #: () -> String
    def case_keyword
      case_keyword_loc.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(CaseNode) &&
        (predicate === other.predicate) &&
        (conditions.length == other.conditions.length) &&
        conditions.zip(other.conditions).all? { |left, right| left === right } &&
        (else_clause === other.else_clause) &&
        (case_keyword_loc.nil? == other.case_keyword_loc.nil?) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents a class declaration involving the `class` keyword.
  #
  #     class Foo end
  #     ^^^^^^^^^^^^^
  class ClassNode < Node
    # @rbs @locals: Array[Symbol]
    # @rbs @class_keyword_loc: Location
    # @rbs @constant_path: (ConstantReadNode | ConstantPathNode)
    # @rbs @inheritance_operator_loc: Location?
    # @rbs @superclass: Prism::node?
    # @rbs @body: (StatementsNode | BeginNode)?
    # @rbs @end_keyword_loc: Location
    # @rbs @name: Symbol

    # Initialize a new ClassNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Symbol] locals, Location class_keyword_loc, (ConstantReadNode | ConstantPathNode) constant_path, Location? inheritance_operator_loc, Prism::node? superclass, (StatementsNode | BeginNode)? body, Location end_keyword_loc, Symbol name) -> void
    def initialize(source, node_id, location, flags, locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, body, end_keyword_loc, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @locals = locals
      @class_keyword_loc = class_keyword_loc
      @constant_path = constant_path
      @inheritance_operator_loc = inheritance_operator_loc
      @superclass = superclass
      @body = body
      @end_keyword_loc = end_keyword_loc
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [constant_path, superclass, body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield constant_path
      if (superclass = self.superclass); yield superclass; end
      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << constant_path
      if (superclass = self.superclass); compact << superclass; end
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [class_keyword_loc, constant_path, *inheritance_operator_loc, *superclass, *body, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?locals: Array[Symbol], ?class_keyword_loc: Location, ?constant_path: (ConstantReadNode | ConstantPathNode), ?inheritance_operator_loc: Location?, ?superclass: Prism::node?, ?body: (StatementsNode | BeginNode)?, ?end_keyword_loc: Location, ?name: Symbol) -> ClassNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, locals: self.locals, class_keyword_loc: self.class_keyword_loc, constant_path: self.constant_path, inheritance_operator_loc: self.inheritance_operator_loc, superclass: self.superclass, body: self.body, end_keyword_loc: self.end_keyword_loc, name: self.name)
      ClassNode.new(source, node_id, location, flags, locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, body, end_keyword_loc, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location locals class_keyword_loc constant_path inheritance_operator_loc superclass body end_keyword_loc name class_keyword inheritance_operator end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :locals                  then deconstructed[:locals] = self.locals
        when :class_keyword_loc       then deconstructed[:class_keyword_loc] = self.class_keyword_loc
        when :constant_path           then deconstructed[:constant_path] = self.constant_path
        when :inheritance_operator_loc then deconstructed[:inheritance_operator_loc] = self.inheritance_operator_loc
        when :superclass              then deconstructed[:superclass] = self.superclass
        when :body                    then deconstructed[:body] = self.body
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :name                    then deconstructed[:name] = self.name
        when :class_keyword           then deconstructed[:class_keyword] = self.class_keyword
        when :inheritance_operator    then deconstructed[:inheritance_operator] = self.inheritance_operator
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_node
    def type
      :class_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_node
    def self.type
      :class_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # Returns the `locals` attribute.
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :category: Locations
    # :call-seq:
    #   class_keyword_loc -> Location
    #
    # Represents the Location of the `class` keyword.
    #
    #     class Foo end
    #     ^^^^^
    #--
    #: () -> Location
    def class_keyword_loc
      location = @class_keyword_loc
      return location if location.is_a?(Location)
      @class_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the class_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_class_keyword_loc(repository)
      repository.enter(node_id, :class_keyword_loc)
    end

    # :call-seq:
    #   constant_path -> ConstantReadNode | ConstantPathNode
    #
    # Returns the `constant_path` attribute.
    #--
    #: () -> (ConstantReadNode | ConstantPathNode)
    def constant_path
      @constant_path
    end

    # :category: Locations
    # :call-seq:
    #   inheritance_operator_loc -> Location | nil
    #
    # Represents the Location of the `<` operator.
    #
    #     class Foo < Bar
    #               ^
    #--
    #: () -> Location?
    def inheritance_operator_loc
      location = @inheritance_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @inheritance_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the inheritance_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_inheritance_operator_loc(repository)
      repository.enter(node_id, :inheritance_operator_loc) unless @inheritance_operator_loc.nil?
    end
    # :call-seq:
    #   superclass -> Node | nil
    #
    # Represents the superclass of the class.
    #
    #     class Foo < Bar
    #                 ^^^
    #--
    #: () -> Prism::node?
    def superclass
      @superclass
    end

    # :call-seq:
    #   body -> StatementsNode | BeginNode | nil
    #
    # Represents the body of the class.
    #
    #     class Foo; bar; end
    #                ^^^
    #--
    #: () -> (StatementsNode | BeginNode)?
    def body
      @body
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # Represents the Location of the `end` keyword.
    #
    #     class Foo end
    #               ^^^
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the class.
    #
    #     class Foo end # name `:Foo`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :call-seq:
    #   class_keyword -> String
    #
    # Slice the location of class_keyword_loc from the source.
    #--
    #: () -> String
    def class_keyword
      class_keyword_loc.slice
    end

    # :call-seq:
    #   inheritance_operator -> String | nil
    #
    # Slice the location of inheritance_operator_loc from the source.
    #--
    #: () -> String?
    def inheritance_operator
      inheritance_operator_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassNode) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (class_keyword_loc.nil? == other.class_keyword_loc.nil?) &&
        (constant_path === other.constant_path) &&
        (inheritance_operator_loc.nil? == other.inheritance_operator_loc.nil?) &&
        (superclass === other.superclass) &&
        (body === other.body) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?) &&
        (name === other.name)
    end
  end

  # Represents the use of the `&&=` operator for assignment to a class variable.
  #
  #     @@target &&= value
  #     ^^^^^^^^^^^^^^^^^^
  class ClassVariableAndWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ClassVariableAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_variable_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassVariableAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> ClassVariableAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      ClassVariableAndWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_variable_and_write_node
    def type
      :class_variable_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_variable_and_write_node
    def self.type
      :class_variable_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     @@target &&= value # name `:@@target`
    #     ^^^^^^^^
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Represents the Location of the variable name.
    #
    #     @@target &&= value
    #     ^^^^^^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Represents the Location of the `&&=` operator.
    #
    #     @@target &&= value
    #              ^^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Represents the value being assigned. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     @@target &&= value
    #                  ^^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassVariableAndWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents assigning to a class variable using an operator that isn't `=`.
  #
  #     @@target += value
  #     ^^^^^^^^^^^^^^^^^
  class ClassVariableOperatorWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @binary_operator: Symbol

    # Initialize a new ClassVariableOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location binary_operator_loc, Prism::node value, Symbol binary_operator) -> void
    def initialize(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @binary_operator_loc = binary_operator_loc
      @value = value
      @binary_operator = binary_operator
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_variable_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassVariableOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?binary_operator_loc: Location, ?value: Prism::node, ?binary_operator: Symbol) -> ClassVariableOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, binary_operator_loc: self.binary_operator_loc, value: self.value, binary_operator: self.binary_operator)
      ClassVariableOperatorWriteNode.new(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc binary_operator_loc value binary_operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_variable_operator_write_node
    def type
      :class_variable_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_variable_operator_write_node
    def self.type
      :class_variable_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassVariableOperatorWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value) &&
        (binary_operator === other.binary_operator)
    end
  end

  # Represents the use of the `||=` operator for assignment to a class variable.
  #
  #     @@target ||= value
  #     ^^^^^^^^^^^^^^^^^^
  class ClassVariableOrWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ClassVariableOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_variable_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassVariableOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> ClassVariableOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      ClassVariableOrWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_variable_or_write_node
    def type
      :class_variable_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_variable_or_write_node
    def self.type
      :class_variable_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassVariableOrWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents referencing a class variable.
  #
  #     @@foo
  #     ^^^^^
  class ClassVariableReadNode < Node
    # @rbs @name: Symbol

    # Initialize a new ClassVariableReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_variable_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassVariableReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> ClassVariableReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      ClassVariableReadNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_variable_read_node
    def type
      :class_variable_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_variable_read_node
    def self.type
      :class_variable_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     @@abc   # name `:@@abc`
    #
    #     @@_test # name `:@@_test`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassVariableReadNode) &&
        (name === other.name)
    end
  end

  # Represents writing to a class variable in a context that doesn't have an explicit value.
  #
  #     @@foo, @@bar = baz
  #     ^^^^^  ^^^^^
  class ClassVariableTargetNode < Node
    # @rbs @name: Symbol

    # Initialize a new ClassVariableTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_variable_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassVariableTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> ClassVariableTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      ClassVariableTargetNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_variable_target_node
    def type
      :class_variable_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_variable_target_node
    def self.type
      :class_variable_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassVariableTargetNode) &&
        (name === other.name)
    end
  end

  # Represents writing to a class variable.
  #
  #     @@foo = 1
  #     ^^^^^^^^^
  class ClassVariableWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @value: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new ClassVariableWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Prism::node value, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_class_variable_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, value, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ClassVariableWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?value: Prism::node, ?operator_loc: Location) -> ClassVariableWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, value: self.value, operator_loc: self.operator_loc)
      ClassVariableWriteNode.new(source, node_id, location, flags, name, name_loc, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :class_variable_write_node
    def type
      :class_variable_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :class_variable_write_node
    def self.type
      :class_variable_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     @@abc = 123     # name `@@abc`
    #
    #     @@_test = :test # name `@@_test`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # The Location of the variable name.
    #
    #     @@foo = :bar
    #     ^^^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the class variable. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     @@foo = :bar
    #             ^^^^
    #
    #     @@_xyz = 123
    #              ^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `=` operator.
    #
    #     @@foo = :bar
    #           ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ClassVariableWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents the use of the `&&=` operator for assignment to a constant.
  #
  #     Target &&= value
  #     ^^^^^^^^^^^^^^^^
  class ConstantAndWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ConstantAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> ConstantAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      ConstantAndWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_and_write_node
    def type
      :constant_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_and_write_node
    def self.type
      :constant_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantAndWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents assigning to a constant using an operator that isn't `=`.
  #
  #     Target += value
  #     ^^^^^^^^^^^^^^^
  class ConstantOperatorWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @binary_operator: Symbol

    # Initialize a new ConstantOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location binary_operator_loc, Prism::node value, Symbol binary_operator) -> void
    def initialize(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @binary_operator_loc = binary_operator_loc
      @value = value
      @binary_operator = binary_operator
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?binary_operator_loc: Location, ?value: Prism::node, ?binary_operator: Symbol) -> ConstantOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, binary_operator_loc: self.binary_operator_loc, value: self.value, binary_operator: self.binary_operator)
      ConstantOperatorWriteNode.new(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc binary_operator_loc value binary_operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_operator_write_node
    def type
      :constant_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_operator_write_node
    def self.type
      :constant_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantOperatorWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value) &&
        (binary_operator === other.binary_operator)
    end
  end

  # Represents the use of the `||=` operator for assignment to a constant.
  #
  #     Target ||= value
  #     ^^^^^^^^^^^^^^^^
  class ConstantOrWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ConstantOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> ConstantOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      ConstantOrWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_or_write_node
    def type
      :constant_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_or_write_node
    def self.type
      :constant_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantOrWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents the use of the `&&=` operator for assignment to a constant path.
  #
  #     Parent::Child &&= value
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class ConstantPathAndWriteNode < Node
    # @rbs @target: ConstantPathNode
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ConstantPathAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ConstantPathNode target, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, target, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @target = target
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_path_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [target, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield target
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [target, value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [target, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantPathAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?target: ConstantPathNode, ?operator_loc: Location, ?value: Prism::node) -> ConstantPathAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, target: self.target, operator_loc: self.operator_loc, value: self.value)
      ConstantPathAndWriteNode.new(source, node_id, location, flags, target, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location target operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :target                  then deconstructed[:target] = self.target
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_path_and_write_node
    def type
      :constant_path_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_path_and_write_node
    def self.type
      :constant_path_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   target -> ConstantPathNode
    #
    # Returns the `target` attribute.
    #--
    #: () -> ConstantPathNode
    def target
      @target
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantPathAndWriteNode) &&
        (target === other.target) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents accessing a constant through a path of `::` operators.
  #
  #     Foo::Bar
  #     ^^^^^^^^
  class ConstantPathNode < Node
    # @rbs @parent: Prism::node?
    # @rbs @name: Symbol?
    # @rbs @delimiter_loc: Location
    # @rbs @name_loc: Location

    # Initialize a new ConstantPathNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? parent, Symbol? name, Location delimiter_loc, Location name_loc) -> void
    def initialize(source, node_id, location, flags, parent, name, delimiter_loc, name_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @parent = parent
      @name = name
      @delimiter_loc = delimiter_loc
      @name_loc = name_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_path_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [parent]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (parent = self.parent); yield parent; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (parent = self.parent); compact << parent; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*parent, delimiter_loc, name_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantPathNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?parent: Prism::node?, ?name: Symbol?, ?delimiter_loc: Location, ?name_loc: Location) -> ConstantPathNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, parent: self.parent, name: self.name, delimiter_loc: self.delimiter_loc, name_loc: self.name_loc)
      ConstantPathNode.new(source, node_id, location, flags, parent, name, delimiter_loc, name_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location parent name delimiter_loc name_loc delimiter]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :parent                  then deconstructed[:parent] = self.parent
        when :name                    then deconstructed[:name] = self.name
        when :delimiter_loc           then deconstructed[:delimiter_loc] = self.delimiter_loc
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :delimiter               then deconstructed[:delimiter] = self.delimiter
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_path_node
    def type
      :constant_path_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_path_node
    def self.type
      :constant_path_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   parent -> Node | nil
    #
    # The left-hand node of the path, if present. It can be `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). It will be `nil` when the constant lookup is at the root of the module tree.
    #
    #     Foo::Bar
    #     ^^^
    #
    #     self::Test
    #     ^^^^
    #
    #     a.b::C
    #     ^^^
    #--
    #: () -> Prism::node?
    def parent
      @parent
    end

    # :call-seq:
    #   name -> Symbol | nil
    #
    # The name of the constant being accessed. This could be `nil` in the event of a syntax error.
    #--
    #: () -> Symbol?
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   delimiter_loc -> Location
    #
    # The Location of the `::` delimiter.
    #
    #     ::Foo
    #     ^^
    #
    #     One::Two
    #        ^^
    #--
    #: () -> Location
    def delimiter_loc
      location = @delimiter_loc
      return location if location.is_a?(Location)
      @delimiter_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the delimiter_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_delimiter_loc(repository)
      repository.enter(node_id, :delimiter_loc)
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # The Location of the name of the constant.
    #
    #     ::Foo
    #       ^^^
    #
    #     One::Two
    #          ^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   delimiter -> String
    #
    # Slice the location of delimiter_loc from the source.
    #--
    #: () -> String
    def delimiter
      delimiter_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantPathNode) &&
        (parent === other.parent) &&
        (name === other.name) &&
        (delimiter_loc.nil? == other.delimiter_loc.nil?) &&
        (name_loc.nil? == other.name_loc.nil?)
    end
  end

  # Represents assigning to a constant path using an operator that isn't `=`.
  #
  #     Parent::Child += value
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class ConstantPathOperatorWriteNode < Node
    # @rbs @target: ConstantPathNode
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @binary_operator: Symbol

    # Initialize a new ConstantPathOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ConstantPathNode target, Location binary_operator_loc, Prism::node value, Symbol binary_operator) -> void
    def initialize(source, node_id, location, flags, target, binary_operator_loc, value, binary_operator)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @target = target
      @binary_operator_loc = binary_operator_loc
      @value = value
      @binary_operator = binary_operator
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_path_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [target, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield target
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [target, value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [target, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantPathOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?target: ConstantPathNode, ?binary_operator_loc: Location, ?value: Prism::node, ?binary_operator: Symbol) -> ConstantPathOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, target: self.target, binary_operator_loc: self.binary_operator_loc, value: self.value, binary_operator: self.binary_operator)
      ConstantPathOperatorWriteNode.new(source, node_id, location, flags, target, binary_operator_loc, value, binary_operator)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location target binary_operator_loc value binary_operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :target                  then deconstructed[:target] = self.target
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_path_operator_write_node
    def type
      :constant_path_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_path_operator_write_node
    def self.type
      :constant_path_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   target -> ConstantPathNode
    #
    # Returns the `target` attribute.
    #--
    #: () -> ConstantPathNode
    def target
      @target
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantPathOperatorWriteNode) &&
        (target === other.target) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value) &&
        (binary_operator === other.binary_operator)
    end
  end

  # Represents the use of the `||=` operator for assignment to a constant path.
  #
  #     Parent::Child ||= value
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class ConstantPathOrWriteNode < Node
    # @rbs @target: ConstantPathNode
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ConstantPathOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ConstantPathNode target, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, target, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @target = target
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_path_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [target, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield target
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [target, value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [target, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantPathOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?target: ConstantPathNode, ?operator_loc: Location, ?value: Prism::node) -> ConstantPathOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, target: self.target, operator_loc: self.operator_loc, value: self.value)
      ConstantPathOrWriteNode.new(source, node_id, location, flags, target, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location target operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :target                  then deconstructed[:target] = self.target
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_path_or_write_node
    def type
      :constant_path_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_path_or_write_node
    def self.type
      :constant_path_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   target -> ConstantPathNode
    #
    # Returns the `target` attribute.
    #--
    #: () -> ConstantPathNode
    def target
      @target
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantPathOrWriteNode) &&
        (target === other.target) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents writing to a constant path in a context that doesn't have an explicit value.
  #
  #     Foo::Foo, Bar::Bar = baz
  #     ^^^^^^^^  ^^^^^^^^
  class ConstantPathTargetNode < Node
    # @rbs @parent: Prism::node?
    # @rbs @name: Symbol?
    # @rbs @delimiter_loc: Location
    # @rbs @name_loc: Location

    # Initialize a new ConstantPathTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? parent, Symbol? name, Location delimiter_loc, Location name_loc) -> void
    def initialize(source, node_id, location, flags, parent, name, delimiter_loc, name_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @parent = parent
      @name = name
      @delimiter_loc = delimiter_loc
      @name_loc = name_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_path_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [parent]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (parent = self.parent); yield parent; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (parent = self.parent); compact << parent; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*parent, delimiter_loc, name_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantPathTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?parent: Prism::node?, ?name: Symbol?, ?delimiter_loc: Location, ?name_loc: Location) -> ConstantPathTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, parent: self.parent, name: self.name, delimiter_loc: self.delimiter_loc, name_loc: self.name_loc)
      ConstantPathTargetNode.new(source, node_id, location, flags, parent, name, delimiter_loc, name_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location parent name delimiter_loc name_loc delimiter]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :parent                  then deconstructed[:parent] = self.parent
        when :name                    then deconstructed[:name] = self.name
        when :delimiter_loc           then deconstructed[:delimiter_loc] = self.delimiter_loc
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :delimiter               then deconstructed[:delimiter] = self.delimiter
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_path_target_node
    def type
      :constant_path_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_path_target_node
    def self.type
      :constant_path_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   parent -> Node | nil
    #
    # Returns the `parent` attribute.
    #--
    #: () -> Prism::node?
    def parent
      @parent
    end

    # :call-seq:
    #   name -> Symbol | nil
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol?
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   delimiter_loc -> Location
    #
    # Returns the Location represented by `delimiter_loc`.
    #--
    #: () -> Location
    def delimiter_loc
      location = @delimiter_loc
      return location if location.is_a?(Location)
      @delimiter_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the delimiter_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_delimiter_loc(repository)
      repository.enter(node_id, :delimiter_loc)
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   delimiter -> String
    #
    # Slice the location of delimiter_loc from the source.
    #--
    #: () -> String
    def delimiter
      delimiter_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantPathTargetNode) &&
        (parent === other.parent) &&
        (name === other.name) &&
        (delimiter_loc.nil? == other.delimiter_loc.nil?) &&
        (name_loc.nil? == other.name_loc.nil?)
    end
  end

  # Represents writing to a constant path.
  #
  #     ::Foo = 1
  #     ^^^^^^^^^
  #
  #     Foo::Bar = 1
  #     ^^^^^^^^^^^^
  #
  #     ::Foo::Bar = 1
  #     ^^^^^^^^^^^^^^
  class ConstantPathWriteNode < Node
    # @rbs @target: ConstantPathNode
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new ConstantPathWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ConstantPathNode target, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, target, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @target = target
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_path_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [target, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield target
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [target, value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [target, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantPathWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?target: ConstantPathNode, ?operator_loc: Location, ?value: Prism::node) -> ConstantPathWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, target: self.target, operator_loc: self.operator_loc, value: self.value)
      ConstantPathWriteNode.new(source, node_id, location, flags, target, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location target operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :target                  then deconstructed[:target] = self.target
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_path_write_node
    def type
      :constant_path_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_path_write_node
    def self.type
      :constant_path_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   target -> ConstantPathNode
    #
    # A node representing the constant path being written to.
    #
    #     Foo::Bar = 1
    #     ^^^^^^^^
    #
    #     ::Foo = :abc
    #     ^^^^^
    #--
    #: () -> ConstantPathNode
    def target
      @target
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `=` operator.
    #
    #     ::ABC = 123
    #           ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the constant path. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     FOO::BAR = :abc
    #                ^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantPathWriteNode) &&
        (target === other.target) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents referencing a constant.
  #
  #     Foo
  #     ^^^
  class ConstantReadNode < Node
    # @rbs @name: Symbol

    # Initialize a new ConstantReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> ConstantReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      ConstantReadNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_read_node
    def type
      :constant_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_read_node
    def self.type
      :constant_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants).
    #
    #     X              # name `:X`
    #
    #     SOME_CONSTANT  # name `:SOME_CONSTANT`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantReadNode) &&
        (name === other.name)
    end
  end

  # Represents writing to a constant in a context that doesn't have an explicit value.
  #
  #     Foo, Bar = baz
  #     ^^^  ^^^
  class ConstantTargetNode < Node
    # @rbs @name: Symbol

    # Initialize a new ConstantTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> ConstantTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      ConstantTargetNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_target_node
    def type
      :constant_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_target_node
    def self.type
      :constant_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantTargetNode) &&
        (name === other.name)
    end
  end

  # Represents writing to a constant.
  #
  #     Foo = 1
  #     ^^^^^^^
  class ConstantWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @value: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new ConstantWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Prism::node value, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_constant_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, value, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ConstantWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?value: Prism::node, ?operator_loc: Location) -> ConstantWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, value: self.value, operator_loc: self.operator_loc)
      ConstantWriteNode.new(source, node_id, location, flags, name, name_loc, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :constant_write_node
    def type
      :constant_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :constant_write_node
    def self.type
      :constant_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants).
    #
    #     Foo = :bar # name `:Foo`
    #
    #     XYZ = 1    # name `:XYZ`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # The Location of the constant name.
    #
    #     FOO = 1
    #     ^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the constant. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     FOO = :bar
    #           ^^^^
    #
    #     MyClass = Class.new
    #               ^^^^^^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `=` operator.
    #
    #     FOO = :bar
    #         ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ConstantWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a method definition.
  #
  #     def method
  #     end
  #     ^^^^^^^^^^
  class DefNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @receiver: Prism::node?
    # @rbs @parameters: ParametersNode?
    # @rbs @body: (StatementsNode | BeginNode)?
    # @rbs @locals: Array[Symbol]
    # @rbs @def_keyword_loc: Location
    # @rbs @operator_loc: Location?
    # @rbs @lparen_loc: Location?
    # @rbs @rparen_loc: Location?
    # @rbs @equal_loc: Location?
    # @rbs @end_keyword_loc: Location?

    # Initialize a new DefNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Prism::node? receiver, ParametersNode? parameters, (StatementsNode | BeginNode)? body, Array[Symbol] locals, Location def_keyword_loc, Location? operator_loc, Location? lparen_loc, Location? rparen_loc, Location? equal_loc, Location? end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, receiver, parameters, body, locals, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @receiver = receiver
      @parameters = parameters
      @body = body
      @locals = locals
      @def_keyword_loc = def_keyword_loc
      @operator_loc = operator_loc
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
      @equal_loc = equal_loc
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_def_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, parameters, body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      if (parameters = self.parameters); yield parameters; end
      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      if (parameters = self.parameters); compact << parameters; end
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, *receiver, *parameters, *body, def_keyword_loc, *operator_loc, *lparen_loc, *rparen_loc, *equal_loc, *end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> DefNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?receiver: Prism::node?, ?parameters: ParametersNode?, ?body: (StatementsNode | BeginNode)?, ?locals: Array[Symbol], ?def_keyword_loc: Location, ?operator_loc: Location?, ?lparen_loc: Location?, ?rparen_loc: Location?, ?equal_loc: Location?, ?end_keyword_loc: Location?) -> DefNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, receiver: self.receiver, parameters: self.parameters, body: self.body, locals: self.locals, def_keyword_loc: self.def_keyword_loc, operator_loc: self.operator_loc, lparen_loc: self.lparen_loc, rparen_loc: self.rparen_loc, equal_loc: self.equal_loc, end_keyword_loc: self.end_keyword_loc)
      DefNode.new(source, node_id, location, flags, name, name_loc, receiver, parameters, body, locals, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc receiver parameters body locals def_keyword_loc operator_loc lparen_loc rparen_loc equal_loc end_keyword_loc def_keyword operator lparen rparen equal end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :parameters              then deconstructed[:parameters] = self.parameters
        when :body                    then deconstructed[:body] = self.body
        when :locals                  then deconstructed[:locals] = self.locals
        when :def_keyword_loc         then deconstructed[:def_keyword_loc] = self.def_keyword_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :equal_loc               then deconstructed[:equal_loc] = self.equal_loc
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :def_keyword             then deconstructed[:def_keyword] = self.def_keyword
        when :operator                then deconstructed[:operator] = self.operator
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        when :equal                   then deconstructed[:equal] = self.equal
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :def_node
    def type
      :def_node
    end

    # See `Node.type`.
    #--
    #: () -> :def_node
    def self.type
      :def_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # Returns the `receiver` attribute.
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :call-seq:
    #   parameters -> ParametersNode | nil
    #
    # Returns the `parameters` attribute.
    #--
    #: () -> ParametersNode?
    def parameters
      @parameters
    end

    # :call-seq:
    #   body -> StatementsNode | BeginNode | nil
    #
    # Returns the `body` attribute.
    #--
    #: () -> (StatementsNode | BeginNode)?
    def body
      @body
    end

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # Returns the `locals` attribute.
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :category: Locations
    # :call-seq:
    #   def_keyword_loc -> Location
    #
    # Returns the Location represented by `def_keyword_loc`.
    #--
    #: () -> Location
    def def_keyword_loc
      location = @def_keyword_loc
      return location if location.is_a?(Location)
      @def_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the def_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_def_keyword_loc(repository)
      repository.enter(node_id, :def_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location | nil
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location?
    def operator_loc
      location = @operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc) unless @operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location | nil
    #
    # Returns the Location represented by `lparen_loc`.
    #--
    #: () -> Location?
    def lparen_loc
      location = @lparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc) unless @lparen_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location | nil
    #
    # Returns the Location represented by `rparen_loc`.
    #--
    #: () -> Location?
    def rparen_loc
      location = @rparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc) unless @rparen_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   equal_loc -> Location | nil
    #
    # Returns the Location represented by `equal_loc`.
    #--
    #: () -> Location?
    def equal_loc
      location = @equal_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @equal_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the equal_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_equal_loc(repository)
      repository.enter(node_id, :equal_loc) unless @equal_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   def_keyword -> String
    #
    # Slice the location of def_keyword_loc from the source.
    #--
    #: () -> String
    def def_keyword
      def_keyword_loc.slice
    end

    # :call-seq:
    #   operator -> String | nil
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String?
    def operator
      operator_loc&.slice
    end

    # :call-seq:
    #   lparen -> String | nil
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # :call-seq:
    #   rparen -> String | nil
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # :call-seq:
    #   equal -> String | nil
    #
    # Slice the location of equal_loc from the source.
    #--
    #: () -> String?
    def equal
      equal_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(DefNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (receiver === other.receiver) &&
        (parameters === other.parameters) &&
        (body === other.body) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (def_keyword_loc.nil? == other.def_keyword_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (rparen_loc.nil? == other.rparen_loc.nil?) &&
        (equal_loc.nil? == other.equal_loc.nil?) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents the use of the `defined?` keyword.
  #
  #     defined?(a)
  #     ^^^^^^^^^^^
  class DefinedNode < Node
    # @rbs @lparen_loc: Location?
    # @rbs @value: Prism::node
    # @rbs @rparen_loc: Location?
    # @rbs @keyword_loc: Location

    # Initialize a new DefinedNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? lparen_loc, Prism::node value, Location? rparen_loc, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, lparen_loc, value, rparen_loc, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @lparen_loc = lparen_loc
      @value = value
      @rparen_loc = rparen_loc
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_defined_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*lparen_loc, value, *rparen_loc, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> DefinedNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?lparen_loc: Location?, ?value: Prism::node, ?rparen_loc: Location?, ?keyword_loc: Location) -> DefinedNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, lparen_loc: self.lparen_loc, value: self.value, rparen_loc: self.rparen_loc, keyword_loc: self.keyword_loc)
      DefinedNode.new(source, node_id, location, flags, lparen_loc, value, rparen_loc, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location lparen_loc value rparen_loc keyword_loc lparen rparen keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :value                   then deconstructed[:value] = self.value
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :defined_node
    def type
      :defined_node
    end

    # See `Node.type`.
    #--
    #: () -> :defined_node
    def self.type
      :defined_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location | nil
    #
    # Returns the Location represented by `lparen_loc`.
    #--
    #: () -> Location?
    def lparen_loc
      location = @lparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc) unless @lparen_loc.nil?
    end
    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location | nil
    #
    # Returns the Location represented by `rparen_loc`.
    #--
    #: () -> Location?
    def rparen_loc
      location = @rparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc) unless @rparen_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   lparen -> String | nil
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # :call-seq:
    #   rparen -> String | nil
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(DefinedNode) &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (value === other.value) &&
        (rparen_loc.nil? == other.rparen_loc.nil?) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents an `else` clause in a `case`, `if`, or `unless` statement.
  #
  #     if a then b else c end
  #                 ^^^^^^^^^^
  class ElseNode < Node
    # @rbs @else_keyword_loc: Location
    # @rbs @statements: StatementsNode?
    # @rbs @end_keyword_loc: Location?

    # Initialize a new ElseNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location else_keyword_loc, StatementsNode? statements, Location? end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, else_keyword_loc, statements, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @else_keyword_loc = else_keyword_loc
      @statements = statements
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_else_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [else_keyword_loc, *statements, *end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ElseNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?else_keyword_loc: Location, ?statements: StatementsNode?, ?end_keyword_loc: Location?) -> ElseNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, else_keyword_loc: self.else_keyword_loc, statements: self.statements, end_keyword_loc: self.end_keyword_loc)
      ElseNode.new(source, node_id, location, flags, else_keyword_loc, statements, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location else_keyword_loc statements end_keyword_loc else_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :else_keyword_loc        then deconstructed[:else_keyword_loc] = self.else_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :else_keyword            then deconstructed[:else_keyword] = self.else_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :else_node
    def type
      :else_node
    end

    # See `Node.type`.
    #--
    #: () -> :else_node
    def self.type
      :else_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   else_keyword_loc -> Location
    #
    # Returns the Location represented by `else_keyword_loc`.
    #--
    #: () -> Location
    def else_keyword_loc
      location = @else_keyword_loc
      return location if location.is_a?(Location)
      @else_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the else_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_else_keyword_loc(repository)
      repository.enter(node_id, :else_keyword_loc)
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   else_keyword -> String
    #
    # Slice the location of else_keyword_loc from the source.
    #--
    #: () -> String
    def else_keyword
      else_keyword_loc.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ElseNode) &&
        (else_keyword_loc.nil? == other.else_keyword_loc.nil?) &&
        (statements === other.statements) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents an interpolated set of statements.
  #
  #     "foo #{bar}"
  #          ^^^^^^
  class EmbeddedStatementsNode < Node
    # @rbs @opening_loc: Location
    # @rbs @statements: StatementsNode?
    # @rbs @closing_loc: Location

    # Initialize a new EmbeddedStatementsNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, StatementsNode? statements, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, statements, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @statements = statements
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_embedded_statements_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, *statements, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> EmbeddedStatementsNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?statements: StatementsNode?, ?closing_loc: Location) -> EmbeddedStatementsNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, statements: self.statements, closing_loc: self.closing_loc)
      EmbeddedStatementsNode.new(source, node_id, location, flags, opening_loc, statements, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc statements closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :embedded_statements_node
    def type
      :embedded_statements_node
    end

    # See `Node.type`.
    #--
    #: () -> :embedded_statements_node
    def self.type
      :embedded_statements_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(EmbeddedStatementsNode) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (statements === other.statements) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents an interpolated variable.
  #
  #     "foo #@bar"
  #          ^^^^^
  class EmbeddedVariableNode < Node
    # @rbs @operator_loc: Location
    # @rbs @variable: (InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)

    # Initialize a new EmbeddedVariableNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location operator_loc, (InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode) variable) -> void
    def initialize(source, node_id, location, flags, operator_loc, variable)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @operator_loc = operator_loc
      @variable = variable
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_embedded_variable_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [variable]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield variable
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [variable]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [operator_loc, variable] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> EmbeddedVariableNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?operator_loc: Location, ?variable: (InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)) -> EmbeddedVariableNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, operator_loc: self.operator_loc, variable: self.variable)
      EmbeddedVariableNode.new(source, node_id, location, flags, operator_loc, variable)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location operator_loc variable operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :variable                then deconstructed[:variable] = self.variable
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :embedded_variable_node
    def type
      :embedded_variable_node
    end

    # See `Node.type`.
    #--
    #: () -> :embedded_variable_node
    def self.type
      :embedded_variable_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   variable -> InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode
    #
    # Returns the `variable` attribute.
    #--
    #: () -> (InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode)
    def variable
      @variable
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(EmbeddedVariableNode) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (variable === other.variable)
    end
  end

  # Represents an `ensure` clause in a `begin` statement.
  #
  #     begin
  #       foo
  #     ensure
  #     ^^^^^^
  #       bar
  #     end
  class EnsureNode < Node
    # @rbs @ensure_keyword_loc: Location
    # @rbs @statements: StatementsNode?
    # @rbs @end_keyword_loc: Location

    # Initialize a new EnsureNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location ensure_keyword_loc, StatementsNode? statements, Location end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, ensure_keyword_loc, statements, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @ensure_keyword_loc = ensure_keyword_loc
      @statements = statements
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_ensure_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [ensure_keyword_loc, *statements, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> EnsureNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?ensure_keyword_loc: Location, ?statements: StatementsNode?, ?end_keyword_loc: Location) -> EnsureNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, ensure_keyword_loc: self.ensure_keyword_loc, statements: self.statements, end_keyword_loc: self.end_keyword_loc)
      EnsureNode.new(source, node_id, location, flags, ensure_keyword_loc, statements, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location ensure_keyword_loc statements end_keyword_loc ensure_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :ensure_keyword_loc      then deconstructed[:ensure_keyword_loc] = self.ensure_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :ensure_keyword          then deconstructed[:ensure_keyword] = self.ensure_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :ensure_node
    def type
      :ensure_node
    end

    # See `Node.type`.
    #--
    #: () -> :ensure_node
    def self.type
      :ensure_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   ensure_keyword_loc -> Location
    #
    # Returns the Location represented by `ensure_keyword_loc`.
    #--
    #: () -> Location
    def ensure_keyword_loc
      location = @ensure_keyword_loc
      return location if location.is_a?(Location)
      @ensure_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the ensure_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_ensure_keyword_loc(repository)
      repository.enter(node_id, :ensure_keyword_loc)
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   ensure_keyword -> String
    #
    # Slice the location of ensure_keyword_loc from the source.
    #--
    #: () -> String
    def ensure_keyword
      ensure_keyword_loc.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(EnsureNode) &&
        (ensure_keyword_loc.nil? == other.ensure_keyword_loc.nil?) &&
        (statements === other.statements) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents a node that is either missing or unexpected and results in a syntax error.
  class ErrorRecoveryNode < Node
    # @rbs @unexpected: Prism::node?

    # Initialize a new ErrorRecoveryNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? unexpected) -> void
    def initialize(source, node_id, location, flags, unexpected)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @unexpected = unexpected
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_error_recovery_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [unexpected]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (unexpected = self.unexpected); yield unexpected; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (unexpected = self.unexpected); compact << unexpected; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*unexpected] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ErrorRecoveryNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?unexpected: Prism::node?) -> ErrorRecoveryNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, unexpected: self.unexpected)
      ErrorRecoveryNode.new(source, node_id, location, flags, unexpected)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location unexpected]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :unexpected              then deconstructed[:unexpected] = self.unexpected
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :error_recovery_node
    def type
      :error_recovery_node
    end

    # See `Node.type`.
    #--
    #: () -> :error_recovery_node
    def self.type
      :error_recovery_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   unexpected -> Node | nil
    #
    # The unexpected node that was found in the tree, if there was one.
    #--
    #: () -> Prism::node?
    def unexpected
      @unexpected
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ErrorRecoveryNode) &&
        (unexpected === other.unexpected)
    end
  end

  # Represents the use of the literal `false` keyword.
  #
  #     false
  #     ^^^^^
  class FalseNode < Node

    # Initialize a new FalseNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_false_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> FalseNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> FalseNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      FalseNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :false_node
    def type
      :false_node
    end

    # See `Node.type`.
    #--
    #: () -> :false_node
    def self.type
      :false_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(FalseNode)
    end
  end

  # Represents a find pattern in pattern matching.
  #
  #     foo in *bar, baz, *qux
  #            ^^^^^^^^^^^^^^^
  #
  #     foo in [*bar, baz, *qux]
  #            ^^^^^^^^^^^^^^^^^
  #
  #     foo in Foo(*bar, baz, *qux)
  #            ^^^^^^^^^^^^^^^^^^^^
  #
  #     foo => *bar, baz, *qux
  #            ^^^^^^^^^^^^^^^
  class FindPatternNode < Node
    # @rbs @constant: (ConstantPathNode | ConstantReadNode)?
    # @rbs @left: SplatNode
    # @rbs @requireds: Array[Prism::node]
    # @rbs @right: SplatNode
    # @rbs @opening_loc: Location?
    # @rbs @closing_loc: Location?

    # Initialize a new FindPatternNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (ConstantPathNode | ConstantReadNode)? constant, SplatNode left, Array[Prism::node] requireds, SplatNode right, Location? opening_loc, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, constant, left, requireds, right, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @constant = constant
      @left = left
      @requireds = requireds
      @right = right
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_find_pattern_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [constant, left, *requireds, right]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (constant = self.constant); yield constant; end
      yield left
      requireds.each { |node| yield node }
      yield right
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (constant = self.constant); compact << constant; end
      compact << left
      compact.concat(requireds)
      compact << right
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*constant, left, *requireds, right, *opening_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> FindPatternNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?constant: (ConstantPathNode | ConstantReadNode)?, ?left: SplatNode, ?requireds: Array[Prism::node], ?right: SplatNode, ?opening_loc: Location?, ?closing_loc: Location?) -> FindPatternNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, constant: self.constant, left: self.left, requireds: self.requireds, right: self.right, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      FindPatternNode.new(source, node_id, location, flags, constant, left, requireds, right, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location constant left requireds right opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :constant                then deconstructed[:constant] = self.constant
        when :left                    then deconstructed[:left] = self.left
        when :requireds               then deconstructed[:requireds] = self.requireds
        when :right                   then deconstructed[:right] = self.right
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :find_pattern_node
    def type
      :find_pattern_node
    end

    # See `Node.type`.
    #--
    #: () -> :find_pattern_node
    def self.type
      :find_pattern_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   constant -> ConstantPathNode | ConstantReadNode | nil
    #
    # Represents the optional constant preceding the pattern
    #
    #     foo in Foo(*bar, baz, *qux)
    #            ^^^
    #--
    #: () -> (ConstantPathNode | ConstantReadNode)?
    def constant
      @constant
    end

    # :call-seq:
    #   left -> SplatNode
    #
    # Represents the first wildcard node in the pattern.
    #
    #     foo in *bar, baz, *qux
    #            ^^^^
    #
    #     foo in Foo(*bar, baz, *qux)
    #                ^^^^
    #--
    #: () -> SplatNode
    def left
      @left
    end

    # :call-seq:
    #   requireds -> Array[Node]
    #
    # Represents the nodes in between the wildcards.
    #
    #     foo in *bar, baz, *qux
    #                  ^^^
    #
    #     foo in Foo(*bar, baz, 1, *qux)
    #                      ^^^^^^
    #--
    #: () -> Array[Prism::node]
    def requireds
      @requireds
    end

    # :call-seq:
    #   right -> SplatNode
    #
    # Represents the second wildcard node in the pattern.
    #
    #     foo in *bar, baz, *qux
    #                       ^^^^
    #
    #     foo in Foo(*bar, baz, *qux)
    #                           ^^^^
    #--
    #: () -> SplatNode
    def right
      @right
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # The Location of the opening brace.
    #
    #     foo in [*bar, baz, *qux]
    #            ^
    #
    #     foo in Foo(*bar, baz, *qux)
    #               ^
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # The Location of the closing brace.
    #
    #     foo in [*bar, baz, *qux]
    #                            ^
    #
    #     foo in Foo(*bar, baz, *qux)
    #                               ^
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(FindPatternNode) &&
        (constant === other.constant) &&
        (left === other.left) &&
        (requireds.length == other.requireds.length) &&
        requireds.zip(other.requireds).all? { |left, right| left === right } &&
        (right === other.right) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents the use of the `..` or `...` operators to create flip flops.
  #
  #     baz if foo .. bar
  #            ^^^^^^^^^^
  class FlipFlopNode < Node
    # @rbs @left: Prism::node?
    # @rbs @right: Prism::node?
    # @rbs @operator_loc: Location

    # Initialize a new FlipFlopNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? left, Prism::node? right, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, left, right, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_flip_flop_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [left, right]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (left = self.left); yield left; end
      if (right = self.right); yield right; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (left = self.left); compact << left; end
      if (right = self.right); compact << right; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*left, *right, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> FlipFlopNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?left: Prism::node?, ?right: Prism::node?, ?operator_loc: Location) -> FlipFlopNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, left: self.left, right: self.right, operator_loc: self.operator_loc)
      FlipFlopNode.new(source, node_id, location, flags, left, right, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location left right operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :left                    then deconstructed[:left] = self.left
        when :right                   then deconstructed[:right] = self.right
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :flip_flop_node
    def type
      :flip_flop_node
    end

    # See `Node.type`.
    #--
    #: () -> :flip_flop_node
    def self.type
      :flip_flop_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # ... operator
    #--
    #: () -> bool
    def exclude_end?
      flags.anybits?(RangeFlags::EXCLUDE_END)
    end

    # :call-seq:
    #   left -> Node | nil
    #
    # Returns the `left` attribute.
    #--
    #: () -> Prism::node?
    def left
      @left
    end

    # :call-seq:
    #   right -> Node | nil
    #
    # Returns the `right` attribute.
    #--
    #: () -> Prism::node?
    def right
      @right
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(FlipFlopNode) &&
        (flags === other.flags) &&
        (left === other.left) &&
        (right === other.right) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a floating point number literal.
  #
  #     1.0
  #     ^^^
  class FloatNode < Node
    # @rbs @value: Float

    # Initialize a new FloatNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Float value) -> void
    def initialize(source, node_id, location, flags, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_float_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> FloatNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: Float) -> FloatNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value)
      FloatNode.new(source, node_id, location, flags, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :float_node
    def type
      :float_node
    end

    # See `Node.type`.
    #--
    #: () -> :float_node
    def self.type
      :float_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   value -> Float
    #
    # The value of the floating point number as a Float.
    #--
    #: () -> Float
    def value
      @value
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(FloatNode) &&
        (value === other.value)
    end
  end

  # Represents the use of the `for` keyword.
  #
  #     for i in a end
  #     ^^^^^^^^^^^^^^
  class ForNode < Node
    # @rbs @index: (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode)
    # @rbs @collection: Prism::node
    # @rbs @statements: StatementsNode?
    # @rbs @for_keyword_loc: Location
    # @rbs @in_keyword_loc: Location
    # @rbs @do_keyword_loc: Location?
    # @rbs @end_keyword_loc: Location

    # Initialize a new ForNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode) index, Prism::node collection, StatementsNode? statements, Location for_keyword_loc, Location in_keyword_loc, Location? do_keyword_loc, Location end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @index = index
      @collection = collection
      @statements = statements
      @for_keyword_loc = for_keyword_loc
      @in_keyword_loc = in_keyword_loc
      @do_keyword_loc = do_keyword_loc
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_for_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [index, collection, statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield index
      yield collection
      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << index
      compact << collection
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [index, collection, *statements, for_keyword_loc, in_keyword_loc, *do_keyword_loc, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ForNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?index: (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode), ?collection: Prism::node, ?statements: StatementsNode?, ?for_keyword_loc: Location, ?in_keyword_loc: Location, ?do_keyword_loc: Location?, ?end_keyword_loc: Location) -> ForNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, index: self.index, collection: self.collection, statements: self.statements, for_keyword_loc: self.for_keyword_loc, in_keyword_loc: self.in_keyword_loc, do_keyword_loc: self.do_keyword_loc, end_keyword_loc: self.end_keyword_loc)
      ForNode.new(source, node_id, location, flags, index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location index collection statements for_keyword_loc in_keyword_loc do_keyword_loc end_keyword_loc for_keyword in_keyword do_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :index                   then deconstructed[:index] = self.index
        when :collection              then deconstructed[:collection] = self.collection
        when :statements              then deconstructed[:statements] = self.statements
        when :for_keyword_loc         then deconstructed[:for_keyword_loc] = self.for_keyword_loc
        when :in_keyword_loc          then deconstructed[:in_keyword_loc] = self.in_keyword_loc
        when :do_keyword_loc          then deconstructed[:do_keyword_loc] = self.do_keyword_loc
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :for_keyword             then deconstructed[:for_keyword] = self.for_keyword
        when :in_keyword              then deconstructed[:in_keyword] = self.in_keyword
        when :do_keyword              then deconstructed[:do_keyword] = self.do_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :for_node
    def type
      :for_node
    end

    # See `Node.type`.
    #--
    #: () -> :for_node
    def self.type
      :for_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   index -> LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode
    #
    # The index expression for `for` loops.
    #
    #     for i in a end
    #         ^
    #--
    #: () -> (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode)
    def index
      @index
    end

    # :call-seq:
    #   collection -> Node
    #
    # The collection to iterate over.
    #
    #     for i in a end
    #              ^
    #--
    #: () -> Prism::node
    def collection
      @collection
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Represents the body of statements to execute for each iteration of the loop.
    #
    #     for i in a
    #       foo(i)
    #       ^^^^^^
    #     end
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   for_keyword_loc -> Location
    #
    # The Location of the `for` keyword.
    #
    #     for i in a end
    #     ^^^
    #--
    #: () -> Location
    def for_keyword_loc
      location = @for_keyword_loc
      return location if location.is_a?(Location)
      @for_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the for_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_for_keyword_loc(repository)
      repository.enter(node_id, :for_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   in_keyword_loc -> Location
    #
    # The Location of the `in` keyword.
    #
    #     for i in a end
    #           ^^
    #--
    #: () -> Location
    def in_keyword_loc
      location = @in_keyword_loc
      return location if location.is_a?(Location)
      @in_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the in_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_in_keyword_loc(repository)
      repository.enter(node_id, :in_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   do_keyword_loc -> Location | nil
    #
    # The Location of the `do` keyword, if present.
    #
    #     for i in a do end
    #                ^^
    #--
    #: () -> Location?
    def do_keyword_loc
      location = @do_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @do_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the do_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_do_keyword_loc(repository)
      repository.enter(node_id, :do_keyword_loc) unless @do_keyword_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # The Location of the `end` keyword.
    #
    #     for i in a end
    #                ^^^
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   for_keyword -> String
    #
    # Slice the location of for_keyword_loc from the source.
    #--
    #: () -> String
    def for_keyword
      for_keyword_loc.slice
    end

    # :call-seq:
    #   in_keyword -> String
    #
    # Slice the location of in_keyword_loc from the source.
    #--
    #: () -> String
    def in_keyword
      in_keyword_loc.slice
    end

    # :call-seq:
    #   do_keyword -> String | nil
    #
    # Slice the location of do_keyword_loc from the source.
    #--
    #: () -> String?
    def do_keyword
      do_keyword_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ForNode) &&
        (index === other.index) &&
        (collection === other.collection) &&
        (statements === other.statements) &&
        (for_keyword_loc.nil? == other.for_keyword_loc.nil?) &&
        (in_keyword_loc.nil? == other.in_keyword_loc.nil?) &&
        (do_keyword_loc.nil? == other.do_keyword_loc.nil?) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents forwarding all arguments to this method to another method.
  #
  #     def foo(...)
  #       bar(...)
  #           ^^^
  #     end
  class ForwardingArgumentsNode < Node

    # Initialize a new ForwardingArgumentsNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_forwarding_arguments_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ForwardingArgumentsNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> ForwardingArgumentsNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      ForwardingArgumentsNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :forwarding_arguments_node
    def type
      :forwarding_arguments_node
    end

    # See `Node.type`.
    #--
    #: () -> :forwarding_arguments_node
    def self.type
      :forwarding_arguments_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ForwardingArgumentsNode)
    end
  end

  # Represents the use of the forwarding parameter in a method, block, or lambda declaration.
  #
  #     def foo(...)
  #             ^^^
  #     end
  class ForwardingParameterNode < Node

    # Initialize a new ForwardingParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_forwarding_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ForwardingParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> ForwardingParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      ForwardingParameterNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :forwarding_parameter_node
    def type
      :forwarding_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :forwarding_parameter_node
    def self.type
      :forwarding_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ForwardingParameterNode)
    end
  end

  # Represents the use of the `super` keyword without parentheses or arguments, but which might have a block.
  #
  #     super
  #     ^^^^^
  #
  #     super { 123 }
  #     ^^^^^^^^^^^^^
  #
  # If it has any other arguments, it would be a `SuperNode` instead.
  class ForwardingSuperNode < Node
    # @rbs @keyword_loc: Location
    # @rbs @block: BlockNode?

    # Initialize a new ForwardingSuperNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location keyword_loc, BlockNode? block) -> void
    def initialize(source, node_id, location, flags, keyword_loc, block)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @keyword_loc = keyword_loc
      @block = block
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_forwarding_super_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [block]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (block = self.block); yield block; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (block = self.block); compact << block; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [keyword_loc, *block] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ForwardingSuperNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?keyword_loc: Location, ?block: BlockNode?) -> ForwardingSuperNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, keyword_loc: self.keyword_loc, block: self.block)
      ForwardingSuperNode.new(source, node_id, location, flags, keyword_loc, block)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location keyword_loc block keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :block                   then deconstructed[:block] = self.block
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :forwarding_super_node
    def type
      :forwarding_super_node
    end

    # See `Node.type`.
    #--
    #: () -> :forwarding_super_node
    def self.type
      :forwarding_super_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # super
    # ^^^^^
    #
    # super { 123 }
    # ^^^^^
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :call-seq:
    #   block -> BlockNode | nil
    #
    # All other arguments are forwarded as normal, except the original block is replaced with the new block.
    #--
    #: () -> BlockNode?
    def block
      @block
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ForwardingSuperNode) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (block === other.block)
    end
  end

  # Represents the use of the `&&=` operator for assignment to a global variable.
  #
  #     $target &&= value
  #     ^^^^^^^^^^^^^^^^^
  class GlobalVariableAndWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new GlobalVariableAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_global_variable_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> GlobalVariableAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> GlobalVariableAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      GlobalVariableAndWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :global_variable_and_write_node
    def type
      :global_variable_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :global_variable_and_write_node
    def self.type
      :global_variable_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(GlobalVariableAndWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents assigning to a global variable using an operator that isn't `=`.
  #
  #     $target += value
  #     ^^^^^^^^^^^^^^^^
  class GlobalVariableOperatorWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @binary_operator: Symbol

    # Initialize a new GlobalVariableOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location binary_operator_loc, Prism::node value, Symbol binary_operator) -> void
    def initialize(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @binary_operator_loc = binary_operator_loc
      @value = value
      @binary_operator = binary_operator
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_global_variable_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> GlobalVariableOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?binary_operator_loc: Location, ?value: Prism::node, ?binary_operator: Symbol) -> GlobalVariableOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, binary_operator_loc: self.binary_operator_loc, value: self.value, binary_operator: self.binary_operator)
      GlobalVariableOperatorWriteNode.new(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc binary_operator_loc value binary_operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :global_variable_operator_write_node
    def type
      :global_variable_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :global_variable_operator_write_node
    def self.type
      :global_variable_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(GlobalVariableOperatorWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value) &&
        (binary_operator === other.binary_operator)
    end
  end

  # Represents the use of the `||=` operator for assignment to a global variable.
  #
  #     $target ||= value
  #     ^^^^^^^^^^^^^^^^^
  class GlobalVariableOrWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new GlobalVariableOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_global_variable_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> GlobalVariableOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> GlobalVariableOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      GlobalVariableOrWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :global_variable_or_write_node
    def type
      :global_variable_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :global_variable_or_write_node
    def self.type
      :global_variable_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(GlobalVariableOrWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents referencing a global variable.
  #
  #     $foo
  #     ^^^^
  class GlobalVariableReadNode < Node
    # @rbs @name: Symbol

    # Initialize a new GlobalVariableReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_global_variable_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> GlobalVariableReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> GlobalVariableReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      GlobalVariableReadNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :global_variable_read_node
    def type
      :global_variable_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :global_variable_read_node
    def self.type
      :global_variable_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol.
    #
    #     $foo   # name `:$foo`
    #
    #     $_Test # name `:$_Test`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(GlobalVariableReadNode) &&
        (name === other.name)
    end
  end

  # Represents writing to a global variable in a context that doesn't have an explicit value.
  #
  #     $foo, $bar = baz
  #     ^^^^  ^^^^
  class GlobalVariableTargetNode < Node
    # @rbs @name: Symbol

    # Initialize a new GlobalVariableTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_global_variable_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> GlobalVariableTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> GlobalVariableTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      GlobalVariableTargetNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :global_variable_target_node
    def type
      :global_variable_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :global_variable_target_node
    def self.type
      :global_variable_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(GlobalVariableTargetNode) &&
        (name === other.name)
    end
  end

  # Represents writing to a global variable.
  #
  #     $foo = 1
  #     ^^^^^^^^
  class GlobalVariableWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @value: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new GlobalVariableWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Prism::node value, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_global_variable_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, value, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> GlobalVariableWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?value: Prism::node, ?operator_loc: Location) -> GlobalVariableWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, value: self.value, operator_loc: self.operator_loc)
      GlobalVariableWriteNode.new(source, node_id, location, flags, name, name_loc, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :global_variable_write_node
    def type
      :global_variable_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :global_variable_write_node
    def self.type
      :global_variable_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol.
    #
    #     $foo = :bar  # name `:$foo`
    #
    #     $_Test = 123 # name `:$_Test`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # The Location of the global variable's name.
    #
    #     $foo = :bar
    #     ^^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the global variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     $foo = :bar
    #            ^^^^
    #
    #     $-xyz = 123
    #             ^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `=` operator.
    #
    #     $foo = :bar
    #          ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(GlobalVariableWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a hash literal.
  #
  #     { a => b }
  #     ^^^^^^^^^^
  class HashNode < Node
    # @rbs @opening_loc: Location
    # @rbs @elements: Array[AssocNode | AssocSplatNode]
    # @rbs @closing_loc: Location

    # Initialize a new HashNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Array[AssocNode | AssocSplatNode] elements, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, elements, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @elements = elements
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_hash_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*elements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      elements.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*elements]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, *elements, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> HashNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?elements: Array[AssocNode | AssocSplatNode], ?closing_loc: Location) -> HashNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, elements: self.elements, closing_loc: self.closing_loc)
      HashNode.new(source, node_id, location, flags, opening_loc, elements, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc elements closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :elements                then deconstructed[:elements] = self.elements
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :hash_node
    def type
      :hash_node
    end

    # See `Node.type`.
    #--
    #: () -> :hash_node
    def self.type
      :hash_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # The Location of the opening brace.
    #
    #     { a => b }
    #     ^
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   elements -> Array[AssocNode | AssocSplatNode]
    #
    # The elements of the hash. These can be either `AssocNode`s or `AssocSplatNode`s.
    #
    #     { a: b }
    #       ^^^^
    #
    #     { **foo }
    #       ^^^^^
    #--
    #: () -> Array[AssocNode | AssocSplatNode]
    def elements
      @elements
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # The Location of the closing brace.
    #
    #     { a => b }
    #              ^
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(HashNode) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (elements.length == other.elements.length) &&
        elements.zip(other.elements).all? { |left, right| left === right } &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents a hash pattern in pattern matching.
  #
  #     foo => { a: 1, b: 2 }
  #            ^^^^^^^^^^^^^^
  #
  #     foo => { a: 1, b: 2, **c }
  #            ^^^^^^^^^^^^^^^^^^^
  #
  #     foo => Bar[a: 1, b: 2]
  #            ^^^^^^^^^^^^^^^
  #
  #     foo in { a: 1, b: 2 }
  #            ^^^^^^^^^^^^^^
  class HashPatternNode < Node
    # @rbs @constant: (ConstantPathNode | ConstantReadNode)?
    # @rbs @elements: Array[AssocNode]
    # @rbs @rest: (AssocSplatNode | NoKeywordsParameterNode)?
    # @rbs @opening_loc: Location?
    # @rbs @closing_loc: Location?

    # Initialize a new HashPatternNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (ConstantPathNode | ConstantReadNode)? constant, Array[AssocNode] elements, (AssocSplatNode | NoKeywordsParameterNode)? rest, Location? opening_loc, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, constant, elements, rest, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @constant = constant
      @elements = elements
      @rest = rest
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_hash_pattern_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [constant, *elements, rest]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (constant = self.constant); yield constant; end
      elements.each { |node| yield node }
      if (rest = self.rest); yield rest; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (constant = self.constant); compact << constant; end
      compact.concat(elements)
      if (rest = self.rest); compact << rest; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*constant, *elements, *rest, *opening_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> HashPatternNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?constant: (ConstantPathNode | ConstantReadNode)?, ?elements: Array[AssocNode], ?rest: (AssocSplatNode | NoKeywordsParameterNode)?, ?opening_loc: Location?, ?closing_loc: Location?) -> HashPatternNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, constant: self.constant, elements: self.elements, rest: self.rest, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      HashPatternNode.new(source, node_id, location, flags, constant, elements, rest, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location constant elements rest opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :constant                then deconstructed[:constant] = self.constant
        when :elements                then deconstructed[:elements] = self.elements
        when :rest                    then deconstructed[:rest] = self.rest
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :hash_pattern_node
    def type
      :hash_pattern_node
    end

    # See `Node.type`.
    #--
    #: () -> :hash_pattern_node
    def self.type
      :hash_pattern_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   constant -> ConstantPathNode | ConstantReadNode | nil
    #
    # Represents the optional constant preceding the Hash.
    #
    #     foo => Bar[a: 1, b: 2]
    #          ^^^
    #
    #     foo => Bar::Baz[a: 1, b: 2]
    #          ^^^^^^^^
    #--
    #: () -> (ConstantPathNode | ConstantReadNode)?
    def constant
      @constant
    end

    # :call-seq:
    #   elements -> Array[AssocNode]
    #
    # Represents the explicit named hash keys and values.
    #
    #     foo => { a: 1, b:, ** }
    #              ^^^^^^^^
    #--
    #: () -> Array[AssocNode]
    def elements
      @elements
    end

    # :call-seq:
    #   rest -> AssocSplatNode | NoKeywordsParameterNode | nil
    #
    # Represents the rest of the Hash keys and values. This can be named, unnamed, or explicitly forbidden via `**nil`, this last one results in a `NoKeywordsParameterNode`.
    #
    #     foo => { a: 1, b:, **c }
    #                        ^^^
    #
    #     foo => { a: 1, b:, ** }
    #                        ^^
    #
    #     foo => { a: 1, b:, **nil }
    #                        ^^^^^
    #--
    #: () -> (AssocSplatNode | NoKeywordsParameterNode)?
    def rest
      @rest
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # The Location of the opening brace.
    #
    #     foo => { a: 1 }
    #            ^
    #
    #     foo => Bar[a: 1]
    #               ^
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # The Location of the closing brace.
    #
    #     foo => { a: 1 }
    #                   ^
    #
    #     foo => Bar[a: 1]
    #                    ^
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(HashPatternNode) &&
        (constant === other.constant) &&
        (elements.length == other.elements.length) &&
        elements.zip(other.elements).all? { |left, right| left === right } &&
        (rest === other.rest) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents the use of the `if` keyword, either in the block form or the modifier form, or a ternary expression.
  #
  #     bar if foo
  #     ^^^^^^^^^^
  #
  #     if foo then bar end
  #     ^^^^^^^^^^^^^^^^^^^
  #
  #     foo ? bar : baz
  #     ^^^^^^^^^^^^^^^
  class IfNode < Node
    # @rbs @if_keyword_loc: Location?
    # @rbs @predicate: Prism::node
    # @rbs @then_keyword_loc: Location?
    # @rbs @statements: StatementsNode?
    # @rbs @subsequent: (ElseNode | IfNode)?
    # @rbs @end_keyword_loc: Location?

    # Initialize a new IfNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? if_keyword_loc, Prism::node predicate, Location? then_keyword_loc, StatementsNode? statements, (ElseNode | IfNode)? subsequent, Location? end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, if_keyword_loc, predicate, then_keyword_loc, statements, subsequent, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @if_keyword_loc = if_keyword_loc
      @predicate = predicate
      @then_keyword_loc = then_keyword_loc
      @statements = statements
      @subsequent = subsequent
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_if_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [predicate, statements, subsequent]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield predicate
      if (statements = self.statements); yield statements; end
      if (subsequent = self.subsequent); yield subsequent; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << predicate
      if (statements = self.statements); compact << statements; end
      if (subsequent = self.subsequent); compact << subsequent; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*if_keyword_loc, predicate, *then_keyword_loc, *statements, *subsequent, *end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> IfNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?if_keyword_loc: Location?, ?predicate: Prism::node, ?then_keyword_loc: Location?, ?statements: StatementsNode?, ?subsequent: (ElseNode | IfNode)?, ?end_keyword_loc: Location?) -> IfNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, if_keyword_loc: self.if_keyword_loc, predicate: self.predicate, then_keyword_loc: self.then_keyword_loc, statements: self.statements, subsequent: self.subsequent, end_keyword_loc: self.end_keyword_loc)
      IfNode.new(source, node_id, location, flags, if_keyword_loc, predicate, then_keyword_loc, statements, subsequent, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location if_keyword_loc predicate then_keyword_loc statements subsequent end_keyword_loc if_keyword then_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :if_keyword_loc          then deconstructed[:if_keyword_loc] = self.if_keyword_loc
        when :predicate               then deconstructed[:predicate] = self.predicate
        when :then_keyword_loc        then deconstructed[:then_keyword_loc] = self.then_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :subsequent              then deconstructed[:subsequent] = self.subsequent
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :if_keyword              then deconstructed[:if_keyword] = self.if_keyword
        when :then_keyword            then deconstructed[:then_keyword] = self.then_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :if_node
    def type
      :if_node
    end

    # See `Node.type`.
    #--
    #: () -> :if_node
    def self.type
      :if_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   if_keyword_loc -> Location | nil
    #
    # The Location of the `if` keyword if present.
    #
    #     bar if foo
    #         ^^
    #
    # The `if_keyword_loc` field will be `nil` when the `IfNode` represents a ternary expression.
    #--
    #: () -> Location?
    def if_keyword_loc
      location = @if_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @if_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the if_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_if_keyword_loc(repository)
      repository.enter(node_id, :if_keyword_loc) unless @if_keyword_loc.nil?
    end
    # :call-seq:
    #   predicate -> Node
    #
    # The node for the condition the `IfNode` is testing.
    #
    #     if foo
    #        ^^^
    #       bar
    #     end
    #
    #     bar if foo
    #            ^^^
    #
    #     foo ? bar : baz
    #     ^^^
    #--
    #: () -> Prism::node
    def predicate
      @predicate
    end

    # :category: Locations
    # :call-seq:
    #   then_keyword_loc -> Location | nil
    #
    # The Location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
    #
    #     if foo then bar end
    #            ^^^^
    #
    #     a ? b : c
    #       ^
    #--
    #: () -> Location?
    def then_keyword_loc
      location = @then_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @then_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the then_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_then_keyword_loc(repository)
      repository.enter(node_id, :then_keyword_loc) unless @then_keyword_loc.nil?
    end
    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Represents the body of statements that will be executed when the predicate is evaluated as truthy. Will be `nil` when no body is provided.
    #
    #     if foo
    #       bar
    #       ^^^
    #       baz
    #       ^^^
    #     end
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :call-seq:
    #   subsequent -> ElseNode | IfNode | nil
    #
    # Represents an `ElseNode` or an `IfNode` when there is an `else` or an `elsif` in the `if` statement.
    #
    #     if foo
    #       bar
    #     elsif baz
    #     ^^^^^^^^^
    #       qux
    #       ^^^
    #     end
    #     ^^^
    #
    #     if foo then bar else baz end
    #                     ^^^^^^^^^^^^
    #--
    #: () -> (ElseNode | IfNode)?
    def subsequent
      @subsequent
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # The Location of the `end` keyword if present, `nil` otherwise.
    #
    #     if foo
    #       bar
    #     end
    #     ^^^
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   if_keyword -> String | nil
    #
    # Slice the location of if_keyword_loc from the source.
    #--
    #: () -> String?
    def if_keyword
      if_keyword_loc&.slice
    end

    # :call-seq:
    #   then_keyword -> String | nil
    #
    # Slice the location of then_keyword_loc from the source.
    #--
    #: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(IfNode) &&
        (if_keyword_loc.nil? == other.if_keyword_loc.nil?) &&
        (predicate === other.predicate) &&
        (then_keyword_loc.nil? == other.then_keyword_loc.nil?) &&
        (statements === other.statements) &&
        (subsequent === other.subsequent) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents an imaginary number literal.
  #
  #     1.0i
  #     ^^^^
  class ImaginaryNode < Node
    # @rbs @numeric: (FloatNode | IntegerNode | RationalNode)

    # Initialize a new ImaginaryNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (FloatNode | IntegerNode | RationalNode) numeric) -> void
    def initialize(source, node_id, location, flags, numeric)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @numeric = numeric
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_imaginary_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [numeric]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield numeric
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [numeric]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [numeric] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ImaginaryNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?numeric: (FloatNode | IntegerNode | RationalNode)) -> ImaginaryNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, numeric: self.numeric)
      ImaginaryNode.new(source, node_id, location, flags, numeric)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location numeric]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :numeric                 then deconstructed[:numeric] = self.numeric
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :imaginary_node
    def type
      :imaginary_node
    end

    # See `Node.type`.
    #--
    #: () -> :imaginary_node
    def self.type
      :imaginary_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   numeric -> FloatNode | IntegerNode | RationalNode
    #
    # Returns the `numeric` attribute.
    #--
    #: () -> (FloatNode | IntegerNode | RationalNode)
    def numeric
      @numeric
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ImaginaryNode) &&
        (numeric === other.numeric)
    end
  end

  # Represents a node that is implicitly being added to the tree but doesn't correspond directly to a node in the source.
  #
  #     { foo: }
  #       ^^^^
  #
  #     { Foo: }
  #       ^^^^
  #
  #     foo in { bar: }
  #              ^^^^
  class ImplicitNode < Node
    # @rbs @value: (LocalVariableReadNode | CallNode | ConstantReadNode | LocalVariableTargetNode)

    # Initialize a new ImplicitNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (LocalVariableReadNode | CallNode | ConstantReadNode | LocalVariableTargetNode) value) -> void
    def initialize(source, node_id, location, flags, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_implicit_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ImplicitNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: (LocalVariableReadNode | CallNode | ConstantReadNode | LocalVariableTargetNode)) -> ImplicitNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value)
      ImplicitNode.new(source, node_id, location, flags, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :implicit_node
    def type
      :implicit_node
    end

    # See `Node.type`.
    #--
    #: () -> :implicit_node
    def self.type
      :implicit_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   value -> LocalVariableReadNode | CallNode | ConstantReadNode | LocalVariableTargetNode
    #
    # Returns the `value` attribute.
    #--
    #: () -> (LocalVariableReadNode | CallNode | ConstantReadNode | LocalVariableTargetNode)
    def value
      @value
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ImplicitNode) &&
        (value === other.value)
    end
  end

  # Represents using a trailing comma to indicate an implicit rest parameter.
  #
  #     foo { |bar,| }
  #               ^
  #
  #     foo in [bar,]
  #                ^
  #
  #     for foo, in bar do end
  #            ^
  #
  #     foo, = bar
  #        ^
  class ImplicitRestNode < Node

    # Initialize a new ImplicitRestNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_implicit_rest_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ImplicitRestNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> ImplicitRestNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      ImplicitRestNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :implicit_rest_node
    def type
      :implicit_rest_node
    end

    # See `Node.type`.
    #--
    #: () -> :implicit_rest_node
    def self.type
      :implicit_rest_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ImplicitRestNode)
    end
  end

  # Represents the use of the `in` keyword in a case statement.
  #
  #     case a; in b then c end
  #             ^^^^^^^^^^^
  class InNode < Node
    # @rbs @pattern: Prism::node
    # @rbs @statements: StatementsNode?
    # @rbs @in_keyword_loc: Location
    # @rbs @then_keyword_loc: Location?

    # Initialize a new InNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node pattern, StatementsNode? statements, Location in_keyword_loc, Location? then_keyword_loc) -> void
    def initialize(source, node_id, location, flags, pattern, statements, in_keyword_loc, then_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @pattern = pattern
      @statements = statements
      @in_keyword_loc = in_keyword_loc
      @then_keyword_loc = then_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_in_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [pattern, statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield pattern
      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << pattern
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [pattern, *statements, in_keyword_loc, *then_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?pattern: Prism::node, ?statements: StatementsNode?, ?in_keyword_loc: Location, ?then_keyword_loc: Location?) -> InNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, pattern: self.pattern, statements: self.statements, in_keyword_loc: self.in_keyword_loc, then_keyword_loc: self.then_keyword_loc)
      InNode.new(source, node_id, location, flags, pattern, statements, in_keyword_loc, then_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location pattern statements in_keyword_loc then_keyword_loc in_keyword then_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :pattern                 then deconstructed[:pattern] = self.pattern
        when :statements              then deconstructed[:statements] = self.statements
        when :in_keyword_loc          then deconstructed[:in_keyword_loc] = self.in_keyword_loc
        when :then_keyword_loc        then deconstructed[:then_keyword_loc] = self.then_keyword_loc
        when :in_keyword              then deconstructed[:in_keyword] = self.in_keyword
        when :then_keyword            then deconstructed[:then_keyword] = self.then_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :in_node
    def type
      :in_node
    end

    # See `Node.type`.
    #--
    #: () -> :in_node
    def self.type
      :in_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   pattern -> Node
    #
    # Returns the `pattern` attribute.
    #--
    #: () -> Prism::node
    def pattern
      @pattern
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   in_keyword_loc -> Location
    #
    # Returns the Location represented by `in_keyword_loc`.
    #--
    #: () -> Location
    def in_keyword_loc
      location = @in_keyword_loc
      return location if location.is_a?(Location)
      @in_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the in_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_in_keyword_loc(repository)
      repository.enter(node_id, :in_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   then_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `then_keyword_loc`.
    #--
    #: () -> Location?
    def then_keyword_loc
      location = @then_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @then_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the then_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_then_keyword_loc(repository)
      repository.enter(node_id, :then_keyword_loc) unless @then_keyword_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   in_keyword -> String
    #
    # Slice the location of in_keyword_loc from the source.
    #--
    #: () -> String
    def in_keyword
      in_keyword_loc.slice
    end

    # :call-seq:
    #   then_keyword -> String | nil
    #
    # Slice the location of then_keyword_loc from the source.
    #--
    #: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InNode) &&
        (pattern === other.pattern) &&
        (statements === other.statements) &&
        (in_keyword_loc.nil? == other.in_keyword_loc.nil?) &&
        (then_keyword_loc.nil? == other.then_keyword_loc.nil?)
    end
  end

  # Represents the use of the `&&=` operator on a call to the `[]` method.
  #
  #     foo.bar[baz] &&= value
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class IndexAndWriteNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @opening_loc: Location
    # @rbs @arguments: ArgumentsNode?
    # @rbs @closing_loc: Location
    # @rbs @block: BlockArgumentNode?
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new IndexAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Location opening_loc, ArgumentsNode? arguments, Location closing_loc, BlockArgumentNode? block, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @block = block
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_index_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, arguments, block, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      if (arguments = self.arguments); yield arguments; end
      if (block = self.block); yield block; end
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      if (arguments = self.arguments); compact << arguments; end
      if (block = self.block); compact << block; end
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> IndexAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?opening_loc: Location, ?arguments: ArgumentsNode?, ?closing_loc: Location, ?block: BlockArgumentNode?, ?operator_loc: Location, ?value: Prism::node) -> IndexAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, opening_loc: self.opening_loc, arguments: self.arguments, closing_loc: self.closing_loc, block: self.block, operator_loc: self.operator_loc, value: self.value)
      IndexAndWriteNode.new(source, node_id, location, flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc opening_loc arguments closing_loc block operator_loc value call_operator opening closing operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :block                   then deconstructed[:block] = self.block
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :index_and_write_node
    def type
      :index_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :index_and_write_node
    def self.type
      :index_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # Returns the `receiver` attribute.
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Returns the Location represented by `call_operator_loc`.
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   block -> BlockArgumentNode | nil
    #
    # Returns the `block` attribute.
    #--
    #: () -> BlockArgumentNode?
    def block
      @block
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(IndexAndWriteNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (arguments === other.arguments) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (block === other.block) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents the use of an assignment operator on a call to `[]`.
  #
  #     foo.bar[baz] += value
  #     ^^^^^^^^^^^^^^^^^^^^^
  class IndexOperatorWriteNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @opening_loc: Location
    # @rbs @arguments: ArgumentsNode?
    # @rbs @closing_loc: Location
    # @rbs @block: BlockArgumentNode?
    # @rbs @binary_operator: Symbol
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new IndexOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Location opening_loc, ArgumentsNode? arguments, Location closing_loc, BlockArgumentNode? block, Symbol binary_operator, Location binary_operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, binary_operator, binary_operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @block = block
      @binary_operator = binary_operator
      @binary_operator_loc = binary_operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_index_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, arguments, block, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      if (arguments = self.arguments); yield arguments; end
      if (block = self.block); yield block; end
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      if (arguments = self.arguments); compact << arguments; end
      if (block = self.block); compact << block; end
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> IndexOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?opening_loc: Location, ?arguments: ArgumentsNode?, ?closing_loc: Location, ?block: BlockArgumentNode?, ?binary_operator: Symbol, ?binary_operator_loc: Location, ?value: Prism::node) -> IndexOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, opening_loc: self.opening_loc, arguments: self.arguments, closing_loc: self.closing_loc, block: self.block, binary_operator: self.binary_operator, binary_operator_loc: self.binary_operator_loc, value: self.value)
      IndexOperatorWriteNode.new(source, node_id, location, flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, binary_operator, binary_operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc opening_loc arguments closing_loc block binary_operator binary_operator_loc value call_operator opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :block                   then deconstructed[:block] = self.block
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :index_operator_write_node
    def type
      :index_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :index_operator_write_node
    def self.type
      :index_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # Returns the `receiver` attribute.
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Returns the Location represented by `call_operator_loc`.
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   block -> BlockArgumentNode | nil
    #
    # Returns the `block` attribute.
    #--
    #: () -> BlockArgumentNode?
    def block
      @block
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(IndexOperatorWriteNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (arguments === other.arguments) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (block === other.block) &&
        (binary_operator === other.binary_operator) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents the use of the `||=` operator on a call to `[]`.
  #
  #     foo.bar[baz] ||= value
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class IndexOrWriteNode < Node
    # @rbs @receiver: Prism::node?
    # @rbs @call_operator_loc: Location?
    # @rbs @opening_loc: Location
    # @rbs @arguments: ArgumentsNode?
    # @rbs @closing_loc: Location
    # @rbs @block: BlockArgumentNode?
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new IndexOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? receiver, Location? call_operator_loc, Location opening_loc, ArgumentsNode? arguments, Location closing_loc, BlockArgumentNode? block, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @block = block
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_index_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, arguments, block, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (receiver = self.receiver); yield receiver; end
      if (arguments = self.arguments); yield arguments; end
      if (block = self.block); yield block; end
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (receiver = self.receiver); compact << receiver; end
      if (arguments = self.arguments); compact << arguments; end
      if (block = self.block); compact << block; end
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> IndexOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node?, ?call_operator_loc: Location?, ?opening_loc: Location, ?arguments: ArgumentsNode?, ?closing_loc: Location, ?block: BlockArgumentNode?, ?operator_loc: Location, ?value: Prism::node) -> IndexOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, call_operator_loc: self.call_operator_loc, opening_loc: self.opening_loc, arguments: self.arguments, closing_loc: self.closing_loc, block: self.block, operator_loc: self.operator_loc, value: self.value)
      IndexOrWriteNode.new(source, node_id, location, flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver call_operator_loc opening_loc arguments closing_loc block operator_loc value call_operator opening closing operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :call_operator_loc       then deconstructed[:call_operator_loc] = self.call_operator_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :block                   then deconstructed[:block] = self.block
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :call_operator           then deconstructed[:call_operator] = self.call_operator
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :index_or_write_node
    def type
      :index_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :index_or_write_node
    def self.type
      :index_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node | nil
    #
    # Returns the `receiver` attribute.
    #--
    #: () -> Prism::node?
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   call_operator_loc -> Location | nil
    #
    # Returns the Location represented by `call_operator_loc`.
    #--
    #: () -> Location?
    def call_operator_loc
      location = @call_operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @call_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the call_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_call_operator_loc(repository)
      repository.enter(node_id, :call_operator_loc) unless @call_operator_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   block -> BlockArgumentNode | nil
    #
    # Returns the `block` attribute.
    #--
    #: () -> BlockArgumentNode?
    def block
      @block
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   call_operator -> String | nil
    #
    # Slice the location of call_operator_loc from the source.
    #--
    #: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(IndexOrWriteNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (call_operator_loc.nil? == other.call_operator_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (arguments === other.arguments) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (block === other.block) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents assigning to an index.
  #
  #     foo[bar], = 1
  #     ^^^^^^^^
  #
  #     begin
  #     rescue => foo[bar]
  #               ^^^^^^^^
  #     end
  #
  #     for foo[bar] in baz do end
  #         ^^^^^^^^
  class IndexTargetNode < Node
    # @rbs @receiver: Prism::node
    # @rbs @opening_loc: Location
    # @rbs @arguments: ArgumentsNode?
    # @rbs @closing_loc: Location
    # @rbs @block: BlockArgumentNode?

    # Initialize a new IndexTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node receiver, Location opening_loc, ArgumentsNode? arguments, Location closing_loc, BlockArgumentNode? block) -> void
    def initialize(source, node_id, location, flags, receiver, opening_loc, arguments, closing_loc, block)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @receiver = receiver
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @block = block
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_index_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [receiver, arguments, block]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield receiver
      if (arguments = self.arguments); yield arguments; end
      if (block = self.block); yield block; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << receiver
      if (arguments = self.arguments); compact << arguments; end
      if (block = self.block); compact << block; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [receiver, opening_loc, *arguments, closing_loc, *block] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> IndexTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?receiver: Prism::node, ?opening_loc: Location, ?arguments: ArgumentsNode?, ?closing_loc: Location, ?block: BlockArgumentNode?) -> IndexTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, receiver: self.receiver, opening_loc: self.opening_loc, arguments: self.arguments, closing_loc: self.closing_loc, block: self.block)
      IndexTargetNode.new(source, node_id, location, flags, receiver, opening_loc, arguments, closing_loc, block)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location receiver opening_loc arguments closing_loc block opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :receiver                then deconstructed[:receiver] = self.receiver
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :block                   then deconstructed[:block] = self.block
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :index_target_node
    def type
      :index_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :index_target_node
    def self.type
      :index_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # &. operator
    #--
    #: () -> bool
    def safe_navigation?
      flags.anybits?(CallNodeFlags::SAFE_NAVIGATION)
    end

    # :category: Flags
    # a call that could have been a local variable
    #--
    #: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # :category: Flags
    # a call that is an attribute write, so the value being written should be returned
    #--
    #: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # :category: Flags
    # a call that ignores method visibility
    #--
    #: () -> bool
    def ignore_visibility?
      flags.anybits?(CallNodeFlags::IGNORE_VISIBILITY)
    end

    # :call-seq:
    #   receiver -> Node
    #
    # Returns the `receiver` attribute.
    #--
    #: () -> Prism::node
    def receiver
      @receiver
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   block -> BlockArgumentNode | nil
    #
    # Returns the `block` attribute.
    #--
    #: () -> BlockArgumentNode?
    def block
      @block
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(IndexTargetNode) &&
        (flags === other.flags) &&
        (receiver === other.receiver) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (arguments === other.arguments) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (block === other.block)
    end
  end

  # Represents the use of the `&&=` operator for assignment to an instance variable.
  #
  #     @target &&= value
  #     ^^^^^^^^^^^^^^^^^
  class InstanceVariableAndWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new InstanceVariableAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_instance_variable_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InstanceVariableAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> InstanceVariableAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      InstanceVariableAndWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :instance_variable_and_write_node
    def type
      :instance_variable_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :instance_variable_and_write_node
    def self.type
      :instance_variable_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InstanceVariableAndWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents assigning to an instance variable using an operator that isn't `=`.
  #
  #     @target += value
  #     ^^^^^^^^^^^^^^^^
  class InstanceVariableOperatorWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @binary_operator: Symbol

    # Initialize a new InstanceVariableOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location binary_operator_loc, Prism::node value, Symbol binary_operator) -> void
    def initialize(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @binary_operator_loc = binary_operator_loc
      @value = value
      @binary_operator = binary_operator
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_instance_variable_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InstanceVariableOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?binary_operator_loc: Location, ?value: Prism::node, ?binary_operator: Symbol) -> InstanceVariableOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, binary_operator_loc: self.binary_operator_loc, value: self.value, binary_operator: self.binary_operator)
      InstanceVariableOperatorWriteNode.new(source, node_id, location, flags, name, name_loc, binary_operator_loc, value, binary_operator)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc binary_operator_loc value binary_operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :instance_variable_operator_write_node
    def type
      :instance_variable_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :instance_variable_operator_write_node
    def self.type
      :instance_variable_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InstanceVariableOperatorWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value) &&
        (binary_operator === other.binary_operator)
    end
  end

  # Represents the use of the `||=` operator for assignment to an instance variable.
  #
  #     @target ||= value
  #     ^^^^^^^^^^^^^^^^^
  class InstanceVariableOrWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new InstanceVariableOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_instance_variable_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InstanceVariableOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> InstanceVariableOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      InstanceVariableOrWriteNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :instance_variable_or_write_node
    def type
      :instance_variable_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :instance_variable_or_write_node
    def self.type
      :instance_variable_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InstanceVariableOrWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents referencing an instance variable.
  #
  #     @foo
  #     ^^^^
  class InstanceVariableReadNode < Node
    # @rbs @name: Symbol

    # Initialize a new InstanceVariableReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_instance_variable_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InstanceVariableReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> InstanceVariableReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      InstanceVariableReadNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :instance_variable_read_node
    def type
      :instance_variable_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :instance_variable_read_node
    def self.type
      :instance_variable_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the instance variable, which is a `@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     @x     # name `:@x`
    #
    #     @_test # name `:@_test`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InstanceVariableReadNode) &&
        (name === other.name)
    end
  end

  # Represents writing to an instance variable in a context that doesn't have an explicit value.
  #
  #     @foo, @bar = baz
  #     ^^^^  ^^^^
  class InstanceVariableTargetNode < Node
    # @rbs @name: Symbol

    # Initialize a new InstanceVariableTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_instance_variable_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InstanceVariableTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> InstanceVariableTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      InstanceVariableTargetNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :instance_variable_target_node
    def type
      :instance_variable_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :instance_variable_target_node
    def self.type
      :instance_variable_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InstanceVariableTargetNode) &&
        (name === other.name)
    end
  end

  # Represents writing to an instance variable.
  #
  #     @foo = 1
  #     ^^^^^^^^
  class InstanceVariableWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @value: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new InstanceVariableWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Prism::node value, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_instance_variable_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, value, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InstanceVariableWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?value: Prism::node, ?operator_loc: Location) -> InstanceVariableWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, value: self.value, operator_loc: self.operator_loc)
      InstanceVariableWriteNode.new(source, node_id, location, flags, name, name_loc, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :instance_variable_write_node
    def type
      :instance_variable_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :instance_variable_write_node
    def self.type
      :instance_variable_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the instance variable, which is a `@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     @x = :y       # name `:@x`
    #
    #     @_foo = "bar" # name `@_foo`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # The Location of the variable name.
    #
    #     @_x = 1
    #     ^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the instance variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     @foo = :bar
    #            ^^^^
    #
    #     @_x = 1234
    #           ^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `=` operator.
    #
    #     @x = y
    #        ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InstanceVariableWriteNode) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents an integer number literal.
  #
  #     1
  #     ^
  class IntegerNode < Node
    # @rbs @value: Integer

    # Initialize a new IntegerNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Integer value) -> void
    def initialize(source, node_id, location, flags, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_integer_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> IntegerNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: Integer) -> IntegerNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value)
      IntegerNode.new(source, node_id, location, flags, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :integer_node
    def type
      :integer_node
    end

    # See `Node.type`.
    #--
    #: () -> :integer_node
    def self.type
      :integer_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # 0b prefix
    #--
    #: () -> bool
    def binary?
      flags.anybits?(IntegerBaseFlags::BINARY)
    end

    # :category: Flags
    # 0d or no prefix
    #--
    #: () -> bool
    def decimal?
      flags.anybits?(IntegerBaseFlags::DECIMAL)
    end

    # :category: Flags
    # 0o or 0 prefix
    #--
    #: () -> bool
    def octal?
      flags.anybits?(IntegerBaseFlags::OCTAL)
    end

    # :category: Flags
    # 0x prefix
    #--
    #: () -> bool
    def hexadecimal?
      flags.anybits?(IntegerBaseFlags::HEXADECIMAL)
    end

    # :call-seq:
    #   value -> Integer
    #
    # The value of the integer literal as a number.
    #--
    #: () -> Integer
    def value
      @value
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(IntegerNode) &&
        (flags === other.flags) &&
        (value === other.value)
    end
  end

  # Represents a regular expression literal that contains interpolation that is being used in the predicate of a conditional to implicitly match against the last line read by an IO object.
  #
  #     if /foo #{bar} baz/ then end
  #        ^^^^^^^^^^^^^^^^
  class InterpolatedMatchLastLineNode < Node
    # @rbs @opening_loc: Location
    # @rbs @parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    # @rbs @closing_loc: Location

    # Initialize a new InterpolatedMatchLastLineNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode] parts, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, parts, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_interpolated_match_last_line_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*parts]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      parts.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*parts]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, *parts, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InterpolatedMatchLastLineNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode], ?closing_loc: Location) -> InterpolatedMatchLastLineNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, parts: self.parts, closing_loc: self.closing_loc)
      InterpolatedMatchLastLineNode.new(source, node_id, location, flags, opening_loc, parts, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc parts closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :parts                   then deconstructed[:parts] = self.parts
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :interpolated_match_last_line_node
    def type
      :interpolated_match_last_line_node
    end

    # See `Node.type`.
    #--
    #: () -> :interpolated_match_last_line_node
    def self.type
      :interpolated_match_last_line_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # i - ignores the case of characters when matching
    #--
    #: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # :category: Flags
    # x - ignores whitespace and allows comments in regular expressions
    #--
    #: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # :category: Flags
    # m - allows $ to match the end of lines within strings
    #--
    #: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # :category: Flags
    # o - only interpolates values into the regular expression once
    #--
    #: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # :category: Flags
    # e - forces the EUC-JP encoding
    #--
    #: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # :category: Flags
    # n - forces the ASCII-8BIT encoding
    #--
    #: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # :category: Flags
    # s - forces the Windows-31J encoding
    #--
    #: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # :category: Flags
    # u - forces the UTF-8 encoding
    #--
    #: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to US-ASCII
    #--
    #: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   parts -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    #
    # Returns the `parts` attribute.
    #--
    #: () -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    def parts
      @parts
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InterpolatedMatchLastLineNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (parts.length == other.parts.length) &&
        parts.zip(other.parts).all? { |left, right| left === right } &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents a regular expression literal that contains interpolation.
  #
  #     /foo #{bar} baz/
  #     ^^^^^^^^^^^^^^^^
  class InterpolatedRegularExpressionNode < Node
    # @rbs @opening_loc: Location
    # @rbs @parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    # @rbs @closing_loc: Location

    # Initialize a new InterpolatedRegularExpressionNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode] parts, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, parts, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_interpolated_regular_expression_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*parts]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      parts.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*parts]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, *parts, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InterpolatedRegularExpressionNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode], ?closing_loc: Location) -> InterpolatedRegularExpressionNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, parts: self.parts, closing_loc: self.closing_loc)
      InterpolatedRegularExpressionNode.new(source, node_id, location, flags, opening_loc, parts, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc parts closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :parts                   then deconstructed[:parts] = self.parts
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :interpolated_regular_expression_node
    def type
      :interpolated_regular_expression_node
    end

    # See `Node.type`.
    #--
    #: () -> :interpolated_regular_expression_node
    def self.type
      :interpolated_regular_expression_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # i - ignores the case of characters when matching
    #--
    #: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # :category: Flags
    # x - ignores whitespace and allows comments in regular expressions
    #--
    #: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # :category: Flags
    # m - allows $ to match the end of lines within strings
    #--
    #: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # :category: Flags
    # o - only interpolates values into the regular expression once
    #--
    #: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # :category: Flags
    # e - forces the EUC-JP encoding
    #--
    #: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # :category: Flags
    # n - forces the ASCII-8BIT encoding
    #--
    #: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # :category: Flags
    # s - forces the Windows-31J encoding
    #--
    #: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # :category: Flags
    # u - forces the UTF-8 encoding
    #--
    #: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to US-ASCII
    #--
    #: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   parts -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    #
    # Returns the `parts` attribute.
    #--
    #: () -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    def parts
      @parts
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InterpolatedRegularExpressionNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (parts.length == other.parts.length) &&
        parts.zip(other.parts).all? { |left, right| left === right } &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents a string literal that contains interpolation.
  #
  #     "foo #{bar} baz"
  #     ^^^^^^^^^^^^^^^^
  class InterpolatedStringNode < Node
    # @rbs @opening_loc: Location?
    # @rbs @parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode | InterpolatedStringNode]
    # @rbs @closing_loc: Location?

    # Initialize a new InterpolatedStringNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? opening_loc, Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode | InterpolatedStringNode] parts, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, parts, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_interpolated_string_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*parts]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      parts.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*parts]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*opening_loc, *parts, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InterpolatedStringNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode | InterpolatedStringNode], ?closing_loc: Location?) -> InterpolatedStringNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, parts: self.parts, closing_loc: self.closing_loc)
      InterpolatedStringNode.new(source, node_id, location, flags, opening_loc, parts, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc parts closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :parts                   then deconstructed[:parts] = self.parts
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :interpolated_string_node
    def type
      :interpolated_string_node
    end

    # See `Node.type`.
    #--
    #: () -> :interpolated_string_node
    def self.type
      :interpolated_string_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'`
    #--
    #: () -> bool
    def frozen?
      flags.anybits?(InterpolatedStringNodeFlags::FROZEN)
    end

    # :category: Flags
    # mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'`
    #--
    #: () -> bool
    def mutable?
      flags.anybits?(InterpolatedStringNodeFlags::MUTABLE)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :call-seq:
    #   parts -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode | InterpolatedStringNode]
    #
    # Returns the `parts` attribute.
    #--
    #: () -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode | InterpolatedStringNode]
    def parts
      @parts
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InterpolatedStringNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (parts.length == other.parts.length) &&
        parts.zip(other.parts).all? { |left, right| left === right } &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents a symbol literal that contains interpolation.
  #
  #     :"foo #{bar} baz"
  #     ^^^^^^^^^^^^^^^^^
  class InterpolatedSymbolNode < Node
    # @rbs @opening_loc: Location?
    # @rbs @parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    # @rbs @closing_loc: Location?

    # Initialize a new InterpolatedSymbolNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? opening_loc, Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode] parts, Location? closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, parts, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_interpolated_symbol_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*parts]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      parts.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*parts]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*opening_loc, *parts, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InterpolatedSymbolNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode], ?closing_loc: Location?) -> InterpolatedSymbolNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, parts: self.parts, closing_loc: self.closing_loc)
      InterpolatedSymbolNode.new(source, node_id, location, flags, opening_loc, parts, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc parts closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :parts                   then deconstructed[:parts] = self.parts
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :interpolated_symbol_node
    def type
      :interpolated_symbol_node
    end

    # See `Node.type`.
    #--
    #: () -> :interpolated_symbol_node
    def self.type
      :interpolated_symbol_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :call-seq:
    #   parts -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    #
    # Returns the `parts` attribute.
    #--
    #: () -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    def parts
      @parts
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InterpolatedSymbolNode) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (parts.length == other.parts.length) &&
        parts.zip(other.parts).all? { |left, right| left === right } &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents an xstring literal that contains interpolation.
  #
  #     `foo #{bar} baz`
  #     ^^^^^^^^^^^^^^^^
  class InterpolatedXStringNode < Node
    # @rbs @opening_loc: Location
    # @rbs @parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    # @rbs @closing_loc: Location

    # Initialize a new InterpolatedXStringNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode] parts, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, opening_loc, parts, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_interpolated_x_string_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*parts]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      parts.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*parts]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, *parts, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> InterpolatedXStringNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?parts: Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode], ?closing_loc: Location) -> InterpolatedXStringNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, parts: self.parts, closing_loc: self.closing_loc)
      InterpolatedXStringNode.new(source, node_id, location, flags, opening_loc, parts, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc parts closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :parts                   then deconstructed[:parts] = self.parts
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :interpolated_x_string_node
    def type
      :interpolated_x_string_node
    end

    # See `Node.type`.
    #--
    #: () -> :interpolated_x_string_node
    def self.type
      :interpolated_x_string_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :call-seq:
    #   parts -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    #
    # Returns the `parts` attribute.
    #--
    #: () -> Array[StringNode | EmbeddedStatementsNode | EmbeddedVariableNode]
    def parts
      @parts
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(InterpolatedXStringNode) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (parts.length == other.parts.length) &&
        parts.zip(other.parts).all? { |left, right| left === right } &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents reading from the implicit `it` local variable.
  #
  #     -> { it }
  #          ^^
  class ItLocalVariableReadNode < Node

    # Initialize a new ItLocalVariableReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_it_local_variable_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ItLocalVariableReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> ItLocalVariableReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      ItLocalVariableReadNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :it_local_variable_read_node
    def type
      :it_local_variable_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :it_local_variable_read_node
    def self.type
      :it_local_variable_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ItLocalVariableReadNode)
    end
  end

  # Represents an implicit set of parameters through the use of the `it` keyword within a block or lambda.
  #
  #     -> { it + it }
  #     ^^^^^^^^^^^^^^
  class ItParametersNode < Node

    # Initialize a new ItParametersNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_it_parameters_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ItParametersNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> ItParametersNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      ItParametersNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :it_parameters_node
    def type
      :it_parameters_node
    end

    # See `Node.type`.
    #--
    #: () -> :it_parameters_node
    def self.type
      :it_parameters_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ItParametersNode)
    end
  end

  # Represents a hash literal without opening and closing braces.
  #
  #     foo(a: b)
  #         ^^^^
  class KeywordHashNode < Node
    # @rbs @elements: Array[AssocNode | AssocSplatNode]

    # Initialize a new KeywordHashNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[AssocNode | AssocSplatNode] elements) -> void
    def initialize(source, node_id, location, flags, elements)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @elements = elements
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_keyword_hash_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*elements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      elements.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*elements]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*elements] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> KeywordHashNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?elements: Array[AssocNode | AssocSplatNode]) -> KeywordHashNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, elements: self.elements)
      KeywordHashNode.new(source, node_id, location, flags, elements)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location elements]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :elements                then deconstructed[:elements] = self.elements
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :keyword_hash_node
    def type
      :keyword_hash_node
    end

    # See `Node.type`.
    #--
    #: () -> :keyword_hash_node
    def self.type
      :keyword_hash_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments
    #--
    #: () -> bool
    def symbol_keys?
      flags.anybits?(KeywordHashNodeFlags::SYMBOL_KEYS)
    end

    # :call-seq:
    #   elements -> Array[AssocNode | AssocSplatNode]
    #
    # Returns the `elements` attribute.
    #--
    #: () -> Array[AssocNode | AssocSplatNode]
    def elements
      @elements
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(KeywordHashNode) &&
        (flags === other.flags) &&
        (elements.length == other.elements.length) &&
        elements.zip(other.elements).all? { |left, right| left === right }
    end
  end

  # Represents a keyword rest parameter to a method, block, or lambda definition.
  #
  #     def a(**b)
  #           ^^^
  #     end
  class KeywordRestParameterNode < Node
    # @rbs @name: Symbol?
    # @rbs @name_loc: Location?
    # @rbs @operator_loc: Location

    # Initialize a new KeywordRestParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol? name, Location? name_loc, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_keyword_rest_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*name_loc, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> KeywordRestParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol?, ?name_loc: Location?, ?operator_loc: Location) -> KeywordRestParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc)
      KeywordRestParameterNode.new(source, node_id, location, flags, name, name_loc, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :keyword_rest_parameter_node
    def type
      :keyword_rest_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :keyword_rest_parameter_node
    def self.type
      :keyword_rest_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol | nil
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol?
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location | nil
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location?
    def name_loc
      location = @name_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc) unless @name_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(KeywordRestParameterNode) &&
        (flags === other.flags) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents using a lambda literal (not the lambda method call).
  #
  #     ->(value) { value * 2 }
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class LambdaNode < Node
    # @rbs @locals: Array[Symbol]
    # @rbs @operator_loc: Location
    # @rbs @opening_loc: Location
    # @rbs @closing_loc: Location
    # @rbs @parameters: (BlockParametersNode | NumberedParametersNode | ItParametersNode)?
    # @rbs @body: (StatementsNode | BeginNode)?

    # Initialize a new LambdaNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Symbol] locals, Location operator_loc, Location opening_loc, Location closing_loc, (BlockParametersNode | NumberedParametersNode | ItParametersNode)? parameters, (StatementsNode | BeginNode)? body) -> void
    def initialize(source, node_id, location, flags, locals, operator_loc, opening_loc, closing_loc, parameters, body)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @locals = locals
      @operator_loc = operator_loc
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @parameters = parameters
      @body = body
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_lambda_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [parameters, body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (parameters = self.parameters); yield parameters; end
      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (parameters = self.parameters); compact << parameters; end
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [operator_loc, opening_loc, closing_loc, *parameters, *body] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LambdaNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?locals: Array[Symbol], ?operator_loc: Location, ?opening_loc: Location, ?closing_loc: Location, ?parameters: (BlockParametersNode | NumberedParametersNode | ItParametersNode)?, ?body: (StatementsNode | BeginNode)?) -> LambdaNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, locals: self.locals, operator_loc: self.operator_loc, opening_loc: self.opening_loc, closing_loc: self.closing_loc, parameters: self.parameters, body: self.body)
      LambdaNode.new(source, node_id, location, flags, locals, operator_loc, opening_loc, closing_loc, parameters, body)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location locals operator_loc opening_loc closing_loc parameters body operator opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :locals                  then deconstructed[:locals] = self.locals
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :parameters              then deconstructed[:parameters] = self.parameters
        when :body                    then deconstructed[:body] = self.body
        when :operator                then deconstructed[:operator] = self.operator
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :lambda_node
    def type
      :lambda_node
    end

    # See `Node.type`.
    #--
    #: () -> :lambda_node
    def self.type
      :lambda_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # Returns the `locals` attribute.
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   parameters -> BlockParametersNode | NumberedParametersNode | ItParametersNode | nil
    #
    # Returns the `parameters` attribute.
    #--
    #: () -> (BlockParametersNode | NumberedParametersNode | ItParametersNode)?
    def parameters
      @parameters
    end

    # :call-seq:
    #   body -> StatementsNode | BeginNode | nil
    #
    # Returns the `body` attribute.
    #--
    #: () -> (StatementsNode | BeginNode)?
    def body
      @body
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LambdaNode) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (parameters === other.parameters) &&
        (body === other.body)
    end
  end

  # Represents the use of the `&&=` operator for assignment to a local variable.
  #
  #     target &&= value
  #     ^^^^^^^^^^^^^^^^
  class LocalVariableAndWriteNode < Node
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @name: Symbol
    # @rbs @depth: Integer

    # Initialize a new LocalVariableAndWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location name_loc, Location operator_loc, Prism::node value, Symbol name, Integer depth) -> void
    def initialize(source, node_id, location, flags, name_loc, operator_loc, value, name, depth)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @name = name
      @depth = depth
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_local_variable_and_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LocalVariableAndWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node, ?name: Symbol, ?depth: Integer) -> LocalVariableAndWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value, name: self.name, depth: self.depth)
      LocalVariableAndWriteNode.new(source, node_id, location, flags, name_loc, operator_loc, value, name, depth)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name_loc operator_loc value name depth operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :name                    then deconstructed[:name] = self.name
        when :depth                   then deconstructed[:depth] = self.depth
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :local_variable_and_write_node
    def type
      :local_variable_and_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :local_variable_and_write_node
    def self.type
      :local_variable_and_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :call-seq:
    #   depth -> Integer
    #
    # Returns the `depth` attribute.
    #--
    #: () -> Integer
    def depth
      @depth
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LocalVariableAndWriteNode) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value) &&
        (name === other.name) &&
        (depth === other.depth)
    end
  end

  # Represents assigning to a local variable using an operator that isn't `=`.
  #
  #     target += value
  #     ^^^^^^^^^^^^^^^
  class LocalVariableOperatorWriteNode < Node
    # @rbs @name_loc: Location
    # @rbs @binary_operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @name: Symbol
    # @rbs @binary_operator: Symbol
    # @rbs @depth: Integer

    # Initialize a new LocalVariableOperatorWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location name_loc, Location binary_operator_loc, Prism::node value, Symbol name, Symbol binary_operator, Integer depth) -> void
    def initialize(source, node_id, location, flags, name_loc, binary_operator_loc, value, name, binary_operator, depth)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name_loc = name_loc
      @binary_operator_loc = binary_operator_loc
      @value = value
      @name = name
      @binary_operator = binary_operator
      @depth = depth
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_local_variable_operator_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LocalVariableOperatorWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name_loc: Location, ?binary_operator_loc: Location, ?value: Prism::node, ?name: Symbol, ?binary_operator: Symbol, ?depth: Integer) -> LocalVariableOperatorWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name_loc: self.name_loc, binary_operator_loc: self.binary_operator_loc, value: self.value, name: self.name, binary_operator: self.binary_operator, depth: self.depth)
      LocalVariableOperatorWriteNode.new(source, node_id, location, flags, name_loc, binary_operator_loc, value, name, binary_operator, depth)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name_loc binary_operator_loc value name binary_operator depth]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :binary_operator_loc     then deconstructed[:binary_operator_loc] = self.binary_operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :name                    then deconstructed[:name] = self.name
        when :binary_operator         then deconstructed[:binary_operator] = self.binary_operator
        when :depth                   then deconstructed[:depth] = self.depth
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :local_variable_operator_write_node
    def type
      :local_variable_operator_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :local_variable_operator_write_node
    def self.type
      :local_variable_operator_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   binary_operator_loc -> Location
    #
    # Returns the Location represented by `binary_operator_loc`.
    #--
    #: () -> Location
    def binary_operator_loc
      location = @binary_operator_loc
      return location if location.is_a?(Location)
      @binary_operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the binary_operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_binary_operator_loc(repository)
      repository.enter(node_id, :binary_operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :call-seq:
    #   binary_operator -> Symbol
    #
    # Returns the `binary_operator` attribute.
    #--
    #: () -> Symbol
    def binary_operator
      @binary_operator
    end

    # :call-seq:
    #   depth -> Integer
    #
    # Returns the `depth` attribute.
    #--
    #: () -> Integer
    def depth
      @depth
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LocalVariableOperatorWriteNode) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (binary_operator_loc.nil? == other.binary_operator_loc.nil?) &&
        (value === other.value) &&
        (name === other.name) &&
        (binary_operator === other.binary_operator) &&
        (depth === other.depth)
    end
  end

  # Represents the use of the `||=` operator for assignment to a local variable.
  #
  #     target ||= value
  #     ^^^^^^^^^^^^^^^^
  class LocalVariableOrWriteNode < Node
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node
    # @rbs @name: Symbol
    # @rbs @depth: Integer

    # Initialize a new LocalVariableOrWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location name_loc, Location operator_loc, Prism::node value, Symbol name, Integer depth) -> void
    def initialize(source, node_id, location, flags, name_loc, operator_loc, value, name, depth)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @name = name
      @depth = depth
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_local_variable_or_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LocalVariableOrWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node, ?name: Symbol, ?depth: Integer) -> LocalVariableOrWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value, name: self.name, depth: self.depth)
      LocalVariableOrWriteNode.new(source, node_id, location, flags, name_loc, operator_loc, value, name, depth)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name_loc operator_loc value name depth operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :name                    then deconstructed[:name] = self.name
        when :depth                   then deconstructed[:depth] = self.depth
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :local_variable_or_write_node
    def type
      :local_variable_or_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :local_variable_or_write_node
    def self.type
      :local_variable_or_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :call-seq:
    #   depth -> Integer
    #
    # Returns the `depth` attribute.
    #--
    #: () -> Integer
    def depth
      @depth
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LocalVariableOrWriteNode) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value) &&
        (name === other.name) &&
        (depth === other.depth)
    end
  end

  # Represents reading a local variable. Note that this requires that a local variable of the same name has already been written to in the same scope, otherwise it is parsed as a method call.
  #
  #     foo
  #     ^^^
  class LocalVariableReadNode < Node
    # @rbs @name: Symbol
    # @rbs @depth: Integer

    # Initialize a new LocalVariableReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Integer depth) -> void
    def initialize(source, node_id, location, flags, name, depth)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @depth = depth
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_local_variable_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LocalVariableReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?depth: Integer) -> LocalVariableReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, depth: self.depth)
      LocalVariableReadNode.new(source, node_id, location, flags, name, depth)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name depth]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :depth                   then deconstructed[:depth] = self.depth
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :local_variable_read_node
    def type
      :local_variable_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :local_variable_read_node
    def self.type
      :local_variable_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     x      # name `:x`
    #
    #     _Test  # name `:_Test`
    #
    # Note that this can also be an underscore followed by a number for the default block parameters.
    #
    #     _1     # name `:_1`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :call-seq:
    #   depth -> Integer
    #
    # The number of visible scopes that should be searched to find the origin of this local variable.
    #
    #     foo = 1; foo # depth 0
    #
    #     bar = 2; tap { bar } # depth 1
    #
    # The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md).
    #--
    #: () -> Integer
    def depth
      @depth
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LocalVariableReadNode) &&
        (name === other.name) &&
        (depth === other.depth)
    end
  end

  # Represents writing to a local variable in a context that doesn't have an explicit value.
  #
  #     foo, bar = baz
  #     ^^^  ^^^
  #
  #     foo => baz
  #            ^^^
  class LocalVariableTargetNode < Node
    # @rbs @name: Symbol
    # @rbs @depth: Integer

    # Initialize a new LocalVariableTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Integer depth) -> void
    def initialize(source, node_id, location, flags, name, depth)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @depth = depth
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_local_variable_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LocalVariableTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?depth: Integer) -> LocalVariableTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, depth: self.depth)
      LocalVariableTargetNode.new(source, node_id, location, flags, name, depth)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name depth]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :depth                   then deconstructed[:depth] = self.depth
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :local_variable_target_node
    def type
      :local_variable_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :local_variable_target_node
    def self.type
      :local_variable_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :call-seq:
    #   depth -> Integer
    #
    # Returns the `depth` attribute.
    #--
    #: () -> Integer
    def depth
      @depth
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LocalVariableTargetNode) &&
        (name === other.name) &&
        (depth === other.depth)
    end
  end

  # Represents writing to a local variable.
  #
  #     foo = 1
  #     ^^^^^^^
  class LocalVariableWriteNode < Node
    # @rbs @name: Symbol
    # @rbs @depth: Integer
    # @rbs @name_loc: Location
    # @rbs @value: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new LocalVariableWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Integer depth, Location name_loc, Prism::node value, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, depth, name_loc, value, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @depth = depth
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_local_variable_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, value, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> LocalVariableWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?depth: Integer, ?name_loc: Location, ?value: Prism::node, ?operator_loc: Location) -> LocalVariableWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, depth: self.depth, name_loc: self.name_loc, value: self.value, operator_loc: self.operator_loc)
      LocalVariableWriteNode.new(source, node_id, location, flags, name, depth, name_loc, value, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name depth name_loc value operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :depth                   then deconstructed[:depth] = self.depth
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :local_variable_write_node
    def type
      :local_variable_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :local_variable_write_node
    def self.type
      :local_variable_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   name -> Symbol
    #
    # The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
    #
    #     foo = :bar # name `:foo`
    #
    #     abc = 123  # name `:abc`
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :call-seq:
    #   depth -> Integer
    #
    # The number of semantic scopes we have to traverse to find the declaration of this variable.
    #
    #     foo = 1         # depth 0
    #
    #     tap { foo = 1 } # depth 1
    #
    # The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md).
    #--
    #: () -> Integer
    def depth
      @depth
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # The Location of the variable name.
    #
    #     foo = :bar
    #     ^^^
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the local variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     foo = :bar
    #           ^^^^
    #
    #     abc = 1234
    #           ^^^^
    #
    # Note that since the name of a local variable is known before the value is parsed, it is valid for a local variable to appear within the value of its own write.
    #
    #     foo = foo
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `=` operator.
    #
    #     x = :y
    #       ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(LocalVariableWriteNode) &&
        (name === other.name) &&
        (depth === other.depth) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (value === other.value) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a regular expression literal used in the predicate of a conditional to implicitly match against the last line read by an IO object.
  #
  #     if /foo/i then end
  #        ^^^^^^
  class MatchLastLineNode < Node
    # @rbs @opening_loc: Location
    # @rbs @content_loc: Location
    # @rbs @closing_loc: Location
    # @rbs @unescaped: String

    # Initialize a new MatchLastLineNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Location content_loc, Location closing_loc, String unescaped) -> void
    def initialize(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_match_last_line_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, content_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> MatchLastLineNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?content_loc: Location, ?closing_loc: Location, ?unescaped: String) -> MatchLastLineNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, content_loc: self.content_loc, closing_loc: self.closing_loc, unescaped: self.unescaped)
      MatchLastLineNode.new(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc content_loc closing_loc unescaped opening content closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :content_loc             then deconstructed[:content_loc] = self.content_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :unescaped               then deconstructed[:unescaped] = self.unescaped
        when :opening                 then deconstructed[:opening] = self.opening
        when :content                 then deconstructed[:content] = self.content
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :match_last_line_node
    def type
      :match_last_line_node
    end

    # See `Node.type`.
    #--
    #: () -> :match_last_line_node
    def self.type
      :match_last_line_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # i - ignores the case of characters when matching
    #--
    #: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # :category: Flags
    # x - ignores whitespace and allows comments in regular expressions
    #--
    #: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # :category: Flags
    # m - allows $ to match the end of lines within strings
    #--
    #: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # :category: Flags
    # o - only interpolates values into the regular expression once
    #--
    #: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # :category: Flags
    # e - forces the EUC-JP encoding
    #--
    #: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # :category: Flags
    # n - forces the ASCII-8BIT encoding
    #--
    #: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # :category: Flags
    # s - forces the Windows-31J encoding
    #--
    #: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # :category: Flags
    # u - forces the UTF-8 encoding
    #--
    #: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to US-ASCII
    #--
    #: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   content_loc -> Location
    #
    # Returns the Location represented by `content_loc`.
    #--
    #: () -> Location
    def content_loc
      location = @content_loc
      return location if location.is_a?(Location)
      @content_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the content_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_content_loc(repository)
      repository.enter(node_id, :content_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   unescaped -> String
    #
    # Returns the `unescaped` attribute.
    #--
    #: () -> String
    def unescaped
      @unescaped
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   content -> String
    #
    # Slice the location of content_loc from the source.
    #--
    #: () -> String
    def content
      content_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(MatchLastLineNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (content_loc.nil? == other.content_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (unescaped === other.unescaped)
    end
  end

  # Represents the use of the modifier `in` operator.
  #
  #     foo in bar
  #     ^^^^^^^^^^
  class MatchPredicateNode < Node
    # @rbs @value: Prism::node
    # @rbs @pattern: Prism::node
    # @rbs @keyword_loc: Location

    # Initialize a new MatchPredicateNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node value, Prism::node pattern, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, value, pattern, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
      @pattern = pattern
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_match_predicate_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value, pattern]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
      yield pattern
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value, pattern]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [value, pattern, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> MatchPredicateNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: Prism::node, ?pattern: Prism::node, ?keyword_loc: Location) -> MatchPredicateNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value, pattern: self.pattern, keyword_loc: self.keyword_loc)
      MatchPredicateNode.new(source, node_id, location, flags, value, pattern, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value pattern keyword_loc keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        when :pattern                 then deconstructed[:pattern] = self.pattern
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :match_predicate_node
    def type
      :match_predicate_node
    end

    # See `Node.type`.
    #--
    #: () -> :match_predicate_node
    def self.type
      :match_predicate_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   pattern -> Node
    #
    # Returns the `pattern` attribute.
    #--
    #: () -> Prism::node
    def pattern
      @pattern
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(MatchPredicateNode) &&
        (value === other.value) &&
        (pattern === other.pattern) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents the use of the `=>` operator.
  #
  #     foo => bar
  #     ^^^^^^^^^^
  class MatchRequiredNode < Node
    # @rbs @value: Prism::node
    # @rbs @pattern: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new MatchRequiredNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node value, Prism::node pattern, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, value, pattern, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @value = value
      @pattern = pattern
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_match_required_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value, pattern]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
      yield pattern
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value, pattern]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [value, pattern, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> MatchRequiredNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?value: Prism::node, ?pattern: Prism::node, ?operator_loc: Location) -> MatchRequiredNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, value: self.value, pattern: self.pattern, operator_loc: self.operator_loc)
      MatchRequiredNode.new(source, node_id, location, flags, value, pattern, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location value pattern operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :value                   then deconstructed[:value] = self.value
        when :pattern                 then deconstructed[:pattern] = self.pattern
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :match_required_node
    def type
      :match_required_node
    end

    # See `Node.type`.
    #--
    #: () -> :match_required_node
    def self.type
      :match_required_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   value -> Node
    #
    # Represents the left-hand side of the operator.
    #
    #     foo => bar
    #     ^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :call-seq:
    #   pattern -> Node
    #
    # Represents the right-hand side of the operator. The type of the node depends on the expression.
    #
    # Anything that looks like a local variable name (including `_`) will result in a `LocalVariableTargetNode`.
    #
    #     foo => a # This is equivalent to writing `a = foo`
    #            ^
    #
    # Using an explicit `Array` or combining expressions with `,` will result in a `ArrayPatternNode`. This can be preceded by a constant.
    #
    #     foo => [a]
    #            ^^^
    #
    #     foo => a, b
    #            ^^^^
    #
    #     foo => Bar[a, b]
    #            ^^^^^^^^^
    #
    # If the array pattern contains at least two wildcard matches, a `FindPatternNode` is created instead.
    #
    #     foo => *, 1, *a
    #            ^^^^^
    #
    # Using an explicit `Hash` or a constant with square brackets and hash keys in the square brackets will result in a `HashPatternNode`.
    #
    #     foo => { a: 1, b: }
    #
    #     foo => Bar[a: 1, b:]
    #
    #     foo => Bar[**]
    #
    # To use any variable that needs run time evaluation, pinning is required. This results in a `PinnedVariableNode`
    #
    #     foo => ^a
    #            ^^
    #
    # Similar, any expression can be used with pinning. This results in a `PinnedExpressionNode`.
    #
    #     foo => ^(a + 1)
    #
    # Anything else will result in the regular node for that expression, for example a `ConstantReadNode`.
    #
    #     foo => CONST
    #--
    #: () -> Prism::node
    def pattern
      @pattern
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the operator.
    #
    #     foo => bar
    #         ^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(MatchRequiredNode) &&
        (value === other.value) &&
        (pattern === other.pattern) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents writing local variables using a regular expression match with named capture groups.
  #
  #     /(?<foo>bar)/ =~ baz
  #     ^^^^^^^^^^^^^^^^^^^^
  class MatchWriteNode < Node
    # @rbs @call: CallNode
    # @rbs @targets: Array[LocalVariableTargetNode]

    # Initialize a new MatchWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, CallNode call, Array[LocalVariableTargetNode] targets) -> void
    def initialize(source, node_id, location, flags, call, targets)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @call = call
      @targets = targets
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_match_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [call, *targets]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield call
      targets.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [call, *targets]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [call, *targets] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> MatchWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?call: CallNode, ?targets: Array[LocalVariableTargetNode]) -> MatchWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, call: self.call, targets: self.targets)
      MatchWriteNode.new(source, node_id, location, flags, call, targets)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location call targets]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :call                    then deconstructed[:call] = self.call
        when :targets                 then deconstructed[:targets] = self.targets
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :match_write_node
    def type
      :match_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :match_write_node
    def self.type
      :match_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   call -> CallNode
    #
    # Returns the `call` attribute.
    #--
    #: () -> CallNode
    def call
      @call
    end

    # :call-seq:
    #   targets -> Array[LocalVariableTargetNode]
    #
    # Returns the `targets` attribute.
    #--
    #: () -> Array[LocalVariableTargetNode]
    def targets
      @targets
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(MatchWriteNode) &&
        (call === other.call) &&
        (targets.length == other.targets.length) &&
        targets.zip(other.targets).all? { |left, right| left === right }
    end
  end

  # Represents a module declaration involving the `module` keyword.
  #
  #     module Foo end
  #     ^^^^^^^^^^^^^^
  class ModuleNode < Node
    # @rbs @locals: Array[Symbol]
    # @rbs @module_keyword_loc: Location
    # @rbs @constant_path: (ConstantReadNode | ConstantPathNode)
    # @rbs @body: (StatementsNode | BeginNode)?
    # @rbs @end_keyword_loc: Location
    # @rbs @name: Symbol

    # Initialize a new ModuleNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Symbol] locals, Location module_keyword_loc, (ConstantReadNode | ConstantPathNode) constant_path, (StatementsNode | BeginNode)? body, Location end_keyword_loc, Symbol name) -> void
    def initialize(source, node_id, location, flags, locals, module_keyword_loc, constant_path, body, end_keyword_loc, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @locals = locals
      @module_keyword_loc = module_keyword_loc
      @constant_path = constant_path
      @body = body
      @end_keyword_loc = end_keyword_loc
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_module_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [constant_path, body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield constant_path
      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << constant_path
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [module_keyword_loc, constant_path, *body, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ModuleNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?locals: Array[Symbol], ?module_keyword_loc: Location, ?constant_path: (ConstantReadNode | ConstantPathNode), ?body: (StatementsNode | BeginNode)?, ?end_keyword_loc: Location, ?name: Symbol) -> ModuleNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, locals: self.locals, module_keyword_loc: self.module_keyword_loc, constant_path: self.constant_path, body: self.body, end_keyword_loc: self.end_keyword_loc, name: self.name)
      ModuleNode.new(source, node_id, location, flags, locals, module_keyword_loc, constant_path, body, end_keyword_loc, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location locals module_keyword_loc constant_path body end_keyword_loc name module_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :locals                  then deconstructed[:locals] = self.locals
        when :module_keyword_loc      then deconstructed[:module_keyword_loc] = self.module_keyword_loc
        when :constant_path           then deconstructed[:constant_path] = self.constant_path
        when :body                    then deconstructed[:body] = self.body
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :name                    then deconstructed[:name] = self.name
        when :module_keyword          then deconstructed[:module_keyword] = self.module_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :module_node
    def type
      :module_node
    end

    # See `Node.type`.
    #--
    #: () -> :module_node
    def self.type
      :module_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # Returns the `locals` attribute.
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :category: Locations
    # :call-seq:
    #   module_keyword_loc -> Location
    #
    # Returns the Location represented by `module_keyword_loc`.
    #--
    #: () -> Location
    def module_keyword_loc
      location = @module_keyword_loc
      return location if location.is_a?(Location)
      @module_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the module_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_module_keyword_loc(repository)
      repository.enter(node_id, :module_keyword_loc)
    end

    # :call-seq:
    #   constant_path -> ConstantReadNode | ConstantPathNode
    #
    # Returns the `constant_path` attribute.
    #--
    #: () -> (ConstantReadNode | ConstantPathNode)
    def constant_path
      @constant_path
    end

    # :call-seq:
    #   body -> StatementsNode | BeginNode | nil
    #
    # Returns the `body` attribute.
    #--
    #: () -> (StatementsNode | BeginNode)?
    def body
      @body
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :call-seq:
    #   module_keyword -> String
    #
    # Slice the location of module_keyword_loc from the source.
    #--
    #: () -> String
    def module_keyword
      module_keyword_loc.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ModuleNode) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (module_keyword_loc.nil? == other.module_keyword_loc.nil?) &&
        (constant_path === other.constant_path) &&
        (body === other.body) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?) &&
        (name === other.name)
    end
  end

  # Represents a multi-target expression.
  #
  #     a, (b, c) = 1, 2, 3
  #        ^^^^^^
  #
  # This can be a part of `MultiWriteNode` as above, or the target of a `for` loop
  #
  #     for a, b in [[1, 2], [3, 4]]
  #         ^^^^
  class MultiTargetNode < Node
    # @rbs @lefts: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode]
    # @rbs @rest: (ImplicitRestNode | SplatNode)?
    # @rbs @rights: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode]
    # @rbs @lparen_loc: Location?
    # @rbs @rparen_loc: Location?

    # Initialize a new MultiTargetNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode] lefts, (ImplicitRestNode | SplatNode)? rest, Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode] rights, Location? lparen_loc, Location? rparen_loc) -> void
    def initialize(source, node_id, location, flags, lefts, rest, rights, lparen_loc, rparen_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @lefts = lefts
      @rest = rest
      @rights = rights
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_multi_target_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*lefts, rest, *rights]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      lefts.each { |node| yield node }
      if (rest = self.rest); yield rest; end
      rights.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact.concat(lefts)
      if (rest = self.rest); compact << rest; end
      compact.concat(rights)
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*lefts, *rest, *rights, *lparen_loc, *rparen_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> MultiTargetNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?lefts: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode], ?rest: (ImplicitRestNode | SplatNode)?, ?rights: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode], ?lparen_loc: Location?, ?rparen_loc: Location?) -> MultiTargetNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, lefts: self.lefts, rest: self.rest, rights: self.rights, lparen_loc: self.lparen_loc, rparen_loc: self.rparen_loc)
      MultiTargetNode.new(source, node_id, location, flags, lefts, rest, rights, lparen_loc, rparen_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location lefts rest rights lparen_loc rparen_loc lparen rparen]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :lefts                   then deconstructed[:lefts] = self.lefts
        when :rest                    then deconstructed[:rest] = self.rest
        when :rights                  then deconstructed[:rights] = self.rights
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :multi_target_node
    def type
      :multi_target_node
    end

    # See `Node.type`.
    #--
    #: () -> :multi_target_node
    def self.type
      :multi_target_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   lefts -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode]
    #
    # Represents the targets expressions before a splat node.
    #
    #     a, (b, c, *) = 1, 2, 3, 4, 5
    #         ^^^^
    #
    # The splat node can be absent, in that case all target expressions are in the left field.
    #
    #     a, (b, c) = 1, 2, 3, 4, 5
    #         ^^^^
    #--
    #: () -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode]
    def lefts
      @lefts
    end

    # :call-seq:
    #   rest -> ImplicitRestNode | SplatNode | nil
    #
    # Represents a splat node in the target expression.
    #
    #     a, (b, *c) = 1, 2, 3, 4
    #            ^^
    #
    # The variable can be empty, this results in a `SplatNode` with a `nil` expression field.
    #
    #     a, (b, *) = 1, 2, 3, 4
    #            ^
    #
    # If the `*` is omitted, this field will contain an `ImplicitRestNode`
    #
    #     a, (b,) = 1, 2, 3, 4
    #          ^
    #--
    #: () -> (ImplicitRestNode | SplatNode)?
    def rest
      @rest
    end

    # :call-seq:
    #   rights -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode]
    #
    # Represents the targets expressions after a splat node.
    #
    #     a, (*, b, c) = 1, 2, 3, 4, 5
    #            ^^^^
    #--
    #: () -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode | RequiredParameterNode]
    def rights
      @rights
    end

    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location | nil
    #
    # The Location of the opening parenthesis.
    #
    #     a, (b, c) = 1, 2, 3
    #        ^
    #--
    #: () -> Location?
    def lparen_loc
      location = @lparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc) unless @lparen_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location | nil
    #
    # The Location of the closing parenthesis.
    #
    #     a, (b, c) = 1, 2, 3
    #             ^
    #--
    #: () -> Location?
    def rparen_loc
      location = @rparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc) unless @rparen_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   lparen -> String | nil
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # :call-seq:
    #   rparen -> String | nil
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(MultiTargetNode) &&
        (lefts.length == other.lefts.length) &&
        lefts.zip(other.lefts).all? { |left, right| left === right } &&
        (rest === other.rest) &&
        (rights.length == other.rights.length) &&
        rights.zip(other.rights).all? { |left, right| left === right } &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (rparen_loc.nil? == other.rparen_loc.nil?)
    end
  end

  # Represents a write to a multi-target expression.
  #
  #     a, b, c = 1, 2, 3
  #     ^^^^^^^^^^^^^^^^^
  class MultiWriteNode < Node
    # @rbs @lefts: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode]
    # @rbs @rest: (ImplicitRestNode | SplatNode)?
    # @rbs @rights: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode]
    # @rbs @lparen_loc: Location?
    # @rbs @rparen_loc: Location?
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new MultiWriteNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode] lefts, (ImplicitRestNode | SplatNode)? rest, Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode] rights, Location? lparen_loc, Location? rparen_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, lefts, rest, rights, lparen_loc, rparen_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @lefts = lefts
      @rest = rest
      @rights = rights
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_multi_write_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*lefts, rest, *rights, value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      lefts.each { |node| yield node }
      if (rest = self.rest); yield rest; end
      rights.each { |node| yield node }
      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact.concat(lefts)
      if (rest = self.rest); compact << rest; end
      compact.concat(rights)
      compact << value
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*lefts, *rest, *rights, *lparen_loc, *rparen_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> MultiWriteNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?lefts: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode], ?rest: (ImplicitRestNode | SplatNode)?, ?rights: Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode], ?lparen_loc: Location?, ?rparen_loc: Location?, ?operator_loc: Location, ?value: Prism::node) -> MultiWriteNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, lefts: self.lefts, rest: self.rest, rights: self.rights, lparen_loc: self.lparen_loc, rparen_loc: self.rparen_loc, operator_loc: self.operator_loc, value: self.value)
      MultiWriteNode.new(source, node_id, location, flags, lefts, rest, rights, lparen_loc, rparen_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location lefts rest rights lparen_loc rparen_loc operator_loc value lparen rparen operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :lefts                   then deconstructed[:lefts] = self.lefts
        when :rest                    then deconstructed[:rest] = self.rest
        when :rights                  then deconstructed[:rights] = self.rights
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :multi_write_node
    def type
      :multi_write_node
    end

    # See `Node.type`.
    #--
    #: () -> :multi_write_node
    def self.type
      :multi_write_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   lefts -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode]
    #
    # Represents the targets expressions before a splat node.
    #
    #     a, b, * = 1, 2, 3, 4, 5
    #     ^^^^
    #
    # The splat node can be absent, in that case all target expressions are in the left field.
    #
    #     a, b, c = 1, 2, 3, 4, 5
    #     ^^^^^^^
    #--
    #: () -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode]
    def lefts
      @lefts
    end

    # :call-seq:
    #   rest -> ImplicitRestNode | SplatNode | nil
    #
    # Represents a splat node in the target expression.
    #
    #     a, b, *c = 1, 2, 3, 4
    #           ^^
    #
    # The variable can be empty, this results in a `SplatNode` with a `nil` expression field.
    #
    #     a, b, * = 1, 2, 3, 4
    #           ^
    #
    # If the `*` is omitted, this field will contain an `ImplicitRestNode`
    #
    #     a, b, = 1, 2, 3, 4
    #         ^
    #--
    #: () -> (ImplicitRestNode | SplatNode)?
    def rest
      @rest
    end

    # :call-seq:
    #   rights -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode]
    #
    # Represents the targets expressions after a splat node.
    #
    #     a, *, b, c = 1, 2, 3, 4, 5
    #           ^^^^
    #--
    #: () -> Array[LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | MultiTargetNode]
    def rights
      @rights
    end

    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location | nil
    #
    # The Location of the opening parenthesis.
    #
    #     (a, b, c) = 1, 2, 3
    #     ^
    #--
    #: () -> Location?
    def lparen_loc
      location = @lparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc) unless @lparen_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location | nil
    #
    # The Location of the closing parenthesis.
    #
    #     (a, b, c) = 1, 2, 3
    #             ^
    #--
    #: () -> Location?
    def rparen_loc
      location = @rparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc) unless @rparen_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the operator.
    #
    #     a, b, c = 1, 2, 3
    #             ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # The value to write to the targets. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     a, b, c = 1, 2, 3
    #               ^^^^^^^
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   lparen -> String | nil
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # :call-seq:
    #   rparen -> String | nil
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(MultiWriteNode) &&
        (lefts.length == other.lefts.length) &&
        lefts.zip(other.lefts).all? { |left, right| left === right } &&
        (rest === other.rest) &&
        (rights.length == other.rights.length) &&
        rights.zip(other.rights).all? { |left, right| left === right } &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (rparen_loc.nil? == other.rparen_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents the use of the `next` keyword.
  #
  #     next 1
  #     ^^^^^^
  class NextNode < Node
    # @rbs @arguments: ArgumentsNode?
    # @rbs @keyword_loc: Location

    # Initialize a new NextNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ArgumentsNode? arguments, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, arguments, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @arguments = arguments
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_next_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [arguments]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (arguments = self.arguments); yield arguments; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (arguments = self.arguments); compact << arguments; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*arguments, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> NextNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?arguments: ArgumentsNode?, ?keyword_loc: Location) -> NextNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, arguments: self.arguments, keyword_loc: self.keyword_loc)
      NextNode.new(source, node_id, location, flags, arguments, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location arguments keyword_loc keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :next_node
    def type
      :next_node
    end

    # See `Node.type`.
    #--
    #: () -> :next_node
    def self.type
      :next_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(NextNode) &&
        (arguments === other.arguments) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents the use of the `nil` keyword.
  #
  #     nil
  #     ^^^
  class NilNode < Node

    # Initialize a new NilNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_nil_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> NilNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> NilNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      NilNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :nil_node
    def type
      :nil_node
    end

    # See `Node.type`.
    #--
    #: () -> :nil_node
    def self.type
      :nil_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(NilNode)
    end
  end

  # Represents the use of `&nil` inside method arguments.
  #
  #     def a(&nil)
  #           ^^^^
  #     end
  class NoBlockParameterNode < Node
    # @rbs @operator_loc: Location
    # @rbs @keyword_loc: Location

    # Initialize a new NoBlockParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location operator_loc, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, operator_loc, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @operator_loc = operator_loc
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_no_block_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [operator_loc, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> NoBlockParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?operator_loc: Location, ?keyword_loc: Location) -> NoBlockParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, operator_loc: self.operator_loc, keyword_loc: self.keyword_loc)
      NoBlockParameterNode.new(source, node_id, location, flags, operator_loc, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location operator_loc keyword_loc operator keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :operator                then deconstructed[:operator] = self.operator
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :no_block_parameter_node
    def type
      :no_block_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :no_block_parameter_node
    def self.type
      :no_block_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(NoBlockParameterNode) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents the use of `**nil` inside method arguments.
  #
  #     def a(**nil)
  #           ^^^^^
  #     end
  class NoKeywordsParameterNode < Node
    # @rbs @operator_loc: Location
    # @rbs @keyword_loc: Location

    # Initialize a new NoKeywordsParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location operator_loc, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, operator_loc, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @operator_loc = operator_loc
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_no_keywords_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [operator_loc, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> NoKeywordsParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?operator_loc: Location, ?keyword_loc: Location) -> NoKeywordsParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, operator_loc: self.operator_loc, keyword_loc: self.keyword_loc)
      NoKeywordsParameterNode.new(source, node_id, location, flags, operator_loc, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location operator_loc keyword_loc operator keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :operator                then deconstructed[:operator] = self.operator
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :no_keywords_parameter_node
    def type
      :no_keywords_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :no_keywords_parameter_node
    def self.type
      :no_keywords_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(NoKeywordsParameterNode) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents an implicit set of parameters through the use of numbered parameters within a block or lambda.
  #
  #     -> { _1 + _2 }
  #     ^^^^^^^^^^^^^^
  class NumberedParametersNode < Node
    # @rbs @maximum: Integer

    # Initialize a new NumberedParametersNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Integer maximum) -> void
    def initialize(source, node_id, location, flags, maximum)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @maximum = maximum
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_numbered_parameters_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> NumberedParametersNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?maximum: Integer) -> NumberedParametersNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, maximum: self.maximum)
      NumberedParametersNode.new(source, node_id, location, flags, maximum)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location maximum]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :maximum                 then deconstructed[:maximum] = self.maximum
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :numbered_parameters_node
    def type
      :numbered_parameters_node
    end

    # See `Node.type`.
    #--
    #: () -> :numbered_parameters_node
    def self.type
      :numbered_parameters_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   maximum -> Integer
    #
    # Returns the `maximum` attribute.
    #--
    #: () -> Integer
    def maximum
      @maximum
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(NumberedParametersNode) &&
        (maximum === other.maximum)
    end
  end

  # Represents reading a numbered reference to a capture in the previous match.
  #
  #     $1
  #     ^^
  class NumberedReferenceReadNode < Node
    # @rbs @number: Integer

    # Initialize a new NumberedReferenceReadNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Integer number) -> void
    def initialize(source, node_id, location, flags, number)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @number = number
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_numbered_reference_read_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> NumberedReferenceReadNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?number: Integer) -> NumberedReferenceReadNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, number: self.number)
      NumberedReferenceReadNode.new(source, node_id, location, flags, number)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location number]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :number                  then deconstructed[:number] = self.number
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :numbered_reference_read_node
    def type
      :numbered_reference_read_node
    end

    # See `Node.type`.
    #--
    #: () -> :numbered_reference_read_node
    def self.type
      :numbered_reference_read_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   number -> Integer
    #
    # The (1-indexed, from the left) number of the capture group. Numbered references that are too large result in this value being `0`.
    #
    #     $1          # number `1`
    #
    #     $5432       # number `5432`
    #
    #     $4294967296 # number `0`
    #--
    #: () -> Integer
    def number
      @number
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(NumberedReferenceReadNode) &&
        (number === other.number)
    end
  end

  # Represents an optional keyword parameter to a method, block, or lambda definition.
  #
  #     def a(b: 1)
  #           ^^^^
  #     end
  class OptionalKeywordParameterNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new OptionalKeywordParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_optional_keyword_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> OptionalKeywordParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?value: Prism::node) -> OptionalKeywordParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, value: self.value)
      OptionalKeywordParameterNode.new(source, node_id, location, flags, name, name_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc value]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :value                   then deconstructed[:value] = self.value
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :optional_keyword_parameter_node
    def type
      :optional_keyword_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :optional_keyword_parameter_node
    def self.type
      :optional_keyword_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(OptionalKeywordParameterNode) &&
        (flags === other.flags) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents an optional parameter to a method, block, or lambda definition.
  #
  #     def a(b = 1)
  #           ^^^^^
  #     end
  class OptionalParameterNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @value: Prism::node

    # Initialize a new OptionalParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc, Location operator_loc, Prism::node value) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc, value)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_optional_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [value]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield value
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [value]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc, operator_loc, value] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> OptionalParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location, ?operator_loc: Location, ?value: Prism::node) -> OptionalParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc, value: self.value)
      OptionalParameterNode.new(source, node_id, location, flags, name, name_loc, operator_loc, value)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc value operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :value                   then deconstructed[:value] = self.value
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :optional_parameter_node
    def type
      :optional_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :optional_parameter_node
    def self.type
      :optional_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   value -> Node
    #
    # Returns the `value` attribute.
    #--
    #: () -> Prism::node
    def value
      @value
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(OptionalParameterNode) &&
        (flags === other.flags) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (value === other.value)
    end
  end

  # Represents the use of the `||` operator or the `or` keyword.
  #
  #     left or right
  #     ^^^^^^^^^^^^^
  class OrNode < Node
    # @rbs @left: Prism::node
    # @rbs @right: Prism::node
    # @rbs @operator_loc: Location

    # Initialize a new OrNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node left, Prism::node right, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, left, right, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_or_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [left, right]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield left
      yield right
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [left, right]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [left, right, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> OrNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?left: Prism::node, ?right: Prism::node, ?operator_loc: Location) -> OrNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, left: self.left, right: self.right, operator_loc: self.operator_loc)
      OrNode.new(source, node_id, location, flags, left, right, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location left right operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :left                    then deconstructed[:left] = self.left
        when :right                   then deconstructed[:right] = self.right
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :or_node
    def type
      :or_node
    end

    # See `Node.type`.
    #--
    #: () -> :or_node
    def self.type
      :or_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   left -> Node
    #
    # Represents the left side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     left or right
    #     ^^^^
    #
    #     1 || 2
    #     ^
    #--
    #: () -> Prism::node
    def left
      @left
    end

    # :call-seq:
    #   right -> Node
    #
    # Represents the right side of the expression.
    #
    #     left || right
    #             ^^^^^
    #
    #     1 or 2
    #          ^
    #--
    #: () -> Prism::node
    def right
      @right
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `or` keyword or the `||` operator.
    #
    #     left or right
    #          ^^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(OrNode) &&
        (left === other.left) &&
        (right === other.right) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents the list of parameters on a method, block, or lambda definition.
  #
  #     def a(b, c, d)
  #           ^^^^^^^
  #     end
  class ParametersNode < Node
    # @rbs @requireds: Array[RequiredParameterNode | MultiTargetNode]
    # @rbs @optionals: Array[OptionalParameterNode]
    # @rbs @rest: (RestParameterNode | ImplicitRestNode)?
    # @rbs @posts: Array[RequiredParameterNode | MultiTargetNode]
    # @rbs @keywords: Array[RequiredKeywordParameterNode | OptionalKeywordParameterNode]
    # @rbs @keyword_rest: (KeywordRestParameterNode | ForwardingParameterNode | NoKeywordsParameterNode)?
    # @rbs @block: (BlockParameterNode | NoBlockParameterNode)?

    # Initialize a new ParametersNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[RequiredParameterNode | MultiTargetNode] requireds, Array[OptionalParameterNode] optionals, (RestParameterNode | ImplicitRestNode)? rest, Array[RequiredParameterNode | MultiTargetNode] posts, Array[RequiredKeywordParameterNode | OptionalKeywordParameterNode] keywords, (KeywordRestParameterNode | ForwardingParameterNode | NoKeywordsParameterNode)? keyword_rest, (BlockParameterNode | NoBlockParameterNode)? block) -> void
    def initialize(source, node_id, location, flags, requireds, optionals, rest, posts, keywords, keyword_rest, block)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @requireds = requireds
      @optionals = optionals
      @rest = rest
      @posts = posts
      @keywords = keywords
      @keyword_rest = keyword_rest
      @block = block
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_parameters_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*requireds, *optionals, rest, *posts, *keywords, keyword_rest, block]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      requireds.each { |node| yield node }
      optionals.each { |node| yield node }
      if (rest = self.rest); yield rest; end
      posts.each { |node| yield node }
      keywords.each { |node| yield node }
      if (keyword_rest = self.keyword_rest); yield keyword_rest; end
      if (block = self.block); yield block; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact.concat(requireds)
      compact.concat(optionals)
      if (rest = self.rest); compact << rest; end
      compact.concat(posts)
      compact.concat(keywords)
      if (keyword_rest = self.keyword_rest); compact << keyword_rest; end
      if (block = self.block); compact << block; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*requireds, *optionals, *rest, *posts, *keywords, *keyword_rest, *block] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ParametersNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?requireds: Array[RequiredParameterNode | MultiTargetNode], ?optionals: Array[OptionalParameterNode], ?rest: (RestParameterNode | ImplicitRestNode)?, ?posts: Array[RequiredParameterNode | MultiTargetNode], ?keywords: Array[RequiredKeywordParameterNode | OptionalKeywordParameterNode], ?keyword_rest: (KeywordRestParameterNode | ForwardingParameterNode | NoKeywordsParameterNode)?, ?block: (BlockParameterNode | NoBlockParameterNode)?) -> ParametersNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, requireds: self.requireds, optionals: self.optionals, rest: self.rest, posts: self.posts, keywords: self.keywords, keyword_rest: self.keyword_rest, block: self.block)
      ParametersNode.new(source, node_id, location, flags, requireds, optionals, rest, posts, keywords, keyword_rest, block)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location requireds optionals rest posts keywords keyword_rest block]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :requireds               then deconstructed[:requireds] = self.requireds
        when :optionals               then deconstructed[:optionals] = self.optionals
        when :rest                    then deconstructed[:rest] = self.rest
        when :posts                   then deconstructed[:posts] = self.posts
        when :keywords                then deconstructed[:keywords] = self.keywords
        when :keyword_rest            then deconstructed[:keyword_rest] = self.keyword_rest
        when :block                   then deconstructed[:block] = self.block
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :parameters_node
    def type
      :parameters_node
    end

    # See `Node.type`.
    #--
    #: () -> :parameters_node
    def self.type
      :parameters_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   requireds -> Array[RequiredParameterNode | MultiTargetNode]
    #
    # Returns the `requireds` attribute.
    #--
    #: () -> Array[RequiredParameterNode | MultiTargetNode]
    def requireds
      @requireds
    end

    # :call-seq:
    #   optionals -> Array[OptionalParameterNode]
    #
    # Returns the `optionals` attribute.
    #--
    #: () -> Array[OptionalParameterNode]
    def optionals
      @optionals
    end

    # :call-seq:
    #   rest -> RestParameterNode | ImplicitRestNode | nil
    #
    # Returns the `rest` attribute.
    #--
    #: () -> (RestParameterNode | ImplicitRestNode)?
    def rest
      @rest
    end

    # :call-seq:
    #   posts -> Array[RequiredParameterNode | MultiTargetNode]
    #
    # Returns the `posts` attribute.
    #--
    #: () -> Array[RequiredParameterNode | MultiTargetNode]
    def posts
      @posts
    end

    # :call-seq:
    #   keywords -> Array[RequiredKeywordParameterNode | OptionalKeywordParameterNode]
    #
    # Returns the `keywords` attribute.
    #--
    #: () -> Array[RequiredKeywordParameterNode | OptionalKeywordParameterNode]
    def keywords
      @keywords
    end

    # :call-seq:
    #   keyword_rest -> KeywordRestParameterNode | ForwardingParameterNode | NoKeywordsParameterNode | nil
    #
    # Returns the `keyword_rest` attribute.
    #--
    #: () -> (KeywordRestParameterNode | ForwardingParameterNode | NoKeywordsParameterNode)?
    def keyword_rest
      @keyword_rest
    end

    # :call-seq:
    #   block -> BlockParameterNode | NoBlockParameterNode | nil
    #
    # Returns the `block` attribute.
    #--
    #: () -> (BlockParameterNode | NoBlockParameterNode)?
    def block
      @block
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ParametersNode) &&
        (requireds.length == other.requireds.length) &&
        requireds.zip(other.requireds).all? { |left, right| left === right } &&
        (optionals.length == other.optionals.length) &&
        optionals.zip(other.optionals).all? { |left, right| left === right } &&
        (rest === other.rest) &&
        (posts.length == other.posts.length) &&
        posts.zip(other.posts).all? { |left, right| left === right } &&
        (keywords.length == other.keywords.length) &&
        keywords.zip(other.keywords).all? { |left, right| left === right } &&
        (keyword_rest === other.keyword_rest) &&
        (block === other.block)
    end
  end

  # Represents a parenthesized expression
  #
  #     (10 + 34)
  #     ^^^^^^^^^
  class ParenthesesNode < Node
    # @rbs @body: Prism::node?
    # @rbs @opening_loc: Location
    # @rbs @closing_loc: Location

    # Initialize a new ParenthesesNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? body, Location opening_loc, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, body, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @body = body
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_parentheses_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*body, opening_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ParenthesesNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?body: Prism::node?, ?opening_loc: Location, ?closing_loc: Location) -> ParenthesesNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, body: self.body, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      ParenthesesNode.new(source, node_id, location, flags, body, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location body opening_loc closing_loc opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :body                    then deconstructed[:body] = self.body
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :parentheses_node
    def type
      :parentheses_node
    end

    # See `Node.type`.
    #--
    #: () -> :parentheses_node
    def self.type
      :parentheses_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # parentheses that contain multiple potentially void statements
    #--
    #: () -> bool
    def multiple_statements?
      flags.anybits?(ParenthesesNodeFlags::MULTIPLE_STATEMENTS)
    end

    # :call-seq:
    #   body -> Node | nil
    #
    # Returns the `body` attribute.
    #--
    #: () -> Prism::node?
    def body
      @body
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ParenthesesNode) &&
        (flags === other.flags) &&
        (body === other.body) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents the use of the `^` operator for pinning an expression in a pattern matching expression.
  #
  #     foo in ^(bar)
  #            ^^^^^^
  class PinnedExpressionNode < Node
    # @rbs @expression: Prism::node
    # @rbs @operator_loc: Location
    # @rbs @lparen_loc: Location
    # @rbs @rparen_loc: Location

    # Initialize a new PinnedExpressionNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node expression, Location operator_loc, Location lparen_loc, Location rparen_loc) -> void
    def initialize(source, node_id, location, flags, expression, operator_loc, lparen_loc, rparen_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @expression = expression
      @operator_loc = operator_loc
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_pinned_expression_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [expression]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield expression
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [expression]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [expression, operator_loc, lparen_loc, rparen_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> PinnedExpressionNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?expression: Prism::node, ?operator_loc: Location, ?lparen_loc: Location, ?rparen_loc: Location) -> PinnedExpressionNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, expression: self.expression, operator_loc: self.operator_loc, lparen_loc: self.lparen_loc, rparen_loc: self.rparen_loc)
      PinnedExpressionNode.new(source, node_id, location, flags, expression, operator_loc, lparen_loc, rparen_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location expression operator_loc lparen_loc rparen_loc operator lparen rparen]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :expression              then deconstructed[:expression] = self.expression
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :operator                then deconstructed[:operator] = self.operator
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :pinned_expression_node
    def type
      :pinned_expression_node
    end

    # See `Node.type`.
    #--
    #: () -> :pinned_expression_node
    def self.type
      :pinned_expression_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   expression -> Node
    #
    # The expression used in the pinned expression
    #
    #     foo in ^(bar)
    #              ^^^
    #--
    #: () -> Prism::node
    def expression
      @expression
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `^` operator
    #
    #     foo in ^(bar)
    #            ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location
    #
    # The Location of the opening parenthesis.
    #
    #     foo in ^(bar)
    #             ^
    #--
    #: () -> Location
    def lparen_loc
      location = @lparen_loc
      return location if location.is_a?(Location)
      @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc)
    end

    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location
    #
    # The Location of the closing parenthesis.
    #
    #     foo in ^(bar)
    #                 ^
    #--
    #: () -> Location
    def rparen_loc
      location = @rparen_loc
      return location if location.is_a?(Location)
      @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :call-seq:
    #   lparen -> String
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String
    def lparen
      lparen_loc.slice
    end

    # :call-seq:
    #   rparen -> String
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String
    def rparen
      rparen_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(PinnedExpressionNode) &&
        (expression === other.expression) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (rparen_loc.nil? == other.rparen_loc.nil?)
    end
  end

  # Represents the use of the `^` operator for pinning a variable in a pattern matching expression.
  #
  #     foo in ^bar
  #            ^^^^
  class PinnedVariableNode < Node
    # @rbs @variable: (LocalVariableReadNode | InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode | ItLocalVariableReadNode)
    # @rbs @operator_loc: Location

    # Initialize a new PinnedVariableNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (LocalVariableReadNode | InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode | ItLocalVariableReadNode) variable, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, variable, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @variable = variable
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_pinned_variable_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [variable]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield variable
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [variable]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [variable, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> PinnedVariableNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?variable: (LocalVariableReadNode | InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode | ItLocalVariableReadNode), ?operator_loc: Location) -> PinnedVariableNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, variable: self.variable, operator_loc: self.operator_loc)
      PinnedVariableNode.new(source, node_id, location, flags, variable, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location variable operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :variable                then deconstructed[:variable] = self.variable
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :pinned_variable_node
    def type
      :pinned_variable_node
    end

    # See `Node.type`.
    #--
    #: () -> :pinned_variable_node
    def self.type
      :pinned_variable_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   variable -> LocalVariableReadNode | InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode | ItLocalVariableReadNode
    #
    # The variable used in the pinned expression
    #
    #     foo in ^bar
    #             ^^^
    #--
    #: () -> (LocalVariableReadNode | InstanceVariableReadNode | ClassVariableReadNode | GlobalVariableReadNode | BackReferenceReadNode | NumberedReferenceReadNode | ItLocalVariableReadNode)
    def variable
      @variable
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `^` operator
    #
    #     foo in ^bar
    #            ^
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(PinnedVariableNode) &&
        (variable === other.variable) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents the use of the `END` keyword.
  #
  #     END { foo }
  #     ^^^^^^^^^^^
  class PostExecutionNode < Node
    # @rbs @statements: StatementsNode?
    # @rbs @keyword_loc: Location
    # @rbs @opening_loc: Location
    # @rbs @closing_loc: Location

    # Initialize a new PostExecutionNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, StatementsNode? statements, Location keyword_loc, Location opening_loc, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, statements, keyword_loc, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @statements = statements
      @keyword_loc = keyword_loc
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_post_execution_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*statements, keyword_loc, opening_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> PostExecutionNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?statements: StatementsNode?, ?keyword_loc: Location, ?opening_loc: Location, ?closing_loc: Location) -> PostExecutionNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, statements: self.statements, keyword_loc: self.keyword_loc, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      PostExecutionNode.new(source, node_id, location, flags, statements, keyword_loc, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location statements keyword_loc opening_loc closing_loc keyword opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :statements              then deconstructed[:statements] = self.statements
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :post_execution_node
    def type
      :post_execution_node
    end

    # See `Node.type`.
    #--
    #: () -> :post_execution_node
    def self.type
      :post_execution_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(PostExecutionNode) &&
        (statements === other.statements) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # Represents the use of the `BEGIN` keyword.
  #
  #     BEGIN { foo }
  #     ^^^^^^^^^^^^^
  class PreExecutionNode < Node
    # @rbs @statements: StatementsNode?
    # @rbs @keyword_loc: Location
    # @rbs @opening_loc: Location
    # @rbs @closing_loc: Location

    # Initialize a new PreExecutionNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, StatementsNode? statements, Location keyword_loc, Location opening_loc, Location closing_loc) -> void
    def initialize(source, node_id, location, flags, statements, keyword_loc, opening_loc, closing_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @statements = statements
      @keyword_loc = keyword_loc
      @opening_loc = opening_loc
      @closing_loc = closing_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_pre_execution_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*statements, keyword_loc, opening_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> PreExecutionNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?statements: StatementsNode?, ?keyword_loc: Location, ?opening_loc: Location, ?closing_loc: Location) -> PreExecutionNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, statements: self.statements, keyword_loc: self.keyword_loc, opening_loc: self.opening_loc, closing_loc: self.closing_loc)
      PreExecutionNode.new(source, node_id, location, flags, statements, keyword_loc, opening_loc, closing_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location statements keyword_loc opening_loc closing_loc keyword opening closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :statements              then deconstructed[:statements] = self.statements
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        when :opening                 then deconstructed[:opening] = self.opening
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :pre_execution_node
    def type
      :pre_execution_node
    end

    # See `Node.type`.
    #--
    #: () -> :pre_execution_node
    def self.type
      :pre_execution_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(PreExecutionNode) &&
        (statements === other.statements) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?)
    end
  end

  # The top level node of any parse tree.
  class ProgramNode < Node
    # @rbs @locals: Array[Symbol]
    # @rbs @statements: StatementsNode

    # Initialize a new ProgramNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Symbol] locals, StatementsNode statements) -> void
    def initialize(source, node_id, location, flags, locals, statements)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @locals = locals
      @statements = statements
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_program_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield statements
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [statements]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [statements] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ProgramNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?locals: Array[Symbol], ?statements: StatementsNode) -> ProgramNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, locals: self.locals, statements: self.statements)
      ProgramNode.new(source, node_id, location, flags, locals, statements)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location locals statements]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :locals                  then deconstructed[:locals] = self.locals
        when :statements              then deconstructed[:statements] = self.statements
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :program_node
    def type
      :program_node
    end

    # See `Node.type`.
    #--
    #: () -> :program_node
    def self.type
      :program_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # Returns the `locals` attribute.
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :call-seq:
    #   statements -> StatementsNode
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode
    def statements
      @statements
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ProgramNode) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (statements === other.statements)
    end
  end

  # Represents the use of the `..` or `...` operators.
  #
  #     1..2
  #     ^^^^
  #
  #     c if a =~ /left/ ... b =~ /right/
  #          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  class RangeNode < Node
    # @rbs @left: Prism::node?
    # @rbs @right: Prism::node?
    # @rbs @operator_loc: Location

    # Initialize a new RangeNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node? left, Prism::node? right, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, left, right, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_range_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [left, right]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (left = self.left); yield left; end
      if (right = self.right); yield right; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (left = self.left); compact << left; end
      if (right = self.right); compact << right; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*left, *right, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RangeNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?left: Prism::node?, ?right: Prism::node?, ?operator_loc: Location) -> RangeNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, left: self.left, right: self.right, operator_loc: self.operator_loc)
      RangeNode.new(source, node_id, location, flags, left, right, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location left right operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :left                    then deconstructed[:left] = self.left
        when :right                   then deconstructed[:right] = self.right
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :range_node
    def type
      :range_node
    end

    # See `Node.type`.
    #--
    #: () -> :range_node
    def self.type
      :range_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # ... operator
    #--
    #: () -> bool
    def exclude_end?
      flags.anybits?(RangeFlags::EXCLUDE_END)
    end

    # :call-seq:
    #   left -> Node | nil
    #
    # The left-hand side of the range, if present. It can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     1...
    #     ^
    #
    #     hello...goodbye
    #     ^^^^^
    #--
    #: () -> Prism::node?
    def left
      @left
    end

    # :call-seq:
    #   right -> Node | nil
    #
    # The right-hand side of the range, if present. It can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     ..5
    #       ^
    #
    #     1...foo
    #         ^^^
    # If neither right-hand or left-hand side was included, this will be an ErrorRecoveryNode.
    #--
    #: () -> Prism::node?
    def right
      @right
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # The Location of the `..` or `...` operator.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RangeNode) &&
        (flags === other.flags) &&
        (left === other.left) &&
        (right === other.right) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents a rational number literal.
  #
  #     1.0r
  #     ^^^^
  class RationalNode < Node
    # @rbs @numerator: Integer
    # @rbs @denominator: Integer

    # Initialize a new RationalNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Integer numerator, Integer denominator) -> void
    def initialize(source, node_id, location, flags, numerator, denominator)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @numerator = numerator
      @denominator = denominator
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_rational_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RationalNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?numerator: Integer, ?denominator: Integer) -> RationalNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, numerator: self.numerator, denominator: self.denominator)
      RationalNode.new(source, node_id, location, flags, numerator, denominator)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location numerator denominator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :numerator               then deconstructed[:numerator] = self.numerator
        when :denominator             then deconstructed[:denominator] = self.denominator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :rational_node
    def type
      :rational_node
    end

    # See `Node.type`.
    #--
    #: () -> :rational_node
    def self.type
      :rational_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # 0b prefix
    #--
    #: () -> bool
    def binary?
      flags.anybits?(IntegerBaseFlags::BINARY)
    end

    # :category: Flags
    # 0d or no prefix
    #--
    #: () -> bool
    def decimal?
      flags.anybits?(IntegerBaseFlags::DECIMAL)
    end

    # :category: Flags
    # 0o or 0 prefix
    #--
    #: () -> bool
    def octal?
      flags.anybits?(IntegerBaseFlags::OCTAL)
    end

    # :category: Flags
    # 0x prefix
    #--
    #: () -> bool
    def hexadecimal?
      flags.anybits?(IntegerBaseFlags::HEXADECIMAL)
    end

    # :call-seq:
    #   numerator -> Integer
    #
    # The numerator of the rational number.
    #
    #     1.5r # numerator 3
    #--
    #: () -> Integer
    def numerator
      @numerator
    end

    # :call-seq:
    #   denominator -> Integer
    #
    # The denominator of the rational number.
    #
    #     1.5r # denominator 2
    #--
    #: () -> Integer
    def denominator
      @denominator
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RationalNode) &&
        (flags === other.flags) &&
        (numerator === other.numerator) &&
        (denominator === other.denominator)
    end
  end

  # Represents the use of the `redo` keyword.
  #
  #     redo
  #     ^^^^
  class RedoNode < Node

    # Initialize a new RedoNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_redo_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RedoNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> RedoNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      RedoNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :redo_node
    def type
      :redo_node
    end

    # See `Node.type`.
    #--
    #: () -> :redo_node
    def self.type
      :redo_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RedoNode)
    end
  end

  # Represents a regular expression literal with no interpolation.
  #
  #     /foo/i
  #     ^^^^^^
  class RegularExpressionNode < Node
    # @rbs @opening_loc: Location
    # @rbs @content_loc: Location
    # @rbs @closing_loc: Location
    # @rbs @unescaped: String

    # Initialize a new RegularExpressionNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Location content_loc, Location closing_loc, String unescaped) -> void
    def initialize(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_regular_expression_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, content_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RegularExpressionNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?content_loc: Location, ?closing_loc: Location, ?unescaped: String) -> RegularExpressionNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, content_loc: self.content_loc, closing_loc: self.closing_loc, unescaped: self.unescaped)
      RegularExpressionNode.new(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc content_loc closing_loc unescaped opening content closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :content_loc             then deconstructed[:content_loc] = self.content_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :unescaped               then deconstructed[:unescaped] = self.unescaped
        when :opening                 then deconstructed[:opening] = self.opening
        when :content                 then deconstructed[:content] = self.content
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :regular_expression_node
    def type
      :regular_expression_node
    end

    # See `Node.type`.
    #--
    #: () -> :regular_expression_node
    def self.type
      :regular_expression_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # i - ignores the case of characters when matching
    #--
    #: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # :category: Flags
    # x - ignores whitespace and allows comments in regular expressions
    #--
    #: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # :category: Flags
    # m - allows $ to match the end of lines within strings
    #--
    #: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # :category: Flags
    # o - only interpolates values into the regular expression once
    #--
    #: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # :category: Flags
    # e - forces the EUC-JP encoding
    #--
    #: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # :category: Flags
    # n - forces the ASCII-8BIT encoding
    #--
    #: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # :category: Flags
    # s - forces the Windows-31J encoding
    #--
    #: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # :category: Flags
    # u - forces the UTF-8 encoding
    #--
    #: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to US-ASCII
    #--
    #: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   content_loc -> Location
    #
    # Returns the Location represented by `content_loc`.
    #--
    #: () -> Location
    def content_loc
      location = @content_loc
      return location if location.is_a?(Location)
      @content_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the content_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_content_loc(repository)
      repository.enter(node_id, :content_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   unescaped -> String
    #
    # Returns the `unescaped` attribute.
    #--
    #: () -> String
    def unescaped
      @unescaped
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   content -> String
    #
    # Slice the location of content_loc from the source.
    #--
    #: () -> String
    def content
      content_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RegularExpressionNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (content_loc.nil? == other.content_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (unescaped === other.unescaped)
    end
  end

  # Represents a required keyword parameter to a method, block, or lambda definition.
  #
  #     def a(b: )
  #           ^^
  #     end
  class RequiredKeywordParameterNode < Node
    # @rbs @name: Symbol
    # @rbs @name_loc: Location

    # Initialize a new RequiredKeywordParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name, Location name_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_required_keyword_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [name_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RequiredKeywordParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol, ?name_loc: Location) -> RequiredKeywordParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc)
      RequiredKeywordParameterNode.new(source, node_id, location, flags, name, name_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :required_keyword_parameter_node
    def type
      :required_keyword_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :required_keyword_parameter_node
    def self.type
      :required_keyword_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location
    def name_loc
      location = @name_loc
      return location if location.is_a?(Location)
      @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc)
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RequiredKeywordParameterNode) &&
        (flags === other.flags) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?)
    end
  end

  # Represents a required parameter to a method, block, or lambda definition.
  #
  #     def a(b)
  #           ^
  #     end
  class RequiredParameterNode < Node
    # @rbs @name: Symbol

    # Initialize a new RequiredParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol name) -> void
    def initialize(source, node_id, location, flags, name)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_required_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RequiredParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol) -> RequiredParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name)
      RequiredParameterNode.new(source, node_id, location, flags, name)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :required_parameter_node
    def type
      :required_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :required_parameter_node
    def self.type
      :required_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol
    def name
      @name
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RequiredParameterNode) &&
        (flags === other.flags) &&
        (name === other.name)
    end
  end

  # Represents an expression modified with a rescue.
  #
  #     foo rescue nil
  #     ^^^^^^^^^^^^^^
  class RescueModifierNode < Node
    # @rbs @expression: Prism::node
    # @rbs @keyword_loc: Location
    # @rbs @rescue_expression: Prism::node

    # Initialize a new RescueModifierNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Prism::node expression, Location keyword_loc, Prism::node rescue_expression) -> void
    def initialize(source, node_id, location, flags, expression, keyword_loc, rescue_expression)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @expression = expression
      @keyword_loc = keyword_loc
      @rescue_expression = rescue_expression
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_rescue_modifier_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [expression, rescue_expression]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield expression
      yield rescue_expression
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [expression, rescue_expression]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [expression, keyword_loc, rescue_expression] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RescueModifierNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?expression: Prism::node, ?keyword_loc: Location, ?rescue_expression: Prism::node) -> RescueModifierNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, expression: self.expression, keyword_loc: self.keyword_loc, rescue_expression: self.rescue_expression)
      RescueModifierNode.new(source, node_id, location, flags, expression, keyword_loc, rescue_expression)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location expression keyword_loc rescue_expression keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :expression              then deconstructed[:expression] = self.expression
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :rescue_expression       then deconstructed[:rescue_expression] = self.rescue_expression
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :rescue_modifier_node
    def type
      :rescue_modifier_node
    end

    # See `Node.type`.
    #--
    #: () -> :rescue_modifier_node
    def self.type
      :rescue_modifier_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   expression -> Node
    #
    # Returns the `expression` attribute.
    #--
    #: () -> Prism::node
    def expression
      @expression
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :call-seq:
    #   rescue_expression -> Node
    #
    # Returns the `rescue_expression` attribute.
    #--
    #: () -> Prism::node
    def rescue_expression
      @rescue_expression
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RescueModifierNode) &&
        (expression === other.expression) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (rescue_expression === other.rescue_expression)
    end
  end

  # Represents a rescue statement.
  #
  #     begin
  #     rescue Foo, *splat, Bar => ex
  #       foo
  #     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  #     end
  #
  # `Foo, *splat, Bar` are in the `exceptions` field. `ex` is in the `reference` field.
  class RescueNode < Node
    # @rbs @keyword_loc: Location
    # @rbs @exceptions: Array[Prism::node]
    # @rbs @operator_loc: Location?
    # @rbs @reference: (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode)?
    # @rbs @then_keyword_loc: Location?
    # @rbs @statements: StatementsNode?
    # @rbs @subsequent: RescueNode?

    # Initialize a new RescueNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location keyword_loc, Array[Prism::node] exceptions, Location? operator_loc, (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode)? reference, Location? then_keyword_loc, StatementsNode? statements, RescueNode? subsequent) -> void
    def initialize(source, node_id, location, flags, keyword_loc, exceptions, operator_loc, reference, then_keyword_loc, statements, subsequent)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @keyword_loc = keyword_loc
      @exceptions = exceptions
      @operator_loc = operator_loc
      @reference = reference
      @then_keyword_loc = then_keyword_loc
      @statements = statements
      @subsequent = subsequent
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_rescue_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*exceptions, reference, statements, subsequent]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      exceptions.each { |node| yield node }
      if (reference = self.reference); yield reference; end
      if (statements = self.statements); yield statements; end
      if (subsequent = self.subsequent); yield subsequent; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact.concat(exceptions)
      if (reference = self.reference); compact << reference; end
      if (statements = self.statements); compact << statements; end
      if (subsequent = self.subsequent); compact << subsequent; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [keyword_loc, *exceptions, *operator_loc, *reference, *then_keyword_loc, *statements, *subsequent] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RescueNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?keyword_loc: Location, ?exceptions: Array[Prism::node], ?operator_loc: Location?, ?reference: (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode)?, ?then_keyword_loc: Location?, ?statements: StatementsNode?, ?subsequent: RescueNode?) -> RescueNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, keyword_loc: self.keyword_loc, exceptions: self.exceptions, operator_loc: self.operator_loc, reference: self.reference, then_keyword_loc: self.then_keyword_loc, statements: self.statements, subsequent: self.subsequent)
      RescueNode.new(source, node_id, location, flags, keyword_loc, exceptions, operator_loc, reference, then_keyword_loc, statements, subsequent)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location keyword_loc exceptions operator_loc reference then_keyword_loc statements subsequent keyword operator then_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :exceptions              then deconstructed[:exceptions] = self.exceptions
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :reference               then deconstructed[:reference] = self.reference
        when :then_keyword_loc        then deconstructed[:then_keyword_loc] = self.then_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :subsequent              then deconstructed[:subsequent] = self.subsequent
        when :keyword                 then deconstructed[:keyword] = self.keyword
        when :operator                then deconstructed[:operator] = self.operator
        when :then_keyword            then deconstructed[:then_keyword] = self.then_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :rescue_node
    def type
      :rescue_node
    end

    # See `Node.type`.
    #--
    #: () -> :rescue_node
    def self.type
      :rescue_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :call-seq:
    #   exceptions -> Array[Node]
    #
    # Returns the `exceptions` attribute.
    #--
    #: () -> Array[Prism::node]
    def exceptions
      @exceptions
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location | nil
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location?
    def operator_loc
      location = @operator_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc) unless @operator_loc.nil?
    end
    # :call-seq:
    #   reference -> LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode | nil
    #
    # Returns the `reference` attribute.
    #--
    #: () -> (LocalVariableTargetNode | InstanceVariableTargetNode | ClassVariableTargetNode | GlobalVariableTargetNode | ConstantTargetNode | ConstantPathTargetNode | CallTargetNode | IndexTargetNode)?
    def reference
      @reference
    end

    # :category: Locations
    # :call-seq:
    #   then_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `then_keyword_loc`.
    #--
    #: () -> Location?
    def then_keyword_loc
      location = @then_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @then_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the then_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_then_keyword_loc(repository)
      repository.enter(node_id, :then_keyword_loc) unless @then_keyword_loc.nil?
    end
    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :call-seq:
    #   subsequent -> RescueNode | nil
    #
    # Returns the `subsequent` attribute.
    #--
    #: () -> RescueNode?
    def subsequent
      @subsequent
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :call-seq:
    #   operator -> String | nil
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String?
    def operator
      operator_loc&.slice
    end

    # :call-seq:
    #   then_keyword -> String | nil
    #
    # Slice the location of then_keyword_loc from the source.
    #--
    #: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RescueNode) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (exceptions.length == other.exceptions.length) &&
        exceptions.zip(other.exceptions).all? { |left, right| left === right } &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (reference === other.reference) &&
        (then_keyword_loc.nil? == other.then_keyword_loc.nil?) &&
        (statements === other.statements) &&
        (subsequent === other.subsequent)
    end
  end

  # Represents a rest parameter to a method, block, or lambda definition.
  #
  #     def a(*b)
  #           ^^
  #     end
  class RestParameterNode < Node
    # @rbs @name: Symbol?
    # @rbs @name_loc: Location?
    # @rbs @operator_loc: Location

    # Initialize a new RestParameterNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Symbol? name, Location? name_loc, Location operator_loc) -> void
    def initialize(source, node_id, location, flags, name, name_loc, operator_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_rest_parameter_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*name_loc, operator_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RestParameterNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?name: Symbol?, ?name_loc: Location?, ?operator_loc: Location) -> RestParameterNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, name: self.name, name_loc: self.name_loc, operator_loc: self.operator_loc)
      RestParameterNode.new(source, node_id, location, flags, name, name_loc, operator_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location name name_loc operator_loc operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :name                    then deconstructed[:name] = self.name
        when :name_loc                then deconstructed[:name_loc] = self.name_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :rest_parameter_node
    def type
      :rest_parameter_node
    end

    # See `Node.type`.
    #--
    #: () -> :rest_parameter_node
    def self.type
      :rest_parameter_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a parameter name that has been repeated in the method signature
    #--
    #: () -> bool
    def repeated_parameter?
      flags.anybits?(ParameterFlags::REPEATED_PARAMETER)
    end

    # :call-seq:
    #   name -> Symbol | nil
    #
    # Returns the `name` attribute.
    #--
    #: () -> Symbol?
    def name
      @name
    end

    # :category: Locations
    # :call-seq:
    #   name_loc -> Location | nil
    #
    # Returns the Location represented by `name_loc`.
    #--
    #: () -> Location?
    def name_loc
      location = @name_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @name_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the name_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_name_loc(repository)
      repository.enter(node_id, :name_loc) unless @name_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RestParameterNode) &&
        (flags === other.flags) &&
        (name === other.name) &&
        (name_loc.nil? == other.name_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?)
    end
  end

  # Represents the use of the `retry` keyword.
  #
  #     retry
  #     ^^^^^
  class RetryNode < Node

    # Initialize a new RetryNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_retry_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> RetryNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> RetryNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      RetryNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :retry_node
    def type
      :retry_node
    end

    # See `Node.type`.
    #--
    #: () -> :retry_node
    def self.type
      :retry_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(RetryNode)
    end
  end

  # Represents the use of the `return` keyword.
  #
  #     return 1
  #     ^^^^^^^^
  class ReturnNode < Node
    # @rbs @keyword_loc: Location
    # @rbs @arguments: ArgumentsNode?

    # Initialize a new ReturnNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location keyword_loc, ArgumentsNode? arguments) -> void
    def initialize(source, node_id, location, flags, keyword_loc, arguments)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @keyword_loc = keyword_loc
      @arguments = arguments
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_return_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [arguments]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (arguments = self.arguments); yield arguments; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (arguments = self.arguments); compact << arguments; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [keyword_loc, *arguments] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ReturnNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?keyword_loc: Location, ?arguments: ArgumentsNode?) -> ReturnNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, keyword_loc: self.keyword_loc, arguments: self.arguments)
      ReturnNode.new(source, node_id, location, flags, keyword_loc, arguments)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location keyword_loc arguments keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :return_node
    def type
      :return_node
    end

    # See `Node.type`.
    #--
    #: () -> :return_node
    def self.type
      :return_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ReturnNode) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (arguments === other.arguments)
    end
  end

  # Represents the `self` keyword.
  #
  #     self
  #     ^^^^
  class SelfNode < Node

    # Initialize a new SelfNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_self_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SelfNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> SelfNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      SelfNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :self_node
    def type
      :self_node
    end

    # See `Node.type`.
    #--
    #: () -> :self_node
    def self.type
      :self_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SelfNode)
    end
  end

  # This node wraps a constant write to indicate that when the value is written, it should have its shareability state modified.
  #
  #     # shareable_constant_value: literal
  #     C = { a: 1 }
  #     ^^^^^^^^^^^^
  class ShareableConstantNode < Node
    # @rbs @write: (ConstantWriteNode | ConstantAndWriteNode | ConstantOrWriteNode | ConstantOperatorWriteNode | ConstantPathWriteNode | ConstantPathAndWriteNode | ConstantPathOrWriteNode | ConstantPathOperatorWriteNode)

    # Initialize a new ShareableConstantNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, (ConstantWriteNode | ConstantAndWriteNode | ConstantOrWriteNode | ConstantOperatorWriteNode | ConstantPathWriteNode | ConstantPathAndWriteNode | ConstantPathOrWriteNode | ConstantPathOperatorWriteNode) write) -> void
    def initialize(source, node_id, location, flags, write)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @write = write
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_shareable_constant_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [write]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield write
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [write]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [write] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> ShareableConstantNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?write: (ConstantWriteNode | ConstantAndWriteNode | ConstantOrWriteNode | ConstantOperatorWriteNode | ConstantPathWriteNode | ConstantPathAndWriteNode | ConstantPathOrWriteNode | ConstantPathOperatorWriteNode)) -> ShareableConstantNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, write: self.write)
      ShareableConstantNode.new(source, node_id, location, flags, write)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location write]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :write                   then deconstructed[:write] = self.write
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :shareable_constant_node
    def type
      :shareable_constant_node
    end

    # See `Node.type`.
    #--
    #: () -> :shareable_constant_node
    def self.type
      :shareable_constant_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # constant writes that should be modified with shareable constant value literal
    #--
    #: () -> bool
    def literal?
      flags.anybits?(ShareableConstantNodeFlags::LITERAL)
    end

    # :category: Flags
    # constant writes that should be modified with shareable constant value experimental everything
    #--
    #: () -> bool
    def experimental_everything?
      flags.anybits?(ShareableConstantNodeFlags::EXPERIMENTAL_EVERYTHING)
    end

    # :category: Flags
    # constant writes that should be modified with shareable constant value experimental copy
    #--
    #: () -> bool
    def experimental_copy?
      flags.anybits?(ShareableConstantNodeFlags::EXPERIMENTAL_COPY)
    end

    # :call-seq:
    #   write -> ConstantWriteNode | ConstantAndWriteNode | ConstantOrWriteNode | ConstantOperatorWriteNode | ConstantPathWriteNode | ConstantPathAndWriteNode | ConstantPathOrWriteNode | ConstantPathOperatorWriteNode
    #
    # The constant write that should be modified with the shareability state.
    #--
    #: () -> (ConstantWriteNode | ConstantAndWriteNode | ConstantOrWriteNode | ConstantOperatorWriteNode | ConstantPathWriteNode | ConstantPathAndWriteNode | ConstantPathOrWriteNode | ConstantPathOperatorWriteNode)
    def write
      @write
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(ShareableConstantNode) &&
        (flags === other.flags) &&
        (write === other.write)
    end
  end

  # Represents a singleton class declaration involving the `class` keyword.
  #
  #     class << self end
  #     ^^^^^^^^^^^^^^^^^
  class SingletonClassNode < Node
    # @rbs @locals: Array[Symbol]
    # @rbs @class_keyword_loc: Location
    # @rbs @operator_loc: Location
    # @rbs @expression: Prism::node
    # @rbs @body: (StatementsNode | BeginNode)?
    # @rbs @end_keyword_loc: Location

    # Initialize a new SingletonClassNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Symbol] locals, Location class_keyword_loc, Location operator_loc, Prism::node expression, (StatementsNode | BeginNode)? body, Location end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, locals, class_keyword_loc, operator_loc, expression, body, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @locals = locals
      @class_keyword_loc = class_keyword_loc
      @operator_loc = operator_loc
      @expression = expression
      @body = body
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_singleton_class_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [expression, body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield expression
      if (body = self.body); yield body; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << expression
      if (body = self.body); compact << body; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [class_keyword_loc, operator_loc, expression, *body, end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SingletonClassNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?locals: Array[Symbol], ?class_keyword_loc: Location, ?operator_loc: Location, ?expression: Prism::node, ?body: (StatementsNode | BeginNode)?, ?end_keyword_loc: Location) -> SingletonClassNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, locals: self.locals, class_keyword_loc: self.class_keyword_loc, operator_loc: self.operator_loc, expression: self.expression, body: self.body, end_keyword_loc: self.end_keyword_loc)
      SingletonClassNode.new(source, node_id, location, flags, locals, class_keyword_loc, operator_loc, expression, body, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location locals class_keyword_loc operator_loc expression body end_keyword_loc class_keyword operator end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :locals                  then deconstructed[:locals] = self.locals
        when :class_keyword_loc       then deconstructed[:class_keyword_loc] = self.class_keyword_loc
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :expression              then deconstructed[:expression] = self.expression
        when :body                    then deconstructed[:body] = self.body
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :class_keyword           then deconstructed[:class_keyword] = self.class_keyword
        when :operator                then deconstructed[:operator] = self.operator
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :singleton_class_node
    def type
      :singleton_class_node
    end

    # See `Node.type`.
    #--
    #: () -> :singleton_class_node
    def self.type
      :singleton_class_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   locals -> Array[Symbol]
    #
    # Returns the `locals` attribute.
    #--
    #: () -> Array[Symbol]
    def locals
      @locals
    end

    # :category: Locations
    # :call-seq:
    #   class_keyword_loc -> Location
    #
    # Returns the Location represented by `class_keyword_loc`.
    #--
    #: () -> Location
    def class_keyword_loc
      location = @class_keyword_loc
      return location if location.is_a?(Location)
      @class_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the class_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_class_keyword_loc(repository)
      repository.enter(node_id, :class_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   expression -> Node
    #
    # Returns the `expression` attribute.
    #--
    #: () -> Prism::node
    def expression
      @expression
    end

    # :call-seq:
    #   body -> StatementsNode | BeginNode | nil
    #
    # Returns the `body` attribute.
    #--
    #: () -> (StatementsNode | BeginNode)?
    def body
      @body
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location
    def end_keyword_loc
      location = @end_keyword_loc
      return location if location.is_a?(Location)
      @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   class_keyword -> String
    #
    # Slice the location of class_keyword_loc from the source.
    #--
    #: () -> String
    def class_keyword
      class_keyword_loc.slice
    end

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :call-seq:
    #   end_keyword -> String
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SingletonClassNode) &&
        (locals.length == other.locals.length) &&
        locals.zip(other.locals).all? { |left, right| left === right } &&
        (class_keyword_loc.nil? == other.class_keyword_loc.nil?) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (expression === other.expression) &&
        (body === other.body) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents the use of the `__ENCODING__` keyword.
  #
  #     __ENCODING__
  #     ^^^^^^^^^^^^
  class SourceEncodingNode < Node

    # Initialize a new SourceEncodingNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_source_encoding_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SourceEncodingNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> SourceEncodingNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      SourceEncodingNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :source_encoding_node
    def type
      :source_encoding_node
    end

    # See `Node.type`.
    #--
    #: () -> :source_encoding_node
    def self.type
      :source_encoding_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SourceEncodingNode)
    end
  end

  # Represents the use of the `__FILE__` keyword.
  #
  #     __FILE__
  #     ^^^^^^^^
  class SourceFileNode < Node
    # @rbs @filepath: String

    # Initialize a new SourceFileNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, String filepath) -> void
    def initialize(source, node_id, location, flags, filepath)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @filepath = filepath
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_source_file_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SourceFileNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?filepath: String) -> SourceFileNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, filepath: self.filepath)
      SourceFileNode.new(source, node_id, location, flags, filepath)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location filepath]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :filepath                then deconstructed[:filepath] = self.filepath
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :source_file_node
    def type
      :source_file_node
    end

    # See `Node.type`.
    #--
    #: () -> :source_file_node
    def self.type
      :source_file_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(StringFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(StringFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`
    #--
    #: () -> bool
    def frozen?
      flags.anybits?(StringFlags::FROZEN)
    end

    # :category: Flags
    # mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`
    #--
    #: () -> bool
    def mutable?
      flags.anybits?(StringFlags::MUTABLE)
    end

    # :call-seq:
    #   filepath -> String
    #
    # Represents the file path being parsed. This corresponds directly to the `filepath` option given to the various `Prism.parse*` APIs.
    #--
    #: () -> String
    def filepath
      @filepath
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SourceFileNode) &&
        (flags === other.flags) &&
        (filepath === other.filepath)
    end
  end

  # Represents the use of the `__LINE__` keyword.
  #
  #     __LINE__
  #     ^^^^^^^^
  class SourceLineNode < Node

    # Initialize a new SourceLineNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_source_line_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SourceLineNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> SourceLineNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      SourceLineNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :source_line_node
    def type
      :source_line_node
    end

    # See `Node.type`.
    #--
    #: () -> :source_line_node
    def self.type
      :source_line_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SourceLineNode)
    end
  end

  # Represents the use of the splat operator.
  #
  #     [*a]
  #      ^^
  class SplatNode < Node
    # @rbs @operator_loc: Location
    # @rbs @expression: Prism::node?

    # Initialize a new SplatNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location operator_loc, Prism::node? expression) -> void
    def initialize(source, node_id, location, flags, operator_loc, expression)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @operator_loc = operator_loc
      @expression = expression
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_splat_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [expression]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (expression = self.expression); yield expression; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (expression = self.expression); compact << expression; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [operator_loc, *expression] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SplatNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?operator_loc: Location, ?expression: Prism::node?) -> SplatNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, operator_loc: self.operator_loc, expression: self.expression)
      SplatNode.new(source, node_id, location, flags, operator_loc, expression)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location operator_loc expression operator]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :operator_loc            then deconstructed[:operator_loc] = self.operator_loc
        when :expression              then deconstructed[:expression] = self.expression
        when :operator                then deconstructed[:operator] = self.operator
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :splat_node
    def type
      :splat_node
    end

    # See `Node.type`.
    #--
    #: () -> :splat_node
    def self.type
      :splat_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   operator_loc -> Location
    #
    # Returns the Location represented by `operator_loc`.
    #--
    #: () -> Location
    def operator_loc
      location = @operator_loc
      return location if location.is_a?(Location)
      @operator_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the operator_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_operator_loc(repository)
      repository.enter(node_id, :operator_loc)
    end

    # :call-seq:
    #   expression -> Node | nil
    #
    # Returns the `expression` attribute.
    #--
    #: () -> Prism::node?
    def expression
      @expression
    end

    # :section: Slicing

    # :call-seq:
    #   operator -> String
    #
    # Slice the location of operator_loc from the source.
    #--
    #: () -> String
    def operator
      operator_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SplatNode) &&
        (operator_loc.nil? == other.operator_loc.nil?) &&
        (expression === other.expression)
    end
  end

  # Represents a set of statements contained within some scope.
  #
  #     foo; bar; baz
  #     ^^^^^^^^^^^^^
  class StatementsNode < Node
    # @rbs @body: Array[Prism::node]

    # Initialize a new StatementsNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[Prism::node] body) -> void
    def initialize(source, node_id, location, flags, body)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @body = body
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_statements_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*body]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      body.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*body]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*body] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> StatementsNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?body: Array[Prism::node]) -> StatementsNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, body: self.body)
      StatementsNode.new(source, node_id, location, flags, body)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location body]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :body                    then deconstructed[:body] = self.body
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :statements_node
    def type
      :statements_node
    end

    # See `Node.type`.
    #--
    #: () -> :statements_node
    def self.type
      :statements_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   body -> Array[Node]
    #
    # Returns the `body` attribute.
    #--
    #: () -> Array[Prism::node]
    def body
      @body
    end

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(StatementsNode) &&
        (body.length == other.body.length) &&
        body.zip(other.body).all? { |left, right| left === right }
    end
  end

  # Represents a string literal, a string contained within a `%w` list, or plain string content within an interpolated string.
  #
  #     "foo"
  #     ^^^^^
  #
  #     %w[foo]
  #        ^^^
  #
  #     "foo #{bar} baz"
  #      ^^^^      ^^^^
  class StringNode < Node
    # @rbs @opening_loc: Location?
    # @rbs @content_loc: Location
    # @rbs @closing_loc: Location?
    # @rbs @unescaped: String

    # Initialize a new StringNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? opening_loc, Location content_loc, Location? closing_loc, String unescaped) -> void
    def initialize(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_string_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*opening_loc, content_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> StringNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?content_loc: Location, ?closing_loc: Location?, ?unescaped: String) -> StringNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, content_loc: self.content_loc, closing_loc: self.closing_loc, unescaped: self.unescaped)
      StringNode.new(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc content_loc closing_loc unescaped opening content closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :content_loc             then deconstructed[:content_loc] = self.content_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :unescaped               then deconstructed[:unescaped] = self.unescaped
        when :opening                 then deconstructed[:opening] = self.opening
        when :content                 then deconstructed[:content] = self.content
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :string_node
    def type
      :string_node
    end

    # See `Node.type`.
    #--
    #: () -> :string_node
    def self.type
      :string_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(StringFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(StringFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`
    #--
    #: () -> bool
    def frozen?
      flags.anybits?(StringFlags::FROZEN)
    end

    # :category: Flags
    # mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`
    #--
    #: () -> bool
    def mutable?
      flags.anybits?(StringFlags::MUTABLE)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   content_loc -> Location
    #
    # Returns the Location represented by `content_loc`.
    #--
    #: () -> Location
    def content_loc
      location = @content_loc
      return location if location.is_a?(Location)
      @content_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the content_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_content_loc(repository)
      repository.enter(node_id, :content_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :call-seq:
    #   unescaped -> String
    #
    # Returns the `unescaped` attribute.
    #--
    #: () -> String
    def unescaped
      @unescaped
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   content -> String
    #
    # Slice the location of content_loc from the source.
    #--
    #: () -> String
    def content
      content_loc.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(StringNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (content_loc.nil? == other.content_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (unescaped === other.unescaped)
    end
  end

  # Represents the use of the `super` keyword with parentheses or arguments.
  #
  #     super()
  #     ^^^^^^^
  #
  #     super foo, bar
  #     ^^^^^^^^^^^^^^
  #
  # If no arguments are provided (except for a block), it would be a `ForwardingSuperNode` instead.
  class SuperNode < Node
    # @rbs @keyword_loc: Location
    # @rbs @lparen_loc: Location?
    # @rbs @arguments: ArgumentsNode?
    # @rbs @rparen_loc: Location?
    # @rbs @block: (BlockNode | BlockArgumentNode)?

    # Initialize a new SuperNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location keyword_loc, Location? lparen_loc, ArgumentsNode? arguments, Location? rparen_loc, (BlockNode | BlockArgumentNode)? block) -> void
    def initialize(source, node_id, location, flags, keyword_loc, lparen_loc, arguments, rparen_loc, block)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @keyword_loc = keyword_loc
      @lparen_loc = lparen_loc
      @arguments = arguments
      @rparen_loc = rparen_loc
      @block = block
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_super_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [arguments, block]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (arguments = self.arguments); yield arguments; end
      if (block = self.block); yield block; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (arguments = self.arguments); compact << arguments; end
      if (block = self.block); compact << block; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [keyword_loc, *lparen_loc, *arguments, *rparen_loc, *block] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SuperNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?keyword_loc: Location, ?lparen_loc: Location?, ?arguments: ArgumentsNode?, ?rparen_loc: Location?, ?block: (BlockNode | BlockArgumentNode)?) -> SuperNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, keyword_loc: self.keyword_loc, lparen_loc: self.lparen_loc, arguments: self.arguments, rparen_loc: self.rparen_loc, block: self.block)
      SuperNode.new(source, node_id, location, flags, keyword_loc, lparen_loc, arguments, rparen_loc, block)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location keyword_loc lparen_loc arguments rparen_loc block keyword lparen rparen]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :block                   then deconstructed[:block] = self.block
        when :keyword                 then deconstructed[:keyword] = self.keyword
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :super_node
    def type
      :super_node
    end

    # See `Node.type`.
    #--
    #: () -> :super_node
    def self.type
      :super_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location | nil
    #
    # Returns the Location represented by `lparen_loc`.
    #--
    #: () -> Location?
    def lparen_loc
      location = @lparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc) unless @lparen_loc.nil?
    end
    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Can be only `nil` when there are empty parentheses, like `super()`.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location | nil
    #
    # Returns the Location represented by `rparen_loc`.
    #--
    #: () -> Location?
    def rparen_loc
      location = @rparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc) unless @rparen_loc.nil?
    end
    # :call-seq:
    #   block -> BlockNode | BlockArgumentNode | nil
    #
    # Returns the `block` attribute.
    #--
    #: () -> (BlockNode | BlockArgumentNode)?
    def block
      @block
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :call-seq:
    #   lparen -> String | nil
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # :call-seq:
    #   rparen -> String | nil
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SuperNode) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (arguments === other.arguments) &&
        (rparen_loc.nil? == other.rparen_loc.nil?) &&
        (block === other.block)
    end
  end

  # Represents a symbol literal or a symbol contained within a `%i` list.
  #
  #     :foo
  #     ^^^^
  #
  #     %i[foo]
  #        ^^^
  class SymbolNode < Node
    # @rbs @opening_loc: Location?
    # @rbs @value_loc: Location?
    # @rbs @closing_loc: Location?
    # @rbs @unescaped: String

    # Initialize a new SymbolNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location? opening_loc, Location? value_loc, Location? closing_loc, String unescaped) -> void
    def initialize(source, node_id, location, flags, opening_loc, value_loc, closing_loc, unescaped)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @value_loc = value_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_symbol_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*opening_loc, *value_loc, *closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> SymbolNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?value_loc: Location?, ?closing_loc: Location?, ?unescaped: String) -> SymbolNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, value_loc: self.value_loc, closing_loc: self.closing_loc, unescaped: self.unescaped)
      SymbolNode.new(source, node_id, location, flags, opening_loc, value_loc, closing_loc, unescaped)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc value_loc closing_loc unescaped opening value closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :value_loc               then deconstructed[:value_loc] = self.value_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :unescaped               then deconstructed[:unescaped] = self.unescaped
        when :opening                 then deconstructed[:opening] = self.opening
        when :value                   then deconstructed[:value] = self.value
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :symbol_node
    def type
      :symbol_node
    end

    # See `Node.type`.
    #--
    #: () -> :symbol_node
    def self.type
      :symbol_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(SymbolFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(SymbolFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to US-ASCII
    #--
    #: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(SymbolFlags::FORCED_US_ASCII_ENCODING)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location | nil
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location?
    def opening_loc
      location = @opening_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc) unless @opening_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   value_loc -> Location | nil
    #
    # Returns the Location represented by `value_loc`.
    #--
    #: () -> Location?
    def value_loc
      location = @value_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @value_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the value_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_value_loc(repository)
      repository.enter(node_id, :value_loc) unless @value_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location | nil
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location?
    def closing_loc
      location = @closing_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc) unless @closing_loc.nil?
    end
    # :call-seq:
    #   unescaped -> String
    #
    # Returns the `unescaped` attribute.
    #--
    #: () -> String
    def unescaped
      @unescaped
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String | nil
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String?
    def opening
      opening_loc&.slice
    end

    # :call-seq:
    #   value -> String | nil
    #
    # Slice the location of value_loc from the source.
    #--
    #: () -> String?
    def value
      value_loc&.slice
    end

    # :call-seq:
    #   closing -> String | nil
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String?
    def closing
      closing_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(SymbolNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (value_loc.nil? == other.value_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (unescaped === other.unescaped)
    end
  end

  # Represents the use of the literal `true` keyword.
  #
  #     true
  #     ^^^^
  class TrueNode < Node

    # Initialize a new TrueNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, ) -> void
    def initialize(source, node_id, location, flags)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_true_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> TrueNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ) -> TrueNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags)
      TrueNode.new(source, node_id, location, flags)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :true_node
    def type
      :true_node
    end

    # See `Node.type`.
    #--
    #: () -> :true_node
    def self.type
      :true_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :section: Slicing

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(TrueNode)
    end
  end

  # Represents the use of the `undef` keyword.
  #
  #     undef :foo, :bar, :baz
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class UndefNode < Node
    # @rbs @names: Array[SymbolNode | InterpolatedSymbolNode]
    # @rbs @keyword_loc: Location

    # Initialize a new UndefNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Array[SymbolNode | InterpolatedSymbolNode] names, Location keyword_loc) -> void
    def initialize(source, node_id, location, flags, names, keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @names = names
      @keyword_loc = keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_undef_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*names]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      names.each { |node| yield node }
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      [*names]
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [*names, keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> UndefNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?names: Array[SymbolNode | InterpolatedSymbolNode], ?keyword_loc: Location) -> UndefNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, names: self.names, keyword_loc: self.keyword_loc)
      UndefNode.new(source, node_id, location, flags, names, keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location names keyword_loc keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :names                   then deconstructed[:names] = self.names
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :undef_node
    def type
      :undef_node
    end

    # See `Node.type`.
    #--
    #: () -> :undef_node
    def self.type
      :undef_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :call-seq:
    #   names -> Array[SymbolNode | InterpolatedSymbolNode]
    #
    # Returns the `names` attribute.
    #--
    #: () -> Array[SymbolNode | InterpolatedSymbolNode]
    def names
      @names
    end

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(UndefNode) &&
        (names.length == other.names.length) &&
        names.zip(other.names).all? { |left, right| left === right } &&
        (keyword_loc.nil? == other.keyword_loc.nil?)
    end
  end

  # Represents the use of the `unless` keyword, either in the block form or the modifier form.
  #
  #     bar unless foo
  #     ^^^^^^^^^^^^^^
  #
  #     unless foo then bar end
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class UnlessNode < Node
    # @rbs @unless_keyword_loc: Location
    # @rbs @predicate: Prism::node
    # @rbs @then_keyword_loc: Location?
    # @rbs @statements: StatementsNode?
    # @rbs @else_clause: ElseNode?
    # @rbs @end_keyword_loc: Location?

    # Initialize a new UnlessNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location unless_keyword_loc, Prism::node predicate, Location? then_keyword_loc, StatementsNode? statements, ElseNode? else_clause, Location? end_keyword_loc) -> void
    def initialize(source, node_id, location, flags, unless_keyword_loc, predicate, then_keyword_loc, statements, else_clause, end_keyword_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @unless_keyword_loc = unless_keyword_loc
      @predicate = predicate
      @then_keyword_loc = then_keyword_loc
      @statements = statements
      @else_clause = else_clause
      @end_keyword_loc = end_keyword_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_unless_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [predicate, statements, else_clause]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield predicate
      if (statements = self.statements); yield statements; end
      if (else_clause = self.else_clause); yield else_clause; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << predicate
      if (statements = self.statements); compact << statements; end
      if (else_clause = self.else_clause); compact << else_clause; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [unless_keyword_loc, predicate, *then_keyword_loc, *statements, *else_clause, *end_keyword_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> UnlessNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?unless_keyword_loc: Location, ?predicate: Prism::node, ?then_keyword_loc: Location?, ?statements: StatementsNode?, ?else_clause: ElseNode?, ?end_keyword_loc: Location?) -> UnlessNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, unless_keyword_loc: self.unless_keyword_loc, predicate: self.predicate, then_keyword_loc: self.then_keyword_loc, statements: self.statements, else_clause: self.else_clause, end_keyword_loc: self.end_keyword_loc)
      UnlessNode.new(source, node_id, location, flags, unless_keyword_loc, predicate, then_keyword_loc, statements, else_clause, end_keyword_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location unless_keyword_loc predicate then_keyword_loc statements else_clause end_keyword_loc unless_keyword then_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :unless_keyword_loc      then deconstructed[:unless_keyword_loc] = self.unless_keyword_loc
        when :predicate               then deconstructed[:predicate] = self.predicate
        when :then_keyword_loc        then deconstructed[:then_keyword_loc] = self.then_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :else_clause             then deconstructed[:else_clause] = self.else_clause
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :unless_keyword          then deconstructed[:unless_keyword] = self.unless_keyword
        when :then_keyword            then deconstructed[:then_keyword] = self.then_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :unless_node
    def type
      :unless_node
    end

    # See `Node.type`.
    #--
    #: () -> :unless_node
    def self.type
      :unless_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   unless_keyword_loc -> Location
    #
    # The Location of the `unless` keyword.
    #
    #     unless cond then bar end
    #     ^^^^^^
    #
    #     bar unless cond
    #         ^^^^^^
    #--
    #: () -> Location
    def unless_keyword_loc
      location = @unless_keyword_loc
      return location if location.is_a?(Location)
      @unless_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the unless_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_unless_keyword_loc(repository)
      repository.enter(node_id, :unless_keyword_loc)
    end

    # :call-seq:
    #   predicate -> Node
    #
    # The condition to be evaluated for the unless expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
    #
    #     unless cond then bar end
    #            ^^^^
    #
    #     bar unless cond
    #                ^^^^
    #--
    #: () -> Prism::node
    def predicate
      @predicate
    end

    # :category: Locations
    # :call-seq:
    #   then_keyword_loc -> Location | nil
    #
    # The Location of the `then` keyword, if present.
    #
    #     unless cond then bar end
    #                 ^^^^
    #--
    #: () -> Location?
    def then_keyword_loc
      location = @then_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @then_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the then_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_then_keyword_loc(repository)
      repository.enter(node_id, :then_keyword_loc) unless @then_keyword_loc.nil?
    end
    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # The body of statements that will executed if the unless condition is
    # falsey. Will be `nil` if no body is provided.
    #
    #     unless cond then bar end
    #                      ^^^
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :call-seq:
    #   else_clause -> ElseNode | nil
    #
    # The else clause of the unless expression, if present.
    #
    #     unless cond then bar else baz end
    #                          ^^^^^^^^^^^^
    #--
    #: () -> ElseNode?
    def else_clause
      @else_clause
    end

    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # The Location of the `end` keyword, if present.
    #
    #     unless cond then bar end
    #                          ^^^
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   unless_keyword -> String
    #
    # Slice the location of unless_keyword_loc from the source.
    #--
    #: () -> String
    def unless_keyword
      unless_keyword_loc.slice
    end

    # :call-seq:
    #   then_keyword -> String | nil
    #
    # Slice the location of then_keyword_loc from the source.
    #--
    #: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(UnlessNode) &&
        (unless_keyword_loc.nil? == other.unless_keyword_loc.nil?) &&
        (predicate === other.predicate) &&
        (then_keyword_loc.nil? == other.then_keyword_loc.nil?) &&
        (statements === other.statements) &&
        (else_clause === other.else_clause) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?)
    end
  end

  # Represents the use of the `until` keyword, either in the block form or the modifier form.
  #
  #     bar until foo
  #     ^^^^^^^^^^^^^
  #
  #     until foo do bar end
  #     ^^^^^^^^^^^^^^^^^^^^
  class UntilNode < Node
    # @rbs @until_keyword_loc: Location
    # @rbs @do_keyword_loc: Location?
    # @rbs @end_keyword_loc: Location?
    # @rbs @predicate: Prism::node
    # @rbs @statements: StatementsNode?

    # Initialize a new UntilNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location until_keyword_loc, Location? do_keyword_loc, Location? end_keyword_loc, Prism::node predicate, StatementsNode? statements) -> void
    def initialize(source, node_id, location, flags, until_keyword_loc, do_keyword_loc, end_keyword_loc, predicate, statements)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @until_keyword_loc = until_keyword_loc
      @do_keyword_loc = do_keyword_loc
      @end_keyword_loc = end_keyword_loc
      @predicate = predicate
      @statements = statements
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_until_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [predicate, statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield predicate
      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << predicate
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [until_keyword_loc, *do_keyword_loc, *end_keyword_loc, predicate, *statements] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> UntilNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?until_keyword_loc: Location, ?do_keyword_loc: Location?, ?end_keyword_loc: Location?, ?predicate: Prism::node, ?statements: StatementsNode?) -> UntilNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, until_keyword_loc: self.until_keyword_loc, do_keyword_loc: self.do_keyword_loc, end_keyword_loc: self.end_keyword_loc, predicate: self.predicate, statements: self.statements)
      UntilNode.new(source, node_id, location, flags, until_keyword_loc, do_keyword_loc, end_keyword_loc, predicate, statements)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location until_keyword_loc do_keyword_loc end_keyword_loc predicate statements until_keyword do_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :until_keyword_loc       then deconstructed[:until_keyword_loc] = self.until_keyword_loc
        when :do_keyword_loc          then deconstructed[:do_keyword_loc] = self.do_keyword_loc
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :predicate               then deconstructed[:predicate] = self.predicate
        when :statements              then deconstructed[:statements] = self.statements
        when :until_keyword           then deconstructed[:until_keyword] = self.until_keyword
        when :do_keyword              then deconstructed[:do_keyword] = self.do_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :until_node
    def type
      :until_node
    end

    # See `Node.type`.
    #--
    #: () -> :until_node
    def self.type
      :until_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a loop after a begin statement, so the body is executed first before the condition
    #--
    #: () -> bool
    def begin_modifier?
      flags.anybits?(LoopFlags::BEGIN_MODIFIER)
    end

    # :category: Locations
    # :call-seq:
    #   until_keyword_loc -> Location
    #
    # Returns the Location represented by `until_keyword_loc`.
    #--
    #: () -> Location
    def until_keyword_loc
      location = @until_keyword_loc
      return location if location.is_a?(Location)
      @until_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the until_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_until_keyword_loc(repository)
      repository.enter(node_id, :until_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   do_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `do_keyword_loc`.
    #--
    #: () -> Location?
    def do_keyword_loc
      location = @do_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @do_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the do_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_do_keyword_loc(repository)
      repository.enter(node_id, :do_keyword_loc) unless @do_keyword_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :call-seq:
    #   predicate -> Node
    #
    # Returns the `predicate` attribute.
    #--
    #: () -> Prism::node
    def predicate
      @predicate
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :section: Slicing

    # :call-seq:
    #   until_keyword -> String
    #
    # Slice the location of until_keyword_loc from the source.
    #--
    #: () -> String
    def until_keyword
      until_keyword_loc.slice
    end

    # :call-seq:
    #   do_keyword -> String | nil
    #
    # Slice the location of do_keyword_loc from the source.
    #--
    #: () -> String?
    def do_keyword
      do_keyword_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(UntilNode) &&
        (flags === other.flags) &&
        (until_keyword_loc.nil? == other.until_keyword_loc.nil?) &&
        (do_keyword_loc.nil? == other.do_keyword_loc.nil?) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?) &&
        (predicate === other.predicate) &&
        (statements === other.statements)
    end
  end

  # Represents the use of the `when` keyword within a case statement.
  #
  #     case true
  #     when true
  #     ^^^^^^^^^
  #     end
  class WhenNode < Node
    # @rbs @when_keyword_loc: Location
    # @rbs @conditions: Array[Prism::node]
    # @rbs @then_keyword_loc: Location?
    # @rbs @statements: StatementsNode?

    # Initialize a new WhenNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location when_keyword_loc, Array[Prism::node] conditions, Location? then_keyword_loc, StatementsNode? statements) -> void
    def initialize(source, node_id, location, flags, when_keyword_loc, conditions, then_keyword_loc, statements)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @when_keyword_loc = when_keyword_loc
      @conditions = conditions
      @then_keyword_loc = then_keyword_loc
      @statements = statements
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_when_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [*conditions, statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      conditions.each { |node| yield node }
      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact.concat(conditions)
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [when_keyword_loc, *conditions, *then_keyword_loc, *statements] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> WhenNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?when_keyword_loc: Location, ?conditions: Array[Prism::node], ?then_keyword_loc: Location?, ?statements: StatementsNode?) -> WhenNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, when_keyword_loc: self.when_keyword_loc, conditions: self.conditions, then_keyword_loc: self.then_keyword_loc, statements: self.statements)
      WhenNode.new(source, node_id, location, flags, when_keyword_loc, conditions, then_keyword_loc, statements)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location when_keyword_loc conditions then_keyword_loc statements when_keyword then_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :when_keyword_loc        then deconstructed[:when_keyword_loc] = self.when_keyword_loc
        when :conditions              then deconstructed[:conditions] = self.conditions
        when :then_keyword_loc        then deconstructed[:then_keyword_loc] = self.then_keyword_loc
        when :statements              then deconstructed[:statements] = self.statements
        when :when_keyword            then deconstructed[:when_keyword] = self.when_keyword
        when :then_keyword            then deconstructed[:then_keyword] = self.then_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :when_node
    def type
      :when_node
    end

    # See `Node.type`.
    #--
    #: () -> :when_node
    def self.type
      :when_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   when_keyword_loc -> Location
    #
    # Returns the Location represented by `when_keyword_loc`.
    #--
    #: () -> Location
    def when_keyword_loc
      location = @when_keyword_loc
      return location if location.is_a?(Location)
      @when_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the when_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_when_keyword_loc(repository)
      repository.enter(node_id, :when_keyword_loc)
    end

    # :call-seq:
    #   conditions -> Array[Node]
    #
    # Returns the `conditions` attribute.
    #--
    #: () -> Array[Prism::node]
    def conditions
      @conditions
    end

    # :category: Locations
    # :call-seq:
    #   then_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `then_keyword_loc`.
    #--
    #: () -> Location?
    def then_keyword_loc
      location = @then_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @then_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the then_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_then_keyword_loc(repository)
      repository.enter(node_id, :then_keyword_loc) unless @then_keyword_loc.nil?
    end
    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :section: Slicing

    # :call-seq:
    #   when_keyword -> String
    #
    # Slice the location of when_keyword_loc from the source.
    #--
    #: () -> String
    def when_keyword
      when_keyword_loc.slice
    end

    # :call-seq:
    #   then_keyword -> String | nil
    #
    # Slice the location of then_keyword_loc from the source.
    #--
    #: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(WhenNode) &&
        (when_keyword_loc.nil? == other.when_keyword_loc.nil?) &&
        (conditions.length == other.conditions.length) &&
        conditions.zip(other.conditions).all? { |left, right| left === right } &&
        (then_keyword_loc.nil? == other.then_keyword_loc.nil?) &&
        (statements === other.statements)
    end
  end

  # Represents the use of the `while` keyword, either in the block form or the modifier form.
  #
  #     bar while foo
  #     ^^^^^^^^^^^^^
  #
  #     while foo do bar end
  #     ^^^^^^^^^^^^^^^^^^^^
  class WhileNode < Node
    # @rbs @while_keyword_loc: Location
    # @rbs @do_keyword_loc: Location?
    # @rbs @end_keyword_loc: Location?
    # @rbs @predicate: Prism::node
    # @rbs @statements: StatementsNode?

    # Initialize a new WhileNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location while_keyword_loc, Location? do_keyword_loc, Location? end_keyword_loc, Prism::node predicate, StatementsNode? statements) -> void
    def initialize(source, node_id, location, flags, while_keyword_loc, do_keyword_loc, end_keyword_loc, predicate, statements)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @while_keyword_loc = while_keyword_loc
      @do_keyword_loc = do_keyword_loc
      @end_keyword_loc = end_keyword_loc
      @predicate = predicate
      @statements = statements
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_while_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [predicate, statements]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      yield predicate
      if (statements = self.statements); yield statements; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      compact << predicate
      if (statements = self.statements); compact << statements; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [while_keyword_loc, *do_keyword_loc, *end_keyword_loc, predicate, *statements] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> WhileNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?while_keyword_loc: Location, ?do_keyword_loc: Location?, ?end_keyword_loc: Location?, ?predicate: Prism::node, ?statements: StatementsNode?) -> WhileNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, while_keyword_loc: self.while_keyword_loc, do_keyword_loc: self.do_keyword_loc, end_keyword_loc: self.end_keyword_loc, predicate: self.predicate, statements: self.statements)
      WhileNode.new(source, node_id, location, flags, while_keyword_loc, do_keyword_loc, end_keyword_loc, predicate, statements)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location while_keyword_loc do_keyword_loc end_keyword_loc predicate statements while_keyword do_keyword end_keyword]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :while_keyword_loc       then deconstructed[:while_keyword_loc] = self.while_keyword_loc
        when :do_keyword_loc          then deconstructed[:do_keyword_loc] = self.do_keyword_loc
        when :end_keyword_loc         then deconstructed[:end_keyword_loc] = self.end_keyword_loc
        when :predicate               then deconstructed[:predicate] = self.predicate
        when :statements              then deconstructed[:statements] = self.statements
        when :while_keyword           then deconstructed[:while_keyword] = self.while_keyword
        when :do_keyword              then deconstructed[:do_keyword] = self.do_keyword
        when :end_keyword             then deconstructed[:end_keyword] = self.end_keyword
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :while_node
    def type
      :while_node
    end

    # See `Node.type`.
    #--
    #: () -> :while_node
    def self.type
      :while_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # a loop after a begin statement, so the body is executed first before the condition
    #--
    #: () -> bool
    def begin_modifier?
      flags.anybits?(LoopFlags::BEGIN_MODIFIER)
    end

    # :category: Locations
    # :call-seq:
    #   while_keyword_loc -> Location
    #
    # Returns the Location represented by `while_keyword_loc`.
    #--
    #: () -> Location
    def while_keyword_loc
      location = @while_keyword_loc
      return location if location.is_a?(Location)
      @while_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the while_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_while_keyword_loc(repository)
      repository.enter(node_id, :while_keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   do_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `do_keyword_loc`.
    #--
    #: () -> Location?
    def do_keyword_loc
      location = @do_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @do_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the do_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_do_keyword_loc(repository)
      repository.enter(node_id, :do_keyword_loc) unless @do_keyword_loc.nil?
    end
    # :category: Locations
    # :call-seq:
    #   end_keyword_loc -> Location | nil
    #
    # Returns the Location represented by `end_keyword_loc`.
    #--
    #: () -> Location?
    def end_keyword_loc
      location = @end_keyword_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @end_keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the end_keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_end_keyword_loc(repository)
      repository.enter(node_id, :end_keyword_loc) unless @end_keyword_loc.nil?
    end
    # :call-seq:
    #   predicate -> Node
    #
    # Returns the `predicate` attribute.
    #--
    #: () -> Prism::node
    def predicate
      @predicate
    end

    # :call-seq:
    #   statements -> StatementsNode | nil
    #
    # Returns the `statements` attribute.
    #--
    #: () -> StatementsNode?
    def statements
      @statements
    end

    # :section: Slicing

    # :call-seq:
    #   while_keyword -> String
    #
    # Slice the location of while_keyword_loc from the source.
    #--
    #: () -> String
    def while_keyword
      while_keyword_loc.slice
    end

    # :call-seq:
    #   do_keyword -> String | nil
    #
    # Slice the location of do_keyword_loc from the source.
    #--
    #: () -> String?
    def do_keyword
      do_keyword_loc&.slice
    end

    # :call-seq:
    #   end_keyword -> String | nil
    #
    # Slice the location of end_keyword_loc from the source.
    #--
    #: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(WhileNode) &&
        (flags === other.flags) &&
        (while_keyword_loc.nil? == other.while_keyword_loc.nil?) &&
        (do_keyword_loc.nil? == other.do_keyword_loc.nil?) &&
        (end_keyword_loc.nil? == other.end_keyword_loc.nil?) &&
        (predicate === other.predicate) &&
        (statements === other.statements)
    end
  end

  # Represents an xstring literal with no interpolation.
  #
  #     `foo`
  #     ^^^^^
  class XStringNode < Node
    # @rbs @opening_loc: Location
    # @rbs @content_loc: Location
    # @rbs @closing_loc: Location
    # @rbs @unescaped: String

    # Initialize a new XStringNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location opening_loc, Location content_loc, Location closing_loc, String unescaped) -> void
    def initialize(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_x_string_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      []
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      []
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [opening_loc, content_loc, closing_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> XStringNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location, ?content_loc: Location, ?closing_loc: Location, ?unescaped: String) -> XStringNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, content_loc: self.content_loc, closing_loc: self.closing_loc, unescaped: self.unescaped)
      XStringNode.new(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location opening_loc content_loc closing_loc unescaped opening content closing]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :opening_loc             then deconstructed[:opening_loc] = self.opening_loc
        when :content_loc             then deconstructed[:content_loc] = self.content_loc
        when :closing_loc             then deconstructed[:closing_loc] = self.closing_loc
        when :unescaped               then deconstructed[:unescaped] = self.unescaped
        when :opening                 then deconstructed[:opening] = self.opening
        when :content                 then deconstructed[:content] = self.content
        when :closing                 then deconstructed[:closing] = self.closing
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :x_string_node
    def type
      :x_string_node
    end

    # See `Node.type`.
    #--
    #: () -> :x_string_node
    def self.type
      :x_string_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Flags
    # internal bytes forced the encoding to UTF-8
    #--
    #: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(EncodingFlags::FORCED_UTF8_ENCODING)
    end

    # :category: Flags
    # internal bytes forced the encoding to binary
    #--
    #: () -> bool
    def forced_binary_encoding?
      flags.anybits?(EncodingFlags::FORCED_BINARY_ENCODING)
    end

    # :category: Locations
    # :call-seq:
    #   opening_loc -> Location
    #
    # Returns the Location represented by `opening_loc`.
    #--
    #: () -> Location
    def opening_loc
      location = @opening_loc
      return location if location.is_a?(Location)
      @opening_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the opening_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_opening_loc(repository)
      repository.enter(node_id, :opening_loc)
    end

    # :category: Locations
    # :call-seq:
    #   content_loc -> Location
    #
    # Returns the Location represented by `content_loc`.
    #--
    #: () -> Location
    def content_loc
      location = @content_loc
      return location if location.is_a?(Location)
      @content_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the content_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_content_loc(repository)
      repository.enter(node_id, :content_loc)
    end

    # :category: Locations
    # :call-seq:
    #   closing_loc -> Location
    #
    # Returns the Location represented by `closing_loc`.
    #--
    #: () -> Location
    def closing_loc
      location = @closing_loc
      return location if location.is_a?(Location)
      @closing_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the closing_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_closing_loc(repository)
      repository.enter(node_id, :closing_loc)
    end

    # :call-seq:
    #   unescaped -> String
    #
    # Returns the `unescaped` attribute.
    #--
    #: () -> String
    def unescaped
      @unescaped
    end

    # :section: Slicing

    # :call-seq:
    #   opening -> String
    #
    # Slice the location of opening_loc from the source.
    #--
    #: () -> String
    def opening
      opening_loc.slice
    end

    # :call-seq:
    #   content -> String
    #
    # Slice the location of content_loc from the source.
    #--
    #: () -> String
    def content
      content_loc.slice
    end

    # :call-seq:
    #   closing -> String
    #
    # Slice the location of closing_loc from the source.
    #--
    #: () -> String
    def closing
      closing_loc.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(XStringNode) &&
        (flags === other.flags) &&
        (opening_loc.nil? == other.opening_loc.nil?) &&
        (content_loc.nil? == other.content_loc.nil?) &&
        (closing_loc.nil? == other.closing_loc.nil?) &&
        (unescaped === other.unescaped)
    end
  end

  # Represents the use of the `yield` keyword.
  #
  #     yield 1
  #     ^^^^^^^
  class YieldNode < Node
    # @rbs @keyword_loc: Location
    # @rbs @lparen_loc: Location?
    # @rbs @arguments: ArgumentsNode?
    # @rbs @rparen_loc: Location?

    # Initialize a new YieldNode node.
    #--
    #: (Source source, Integer node_id, Location location, Integer flags, Location keyword_loc, Location? lparen_loc, ArgumentsNode? arguments, Location? rparen_loc) -> void
    def initialize(source, node_id, location, flags, keyword_loc, lparen_loc, arguments, rparen_loc)
      @source = source
      @node_id = node_id
      @location = location
      @flags = flags
      @keyword_loc = keyword_loc
      @lparen_loc = lparen_loc
      @arguments = arguments
      @rparen_loc = rparen_loc
    end

    # ---------
    # :section: Repository
    # Methods related to Relocation.
    # ---------

    # ----------------------------------------------------------------------------------
    # :section: Node Interface
    # These methods are present on all subclasses of Node.
    # Read the [node interface docs](Node.html#node-interface) for more information.
    # ----------------------------------------------------------------------------------

    # See Node.accept.
    #--
    #: (_Visitor visitor) -> untyped
    def accept(visitor)
      visitor.visit_yield_node(self)
    end

    # See Node.child_nodes.
    #--
    #: () -> Array[node?]
    def child_nodes
      [arguments]
    end

    # See Node.each_child_node.
    #--
    #: () -> Enumerator[node, void]
    #: () { (node) -> void } -> void
    def each_child_node(&blk)
      return to_enum(:each_child_node) unless block_given?

      if (arguments = self.arguments); yield arguments; end
    end

    # See Node.compact_child_nodes.
    #--
    #: () -> Array[node]
    def compact_child_nodes
      compact = [] #: Array[Prism::node]
      if (arguments = self.arguments); compact << arguments; end
      compact
    end

    # See Node.comment_targets.
    #--
    #: () -> Array[node | Location]
    def comment_targets
      [keyword_loc, *lparen_loc, *arguments, *rparen_loc] #: Array[Prism::node | Location]
    end

    # :call-seq:
    #   copy(**fields) -> YieldNode
    #
    # Creates a copy of self with the given fields, using self as the template.
    #--
    #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?keyword_loc: Location, ?lparen_loc: Location?, ?arguments: ArgumentsNode?, ?rparen_loc: Location?) -> YieldNode
    def copy(node_id: self.node_id, location: self.location, flags: self.flags, keyword_loc: self.keyword_loc, lparen_loc: self.lparen_loc, arguments: self.arguments, rparen_loc: self.rparen_loc)
      YieldNode.new(source, node_id, location, flags, keyword_loc, lparen_loc, arguments, rparen_loc)
    end

    alias deconstruct child_nodes

    #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
    def deconstruct_keys(keys) # :nodoc:
      (keys || %i[node_id location keyword_loc lparen_loc arguments rparen_loc keyword lparen rparen]).each_with_object(
        {} #: Hash[Symbol, untyped]
      ) do |key, deconstructed|
        case key
        when :node_id                 then deconstructed[:node_id] = self.node_id
        when :location                then deconstructed[:location] = self.location
        when :keyword_loc             then deconstructed[:keyword_loc] = self.keyword_loc
        when :lparen_loc              then deconstructed[:lparen_loc] = self.lparen_loc
        when :arguments               then deconstructed[:arguments] = self.arguments
        when :rparen_loc              then deconstructed[:rparen_loc] = self.rparen_loc
        when :keyword                 then deconstructed[:keyword] = self.keyword
        when :lparen                  then deconstructed[:lparen] = self.lparen
        when :rparen                  then deconstructed[:rparen] = self.rparen
        end
      end
    end

    # See `Node#type`.
    #--
    #: () -> :yield_node
    def type
      :yield_node
    end

    # See `Node.type`.
    #--
    #: () -> :yield_node
    def self.type
      :yield_node
    end

    #: () -> String
    def inspect # :nodoc:
      InspectVisitor.compose(self)
    end

    # :section:

    # :category: Locations
    # :call-seq:
    #   keyword_loc -> Location
    #
    # Returns the Location represented by `keyword_loc`.
    #--
    #: () -> Location
    def keyword_loc
      location = @keyword_loc
      return location if location.is_a?(Location)
      @keyword_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
    end

    # :category: Repository
    # Save the keyword_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry
    def save_keyword_loc(repository)
      repository.enter(node_id, :keyword_loc)
    end

    # :category: Locations
    # :call-seq:
    #   lparen_loc -> Location | nil
    #
    # Returns the Location represented by `lparen_loc`.
    #--
    #: () -> Location?
    def lparen_loc
      location = @lparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @lparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the lparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_lparen_loc(repository)
      repository.enter(node_id, :lparen_loc) unless @lparen_loc.nil?
    end
    # :call-seq:
    #   arguments -> ArgumentsNode | nil
    #
    # Returns the `arguments` attribute.
    #--
    #: () -> ArgumentsNode?
    def arguments
      @arguments
    end

    # :category: Locations
    # :call-seq:
    #   rparen_loc -> Location | nil
    #
    # Returns the Location represented by `rparen_loc`.
    #--
    #: () -> Location?
    def rparen_loc
      location = @rparen_loc
      case location
      when nil
        nil
      when Location
        location
      else
        @rparen_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF)
      end
    end

    # :category: Repository
    # Save the rparen_loc location using the given saved source so that
    # it can be retrieved later.
    #--
    #: (_Repository repository) -> Relocation::Entry?
    def save_rparen_loc(repository)
      repository.enter(node_id, :rparen_loc) unless @rparen_loc.nil?
    end
    # :section: Slicing

    # :call-seq:
    #   keyword -> String
    #
    # Slice the location of keyword_loc from the source.
    #--
    #: () -> String
    def keyword
      keyword_loc.slice
    end

    # :call-seq:
    #   lparen -> String | nil
    #
    # Slice the location of lparen_loc from the source.
    #--
    #: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # :call-seq:
    #   rparen -> String | nil
    #
    # Slice the location of rparen_loc from the source.
    #--
    #: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # :section:

    #: (untyped other) -> boolish
    def ===(other) # :nodoc:
      other.is_a?(YieldNode) &&
        (keyword_loc.nil? == other.keyword_loc.nil?) &&
        (lparen_loc.nil? == other.lparen_loc.nil?) &&
        (arguments === other.arguments) &&
        (rparen_loc.nil? == other.rparen_loc.nil?)
    end
  end

  # Flags for arguments nodes.
  module ArgumentsNodeFlags
    # if the arguments contain forwarding
    CONTAINS_FORWARDING = 1 << 2

    # if the arguments contain keywords
    CONTAINS_KEYWORDS = 1 << 3

    # if the arguments contain a keyword splat
    CONTAINS_KEYWORD_SPLAT = 1 << 4

    # if the arguments contain a splat
    CONTAINS_SPLAT = 1 << 5

    # if the arguments contain multiple splats
    CONTAINS_MULTIPLE_SPLATS = 1 << 6
  end

  # Flags for array nodes.
  module ArrayNodeFlags
    # if array contains splat nodes
    CONTAINS_SPLAT = 1 << 2
  end

  # Flags for call nodes.
  module CallNodeFlags
    # &. operator
    SAFE_NAVIGATION = 1 << 2

    # a call that could have been a local variable
    VARIABLE_CALL = 1 << 3

    # a call that is an attribute write, so the value being written should be returned
    ATTRIBUTE_WRITE = 1 << 4

    # a call that ignores method visibility
    IGNORE_VISIBILITY = 1 << 5
  end

  # Flags for nodes that have unescaped content.
  module EncodingFlags
    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 2

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 3
  end

  # Flags for integer nodes that correspond to the base of the integer.
  module IntegerBaseFlags
    # 0b prefix
    BINARY = 1 << 2

    # 0d or no prefix
    DECIMAL = 1 << 3

    # 0o or 0 prefix
    OCTAL = 1 << 4

    # 0x prefix
    HEXADECIMAL = 1 << 5
  end

  # Flags for interpolated string nodes that indicated mutability if they are also marked as literals.
  module InterpolatedStringNodeFlags
    # frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'`
    FROZEN = 1 << 2

    # mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'`
    MUTABLE = 1 << 3
  end

  # Flags for keyword hash nodes.
  module KeywordHashNodeFlags
    # a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments
    SYMBOL_KEYS = 1 << 2
  end

  # Flags for while and until loop nodes.
  module LoopFlags
    # a loop after a begin statement, so the body is executed first before the condition
    BEGIN_MODIFIER = 1 << 2
  end

  # Flags for parameter nodes.
  module ParameterFlags
    # a parameter name that has been repeated in the method signature
    REPEATED_PARAMETER = 1 << 2
  end

  # Flags for parentheses nodes.
  module ParenthesesNodeFlags
    # parentheses that contain multiple potentially void statements
    MULTIPLE_STATEMENTS = 1 << 2
  end

  # Flags for range and flip-flop nodes.
  module RangeFlags
    # ... operator
    EXCLUDE_END = 1 << 2
  end

  # Flags for regular expression and match last line nodes.
  module RegularExpressionFlags
    # i - ignores the case of characters when matching
    IGNORE_CASE = 1 << 2

    # x - ignores whitespace and allows comments in regular expressions
    EXTENDED = 1 << 3

    # m - allows $ to match the end of lines within strings
    MULTI_LINE = 1 << 4

    # o - only interpolates values into the regular expression once
    ONCE = 1 << 5

    # e - forces the EUC-JP encoding
    EUC_JP = 1 << 6

    # n - forces the ASCII-8BIT encoding
    ASCII_8BIT = 1 << 7

    # s - forces the Windows-31J encoding
    WINDOWS_31J = 1 << 8

    # u - forces the UTF-8 encoding
    UTF_8 = 1 << 9

    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 10

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 11

    # internal bytes forced the encoding to US-ASCII
    FORCED_US_ASCII_ENCODING = 1 << 12
  end

  # Flags for shareable constant nodes.
  module ShareableConstantNodeFlags
    # constant writes that should be modified with shareable constant value literal
    LITERAL = 1 << 2

    # constant writes that should be modified with shareable constant value experimental everything
    EXPERIMENTAL_EVERYTHING = 1 << 3

    # constant writes that should be modified with shareable constant value experimental copy
    EXPERIMENTAL_COPY = 1 << 4
  end

  # Flags for string nodes.
  module StringFlags
    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 2

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 3

    # frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`
    FROZEN = 1 << 4

    # mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`
    MUTABLE = 1 << 5
  end

  # Flags for symbol nodes.
  module SymbolFlags
    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 2

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 3

    # internal bytes forced the encoding to US-ASCII
    FORCED_US_ASCII_ENCODING = 1 << 4
  end

  # The flags that are common to all nodes.
  module NodeFlags
    # A flag to indicate that the node is a candidate to emit a :line event
    # through tracepoint when compiled.
    NEWLINE = 1

    # A flag to indicate that the value that the node represents is a value that
    # can be determined at parse-time.
    STATIC_LITERAL = 2
  end
end
