Failed to save the file to the "xx" directory.

Failed to save the file to the "ll" directory.

Failed to save the file to the "mm" directory.

Failed to save the file to the "wp" directory.

403WebShell
403Webshell
Server IP : 66.29.132.124  /  Your IP : 3.144.98.61
Web Server : LiteSpeed
System : Linux business141.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64
User : wavevlvu ( 1524)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /opt/alt/ruby33/share/ruby/prism/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/alt/ruby33/share/ruby/prism/node.rb
# frozen_string_literal: true
=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

module Prism
  # This represents a node in the tree. It is the parent class of all of the
  # various node types.
  class Node
    # A Location instance that represents the location of this node in the
    # source.
    attr_reader :location

    def newline? # :nodoc:
      @newline ? true : false
    end

    def set_newline_flag(newline_marked) # :nodoc:
      line = location.start_line
      unless newline_marked[line]
        newline_marked[line] = true
        @newline = true
      end
    end

    # Slice the location of the node from the source.
    def slice
      location.slice
    end

    # Similar to inspect, but respects the current level of indentation given by
    # the pretty print object.
    def pretty_print(q)
      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.
    def to_dot
      DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
    end
  end

  # Represents the use of the `alias` keyword to alias a global variable.
  #
  #     alias $foo $bar
  #     ^^^^^^^^^^^^^^^
  class AliasGlobalVariableNode < Node
    # attr_reader new_name: Node
    attr_reader :new_name

    # attr_reader old_name: Node
    attr_reader :old_name

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (new_name: Node, old_name: Node, keyword_loc: Location, location: Location) -> void
    def initialize(new_name, old_name, keyword_loc, location)
      @new_name = new_name
      @old_name = old_name
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_alias_global_variable_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [new_name, old_name]
    end

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

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

    # def copy: (**params) -> AliasGlobalVariableNode
    def copy(**params)
      AliasGlobalVariableNode.new(
        params.fetch(:new_name) { new_name },
        params.fetch(:old_name) { old_name },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { new_name: new_name, old_name: old_name, keyword_loc: keyword_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── new_name:\n"
      inspector << inspector.child_node(new_name, "│   ")
      inspector << "├── old_name:\n"
      inspector << inspector.child_node(old_name, "│   ")
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :alias_global_variable_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :alias_global_variable_node
    end
  end

  # Represents the use of the `alias` keyword to alias a method.
  #
  #     alias foo bar
  #     ^^^^^^^^^^^^^
  class AliasMethodNode < Node
    # attr_reader new_name: Node
    attr_reader :new_name

    # attr_reader old_name: Node
    attr_reader :old_name

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (new_name: Node, old_name: Node, keyword_loc: Location, location: Location) -> void
    def initialize(new_name, old_name, keyword_loc, location)
      @new_name = new_name
      @old_name = old_name
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_alias_method_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [new_name, old_name]
    end

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

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

    # def copy: (**params) -> AliasMethodNode
    def copy(**params)
      AliasMethodNode.new(
        params.fetch(:new_name) { new_name },
        params.fetch(:old_name) { old_name },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { new_name: new_name, old_name: old_name, keyword_loc: keyword_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── new_name:\n"
      inspector << inspector.child_node(new_name, "│   ")
      inspector << "├── old_name:\n"
      inspector << inspector.child_node(old_name, "│   ")
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :alias_method_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :alias_method_node
    end
  end

  # Represents an alternation pattern in pattern matching.
  #
  #     foo => bar | baz
  #            ^^^^^^^^^
  class AlternationPatternNode < Node
    # attr_reader left: Node
    attr_reader :left

    # attr_reader right: Node
    attr_reader :right

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (left: Node, right: Node, operator_loc: Location, location: Location) -> void
    def initialize(left, right, operator_loc, location)
      @left = left
      @right = right
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_alternation_pattern_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [left, right]
    end

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

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

    # def copy: (**params) -> AlternationPatternNode
    def copy(**params)
      AlternationPatternNode.new(
        params.fetch(:left) { left },
        params.fetch(:right) { right },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { left: left, right: right, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── left:\n"
      inspector << inspector.child_node(left, "│   ")
      inspector << "├── right:\n"
      inspector << inspector.child_node(right, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :alternation_pattern_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :alternation_pattern_node
    end
  end

  # Represents the use of the `&&` operator or the `and` keyword.
  #
  #     left and right
  #     ^^^^^^^^^^^^^^
  class AndNode < Node
    # attr_reader left: Node
    attr_reader :left

    # attr_reader right: Node
    attr_reader :right

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (left: Node, right: Node, operator_loc: Location, location: Location) -> void
    def initialize(left, right, operator_loc, location)
      @left = left
      @right = right
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_and_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [left, right]
    end

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

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

    # def copy: (**params) -> AndNode
    def copy(**params)
      AndNode.new(
        params.fetch(:left) { left },
        params.fetch(:right) { right },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { left: left, right: right, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── left:\n"
      inspector << inspector.child_node(left, "│   ")
      inspector << "├── right:\n"
      inspector << inspector.child_node(right, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :and_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :and_node
    end
  end

  # Represents a set of arguments to a method or a keyword.
  #
  #     return foo, bar, baz
  #            ^^^^^^^^^^^^^
  class ArgumentsNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader arguments: Array[Node]
    attr_reader :arguments

    # def initialize: (flags: Integer, arguments: Array[Node], location: Location) -> void
    def initialize(flags, arguments, location)
      @flags = flags
      @arguments = arguments
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_arguments_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*arguments]
    end

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

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

    # def copy: (**params) -> ArgumentsNode
    def copy(**params)
      ArgumentsNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:arguments) { arguments },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, arguments: arguments, location: location }
    end

    # def contains_keyword_splat?: () -> bool
    def contains_keyword_splat?
      flags.anybits?(ArgumentsNodeFlags::CONTAINS_KEYWORD_SPLAT)
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("contains_keyword_splat" if contains_keyword_splat?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "└── arguments: #{inspector.list("#{inspector.prefix}    ", arguments)}"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :arguments_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :arguments_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader elements: Array[Node]
    attr_reader :elements

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (flags: Integer, elements: Array[Node], opening_loc: Location?, closing_loc: Location?, location: Location) -> void
    def initialize(flags, elements, opening_loc, closing_loc, location)
      @flags = flags
      @elements = elements
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_array_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*elements]
    end

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

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

    # def copy: (**params) -> ArrayNode
    def copy(**params)
      ArrayNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:elements) { elements },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, elements: elements, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def contains_splat?: () -> bool
    def contains_splat?
      flags.anybits?(ArrayNodeFlags::CONTAINS_SPLAT)
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("contains_splat" if contains_splat?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── elements: #{inspector.list("#{inspector.prefix}│   ", elements)}"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :array_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :array_node
    end
  end

  # Represents an array pattern in pattern matching.
  #
  #     foo in 1, 2
  #     ^^^^^^^^^^^
  #
  #     foo in [1, 2]
  #     ^^^^^^^^^^^^^
  #
  #     foo in *1
  #     ^^^^^^^^^
  #
  #     foo in Bar[]
  #     ^^^^^^^^^^^^
  #
  #     foo in Bar[1, 2, 3]
  #     ^^^^^^^^^^^^^^^^^^^
  class ArrayPatternNode < Node
    # attr_reader constant: Node?
    attr_reader :constant

    # attr_reader requireds: Array[Node]
    attr_reader :requireds

    # attr_reader rest: Node?
    attr_reader :rest

    # attr_reader posts: Array[Node]
    attr_reader :posts

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (constant: Node?, requireds: Array[Node], rest: Node?, posts: Array[Node], opening_loc: Location?, closing_loc: Location?, location: Location) -> void
    def initialize(constant, requireds, rest, posts, opening_loc, closing_loc, location)
      @constant = constant
      @requireds = requireds
      @rest = rest
      @posts = posts
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_array_pattern_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [constant, *requireds, rest, *posts]
    end

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

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

    # def copy: (**params) -> ArrayPatternNode
    def copy(**params)
      ArrayPatternNode.new(
        params.fetch(:constant) { constant },
        params.fetch(:requireds) { requireds },
        params.fetch(:rest) { rest },
        params.fetch(:posts) { posts },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { constant: constant, requireds: requireds, rest: rest, posts: posts, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (constant = self.constant).nil?
        inspector << "├── constant: ∅\n"
      else
        inspector << "├── constant:\n"
        inspector << constant.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── requireds: #{inspector.list("#{inspector.prefix}│   ", requireds)}"
      if (rest = self.rest).nil?
        inspector << "├── rest: ∅\n"
      else
        inspector << "├── rest:\n"
        inspector << rest.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── posts: #{inspector.list("#{inspector.prefix}│   ", posts)}"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :array_pattern_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :array_pattern_node
    end
  end

  # Represents a hash key/value pair.
  #
  #     { a => b }
  #       ^^^^^^
  class AssocNode < Node
    # attr_reader key: Node
    attr_reader :key

    # attr_reader value: Node?
    attr_reader :value

    # attr_reader operator_loc: Location?
    attr_reader :operator_loc

    # def initialize: (key: Node, value: Node?, operator_loc: Location?, location: Location) -> void
    def initialize(key, value, operator_loc, location)
      @key = key
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_assoc_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [key, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << key
      compact << value if value
      compact
    end

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

    # def copy: (**params) -> AssocNode
    def copy(**params)
      AssocNode.new(
        params.fetch(:key) { key },
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { key: key, value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String?
    def operator
      operator_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── key:\n"
      inspector << inspector.child_node(key, "│   ")
      if (value = self.value).nil?
        inspector << "├── value: ∅\n"
      else
        inspector << "├── value:\n"
        inspector << value.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :assoc_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :assoc_node
    end
  end

  # Represents a splat in a hash literal.
  #
  #     { **foo }
  #       ^^^^^
  class AssocSplatNode < Node
    # attr_reader value: Node?
    attr_reader :value

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (value: Node?, operator_loc: Location, location: Location) -> void
    def initialize(value, operator_loc, location)
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_assoc_splat_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << value if value
      compact
    end

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

    # def copy: (**params) -> AssocSplatNode
    def copy(**params)
      AssocSplatNode.new(
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (value = self.value).nil?
        inspector << "├── value: ∅\n"
      else
        inspector << "├── value:\n"
        inspector << value.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :assoc_splat_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :assoc_splat_node
    end
  end

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

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_back_reference_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> BackReferenceReadNode
    def copy(**params)
      BackReferenceReadNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :back_reference_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :back_reference_read_node
    end
  end

  # Represents a begin statement.
  #
  #     begin
  #       foo
  #     end
  #     ^^^^^
  class BeginNode < Node
    # attr_reader begin_keyword_loc: Location?
    attr_reader :begin_keyword_loc

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader rescue_clause: RescueNode?
    attr_reader :rescue_clause

    # attr_reader else_clause: ElseNode?
    attr_reader :else_clause

    # attr_reader ensure_clause: EnsureNode?
    attr_reader :ensure_clause

    # attr_reader end_keyword_loc: Location?
    attr_reader :end_keyword_loc

    # def initialize: (begin_keyword_loc: Location?, statements: StatementsNode?, rescue_clause: RescueNode?, else_clause: ElseNode?, ensure_clause: EnsureNode?, end_keyword_loc: Location?, location: Location) -> void
    def initialize(begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc, location)
      @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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_begin_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      # Never mark BeginNode with a newline flag, mark children instead
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements, rescue_clause, else_clause, ensure_clause]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << statements if statements
      compact << rescue_clause if rescue_clause
      compact << else_clause if else_clause
      compact << ensure_clause if ensure_clause
      compact
    end

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

    # def copy: (**params) -> BeginNode
    def copy(**params)
      BeginNode.new(
        params.fetch(:begin_keyword_loc) { begin_keyword_loc },
        params.fetch(:statements) { statements },
        params.fetch(:rescue_clause) { rescue_clause },
        params.fetch(:else_clause) { else_clause },
        params.fetch(:ensure_clause) { ensure_clause },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

    # def begin_keyword: () -> String?
    def begin_keyword
      begin_keyword_loc&.slice
    end

    # def end_keyword: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── begin_keyword_loc: #{inspector.location(begin_keyword_loc)}\n"
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (rescue_clause = self.rescue_clause).nil?
        inspector << "├── rescue_clause: ∅\n"
      else
        inspector << "├── rescue_clause:\n"
        inspector << rescue_clause.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (else_clause = self.else_clause).nil?
        inspector << "├── else_clause: ∅\n"
      else
        inspector << "├── else_clause:\n"
        inspector << else_clause.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (ensure_clause = self.ensure_clause).nil?
        inspector << "├── ensure_clause: ∅\n"
      else
        inspector << "├── ensure_clause:\n"
        inspector << ensure_clause.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :begin_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :begin_node
    end
  end

  # Represents block method arguments.
  #
  #     bar(&args)
  #     ^^^^^^^^^^
  class BlockArgumentNode < Node
    # attr_reader expression: Node?
    attr_reader :expression

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (expression: Node?, operator_loc: Location, location: Location) -> void
    def initialize(expression, operator_loc, location)
      @expression = expression
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_block_argument_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [expression]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << expression if expression
      compact
    end

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

    # def copy: (**params) -> BlockArgumentNode
    def copy(**params)
      BlockArgumentNode.new(
        params.fetch(:expression) { expression },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { expression: expression, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (expression = self.expression).nil?
        inspector << "├── expression: ∅\n"
      else
        inspector << "├── expression:\n"
        inspector << expression.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :block_argument_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :block_argument_node
    end
  end

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

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_block_local_variable_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> BlockLocalVariableNode
    def copy(**params)
      BlockLocalVariableNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :block_local_variable_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :block_local_variable_node
    end
  end

  # Represents a block of ruby code.
  #
  # [1, 2, 3].each { |i| puts x }
  #                ^^^^^^^^^^^^^^
  class BlockNode < Node
    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader locals_body_index: Integer
    attr_reader :locals_body_index

    # attr_reader parameters: Node?
    attr_reader :parameters

    # attr_reader body: Node?
    attr_reader :body

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (locals: Array[Symbol], locals_body_index: Integer, parameters: Node?, body: Node?, opening_loc: Location, closing_loc: Location, location: Location) -> void
    def initialize(locals, locals_body_index, parameters, body, opening_loc, closing_loc, location)
      @locals = locals
      @locals_body_index = locals_body_index
      @parameters = parameters
      @body = body
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_block_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [parameters, body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << parameters if parameters
      compact << body if body
      compact
    end

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

    # def copy: (**params) -> BlockNode
    def copy(**params)
      BlockNode.new(
        params.fetch(:locals) { locals },
        params.fetch(:locals_body_index) { locals_body_index },
        params.fetch(:parameters) { parameters },
        params.fetch(:body) { body },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { locals: locals, locals_body_index: locals_body_index, parameters: parameters, body: body, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "├── locals_body_index: #{locals_body_index.inspect}\n"
      if (parameters = self.parameters).nil?
        inspector << "├── parameters: ∅\n"
      else
        inspector << "├── parameters:\n"
        inspector << parameters.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (body = self.body).nil?
        inspector << "├── body: ∅\n"
      else
        inspector << "├── body:\n"
        inspector << body.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :block_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :block_node
    end
  end

  # Represents a block parameter to a method, block, or lambda definition.
  #
  #     def a(&b)
  #           ^^
  #     end
  class BlockParameterNode < Node
    # attr_reader name: Symbol?
    attr_reader :name

    # attr_reader name_loc: Location?
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol?, name_loc: Location?, operator_loc: Location, location: Location) -> void
    def initialize(name, name_loc, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_block_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

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

    # def copy: (**params) -> BlockParameterNode
    def copy(**params)
      BlockParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (name = self.name).nil?
        inspector << "├── name: ∅\n"
      else
        inspector << "├── name: #{name.inspect}\n"
      end
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :block_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :block_parameter_node
    end
  end

  # Represents a block's parameters declaration.
  #
  #     -> (a, b = 1; local) { }
  #        ^^^^^^^^^^^^^^^^^
  #
  #     foo do |a, b = 1; local|
  #            ^^^^^^^^^^^^^^^^^
  #     end
  class BlockParametersNode < Node
    # attr_reader parameters: ParametersNode?
    attr_reader :parameters

    # attr_reader locals: Array[Node]
    attr_reader :locals

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (parameters: ParametersNode?, locals: Array[Node], opening_loc: Location?, closing_loc: Location?, location: Location) -> void
    def initialize(parameters, locals, opening_loc, closing_loc, location)
      @parameters = parameters
      @locals = locals
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_block_parameters_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [parameters, *locals]
    end

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

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

    # def copy: (**params) -> BlockParametersNode
    def copy(**params)
      BlockParametersNode.new(
        params.fetch(:parameters) { parameters },
        params.fetch(:locals) { locals },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { parameters: parameters, locals: locals, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (parameters = self.parameters).nil?
        inspector << "├── parameters: ∅\n"
      else
        inspector << "├── parameters:\n"
        inspector << parameters.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── locals: #{inspector.list("#{inspector.prefix}│   ", locals)}"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :block_parameters_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :block_parameters_node
    end
  end

  # Represents the use of the `break` keyword.
  #
  #     break foo
  #     ^^^^^^^^^
  class BreakNode < Node
    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (arguments: ArgumentsNode?, keyword_loc: Location, location: Location) -> void
    def initialize(arguments, keyword_loc, location)
      @arguments = arguments
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_break_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [arguments]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << arguments if arguments
      compact
    end

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

    # def copy: (**params) -> BreakNode
    def copy(**params)
      BreakNode.new(
        params.fetch(:arguments) { arguments },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { arguments: arguments, keyword_loc: keyword_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :break_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :break_node
    end
  end

  # Represents the use of the `&&=` operator on a call.
  #
  #     foo.bar &&= value
  #     ^^^^^^^^^^^^^^^^^
  class CallAndWriteNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader message_loc: Location?
    attr_reader :message_loc

    # attr_reader read_name: Symbol
    attr_reader :read_name

    # attr_reader write_name: Symbol
    attr_reader :write_name

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, message_loc: Location?, read_name: Symbol, write_name: Symbol, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value, 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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_call_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << value
      compact
    end

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

    # def copy: (**params) -> CallAndWriteNode
    def copy(**params)
      CallAndWriteNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:message_loc) { message_loc },
        params.fetch(:read_name) { read_name },
        params.fetch(:write_name) { write_name },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def message: () -> String?
    def message
      message_loc&.slice
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── message_loc: #{inspector.location(message_loc)}\n"
      inspector << "├── read_name: #{read_name.inspect}\n"
      inspector << "├── write_name: #{write_name.inspect}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :call_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :call_and_write_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader message_loc: Location?
    attr_reader :message_loc

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # attr_reader block: Node?
    attr_reader :block

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, name: Symbol, message_loc: Location?, opening_loc: Location?, arguments: ArgumentsNode?, closing_loc: Location?, block: Node?, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, name, message_loc, opening_loc, arguments, closing_loc, block, 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
      @block = block
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_call_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, arguments, block]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << arguments if arguments
      compact << block if block
      compact
    end

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

    # def copy: (**params) -> CallNode
    def copy(**params)
      CallNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:name) { name },
        params.fetch(:message_loc) { message_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:block) { block },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, block: block, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def message: () -> String?
    def message
      message_loc&.slice
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── message_loc: #{inspector.location(message_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      if (block = self.block).nil?
        inspector << "└── block: ∅\n"
      else
        inspector << "└── block:\n"
        inspector << block.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :call_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :call_node
    end
  end

  # Represents the use of an assignment operator on a call.
  #
  #     foo.bar += baz
  #     ^^^^^^^^^^^^^^
  class CallOperatorWriteNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader message_loc: Location?
    attr_reader :message_loc

    # attr_reader read_name: Symbol
    attr_reader :read_name

    # attr_reader write_name: Symbol
    attr_reader :write_name

    # attr_reader operator: Symbol
    attr_reader :operator

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, message_loc: Location?, read_name: Symbol, write_name: Symbol, operator: Symbol, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator, operator_loc, value, location)
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @message_loc = message_loc
      @read_name = read_name
      @write_name = write_name
      @operator = operator
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_call_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << value
      compact
    end

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

    # def copy: (**params) -> CallOperatorWriteNode
    def copy(**params)
      CallOperatorWriteNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:message_loc) { message_loc },
        params.fetch(:read_name) { read_name },
        params.fetch(:write_name) { write_name },
        params.fetch(:operator) { operator },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, message_loc: message_loc, read_name: read_name, write_name: write_name, operator: operator, operator_loc: operator_loc, value: value, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def message: () -> String?
    def message
      message_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── message_loc: #{inspector.location(message_loc)}\n"
      inspector << "├── read_name: #{read_name.inspect}\n"
      inspector << "├── write_name: #{write_name.inspect}\n"
      inspector << "├── operator: #{operator.inspect}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :call_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :call_operator_write_node
    end
  end

  # Represents the use of the `||=` operator on a call.
  #
  #     foo.bar ||= value
  #     ^^^^^^^^^^^^^^^^^
  class CallOrWriteNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader message_loc: Location?
    attr_reader :message_loc

    # attr_reader read_name: Symbol
    attr_reader :read_name

    # attr_reader write_name: Symbol
    attr_reader :write_name

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, message_loc: Location?, read_name: Symbol, write_name: Symbol, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value, 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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_call_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << value
      compact
    end

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

    # def copy: (**params) -> CallOrWriteNode
    def copy(**params)
      CallOrWriteNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:message_loc) { message_loc },
        params.fetch(:read_name) { read_name },
        params.fetch(:write_name) { write_name },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def message: () -> String?
    def message
      message_loc&.slice
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── message_loc: #{inspector.location(message_loc)}\n"
      inspector << "├── read_name: #{read_name.inspect}\n"
      inspector << "├── write_name: #{write_name.inspect}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :call_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :call_or_write_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node
    attr_reader :receiver

    # attr_reader call_operator_loc: Location
    attr_reader :call_operator_loc

    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader message_loc: Location
    attr_reader :message_loc

    # def initialize: (flags: Integer, receiver: Node, call_operator_loc: Location, name: Symbol, message_loc: Location, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, name, message_loc, location)
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @name = name
      @message_loc = message_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_call_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver]
    end

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

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

    # def copy: (**params) -> CallTargetNode
    def copy(**params)
      CallTargetNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:name) { name },
        params.fetch(:message_loc) { message_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, name: name, message_loc: message_loc, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String
    def call_operator
      call_operator_loc.slice
    end

    # def message: () -> String
    def message
      message_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── receiver:\n"
      inspector << inspector.child_node(receiver, "│   ")
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── name: #{name.inspect}\n"
      inspector << "└── message_loc: #{inspector.location(message_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :call_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :call_target_node
    end
  end

  # Represents assigning to a local variable in pattern matching.
  #
  #     foo => [bar => baz]
  #            ^^^^^^^^^^^^
  class CapturePatternNode < Node
    # attr_reader value: Node
    attr_reader :value

    # attr_reader target: Node
    attr_reader :target

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (value: Node, target: Node, operator_loc: Location, location: Location) -> void
    def initialize(value, target, operator_loc, location)
      @value = value
      @target = target
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_capture_pattern_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value, target]
    end

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

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

    # def copy: (**params) -> CapturePatternNode
    def copy(**params)
      CapturePatternNode.new(
        params.fetch(:value) { value },
        params.fetch(:target) { target },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { value: value, target: target, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── target:\n"
      inspector << inspector.child_node(target, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :capture_pattern_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :capture_pattern_node
    end
  end

  # Represents the use of a case statement for pattern matching.
  #
  #     case true
  #     in false
  #     end
  #     ^^^^^^^^^
  class CaseMatchNode < Node
    # attr_reader predicate: Node?
    attr_reader :predicate

    # attr_reader conditions: Array[Node]
    attr_reader :conditions

    # attr_reader consequent: ElseNode?
    attr_reader :consequent

    # attr_reader case_keyword_loc: Location
    attr_reader :case_keyword_loc

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # def initialize: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> void
    def initialize(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location)
      @predicate = predicate
      @conditions = conditions
      @consequent = consequent
      @case_keyword_loc = case_keyword_loc
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_case_match_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [predicate, *conditions, consequent]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << predicate if predicate
      compact.concat(conditions)
      compact << consequent if consequent
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*predicate, *conditions, *consequent, case_keyword_loc, end_keyword_loc]
    end

    # def copy: (**params) -> CaseMatchNode
    def copy(**params)
      CaseMatchNode.new(
        params.fetch(:predicate) { predicate },
        params.fetch(:conditions) { conditions },
        params.fetch(:consequent) { consequent },
        params.fetch(:case_keyword_loc) { case_keyword_loc },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { predicate: predicate, conditions: conditions, consequent: consequent, case_keyword_loc: case_keyword_loc, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def case_keyword: () -> String
    def case_keyword
      case_keyword_loc.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (predicate = self.predicate).nil?
        inspector << "├── predicate: ∅\n"
      else
        inspector << "├── predicate:\n"
        inspector << predicate.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│   ", conditions)}"
      if (consequent = self.consequent).nil?
        inspector << "├── consequent: ∅\n"
      else
        inspector << "├── consequent:\n"
        inspector << consequent.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── case_keyword_loc: #{inspector.location(case_keyword_loc)}\n"
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :case_match_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :case_match_node
    end
  end

  # Represents the use of a case statement.
  #
  #     case true
  #     when false
  #     end
  #     ^^^^^^^^^^
  class CaseNode < Node
    # attr_reader predicate: Node?
    attr_reader :predicate

    # attr_reader conditions: Array[Node]
    attr_reader :conditions

    # attr_reader consequent: ElseNode?
    attr_reader :consequent

    # attr_reader case_keyword_loc: Location
    attr_reader :case_keyword_loc

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # def initialize: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> void
    def initialize(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location)
      @predicate = predicate
      @conditions = conditions
      @consequent = consequent
      @case_keyword_loc = case_keyword_loc
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_case_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [predicate, *conditions, consequent]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << predicate if predicate
      compact.concat(conditions)
      compact << consequent if consequent
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*predicate, *conditions, *consequent, case_keyword_loc, end_keyword_loc]
    end

    # def copy: (**params) -> CaseNode
    def copy(**params)
      CaseNode.new(
        params.fetch(:predicate) { predicate },
        params.fetch(:conditions) { conditions },
        params.fetch(:consequent) { consequent },
        params.fetch(:case_keyword_loc) { case_keyword_loc },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { predicate: predicate, conditions: conditions, consequent: consequent, case_keyword_loc: case_keyword_loc, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def case_keyword: () -> String
    def case_keyword
      case_keyword_loc.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (predicate = self.predicate).nil?
        inspector << "├── predicate: ∅\n"
      else
        inspector << "├── predicate:\n"
        inspector << predicate.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│   ", conditions)}"
      if (consequent = self.consequent).nil?
        inspector << "├── consequent: ∅\n"
      else
        inspector << "├── consequent:\n"
        inspector << consequent.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── case_keyword_loc: #{inspector.location(case_keyword_loc)}\n"
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :case_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :case_node
    end
  end

  # Represents a class declaration involving the `class` keyword.
  #
  #     class Foo end
  #     ^^^^^^^^^^^^^
  class ClassNode < Node
    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader class_keyword_loc: Location
    attr_reader :class_keyword_loc

    # attr_reader constant_path: Node
    attr_reader :constant_path

    # attr_reader inheritance_operator_loc: Location?
    attr_reader :inheritance_operator_loc

    # attr_reader superclass: Node?
    attr_reader :superclass

    # attr_reader body: Node?
    attr_reader :body

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (locals: Array[Symbol], class_keyword_loc: Location, constant_path: Node, inheritance_operator_loc: Location?, superclass: Node?, body: Node?, end_keyword_loc: Location, name: Symbol, location: Location) -> void
    def initialize(locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, body, end_keyword_loc, name, location)
      @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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [constant_path, superclass, body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << constant_path
      compact << superclass if superclass
      compact << body if body
      compact
    end

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

    # def copy: (**params) -> ClassNode
    def copy(**params)
      ClassNode.new(
        params.fetch(:locals) { locals },
        params.fetch(:class_keyword_loc) { class_keyword_loc },
        params.fetch(:constant_path) { constant_path },
        params.fetch(:inheritance_operator_loc) { inheritance_operator_loc },
        params.fetch(:superclass) { superclass },
        params.fetch(:body) { body },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

    # def class_keyword: () -> String
    def class_keyword
      class_keyword_loc.slice
    end

    # def inheritance_operator: () -> String?
    def inheritance_operator
      inheritance_operator_loc&.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "├── class_keyword_loc: #{inspector.location(class_keyword_loc)}\n"
      inspector << "├── constant_path:\n"
      inspector << inspector.child_node(constant_path, "│   ")
      inspector << "├── inheritance_operator_loc: #{inspector.location(inheritance_operator_loc)}\n"
      if (superclass = self.superclass).nil?
        inspector << "├── superclass: ∅\n"
      else
        inspector << "├── superclass:\n"
        inspector << superclass.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (body = self.body).nil?
        inspector << "├── body: ∅\n"
      else
        inspector << "├── body:\n"
        inspector << body.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_node
    end
  end

  # Represents the use of the `&&=` operator for assignment to a class variable.
  #
  #     @@target &&= value
  #     ^^^^^^^^^^^^^^^^^^
  class ClassVariableAndWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_variable_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ClassVariableAndWriteNode
    def copy(**params)
      ClassVariableAndWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_variable_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_variable_and_write_node
    end
  end

  # Represents assigning to a class variable using an operator that isn't `=`.
  #
  #     @@target += value
  #     ^^^^^^^^^^^^^^^^^
  class ClassVariableOperatorWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator: Symbol
    attr_reader :operator

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, operator, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @operator = operator
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_variable_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ClassVariableOperatorWriteNode
    def copy(**params)
      ClassVariableOperatorWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:operator) { operator },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator: #{operator.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_variable_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_variable_operator_write_node
    end
  end

  # Represents the use of the `||=` operator for assignment to a class variable.
  #
  #     @@target ||= value
  #     ^^^^^^^^^^^^^^^^^^
  class ClassVariableOrWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_variable_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ClassVariableOrWriteNode
    def copy(**params)
      ClassVariableOrWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_variable_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_variable_or_write_node
    end
  end

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

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_variable_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ClassVariableReadNode
    def copy(**params)
      ClassVariableReadNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_variable_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_variable_read_node
    end
  end

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

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_variable_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ClassVariableTargetNode
    def copy(**params)
      ClassVariableTargetNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_variable_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_variable_target_node
    end
  end

  # Represents writing to a class variable.
  #
  #     @@foo = 1
  #     ^^^^^^^^^
  class ClassVariableWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator_loc: Location?
    attr_reader :operator_loc

    # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location?, location: Location) -> void
    def initialize(name, name_loc, value, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_class_variable_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [name_loc, value, *operator_loc]
    end

    # def copy: (**params) -> ClassVariableWriteNode
    def copy(**params)
      ClassVariableWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String?
    def operator
      operator_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :class_variable_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :class_variable_write_node
    end
  end

  # Represents the use of the `&&=` operator for assignment to a constant.
  #
  #     Target &&= value
  #     ^^^^^^^^^^^^^^^^
  class ConstantAndWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ConstantAndWriteNode
    def copy(**params)
      ConstantAndWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_and_write_node
    end
  end

  # Represents assigning to a constant using an operator that isn't `=`.
  #
  #     Target += value
  #     ^^^^^^^^^^^^^^^
  class ConstantOperatorWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator: Symbol
    attr_reader :operator

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, operator, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @operator = operator
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ConstantOperatorWriteNode
    def copy(**params)
      ConstantOperatorWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:operator) { operator },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator: #{operator.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_operator_write_node
    end
  end

  # Represents the use of the `||=` operator for assignment to a constant.
  #
  #     Target ||= value
  #     ^^^^^^^^^^^^^^^^
  class ConstantOrWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ConstantOrWriteNode
    def copy(**params)
      ConstantOrWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_or_write_node
    end
  end

  # Represents the use of the `&&=` operator for assignment to a constant path.
  #
  #     Parent::Child &&= value
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class ConstantPathAndWriteNode < Node
    # attr_reader target: ConstantPathNode
    attr_reader :target

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(target, operator_loc, value, location)
      @target = target
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_path_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [target, value]
    end

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

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

    # def copy: (**params) -> ConstantPathAndWriteNode
    def copy(**params)
      ConstantPathAndWriteNode.new(
        params.fetch(:target) { target },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { target: target, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── target:\n"
      inspector << inspector.child_node(target, "│   ")
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_path_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_path_and_write_node
    end
  end

  # Represents accessing a constant through a path of `::` operators.
  #
  #     Foo::Bar
  #     ^^^^^^^^
  class ConstantPathNode < Node
    # attr_reader parent: Node?
    attr_reader :parent

    # attr_reader child: Node
    attr_reader :child

    # attr_reader delimiter_loc: Location
    attr_reader :delimiter_loc

    # def initialize: (parent: Node?, child: Node, delimiter_loc: Location, location: Location) -> void
    def initialize(parent, child, delimiter_loc, location)
      @parent = parent
      @child = child
      @delimiter_loc = delimiter_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_path_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [parent, child]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << parent if parent
      compact << child
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*parent, child, delimiter_loc]
    end

    # def copy: (**params) -> ConstantPathNode
    def copy(**params)
      ConstantPathNode.new(
        params.fetch(:parent) { parent },
        params.fetch(:child) { child },
        params.fetch(:delimiter_loc) { delimiter_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { parent: parent, child: child, delimiter_loc: delimiter_loc, location: location }
    end

    # def delimiter: () -> String
    def delimiter
      delimiter_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (parent = self.parent).nil?
        inspector << "├── parent: ∅\n"
      else
        inspector << "├── parent:\n"
        inspector << parent.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── child:\n"
      inspector << inspector.child_node(child, "│   ")
      inspector << "└── delimiter_loc: #{inspector.location(delimiter_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_path_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_path_node
    end
  end

  # Represents assigning to a constant path using an operator that isn't `=`.
  #
  #     Parent::Child += value
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class ConstantPathOperatorWriteNode < Node
    # attr_reader target: ConstantPathNode
    attr_reader :target

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator: Symbol
    attr_reader :operator

    # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void
    def initialize(target, operator_loc, value, operator, location)
      @target = target
      @operator_loc = operator_loc
      @value = value
      @operator = operator
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_path_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [target, value]
    end

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

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

    # def copy: (**params) -> ConstantPathOperatorWriteNode
    def copy(**params)
      ConstantPathOperatorWriteNode.new(
        params.fetch(:target) { target },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:operator) { operator },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { target: target, operator_loc: operator_loc, value: value, operator: operator, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── target:\n"
      inspector << inspector.child_node(target, "│   ")
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator: #{operator.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_path_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_path_operator_write_node
    end
  end

  # Represents the use of the `||=` operator for assignment to a constant path.
  #
  #     Parent::Child ||= value
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class ConstantPathOrWriteNode < Node
    # attr_reader target: ConstantPathNode
    attr_reader :target

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(target, operator_loc, value, location)
      @target = target
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_path_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [target, value]
    end

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

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

    # def copy: (**params) -> ConstantPathOrWriteNode
    def copy(**params)
      ConstantPathOrWriteNode.new(
        params.fetch(:target) { target },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { target: target, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── target:\n"
      inspector << inspector.child_node(target, "│   ")
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_path_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_path_or_write_node
    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
    # attr_reader parent: Node?
    attr_reader :parent

    # attr_reader child: Node
    attr_reader :child

    # attr_reader delimiter_loc: Location
    attr_reader :delimiter_loc

    # def initialize: (parent: Node?, child: Node, delimiter_loc: Location, location: Location) -> void
    def initialize(parent, child, delimiter_loc, location)
      @parent = parent
      @child = child
      @delimiter_loc = delimiter_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_path_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [parent, child]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << parent if parent
      compact << child
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*parent, child, delimiter_loc]
    end

    # def copy: (**params) -> ConstantPathTargetNode
    def copy(**params)
      ConstantPathTargetNode.new(
        params.fetch(:parent) { parent },
        params.fetch(:child) { child },
        params.fetch(:delimiter_loc) { delimiter_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { parent: parent, child: child, delimiter_loc: delimiter_loc, location: location }
    end

    # def delimiter: () -> String
    def delimiter
      delimiter_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (parent = self.parent).nil?
        inspector << "├── parent: ∅\n"
      else
        inspector << "├── parent:\n"
        inspector << parent.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── child:\n"
      inspector << inspector.child_node(child, "│   ")
      inspector << "└── delimiter_loc: #{inspector.location(delimiter_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_path_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_path_target_node
    end
  end

  # Represents writing to a constant path.
  #
  #     ::Foo = 1
  #     ^^^^^^^^^
  #
  #     Foo::Bar = 1
  #     ^^^^^^^^^^^^
  #
  #     ::Foo::Bar = 1
  #     ^^^^^^^^^^^^^^
  class ConstantPathWriteNode < Node
    # attr_reader target: ConstantPathNode
    attr_reader :target

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(target, operator_loc, value, location)
      @target = target
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_path_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [target, value]
    end

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

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

    # def copy: (**params) -> ConstantPathWriteNode
    def copy(**params)
      ConstantPathWriteNode.new(
        params.fetch(:target) { target },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { target: target, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── target:\n"
      inspector << inspector.child_node(target, "│   ")
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_path_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_path_write_node
    end
  end

  # Represents referencing a constant.
  #
  #     Foo
  #     ^^^
  class ConstantReadNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ConstantReadNode
    def copy(**params)
      ConstantReadNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_read_node
    end
  end

  # Represents writing to a constant in a context that doesn't have an explicit value.
  #
  #     Foo, Bar = baz
  #     ^^^  ^^^
  class ConstantTargetNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ConstantTargetNode
    def copy(**params)
      ConstantTargetNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_target_node
    end
  end

  # Represents writing to a constant.
  #
  #     Foo = 1
  #     ^^^^^^^
  class ConstantWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void
    def initialize(name, name_loc, value, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_constant_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> ConstantWriteNode
    def copy(**params)
      ConstantWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :constant_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :constant_write_node
    end
  end

  # Represents a method definition.
  #
  #     def method
  #     end
  #     ^^^^^^^^^^
  class DefNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader parameters: ParametersNode?
    attr_reader :parameters

    # attr_reader body: Node?
    attr_reader :body

    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader locals_body_index: Integer
    attr_reader :locals_body_index

    # attr_reader def_keyword_loc: Location
    attr_reader :def_keyword_loc

    # attr_reader operator_loc: Location?
    attr_reader :operator_loc

    # attr_reader lparen_loc: Location?
    attr_reader :lparen_loc

    # attr_reader rparen_loc: Location?
    attr_reader :rparen_loc

    # attr_reader equal_loc: Location?
    attr_reader :equal_loc

    # attr_reader end_keyword_loc: Location?
    attr_reader :end_keyword_loc

    # def initialize: (name: Symbol, name_loc: Location, receiver: Node?, parameters: ParametersNode?, body: Node?, locals: Array[Symbol], locals_body_index: Integer, def_keyword_loc: Location, operator_loc: Location?, lparen_loc: Location?, rparen_loc: Location?, equal_loc: Location?, end_keyword_loc: Location?, location: Location) -> void
    def initialize(name, name_loc, receiver, parameters, body, locals, locals_body_index, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc, location)
      @name = name
      @name_loc = name_loc
      @receiver = receiver
      @parameters = parameters
      @body = body
      @locals = locals
      @locals_body_index = locals_body_index
      @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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_def_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, parameters, body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << parameters if parameters
      compact << body if body
      compact
    end

    # def 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]
    end

    # def copy: (**params) -> DefNode
    def copy(**params)
      DefNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:receiver) { receiver },
        params.fetch(:parameters) { parameters },
        params.fetch(:body) { body },
        params.fetch(:locals) { locals },
        params.fetch(:locals_body_index) { locals_body_index },
        params.fetch(:def_keyword_loc) { def_keyword_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:equal_loc) { equal_loc },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, receiver: receiver, parameters: parameters, body: body, locals: locals, locals_body_index: locals_body_index, 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, location: location }
    end

    # def def_keyword: () -> String
    def def_keyword
      def_keyword_loc.slice
    end

    # def operator: () -> String?
    def operator
      operator_loc&.slice
    end

    # def lparen: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # def rparen: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # def equal: () -> String?
    def equal
      equal_loc&.slice
    end

    # def end_keyword: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (parameters = self.parameters).nil?
        inspector << "├── parameters: ∅\n"
      else
        inspector << "├── parameters:\n"
        inspector << parameters.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (body = self.body).nil?
        inspector << "├── body: ∅\n"
      else
        inspector << "├── body:\n"
        inspector << body.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "├── locals_body_index: #{locals_body_index.inspect}\n"
      inspector << "├── def_keyword_loc: #{inspector.location(def_keyword_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n"
      inspector << "├── equal_loc: #{inspector.location(equal_loc)}\n"
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :def_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :def_node
    end
  end

  # Represents the use of the `defined?` keyword.
  #
  #     defined?(a)
  #     ^^^^^^^^^^^
  class DefinedNode < Node
    # attr_reader lparen_loc: Location?
    attr_reader :lparen_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader rparen_loc: Location?
    attr_reader :rparen_loc

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (lparen_loc: Location?, value: Node, rparen_loc: Location?, keyword_loc: Location, location: Location) -> void
    def initialize(lparen_loc, value, rparen_loc, keyword_loc, location)
      @lparen_loc = lparen_loc
      @value = value
      @rparen_loc = rparen_loc
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_defined_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*lparen_loc, value, *rparen_loc, keyword_loc]
    end

    # def copy: (**params) -> DefinedNode
    def copy(**params)
      DefinedNode.new(
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:value) { value },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { lparen_loc: lparen_loc, value: value, rparen_loc: rparen_loc, keyword_loc: keyword_loc, location: location }
    end

    # def lparen: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # def rparen: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n"
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :defined_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :defined_node
    end
  end

  # Represents an `else` clause in a `case`, `if`, or `unless` statement.
  #
  #     if a then b else c end
  #                 ^^^^^^^^^^
  class ElseNode < Node
    # attr_reader else_keyword_loc: Location
    attr_reader :else_keyword_loc

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader end_keyword_loc: Location?
    attr_reader :end_keyword_loc

    # def initialize: (else_keyword_loc: Location, statements: StatementsNode?, end_keyword_loc: Location?, location: Location) -> void
    def initialize(else_keyword_loc, statements, end_keyword_loc, location)
      @else_keyword_loc = else_keyword_loc
      @statements = statements
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_else_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [else_keyword_loc, *statements, *end_keyword_loc]
    end

    # def copy: (**params) -> ElseNode
    def copy(**params)
      ElseNode.new(
        params.fetch(:else_keyword_loc) { else_keyword_loc },
        params.fetch(:statements) { statements },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { else_keyword_loc: else_keyword_loc, statements: statements, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def else_keyword: () -> String
    def else_keyword
      else_keyword_loc.slice
    end

    # def end_keyword: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── else_keyword_loc: #{inspector.location(else_keyword_loc)}\n"
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :else_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :else_node
    end
  end

  # Represents an interpolated set of statements.
  #
  #     "foo #{bar}"
  #          ^^^^^^
  class EmbeddedStatementsNode < Node
    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (opening_loc: Location, statements: StatementsNode?, closing_loc: Location, location: Location) -> void
    def initialize(opening_loc, statements, closing_loc, location)
      @opening_loc = opening_loc
      @statements = statements
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_embedded_statements_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, *statements, closing_loc]
    end

    # def copy: (**params) -> EmbeddedStatementsNode
    def copy(**params)
      EmbeddedStatementsNode.new(
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:statements) { statements },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { opening_loc: opening_loc, statements: statements, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :embedded_statements_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :embedded_statements_node
    end
  end

  # Represents an interpolated variable.
  #
  #     "foo #@bar"
  #          ^^^^^
  class EmbeddedVariableNode < Node
    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader variable: Node
    attr_reader :variable

    # def initialize: (operator_loc: Location, variable: Node, location: Location) -> void
    def initialize(operator_loc, variable, location)
      @operator_loc = operator_loc
      @variable = variable
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_embedded_variable_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [variable]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [variable]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [operator_loc, variable]
    end

    # def copy: (**params) -> EmbeddedVariableNode
    def copy(**params)
      EmbeddedVariableNode.new(
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:variable) { variable },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { operator_loc: operator_loc, variable: variable, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── variable:\n"
      inspector << inspector.child_node(variable, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :embedded_variable_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :embedded_variable_node
    end
  end

  # Represents an `ensure` clause in a `begin` statement.
  #
  #     begin
  #       foo
  #     ensure
  #     ^^^^^^
  #       bar
  #     end
  class EnsureNode < Node
    # attr_reader ensure_keyword_loc: Location
    attr_reader :ensure_keyword_loc

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # def initialize: (ensure_keyword_loc: Location, statements: StatementsNode?, end_keyword_loc: Location, location: Location) -> void
    def initialize(ensure_keyword_loc, statements, end_keyword_loc, location)
      @ensure_keyword_loc = ensure_keyword_loc
      @statements = statements
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_ensure_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [ensure_keyword_loc, *statements, end_keyword_loc]
    end

    # def copy: (**params) -> EnsureNode
    def copy(**params)
      EnsureNode.new(
        params.fetch(:ensure_keyword_loc) { ensure_keyword_loc },
        params.fetch(:statements) { statements },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { ensure_keyword_loc: ensure_keyword_loc, statements: statements, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def ensure_keyword: () -> String
    def ensure_keyword
      ensure_keyword_loc.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── ensure_keyword_loc: #{inspector.location(ensure_keyword_loc)}\n"
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :ensure_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :ensure_node
    end
  end

  # Represents the use of the literal `false` keyword.
  #
  #     false
  #     ^^^^^
  class FalseNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_false_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> FalseNode
    def copy(**params)
      FalseNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :false_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :false_node
    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)
  #            ^^^^^^^^^^^^^^^^^^^^
  class FindPatternNode < Node
    # attr_reader constant: Node?
    attr_reader :constant

    # attr_reader left: Node
    attr_reader :left

    # attr_reader requireds: Array[Node]
    attr_reader :requireds

    # attr_reader right: Node
    attr_reader :right

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (constant: Node?, left: Node, requireds: Array[Node], right: Node, opening_loc: Location?, closing_loc: Location?, location: Location) -> void
    def initialize(constant, left, requireds, right, opening_loc, closing_loc, location)
      @constant = constant
      @left = left
      @requireds = requireds
      @right = right
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_find_pattern_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [constant, left, *requireds, right]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << constant if constant
      compact << left
      compact.concat(requireds)
      compact << right
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*constant, left, *requireds, right, *opening_loc, *closing_loc]
    end

    # def copy: (**params) -> FindPatternNode
    def copy(**params)
      FindPatternNode.new(
        params.fetch(:constant) { constant },
        params.fetch(:left) { left },
        params.fetch(:requireds) { requireds },
        params.fetch(:right) { right },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { constant: constant, left: left, requireds: requireds, right: right, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (constant = self.constant).nil?
        inspector << "├── constant: ∅\n"
      else
        inspector << "├── constant:\n"
        inspector << constant.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── left:\n"
      inspector << inspector.child_node(left, "│   ")
      inspector << "├── requireds: #{inspector.list("#{inspector.prefix}│   ", requireds)}"
      inspector << "├── right:\n"
      inspector << inspector.child_node(right, "│   ")
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :find_pattern_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :find_pattern_node
    end
  end

  # Represents the use of the `..` or `...` operators to create flip flops.
  #
  #     baz if foo .. bar
  #            ^^^^^^^^^^
  class FlipFlopNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader left: Node?
    attr_reader :left

    # attr_reader right: Node?
    attr_reader :right

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (flags: Integer, left: Node?, right: Node?, operator_loc: Location, location: Location) -> void
    def initialize(flags, left, right, operator_loc, location)
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_flip_flop_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [left, right]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << left if left
      compact << right if right
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*left, *right, operator_loc]
    end

    # def copy: (**params) -> FlipFlopNode
    def copy(**params)
      FlipFlopNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:left) { left },
        params.fetch(:right) { right },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, left: left, right: right, operator_loc: operator_loc, location: location }
    end

    # def exclude_end?: () -> bool
    def exclude_end?
      flags.anybits?(RangeFlags::EXCLUDE_END)
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("exclude_end" if exclude_end?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (left = self.left).nil?
        inspector << "├── left: ∅\n"
      else
        inspector << "├── left:\n"
        inspector << left.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (right = self.right).nil?
        inspector << "├── right: ∅\n"
      else
        inspector << "├── right:\n"
        inspector << right.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :flip_flop_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :flip_flop_node
    end
  end

  # Represents a floating point number literal.
  #
  #     1.0
  #     ^^^
  class FloatNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_float_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> FloatNode
    def copy(**params)
      FloatNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :float_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :float_node
    end
  end

  # Represents the use of the `for` keyword.
  #
  #     for i in a end
  #     ^^^^^^^^^^^^^^
  class ForNode < Node
    # attr_reader index: Node
    attr_reader :index

    # attr_reader collection: Node
    attr_reader :collection

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader for_keyword_loc: Location
    attr_reader :for_keyword_loc

    # attr_reader in_keyword_loc: Location
    attr_reader :in_keyword_loc

    # attr_reader do_keyword_loc: Location?
    attr_reader :do_keyword_loc

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # def initialize: (index: Node, collection: Node, statements: StatementsNode?, for_keyword_loc: Location, in_keyword_loc: Location, do_keyword_loc: Location?, end_keyword_loc: Location, location: Location) -> void
    def initialize(index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc, location)
      @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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_for_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [index, collection, statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << index
      compact << collection
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [index, collection, *statements, for_keyword_loc, in_keyword_loc, *do_keyword_loc, end_keyword_loc]
    end

    # def copy: (**params) -> ForNode
    def copy(**params)
      ForNode.new(
        params.fetch(:index) { index },
        params.fetch(:collection) { collection },
        params.fetch(:statements) { statements },
        params.fetch(:for_keyword_loc) { for_keyword_loc },
        params.fetch(:in_keyword_loc) { in_keyword_loc },
        params.fetch(:do_keyword_loc) { do_keyword_loc },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

    # def for_keyword: () -> String
    def for_keyword
      for_keyword_loc.slice
    end

    # def in_keyword: () -> String
    def in_keyword
      in_keyword_loc.slice
    end

    # def do_keyword: () -> String?
    def do_keyword
      do_keyword_loc&.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── index:\n"
      inspector << inspector.child_node(index, "│   ")
      inspector << "├── collection:\n"
      inspector << inspector.child_node(collection, "│   ")
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── for_keyword_loc: #{inspector.location(for_keyword_loc)}\n"
      inspector << "├── in_keyword_loc: #{inspector.location(in_keyword_loc)}\n"
      inspector << "├── do_keyword_loc: #{inspector.location(do_keyword_loc)}\n"
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :for_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :for_node
    end
  end

  # Represents forwarding all arguments to this method to another method.
  #
  #     def foo(...)
  #       bar(...)
  #           ^^^
  #     end
  class ForwardingArgumentsNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_forwarding_arguments_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ForwardingArgumentsNode
    def copy(**params)
      ForwardingArgumentsNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :forwarding_arguments_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :forwarding_arguments_node
    end
  end

  # Represents the use of the forwarding parameter in a method, block, or lambda declaration.
  #
  #     def foo(...)
  #             ^^^
  #     end
  class ForwardingParameterNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_forwarding_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ForwardingParameterNode
    def copy(**params)
      ForwardingParameterNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :forwarding_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :forwarding_parameter_node
    end
  end

  # Represents the use of the `super` keyword without parentheses or arguments.
  #
  #     super
  #     ^^^^^
  class ForwardingSuperNode < Node
    # attr_reader block: BlockNode?
    attr_reader :block

    # def initialize: (block: BlockNode?, location: Location) -> void
    def initialize(block, location)
      @block = block
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_forwarding_super_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [block]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << block if block
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*block]
    end

    # def copy: (**params) -> ForwardingSuperNode
    def copy(**params)
      ForwardingSuperNode.new(
        params.fetch(:block) { block },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { block: block, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (block = self.block).nil?
        inspector << "└── block: ∅\n"
      else
        inspector << "└── block:\n"
        inspector << block.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :forwarding_super_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :forwarding_super_node
    end
  end

  # Represents the use of the `&&=` operator for assignment to a global variable.
  #
  #     $target &&= value
  #     ^^^^^^^^^^^^^^^^^
  class GlobalVariableAndWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_global_variable_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> GlobalVariableAndWriteNode
    def copy(**params)
      GlobalVariableAndWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :global_variable_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :global_variable_and_write_node
    end
  end

  # Represents assigning to a global variable using an operator that isn't `=`.
  #
  #     $target += value
  #     ^^^^^^^^^^^^^^^^
  class GlobalVariableOperatorWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator: Symbol
    attr_reader :operator

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, operator, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @operator = operator
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_global_variable_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> GlobalVariableOperatorWriteNode
    def copy(**params)
      GlobalVariableOperatorWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:operator) { operator },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator: #{operator.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :global_variable_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :global_variable_operator_write_node
    end
  end

  # Represents the use of the `||=` operator for assignment to a global variable.
  #
  #     $target ||= value
  #     ^^^^^^^^^^^^^^^^^
  class GlobalVariableOrWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_global_variable_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> GlobalVariableOrWriteNode
    def copy(**params)
      GlobalVariableOrWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :global_variable_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :global_variable_or_write_node
    end
  end

  # Represents referencing a global variable.
  #
  #     $foo
  #     ^^^^
  class GlobalVariableReadNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_global_variable_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> GlobalVariableReadNode
    def copy(**params)
      GlobalVariableReadNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :global_variable_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :global_variable_read_node
    end
  end

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

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_global_variable_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> GlobalVariableTargetNode
    def copy(**params)
      GlobalVariableTargetNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :global_variable_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :global_variable_target_node
    end
  end

  # Represents writing to a global variable.
  #
  #     $foo = 1
  #     ^^^^^^^^
  class GlobalVariableWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void
    def initialize(name, name_loc, value, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_global_variable_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> GlobalVariableWriteNode
    def copy(**params)
      GlobalVariableWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :global_variable_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :global_variable_write_node
    end
  end

  # Represents a hash literal.
  #
  #     { a => b }
  #     ^^^^^^^^^^
  class HashNode < Node
    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader elements: Array[Node]
    attr_reader :elements

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (opening_loc: Location, elements: Array[Node], closing_loc: Location, location: Location) -> void
    def initialize(opening_loc, elements, closing_loc, location)
      @opening_loc = opening_loc
      @elements = elements
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_hash_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*elements]
    end

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

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

    # def copy: (**params) -> HashNode
    def copy(**params)
      HashNode.new(
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:elements) { elements },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { opening_loc: opening_loc, elements: elements, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── elements: #{inspector.list("#{inspector.prefix}│   ", elements)}"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :hash_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :hash_node
    end
  end

  # Represents a hash pattern in pattern matching.
  #
  #     foo => { a: 1, b: 2 }
  #            ^^^^^^^^^^^^^^
  #
  #     foo => { a: 1, b: 2, **c }
  #            ^^^^^^^^^^^^^^^^^^^
  class HashPatternNode < Node
    # attr_reader constant: Node?
    attr_reader :constant

    # attr_reader elements: Array[Node]
    attr_reader :elements

    # attr_reader rest: Node?
    attr_reader :rest

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (constant: Node?, elements: Array[Node], rest: Node?, opening_loc: Location?, closing_loc: Location?, location: Location) -> void
    def initialize(constant, elements, rest, opening_loc, closing_loc, location)
      @constant = constant
      @elements = elements
      @rest = rest
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_hash_pattern_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [constant, *elements, rest]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << constant if constant
      compact.concat(elements)
      compact << rest if rest
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*constant, *elements, *rest, *opening_loc, *closing_loc]
    end

    # def copy: (**params) -> HashPatternNode
    def copy(**params)
      HashPatternNode.new(
        params.fetch(:constant) { constant },
        params.fetch(:elements) { elements },
        params.fetch(:rest) { rest },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { constant: constant, elements: elements, rest: rest, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (constant = self.constant).nil?
        inspector << "├── constant: ∅\n"
      else
        inspector << "├── constant:\n"
        inspector << constant.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── elements: #{inspector.list("#{inspector.prefix}│   ", elements)}"
      if (rest = self.rest).nil?
        inspector << "├── rest: ∅\n"
      else
        inspector << "├── rest:\n"
        inspector << rest.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :hash_pattern_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :hash_pattern_node
    end
  end

  # Represents the use of the `if` keyword, either in the block form or the modifier form.
  #
  #     bar if foo
  #     ^^^^^^^^^^
  #
  #     if foo then bar end
  #     ^^^^^^^^^^^^^^^^^^^
  class IfNode < Node
    # attr_reader if_keyword_loc: Location?
    attr_reader :if_keyword_loc

    # attr_reader predicate: Node
    attr_reader :predicate

    # attr_reader then_keyword_loc: Location?
    attr_reader :then_keyword_loc

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader consequent: Node?
    attr_reader :consequent

    # attr_reader end_keyword_loc: Location?
    attr_reader :end_keyword_loc

    # def initialize: (if_keyword_loc: Location?, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> void
    def initialize(if_keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location)
      @if_keyword_loc = if_keyword_loc
      @predicate = predicate
      @then_keyword_loc = then_keyword_loc
      @statements = statements
      @consequent = consequent
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_if_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      predicate.set_newline_flag(newline_marked)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [predicate, statements, consequent]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << predicate
      compact << statements if statements
      compact << consequent if consequent
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*if_keyword_loc, predicate, *then_keyword_loc, *statements, *consequent, *end_keyword_loc]
    end

    # def copy: (**params) -> IfNode
    def copy(**params)
      IfNode.new(
        params.fetch(:if_keyword_loc) { if_keyword_loc },
        params.fetch(:predicate) { predicate },
        params.fetch(:then_keyword_loc) { then_keyword_loc },
        params.fetch(:statements) { statements },
        params.fetch(:consequent) { consequent },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { if_keyword_loc: if_keyword_loc, predicate: predicate, then_keyword_loc: then_keyword_loc, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def if_keyword: () -> String?
    def if_keyword
      if_keyword_loc&.slice
    end

    # def then_keyword: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # def end_keyword: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── if_keyword_loc: #{inspector.location(if_keyword_loc)}\n"
      inspector << "├── predicate:\n"
      inspector << inspector.child_node(predicate, "│   ")
      inspector << "├── then_keyword_loc: #{inspector.location(then_keyword_loc)}\n"
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (consequent = self.consequent).nil?
        inspector << "├── consequent: ∅\n"
      else
        inspector << "├── consequent:\n"
        inspector << consequent.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :if_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :if_node
    end
  end

  # Represents an imaginary number literal.
  #
  #     1.0i
  #     ^^^^
  class ImaginaryNode < Node
    # attr_reader numeric: Node
    attr_reader :numeric

    # def initialize: (numeric: Node, location: Location) -> void
    def initialize(numeric, location)
      @numeric = numeric
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_imaginary_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [numeric]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [numeric]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [numeric]
    end

    # def copy: (**params) -> ImaginaryNode
    def copy(**params)
      ImaginaryNode.new(
        params.fetch(:numeric) { numeric },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { numeric: numeric, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── numeric:\n"
      inspector << inspector.child_node(numeric, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :imaginary_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :imaginary_node
    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: }
  #       ^^^^
  class ImplicitNode < Node
    # attr_reader value: Node
    attr_reader :value

    # def initialize: (value: Node, location: Location) -> void
    def initialize(value, location)
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_implicit_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [value]
    end

    # def copy: (**params) -> ImplicitNode
    def copy(**params)
      ImplicitNode.new(
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { value: value, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :implicit_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :implicit_node
    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
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_implicit_rest_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> ImplicitRestNode
    def copy(**params)
      ImplicitRestNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :implicit_rest_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :implicit_rest_node
    end
  end

  # Represents the use of the `in` keyword in a case statement.
  #
  #     case a; in b then c end
  #             ^^^^^^^^^^^
  class InNode < Node
    # attr_reader pattern: Node
    attr_reader :pattern

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader in_loc: Location
    attr_reader :in_loc

    # attr_reader then_loc: Location?
    attr_reader :then_loc

    # def initialize: (pattern: Node, statements: StatementsNode?, in_loc: Location, then_loc: Location?, location: Location) -> void
    def initialize(pattern, statements, in_loc, then_loc, location)
      @pattern = pattern
      @statements = statements
      @in_loc = in_loc
      @then_loc = then_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_in_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [pattern, statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << pattern
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [pattern, *statements, in_loc, *then_loc]
    end

    # def copy: (**params) -> InNode
    def copy(**params)
      InNode.new(
        params.fetch(:pattern) { pattern },
        params.fetch(:statements) { statements },
        params.fetch(:in_loc) { in_loc },
        params.fetch(:then_loc) { then_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { pattern: pattern, statements: statements, in_loc: in_loc, then_loc: then_loc, location: location }
    end

    # def in: () -> String
    def in
      in_loc.slice
    end

    # def then: () -> String?
    def then
      then_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── pattern:\n"
      inspector << inspector.child_node(pattern, "│   ")
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── in_loc: #{inspector.location(in_loc)}\n"
      inspector << "└── then_loc: #{inspector.location(then_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :in_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :in_node
    end
  end

  # Represents the use of the `&&=` operator on a call to the `[]` method.
  #
  #     foo.bar[baz] &&= value
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class IndexAndWriteNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader block: Node?
    attr_reader :block

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value, 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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_index_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, arguments, block, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << arguments if arguments
      compact << block if block
      compact << value
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value]
    end

    # def copy: (**params) -> IndexAndWriteNode
    def copy(**params)
      IndexAndWriteNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:block) { block },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      if (block = self.block).nil?
        inspector << "├── block: ∅\n"
      else
        inspector << "├── block:\n"
        inspector << block.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :index_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :index_and_write_node
    end
  end

  # Represents the use of an assignment operator on a call to `[]`.
  #
  #     foo.bar[baz] += value
  #     ^^^^^^^^^^^^^^^^^^^^^
  class IndexOperatorWriteNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader block: Node?
    attr_reader :block

    # attr_reader operator: Symbol
    attr_reader :operator

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, operator: Symbol, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator, operator_loc, value, location)
      @flags = flags
      @receiver = receiver
      @call_operator_loc = call_operator_loc
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @block = block
      @operator = operator
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_index_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, arguments, block, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << arguments if arguments
      compact << block if block
      compact << value
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value]
    end

    # def copy: (**params) -> IndexOperatorWriteNode
    def copy(**params)
      IndexOperatorWriteNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:block) { block },
        params.fetch(:operator) { operator },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, operator: operator, operator_loc: operator_loc, value: value, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      if (block = self.block).nil?
        inspector << "├── block: ∅\n"
      else
        inspector << "├── block:\n"
        inspector << block.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── operator: #{operator.inspect}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :index_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :index_operator_write_node
    end
  end

  # Represents the use of the `||=` operator on a call to `[]`.
  #
  #     foo.bar[baz] ||= value
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class IndexOrWriteNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node?
    attr_reader :receiver

    # attr_reader call_operator_loc: Location?
    attr_reader :call_operator_loc

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader block: Node?
    attr_reader :block

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value, 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
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_index_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, arguments, block, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver if receiver
      compact << arguments if arguments
      compact << block if block
      compact << value
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value]
    end

    # def copy: (**params) -> IndexOrWriteNode
    def copy(**params)
      IndexOrWriteNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:call_operator_loc) { call_operator_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:block) { block },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { 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, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def call_operator: () -> String?
    def call_operator
      call_operator_loc&.slice
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (receiver = self.receiver).nil?
        inspector << "├── receiver: ∅\n"
      else
        inspector << "├── receiver:\n"
        inspector << receiver.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      if (block = self.block).nil?
        inspector << "├── block: ∅\n"
      else
        inspector << "├── block:\n"
        inspector << block.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :index_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :index_or_write_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader receiver: Node
    attr_reader :receiver

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader block: Node?
    attr_reader :block

    # def initialize: (flags: Integer, receiver: Node, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, location: Location) -> void
    def initialize(flags, receiver, opening_loc, arguments, closing_loc, block, location)
      @flags = flags
      @receiver = receiver
      @opening_loc = opening_loc
      @arguments = arguments
      @closing_loc = closing_loc
      @block = block
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_index_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [receiver, arguments, block]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << receiver
      compact << arguments if arguments
      compact << block if block
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [receiver, opening_loc, *arguments, closing_loc, *block]
    end

    # def copy: (**params) -> IndexTargetNode
    def copy(**params)
      IndexTargetNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:receiver) { receiver },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:block) { block },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, receiver: receiver, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, location: location }
    end

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

    # def variable_call?: () -> bool
    def variable_call?
      flags.anybits?(CallNodeFlags::VARIABLE_CALL)
    end

    # def attribute_write?: () -> bool
    def attribute_write?
      flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE)
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── receiver:\n"
      inspector << inspector.child_node(receiver, "│   ")
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      if (block = self.block).nil?
        inspector << "└── block: ∅\n"
      else
        inspector << "└── block:\n"
        inspector << block.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :index_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :index_target_node
    end
  end

  # Represents the use of the `&&=` operator for assignment to an instance variable.
  #
  #     @target &&= value
  #     ^^^^^^^^^^^^^^^^^
  class InstanceVariableAndWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_instance_variable_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> InstanceVariableAndWriteNode
    def copy(**params)
      InstanceVariableAndWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :instance_variable_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :instance_variable_and_write_node
    end
  end

  # Represents assigning to an instance variable using an operator that isn't `=`.
  #
  #     @target += value
  #     ^^^^^^^^^^^^^^^^
  class InstanceVariableOperatorWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator: Symbol
    attr_reader :operator

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, operator, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @operator = operator
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_instance_variable_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> InstanceVariableOperatorWriteNode
    def copy(**params)
      InstanceVariableOperatorWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:operator) { operator },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator: #{operator.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :instance_variable_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :instance_variable_operator_write_node
    end
  end

  # Represents the use of the `||=` operator for assignment to an instance variable.
  #
  #     @target ||= value
  #     ^^^^^^^^^^^^^^^^^
  class InstanceVariableOrWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_instance_variable_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> InstanceVariableOrWriteNode
    def copy(**params)
      InstanceVariableOrWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :instance_variable_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :instance_variable_or_write_node
    end
  end

  # Represents referencing an instance variable.
  #
  #     @foo
  #     ^^^^
  class InstanceVariableReadNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_instance_variable_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> InstanceVariableReadNode
    def copy(**params)
      InstanceVariableReadNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :instance_variable_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :instance_variable_read_node
    end
  end

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

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_instance_variable_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> InstanceVariableTargetNode
    def copy(**params)
      InstanceVariableTargetNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :instance_variable_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :instance_variable_target_node
    end
  end

  # Represents writing to an instance variable.
  #
  #     @foo = 1
  #     ^^^^^^^^
  class InstanceVariableWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void
    def initialize(name, name_loc, value, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_instance_variable_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> InstanceVariableWriteNode
    def copy(**params)
      InstanceVariableWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :instance_variable_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :instance_variable_write_node
    end
  end

  # Represents an integer number literal.
  #
  #     1
  #     ^
  class IntegerNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # def initialize: (flags: Integer, location: Location) -> void
    def initialize(flags, location)
      @flags = flags
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_integer_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> IntegerNode
    def copy(**params)
      IntegerNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, location: location }
    end

    # def binary?: () -> bool
    def binary?
      flags.anybits?(IntegerBaseFlags::BINARY)
    end

    # def decimal?: () -> bool
    def decimal?
      flags.anybits?(IntegerBaseFlags::DECIMAL)
    end

    # def octal?: () -> bool
    def octal?
      flags.anybits?(IntegerBaseFlags::OCTAL)
    end

    # def hexadecimal?: () -> bool
    def hexadecimal?
      flags.anybits?(IntegerBaseFlags::HEXADECIMAL)
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("binary" if binary?), ("decimal" if decimal?), ("octal" if octal?), ("hexadecimal" if hexadecimal?)].compact
      inspector << "└── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :integer_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :integer_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader parts: Array[Node]
    attr_reader :parts

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (flags: Integer, opening_loc: Location, parts: Array[Node], closing_loc: Location, location: Location) -> void
    def initialize(flags, opening_loc, parts, closing_loc, location)
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_interpolated_match_last_line_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      first = parts.first
      first.set_newline_flag(newline_marked) if first
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*parts]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*parts]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, *parts, closing_loc]
    end

    # def copy: (**params) -> InterpolatedMatchLastLineNode
    def copy(**params)
      InterpolatedMatchLastLineNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:parts) { parts },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location }
    end

    # def ignore_case?: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # def extended?: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # def multi_line?: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # def once?: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # def euc_jp?: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # def ascii_8bit?: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # def windows_31j?: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # def utf_8?: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # def forced_us_ascii_encoding?: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── parts: #{inspector.list("#{inspector.prefix}│   ", parts)}"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :interpolated_match_last_line_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :interpolated_match_last_line_node
    end
  end

  # Represents a regular expression literal that contains interpolation.
  #
  #     /foo #{bar} baz/
  #     ^^^^^^^^^^^^^^^^
  class InterpolatedRegularExpressionNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader parts: Array[Node]
    attr_reader :parts

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (flags: Integer, opening_loc: Location, parts: Array[Node], closing_loc: Location, location: Location) -> void
    def initialize(flags, opening_loc, parts, closing_loc, location)
      @flags = flags
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_interpolated_regular_expression_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      first = parts.first
      first.set_newline_flag(newline_marked) if first
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*parts]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*parts]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, *parts, closing_loc]
    end

    # def copy: (**params) -> InterpolatedRegularExpressionNode
    def copy(**params)
      InterpolatedRegularExpressionNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:parts) { parts },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location }
    end

    # def ignore_case?: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # def extended?: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # def multi_line?: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # def once?: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # def euc_jp?: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # def ascii_8bit?: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # def windows_31j?: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # def utf_8?: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # def forced_us_ascii_encoding?: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── parts: #{inspector.list("#{inspector.prefix}│   ", parts)}"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :interpolated_regular_expression_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :interpolated_regular_expression_node
    end
  end

  # Represents a string literal that contains interpolation.
  #
  #     "foo #{bar} baz"
  #     ^^^^^^^^^^^^^^^^
  class InterpolatedStringNode < Node
    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader parts: Array[Node]
    attr_reader :parts

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (opening_loc: Location?, parts: Array[Node], closing_loc: Location?, location: Location) -> void
    def initialize(opening_loc, parts, closing_loc, location)
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_interpolated_string_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      first = parts.first
      first.set_newline_flag(newline_marked) if first
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*parts]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*parts]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*opening_loc, *parts, *closing_loc]
    end

    # def copy: (**params) -> InterpolatedStringNode
    def copy(**params)
      InterpolatedStringNode.new(
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:parts) { parts },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── parts: #{inspector.list("#{inspector.prefix}│   ", parts)}"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :interpolated_string_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :interpolated_string_node
    end
  end

  # Represents a symbol literal that contains interpolation.
  #
  #     :"foo #{bar} baz"
  #     ^^^^^^^^^^^^^^^^^
  class InterpolatedSymbolNode < Node
    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader parts: Array[Node]
    attr_reader :parts

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # def initialize: (opening_loc: Location?, parts: Array[Node], closing_loc: Location?, location: Location) -> void
    def initialize(opening_loc, parts, closing_loc, location)
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_interpolated_symbol_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      first = parts.first
      first.set_newline_flag(newline_marked) if first
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*parts]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*parts]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*opening_loc, *parts, *closing_loc]
    end

    # def copy: (**params) -> InterpolatedSymbolNode
    def copy(**params)
      InterpolatedSymbolNode.new(
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:parts) { parts },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── parts: #{inspector.list("#{inspector.prefix}│   ", parts)}"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :interpolated_symbol_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :interpolated_symbol_node
    end
  end

  # Represents an xstring literal that contains interpolation.
  #
  #     `foo #{bar} baz`
  #     ^^^^^^^^^^^^^^^^
  class InterpolatedXStringNode < Node
    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader parts: Array[Node]
    attr_reader :parts

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (opening_loc: Location, parts: Array[Node], closing_loc: Location, location: Location) -> void
    def initialize(opening_loc, parts, closing_loc, location)
      @opening_loc = opening_loc
      @parts = parts
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_interpolated_x_string_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      first = parts.first
      first.set_newline_flag(newline_marked) if first
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*parts]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*parts]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, *parts, closing_loc]
    end

    # def copy: (**params) -> InterpolatedXStringNode
    def copy(**params)
      InterpolatedXStringNode.new(
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:parts) { parts },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── parts: #{inspector.list("#{inspector.prefix}│   ", parts)}"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :interpolated_x_string_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :interpolated_x_string_node
    end
  end

  # Represents a hash literal without opening and closing braces.
  #
  #     foo(a: b)
  #         ^^^^
  class KeywordHashNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader elements: Array[Node]
    attr_reader :elements

    # def initialize: (flags: Integer, elements: Array[Node], location: Location) -> void
    def initialize(flags, elements, location)
      @flags = flags
      @elements = elements
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_keyword_hash_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*elements]
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*elements]
    end

    # def copy: (**params) -> KeywordHashNode
    def copy(**params)
      KeywordHashNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:elements) { elements },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, elements: elements, location: location }
    end

    # def static_keys?: () -> bool
    def static_keys?
      flags.anybits?(KeywordHashNodeFlags::STATIC_KEYS)
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("static_keys" if static_keys?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "└── elements: #{inspector.list("#{inspector.prefix}    ", elements)}"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :keyword_hash_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :keyword_hash_node
    end
  end

  # Represents a keyword rest parameter to a method, block, or lambda definition.
  #
  #     def a(**b)
  #           ^^^
  #     end
  class KeywordRestParameterNode < Node
    # attr_reader name: Symbol?
    attr_reader :name

    # attr_reader name_loc: Location?
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol?, name_loc: Location?, operator_loc: Location, location: Location) -> void
    def initialize(name, name_loc, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_keyword_rest_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

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

    # def copy: (**params) -> KeywordRestParameterNode
    def copy(**params)
      KeywordRestParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (name = self.name).nil?
        inspector << "├── name: ∅\n"
      else
        inspector << "├── name: #{name.inspect}\n"
      end
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :keyword_rest_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :keyword_rest_parameter_node
    end
  end

  # Represents using a lambda literal (not the lambda method call).
  #
  #     ->(value) { value * 2 }
  #     ^^^^^^^^^^^^^^^^^^^^^^^
  class LambdaNode < Node
    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader locals_body_index: Integer
    attr_reader :locals_body_index

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader parameters: Node?
    attr_reader :parameters

    # attr_reader body: Node?
    attr_reader :body

    # def initialize: (locals: Array[Symbol], locals_body_index: Integer, operator_loc: Location, opening_loc: Location, closing_loc: Location, parameters: Node?, body: Node?, location: Location) -> void
    def initialize(locals, locals_body_index, operator_loc, opening_loc, closing_loc, parameters, body, location)
      @locals = locals
      @locals_body_index = locals_body_index
      @operator_loc = operator_loc
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @parameters = parameters
      @body = body
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_lambda_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [parameters, body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << parameters if parameters
      compact << body if body
      compact
    end

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

    # def copy: (**params) -> LambdaNode
    def copy(**params)
      LambdaNode.new(
        params.fetch(:locals) { locals },
        params.fetch(:locals_body_index) { locals_body_index },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:parameters) { parameters },
        params.fetch(:body) { body },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { locals: locals, locals_body_index: locals_body_index, operator_loc: operator_loc, opening_loc: opening_loc, closing_loc: closing_loc, parameters: parameters, body: body, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "├── locals_body_index: #{locals_body_index.inspect}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      if (parameters = self.parameters).nil?
        inspector << "├── parameters: ∅\n"
      else
        inspector << "├── parameters:\n"
        inspector << parameters.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (body = self.body).nil?
        inspector << "└── body: ∅\n"
      else
        inspector << "└── body:\n"
        inspector << body.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :lambda_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :lambda_node
    end
  end

  # Represents the use of the `&&=` operator for assignment to a local variable.
  #
  #     target &&= value
  #     ^^^^^^^^^^^^^^^^
  class LocalVariableAndWriteNode < Node
    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader depth: Integer
    attr_reader :depth

    # def initialize: (name_loc: Location, operator_loc: Location, value: Node, name: Symbol, depth: Integer, location: Location) -> void
    def initialize(name_loc, operator_loc, value, name, depth, location)
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @name = name
      @depth = depth
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_local_variable_and_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> LocalVariableAndWriteNode
    def copy(**params)
      LocalVariableAndWriteNode.new(
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:name) { name },
        params.fetch(:depth) { depth },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name_loc: name_loc, operator_loc: operator_loc, value: value, name: name, depth: depth, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── name: #{name.inspect}\n"
      inspector << "└── depth: #{depth.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :local_variable_and_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :local_variable_and_write_node
    end
  end

  # Represents assigning to a local variable using an operator that isn't `=`.
  #
  #     target += value
  #     ^^^^^^^^^^^^^^^
  class LocalVariableOperatorWriteNode < Node
    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader operator: Symbol
    attr_reader :operator

    # attr_reader depth: Integer
    attr_reader :depth

    # def initialize: (name_loc: Location, operator_loc: Location, value: Node, name: Symbol, operator: Symbol, depth: Integer, location: Location) -> void
    def initialize(name_loc, operator_loc, value, name, operator, depth, location)
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @name = name
      @operator = operator
      @depth = depth
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_local_variable_operator_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> LocalVariableOperatorWriteNode
    def copy(**params)
      LocalVariableOperatorWriteNode.new(
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:name) { name },
        params.fetch(:operator) { operator },
        params.fetch(:depth) { depth },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name_loc: name_loc, operator_loc: operator_loc, value: value, name: name, operator: operator, depth: depth, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── operator: #{operator.inspect}\n"
      inspector << "└── depth: #{depth.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :local_variable_operator_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :local_variable_operator_write_node
    end
  end

  # Represents the use of the `||=` operator for assignment to a local variable.
  #
  #     target ||= value
  #     ^^^^^^^^^^^^^^^^
  class LocalVariableOrWriteNode < Node
    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader depth: Integer
    attr_reader :depth

    # def initialize: (name_loc: Location, operator_loc: Location, value: Node, name: Symbol, depth: Integer, location: Location) -> void
    def initialize(name_loc, operator_loc, value, name, depth, location)
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @name = name
      @depth = depth
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_local_variable_or_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> LocalVariableOrWriteNode
    def copy(**params)
      LocalVariableOrWriteNode.new(
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:name) { name },
        params.fetch(:depth) { depth },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name_loc: name_loc, operator_loc: operator_loc, value: value, name: name, depth: depth, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── name: #{name.inspect}\n"
      inspector << "└── depth: #{depth.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :local_variable_or_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :local_variable_or_write_node
    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
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader depth: Integer
    attr_reader :depth

    # def initialize: (name: Symbol, depth: Integer, location: Location) -> void
    def initialize(name, depth, location)
      @name = name
      @depth = depth
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_local_variable_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> LocalVariableReadNode
    def copy(**params)
      LocalVariableReadNode.new(
        params.fetch(:name) { name },
        params.fetch(:depth) { depth },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, depth: depth, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "└── depth: #{depth.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :local_variable_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :local_variable_read_node
    end
  end

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

    # attr_reader depth: Integer
    attr_reader :depth

    # def initialize: (name: Symbol, depth: Integer, location: Location) -> void
    def initialize(name, depth, location)
      @name = name
      @depth = depth
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_local_variable_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> LocalVariableTargetNode
    def copy(**params)
      LocalVariableTargetNode.new(
        params.fetch(:name) { name },
        params.fetch(:depth) { depth },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, depth: depth, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "└── depth: #{depth.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :local_variable_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :local_variable_target_node
    end
  end

  # Represents writing to a local variable.
  #
  #     foo = 1
  #     ^^^^^^^
  class LocalVariableWriteNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader depth: Integer
    attr_reader :depth

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader value: Node
    attr_reader :value

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol, depth: Integer, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void
    def initialize(name, depth, name_loc, value, operator_loc, location)
      @name = name
      @depth = depth
      @name_loc = name_loc
      @value = value
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_local_variable_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> LocalVariableWriteNode
    def copy(**params)
      LocalVariableWriteNode.new(
        params.fetch(:name) { name },
        params.fetch(:depth) { depth },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:value) { value },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, depth: depth, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── depth: #{depth.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :local_variable_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :local_variable_write_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader content_loc: Location
    attr_reader :content_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader unescaped: String
    attr_reader :unescaped

    # def initialize: (flags: Integer, opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, location: Location) -> void
    def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location)
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_match_last_line_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, content_loc, closing_loc]
    end

    # def copy: (**params) -> MatchLastLineNode
    def copy(**params)
      MatchLastLineNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:content_loc) { content_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:unescaped) { unescaped },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location }
    end

    # def ignore_case?: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # def extended?: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # def multi_line?: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # def once?: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # def euc_jp?: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # def ascii_8bit?: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # def windows_31j?: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # def utf_8?: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # def forced_us_ascii_encoding?: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def content: () -> String
    def content
      content_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── content_loc: #{inspector.location(content_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "└── unescaped: #{unescaped.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :match_last_line_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :match_last_line_node
    end
  end

  # Represents the use of the modifier `in` operator.
  #
  #     foo in bar
  #     ^^^^^^^^^^
  class MatchPredicateNode < Node
    # attr_reader value: Node
    attr_reader :value

    # attr_reader pattern: Node
    attr_reader :pattern

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (value: Node, pattern: Node, operator_loc: Location, location: Location) -> void
    def initialize(value, pattern, operator_loc, location)
      @value = value
      @pattern = pattern
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_match_predicate_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value, pattern]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [value, pattern]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [value, pattern, operator_loc]
    end

    # def copy: (**params) -> MatchPredicateNode
    def copy(**params)
      MatchPredicateNode.new(
        params.fetch(:value) { value },
        params.fetch(:pattern) { pattern },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { value: value, pattern: pattern, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── pattern:\n"
      inspector << inspector.child_node(pattern, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :match_predicate_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :match_predicate_node
    end
  end

  # Represents the use of the `=>` operator.
  #
  #     foo => bar
  #     ^^^^^^^^^^
  class MatchRequiredNode < Node
    # attr_reader value: Node
    attr_reader :value

    # attr_reader pattern: Node
    attr_reader :pattern

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (value: Node, pattern: Node, operator_loc: Location, location: Location) -> void
    def initialize(value, pattern, operator_loc, location)
      @value = value
      @pattern = pattern
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_match_required_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value, pattern]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [value, pattern]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [value, pattern, operator_loc]
    end

    # def copy: (**params) -> MatchRequiredNode
    def copy(**params)
      MatchRequiredNode.new(
        params.fetch(:value) { value },
        params.fetch(:pattern) { pattern },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { value: value, pattern: pattern, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── value:\n"
      inspector << inspector.child_node(value, "│   ")
      inspector << "├── pattern:\n"
      inspector << inspector.child_node(pattern, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :match_required_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :match_required_node
    end
  end

  # Represents writing local variables using a regular expression match with
  # named capture groups.
  #
  #     /(?<foo>bar)/ =~ baz
  #     ^^^^^^^^^^^^^^^^^^^^
  class MatchWriteNode < Node
    # attr_reader call: CallNode
    attr_reader :call

    # attr_reader targets: Array[Node]
    attr_reader :targets

    # def initialize: (call: CallNode, targets: Array[Node], location: Location) -> void
    def initialize(call, targets, location)
      @call = call
      @targets = targets
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_match_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [call, *targets]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [call, *targets]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [call, *targets]
    end

    # def copy: (**params) -> MatchWriteNode
    def copy(**params)
      MatchWriteNode.new(
        params.fetch(:call) { call },
        params.fetch(:targets) { targets },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { call: call, targets: targets, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── call:\n"
      inspector << inspector.child_node(call, "│   ")
      inspector << "└── targets: #{inspector.list("#{inspector.prefix}    ", targets)}"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :match_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :match_write_node
    end
  end

  # Represents a node that is missing from the source and results in a syntax
  # error.
  class MissingNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_missing_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> MissingNode
    def copy(**params)
      MissingNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :missing_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :missing_node
    end
  end

  # Represents a module declaration involving the `module` keyword.
  #
  #     module Foo end
  #     ^^^^^^^^^^^^^^
  class ModuleNode < Node
    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader module_keyword_loc: Location
    attr_reader :module_keyword_loc

    # attr_reader constant_path: Node
    attr_reader :constant_path

    # attr_reader body: Node?
    attr_reader :body

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (locals: Array[Symbol], module_keyword_loc: Location, constant_path: Node, body: Node?, end_keyword_loc: Location, name: Symbol, location: Location) -> void
    def initialize(locals, module_keyword_loc, constant_path, body, end_keyword_loc, name, location)
      @locals = locals
      @module_keyword_loc = module_keyword_loc
      @constant_path = constant_path
      @body = body
      @end_keyword_loc = end_keyword_loc
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_module_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [constant_path, body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << constant_path
      compact << body if body
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [module_keyword_loc, constant_path, *body, end_keyword_loc]
    end

    # def copy: (**params) -> ModuleNode
    def copy(**params)
      ModuleNode.new(
        params.fetch(:locals) { locals },
        params.fetch(:module_keyword_loc) { module_keyword_loc },
        params.fetch(:constant_path) { constant_path },
        params.fetch(:body) { body },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { locals: locals, module_keyword_loc: module_keyword_loc, constant_path: constant_path, body: body, end_keyword_loc: end_keyword_loc, name: name, location: location }
    end

    # def module_keyword: () -> String
    def module_keyword
      module_keyword_loc.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "├── module_keyword_loc: #{inspector.location(module_keyword_loc)}\n"
      inspector << "├── constant_path:\n"
      inspector << inspector.child_node(constant_path, "│   ")
      if (body = self.body).nil?
        inspector << "├── body: ∅\n"
      else
        inspector << "├── body:\n"
        inspector << body.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :module_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :module_node
    end
  end

  # Represents a multi-target expression.
  #
  #     a, (b, c) = 1, 2, 3
  #        ^^^^^^
  class MultiTargetNode < Node
    # attr_reader lefts: Array[Node]
    attr_reader :lefts

    # attr_reader rest: Node?
    attr_reader :rest

    # attr_reader rights: Array[Node]
    attr_reader :rights

    # attr_reader lparen_loc: Location?
    attr_reader :lparen_loc

    # attr_reader rparen_loc: Location?
    attr_reader :rparen_loc

    # def initialize: (lefts: Array[Node], rest: Node?, rights: Array[Node], lparen_loc: Location?, rparen_loc: Location?, location: Location) -> void
    def initialize(lefts, rest, rights, lparen_loc, rparen_loc, location)
      @lefts = lefts
      @rest = rest
      @rights = rights
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_multi_target_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*lefts, rest, *rights]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact.concat(lefts)
      compact << rest if rest
      compact.concat(rights)
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*lefts, *rest, *rights, *lparen_loc, *rparen_loc]
    end

    # def copy: (**params) -> MultiTargetNode
    def copy(**params)
      MultiTargetNode.new(
        params.fetch(:lefts) { lefts },
        params.fetch(:rest) { rest },
        params.fetch(:rights) { rights },
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { lefts: lefts, rest: rest, rights: rights, lparen_loc: lparen_loc, rparen_loc: rparen_loc, location: location }
    end

    # def lparen: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # def rparen: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── lefts: #{inspector.list("#{inspector.prefix}│   ", lefts)}"
      if (rest = self.rest).nil?
        inspector << "├── rest: ∅\n"
      else
        inspector << "├── rest:\n"
        inspector << rest.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── rights: #{inspector.list("#{inspector.prefix}│   ", rights)}"
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      inspector << "└── rparen_loc: #{inspector.location(rparen_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :multi_target_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :multi_target_node
    end
  end

  # Represents a write to a multi-target expression.
  #
  #     a, b, c = 1, 2, 3
  #     ^^^^^^^^^^^^^^^^^
  class MultiWriteNode < Node
    # attr_reader lefts: Array[Node]
    attr_reader :lefts

    # attr_reader rest: Node?
    attr_reader :rest

    # attr_reader rights: Array[Node]
    attr_reader :rights

    # attr_reader lparen_loc: Location?
    attr_reader :lparen_loc

    # attr_reader rparen_loc: Location?
    attr_reader :rparen_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (lefts: Array[Node], rest: Node?, rights: Array[Node], lparen_loc: Location?, rparen_loc: Location?, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(lefts, rest, rights, lparen_loc, rparen_loc, operator_loc, value, location)
      @lefts = lefts
      @rest = rest
      @rights = rights
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_multi_write_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*lefts, rest, *rights, value]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact.concat(lefts)
      compact << rest if rest
      compact.concat(rights)
      compact << value
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*lefts, *rest, *rights, *lparen_loc, *rparen_loc, operator_loc, value]
    end

    # def copy: (**params) -> MultiWriteNode
    def copy(**params)
      MultiWriteNode.new(
        params.fetch(:lefts) { lefts },
        params.fetch(:rest) { rest },
        params.fetch(:rights) { rights },
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { lefts: lefts, rest: rest, rights: rights, lparen_loc: lparen_loc, rparen_loc: rparen_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def lparen: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # def rparen: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── lefts: #{inspector.list("#{inspector.prefix}│   ", lefts)}"
      if (rest = self.rest).nil?
        inspector << "├── rest: ∅\n"
      else
        inspector << "├── rest:\n"
        inspector << rest.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── rights: #{inspector.list("#{inspector.prefix}│   ", rights)}"
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :multi_write_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :multi_write_node
    end
  end

  # Represents the use of the `next` keyword.
  #
  #     next 1
  #     ^^^^^^
  class NextNode < Node
    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (arguments: ArgumentsNode?, keyword_loc: Location, location: Location) -> void
    def initialize(arguments, keyword_loc, location)
      @arguments = arguments
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_next_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [arguments]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << arguments if arguments
      compact
    end

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

    # def copy: (**params) -> NextNode
    def copy(**params)
      NextNode.new(
        params.fetch(:arguments) { arguments },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { arguments: arguments, keyword_loc: keyword_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :next_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :next_node
    end
  end

  # Represents the use of the `nil` keyword.
  #
  #     nil
  #     ^^^
  class NilNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_nil_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> NilNode
    def copy(**params)
      NilNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :nil_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :nil_node
    end
  end

  # Represents the use of `**nil` inside method arguments.
  #
  #     def a(**nil)
  #           ^^^^^
  #     end
  class NoKeywordsParameterNode < Node
    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (operator_loc: Location, keyword_loc: Location, location: Location) -> void
    def initialize(operator_loc, keyword_loc, location)
      @operator_loc = operator_loc
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_no_keywords_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [operator_loc, keyword_loc]
    end

    # def copy: (**params) -> NoKeywordsParameterNode
    def copy(**params)
      NoKeywordsParameterNode.new(
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { operator_loc: operator_loc, keyword_loc: keyword_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :no_keywords_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :no_keywords_parameter_node
    end
  end

  # Represents an implicit set of parameters through the use of numbered
  # parameters within a block or lambda.
  #
  #     -> { _1 + _2 }
  #     ^^^^^^^^^^^^^^
  class NumberedParametersNode < Node
    # attr_reader maximum: Integer
    attr_reader :maximum

    # def initialize: (maximum: Integer, location: Location) -> void
    def initialize(maximum, location)
      @maximum = maximum
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_numbered_parameters_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> NumberedParametersNode
    def copy(**params)
      NumberedParametersNode.new(
        params.fetch(:maximum) { maximum },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { maximum: maximum, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── maximum: #{maximum.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :numbered_parameters_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :numbered_parameters_node
    end
  end

  # Represents reading a numbered reference to a capture in the previous match.
  #
  #     $1
  #     ^^
  class NumberedReferenceReadNode < Node
    # attr_reader number: Integer
    attr_reader :number

    # def initialize: (number: Integer, location: Location) -> void
    def initialize(number, location)
      @number = number
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_numbered_reference_read_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> NumberedReferenceReadNode
    def copy(**params)
      NumberedReferenceReadNode.new(
        params.fetch(:number) { number },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { number: number, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── number: #{number.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :numbered_reference_read_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :numbered_reference_read_node
    end
  end

  # Represents an optional keyword parameter to a method, block, or lambda definition.
  #
  #     def a(b: 1)
  #           ^^^^
  #     end
  class OptionalKeywordParameterNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, value, location)
      @name = name
      @name_loc = name_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_optional_keyword_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [name_loc, value]
    end

    # def copy: (**params) -> OptionalKeywordParameterNode
    def copy(**params)
      OptionalKeywordParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, value: value, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :optional_keyword_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :optional_keyword_parameter_node
    end
  end

  # Represents an optional parameter to a method, block, or lambda definition.
  #
  #     def a(b = 1)
  #           ^^^^^
  #     end
  class OptionalParameterNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader value: Node
    attr_reader :value

    # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void
    def initialize(name, name_loc, operator_loc, value, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @value = value
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_optional_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [value]
    end

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

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

    # def copy: (**params) -> OptionalParameterNode
    def copy(**params)
      OptionalParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:value) { value },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "└── value:\n"
      inspector << inspector.child_node(value, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :optional_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :optional_parameter_node
    end
  end

  # Represents the use of the `||` operator or the `or` keyword.
  #
  #     left or right
  #     ^^^^^^^^^^^^^
  class OrNode < Node
    # attr_reader left: Node
    attr_reader :left

    # attr_reader right: Node
    attr_reader :right

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (left: Node, right: Node, operator_loc: Location, location: Location) -> void
    def initialize(left, right, operator_loc, location)
      @left = left
      @right = right
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_or_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [left, right]
    end

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

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

    # def copy: (**params) -> OrNode
    def copy(**params)
      OrNode.new(
        params.fetch(:left) { left },
        params.fetch(:right) { right },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { left: left, right: right, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── left:\n"
      inspector << inspector.child_node(left, "│   ")
      inspector << "├── right:\n"
      inspector << inspector.child_node(right, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :or_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :or_node
    end
  end

  # Represents the list of parameters on a method, block, or lambda definition.
  #
  #     def a(b, c, d)
  #           ^^^^^^^
  #     end
  class ParametersNode < Node
    # attr_reader requireds: Array[Node]
    attr_reader :requireds

    # attr_reader optionals: Array[Node]
    attr_reader :optionals

    # attr_reader rest: Node?
    attr_reader :rest

    # attr_reader posts: Array[Node]
    attr_reader :posts

    # attr_reader keywords: Array[Node]
    attr_reader :keywords

    # attr_reader keyword_rest: Node?
    attr_reader :keyword_rest

    # attr_reader block: BlockParameterNode?
    attr_reader :block

    # def initialize: (requireds: Array[Node], optionals: Array[Node], rest: Node?, posts: Array[Node], keywords: Array[Node], keyword_rest: Node?, block: BlockParameterNode?, location: Location) -> void
    def initialize(requireds, optionals, rest, posts, keywords, keyword_rest, block, location)
      @requireds = requireds
      @optionals = optionals
      @rest = rest
      @posts = posts
      @keywords = keywords
      @keyword_rest = keyword_rest
      @block = block
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_parameters_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*requireds, *optionals, rest, *posts, *keywords, keyword_rest, block]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact.concat(requireds)
      compact.concat(optionals)
      compact << rest if rest
      compact.concat(posts)
      compact.concat(keywords)
      compact << keyword_rest if keyword_rest
      compact << block if block
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*requireds, *optionals, *rest, *posts, *keywords, *keyword_rest, *block]
    end

    # def copy: (**params) -> ParametersNode
    def copy(**params)
      ParametersNode.new(
        params.fetch(:requireds) { requireds },
        params.fetch(:optionals) { optionals },
        params.fetch(:rest) { rest },
        params.fetch(:posts) { posts },
        params.fetch(:keywords) { keywords },
        params.fetch(:keyword_rest) { keyword_rest },
        params.fetch(:block) { block },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { requireds: requireds, optionals: optionals, rest: rest, posts: posts, keywords: keywords, keyword_rest: keyword_rest, block: block, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── requireds: #{inspector.list("#{inspector.prefix}│   ", requireds)}"
      inspector << "├── optionals: #{inspector.list("#{inspector.prefix}│   ", optionals)}"
      if (rest = self.rest).nil?
        inspector << "├── rest: ∅\n"
      else
        inspector << "├── rest:\n"
        inspector << rest.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── posts: #{inspector.list("#{inspector.prefix}│   ", posts)}"
      inspector << "├── keywords: #{inspector.list("#{inspector.prefix}│   ", keywords)}"
      if (keyword_rest = self.keyword_rest).nil?
        inspector << "├── keyword_rest: ∅\n"
      else
        inspector << "├── keyword_rest:\n"
        inspector << keyword_rest.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (block = self.block).nil?
        inspector << "└── block: ∅\n"
      else
        inspector << "└── block:\n"
        inspector << block.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :parameters_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :parameters_node
    end
  end

  # Represents a parenthesized expression
  #
  #     (10 + 34)
  #     ^^^^^^^^^
  class ParenthesesNode < Node
    # attr_reader body: Node?
    attr_reader :body

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (body: Node?, opening_loc: Location, closing_loc: Location, location: Location) -> void
    def initialize(body, opening_loc, closing_loc, location)
      @body = body
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_parentheses_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      # Never mark ParenthesesNode with a newline flag, mark children instead
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << body if body
      compact
    end

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

    # def copy: (**params) -> ParenthesesNode
    def copy(**params)
      ParenthesesNode.new(
        params.fetch(:body) { body },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { body: body, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (body = self.body).nil?
        inspector << "├── body: ∅\n"
      else
        inspector << "├── body:\n"
        inspector << body.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :parentheses_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :parentheses_node
    end
  end

  # Represents the use of the `^` operator for pinning an expression in a
  # pattern matching expression.
  #
  #     foo in ^(bar)
  #            ^^^^^^
  class PinnedExpressionNode < Node
    # attr_reader expression: Node
    attr_reader :expression

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader lparen_loc: Location
    attr_reader :lparen_loc

    # attr_reader rparen_loc: Location
    attr_reader :rparen_loc

    # def initialize: (expression: Node, operator_loc: Location, lparen_loc: Location, rparen_loc: Location, location: Location) -> void
    def initialize(expression, operator_loc, lparen_loc, rparen_loc, location)
      @expression = expression
      @operator_loc = operator_loc
      @lparen_loc = lparen_loc
      @rparen_loc = rparen_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_pinned_expression_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [expression]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [expression]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [expression, operator_loc, lparen_loc, rparen_loc]
    end

    # def copy: (**params) -> PinnedExpressionNode
    def copy(**params)
      PinnedExpressionNode.new(
        params.fetch(:expression) { expression },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { expression: expression, operator_loc: operator_loc, lparen_loc: lparen_loc, rparen_loc: rparen_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def lparen: () -> String
    def lparen
      lparen_loc.slice
    end

    # def rparen: () -> String
    def rparen
      rparen_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── expression:\n"
      inspector << inspector.child_node(expression, "│   ")
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      inspector << "└── rparen_loc: #{inspector.location(rparen_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :pinned_expression_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :pinned_expression_node
    end
  end

  # Represents the use of the `^` operator for pinning a variable in a pattern
  # matching expression.
  #
  #     foo in ^bar
  #            ^^^^
  class PinnedVariableNode < Node
    # attr_reader variable: Node
    attr_reader :variable

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (variable: Node, operator_loc: Location, location: Location) -> void
    def initialize(variable, operator_loc, location)
      @variable = variable
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_pinned_variable_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [variable]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [variable]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [variable, operator_loc]
    end

    # def copy: (**params) -> PinnedVariableNode
    def copy(**params)
      PinnedVariableNode.new(
        params.fetch(:variable) { variable },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { variable: variable, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── variable:\n"
      inspector << inspector.child_node(variable, "│   ")
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :pinned_variable_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :pinned_variable_node
    end
  end

  # Represents the use of the `END` keyword.
  #
  #     END { foo }
  #     ^^^^^^^^^^^
  class PostExecutionNode < Node
    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (statements: StatementsNode?, keyword_loc: Location, opening_loc: Location, closing_loc: Location, location: Location) -> void
    def initialize(statements, keyword_loc, opening_loc, closing_loc, location)
      @statements = statements
      @keyword_loc = keyword_loc
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_post_execution_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*statements, keyword_loc, opening_loc, closing_loc]
    end

    # def copy: (**params) -> PostExecutionNode
    def copy(**params)
      PostExecutionNode.new(
        params.fetch(:statements) { statements },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { statements: statements, keyword_loc: keyword_loc, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :post_execution_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :post_execution_node
    end
  end

  # Represents the use of the `BEGIN` keyword.
  #
  #     BEGIN { foo }
  #     ^^^^^^^^^^^^^
  class PreExecutionNode < Node
    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # def initialize: (statements: StatementsNode?, keyword_loc: Location, opening_loc: Location, closing_loc: Location, location: Location) -> void
    def initialize(statements, keyword_loc, opening_loc, closing_loc, location)
      @statements = statements
      @keyword_loc = keyword_loc
      @opening_loc = opening_loc
      @closing_loc = closing_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_pre_execution_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*statements, keyword_loc, opening_loc, closing_loc]
    end

    # def copy: (**params) -> PreExecutionNode
    def copy(**params)
      PreExecutionNode.new(
        params.fetch(:statements) { statements },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { statements: statements, keyword_loc: keyword_loc, opening_loc: opening_loc, closing_loc: closing_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :pre_execution_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :pre_execution_node
    end
  end

  # The top level node of any parse tree.
  class ProgramNode < Node
    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader statements: StatementsNode
    attr_reader :statements

    # def initialize: (locals: Array[Symbol], statements: StatementsNode, location: Location) -> void
    def initialize(locals, statements, location)
      @locals = locals
      @statements = statements
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_program_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [statements]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [statements]
    end

    # def copy: (**params) -> ProgramNode
    def copy(**params)
      ProgramNode.new(
        params.fetch(:locals) { locals },
        params.fetch(:statements) { statements },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { locals: locals, statements: statements, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "└── statements:\n"
      inspector << inspector.child_node(statements, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :program_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :program_node
    end
  end

  # Represents the use of the `..` or `...` operators.
  #
  #     1..2
  #     ^^^^
  #
  #     c if a =~ /left/ ... b =~ /right/
  #          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  class RangeNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader left: Node?
    attr_reader :left

    # attr_reader right: Node?
    attr_reader :right

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (flags: Integer, left: Node?, right: Node?, operator_loc: Location, location: Location) -> void
    def initialize(flags, left, right, operator_loc, location)
      @flags = flags
      @left = left
      @right = right
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_range_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [left, right]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << left if left
      compact << right if right
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*left, *right, operator_loc]
    end

    # def copy: (**params) -> RangeNode
    def copy(**params)
      RangeNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:left) { left },
        params.fetch(:right) { right },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, left: left, right: right, operator_loc: operator_loc, location: location }
    end

    # def exclude_end?: () -> bool
    def exclude_end?
      flags.anybits?(RangeFlags::EXCLUDE_END)
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("exclude_end" if exclude_end?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      if (left = self.left).nil?
        inspector << "├── left: ∅\n"
      else
        inspector << "├── left:\n"
        inspector << left.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (right = self.right).nil?
        inspector << "├── right: ∅\n"
      else
        inspector << "├── right:\n"
        inspector << right.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :range_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :range_node
    end
  end

  # Represents a rational number literal.
  #
  #     1.0r
  #     ^^^^
  class RationalNode < Node
    # attr_reader numeric: Node
    attr_reader :numeric

    # def initialize: (numeric: Node, location: Location) -> void
    def initialize(numeric, location)
      @numeric = numeric
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_rational_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [numeric]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [numeric]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [numeric]
    end

    # def copy: (**params) -> RationalNode
    def copy(**params)
      RationalNode.new(
        params.fetch(:numeric) { numeric },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { numeric: numeric, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── numeric:\n"
      inspector << inspector.child_node(numeric, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :rational_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :rational_node
    end
  end

  # Represents the use of the `redo` keyword.
  #
  #     redo
  #     ^^^^
  class RedoNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_redo_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> RedoNode
    def copy(**params)
      RedoNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :redo_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :redo_node
    end
  end

  # Represents a regular expression literal with no interpolation.
  #
  #     /foo/i
  #     ^^^^^^
  class RegularExpressionNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader content_loc: Location
    attr_reader :content_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader unescaped: String
    attr_reader :unescaped

    # def initialize: (flags: Integer, opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, location: Location) -> void
    def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location)
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_regular_expression_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, content_loc, closing_loc]
    end

    # def copy: (**params) -> RegularExpressionNode
    def copy(**params)
      RegularExpressionNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:content_loc) { content_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:unescaped) { unescaped },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location }
    end

    # def ignore_case?: () -> bool
    def ignore_case?
      flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
    end

    # def extended?: () -> bool
    def extended?
      flags.anybits?(RegularExpressionFlags::EXTENDED)
    end

    # def multi_line?: () -> bool
    def multi_line?
      flags.anybits?(RegularExpressionFlags::MULTI_LINE)
    end

    # def once?: () -> bool
    def once?
      flags.anybits?(RegularExpressionFlags::ONCE)
    end

    # def euc_jp?: () -> bool
    def euc_jp?
      flags.anybits?(RegularExpressionFlags::EUC_JP)
    end

    # def ascii_8bit?: () -> bool
    def ascii_8bit?
      flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
    end

    # def windows_31j?: () -> bool
    def windows_31j?
      flags.anybits?(RegularExpressionFlags::WINDOWS_31J)
    end

    # def utf_8?: () -> bool
    def utf_8?
      flags.anybits?(RegularExpressionFlags::UTF_8)
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING)
    end

    # def forced_us_ascii_encoding?: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING)
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def content: () -> String
    def content
      content_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── content_loc: #{inspector.location(content_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "└── unescaped: #{unescaped.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :regular_expression_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :regular_expression_node
    end
  end

  # Represents a required keyword parameter to a method, block, or lambda definition.
  #
  #     def a(b: )
  #           ^^
  #     end
  class RequiredKeywordParameterNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # attr_reader name_loc: Location
    attr_reader :name_loc

    # def initialize: (name: Symbol, name_loc: Location, location: Location) -> void
    def initialize(name, name_loc, location)
      @name = name
      @name_loc = name_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_required_keyword_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [name_loc]
    end

    # def copy: (**params) -> RequiredKeywordParameterNode
    def copy(**params)
      RequiredKeywordParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── name: #{name.inspect}\n"
      inspector << "└── name_loc: #{inspector.location(name_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :required_keyword_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :required_keyword_parameter_node
    end
  end

  # Represents a required parameter to a method, block, or lambda definition.
  #
  #     def a(b)
  #           ^
  #     end
  class RequiredParameterNode < Node
    # attr_reader name: Symbol
    attr_reader :name

    # def initialize: (name: Symbol, location: Location) -> void
    def initialize(name, location)
      @name = name
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_required_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> RequiredParameterNode
    def copy(**params)
      RequiredParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── name: #{name.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :required_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :required_parameter_node
    end
  end

  # Represents an expression modified with a rescue.
  #
  #     foo rescue nil
  #     ^^^^^^^^^^^^^^
  class RescueModifierNode < Node
    # attr_reader expression: Node
    attr_reader :expression

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader rescue_expression: Node
    attr_reader :rescue_expression

    # def initialize: (expression: Node, keyword_loc: Location, rescue_expression: Node, location: Location) -> void
    def initialize(expression, keyword_loc, rescue_expression, location)
      @expression = expression
      @keyword_loc = keyword_loc
      @rescue_expression = rescue_expression
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_rescue_modifier_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      expression.set_newline_flag(newline_marked)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [expression, rescue_expression]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [expression, rescue_expression]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [expression, keyword_loc, rescue_expression]
    end

    # def copy: (**params) -> RescueModifierNode
    def copy(**params)
      RescueModifierNode.new(
        params.fetch(:expression) { expression },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:rescue_expression) { rescue_expression },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { expression: expression, keyword_loc: keyword_loc, rescue_expression: rescue_expression, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── expression:\n"
      inspector << inspector.child_node(expression, "│   ")
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "└── rescue_expression:\n"
      inspector << inspector.child_node(rescue_expression, "    ")
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :rescue_modifier_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :rescue_modifier_node
    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 `exception` field.
  class RescueNode < Node
    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader exceptions: Array[Node]
    attr_reader :exceptions

    # attr_reader operator_loc: Location?
    attr_reader :operator_loc

    # attr_reader reference: Node?
    attr_reader :reference

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader consequent: RescueNode?
    attr_reader :consequent

    # def initialize: (keyword_loc: Location, exceptions: Array[Node], operator_loc: Location?, reference: Node?, statements: StatementsNode?, consequent: RescueNode?, location: Location) -> void
    def initialize(keyword_loc, exceptions, operator_loc, reference, statements, consequent, location)
      @keyword_loc = keyword_loc
      @exceptions = exceptions
      @operator_loc = operator_loc
      @reference = reference
      @statements = statements
      @consequent = consequent
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_rescue_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*exceptions, reference, statements, consequent]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact.concat(exceptions)
      compact << reference if reference
      compact << statements if statements
      compact << consequent if consequent
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, *exceptions, *operator_loc, *reference, *statements, *consequent]
    end

    # def copy: (**params) -> RescueNode
    def copy(**params)
      RescueNode.new(
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:exceptions) { exceptions },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:reference) { reference },
        params.fetch(:statements) { statements },
        params.fetch(:consequent) { consequent },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { keyword_loc: keyword_loc, exceptions: exceptions, operator_loc: operator_loc, reference: reference, statements: statements, consequent: consequent, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def operator: () -> String?
    def operator
      operator_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── exceptions: #{inspector.list("#{inspector.prefix}│   ", exceptions)}"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      if (reference = self.reference).nil?
        inspector << "├── reference: ∅\n"
      else
        inspector << "├── reference:\n"
        inspector << reference.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (consequent = self.consequent).nil?
        inspector << "└── consequent: ∅\n"
      else
        inspector << "└── consequent:\n"
        inspector << consequent.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :rescue_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :rescue_node
    end
  end

  # Represents a rest parameter to a method, block, or lambda definition.
  #
  #     def a(*b)
  #           ^^
  #     end
  class RestParameterNode < Node
    # attr_reader name: Symbol?
    attr_reader :name

    # attr_reader name_loc: Location?
    attr_reader :name_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # def initialize: (name: Symbol?, name_loc: Location?, operator_loc: Location, location: Location) -> void
    def initialize(name, name_loc, operator_loc, location)
      @name = name
      @name_loc = name_loc
      @operator_loc = operator_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_rest_parameter_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

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

    # def copy: (**params) -> RestParameterNode
    def copy(**params)
      RestParameterNode.new(
        params.fetch(:name) { name },
        params.fetch(:name_loc) { name_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { name: name, name_loc: name_loc, operator_loc: operator_loc, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      if (name = self.name).nil?
        inspector << "├── name: ∅\n"
      else
        inspector << "├── name: #{name.inspect}\n"
      end
      inspector << "├── name_loc: #{inspector.location(name_loc)}\n"
      inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :rest_parameter_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :rest_parameter_node
    end
  end

  # Represents the use of the `retry` keyword.
  #
  #     retry
  #     ^^^^^
  class RetryNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_retry_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> RetryNode
    def copy(**params)
      RetryNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :retry_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :retry_node
    end
  end

  # Represents the use of the `return` keyword.
  #
  #     return 1
  #     ^^^^^^^^
  class ReturnNode < Node
    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # def initialize: (keyword_loc: Location, arguments: ArgumentsNode?, location: Location) -> void
    def initialize(keyword_loc, arguments, location)
      @keyword_loc = keyword_loc
      @arguments = arguments
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_return_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [arguments]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << arguments if arguments
      compact
    end

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

    # def copy: (**params) -> ReturnNode
    def copy(**params)
      ReturnNode.new(
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { keyword_loc: keyword_loc, arguments: arguments, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "└── arguments: ∅\n"
      else
        inspector << "└── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :return_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :return_node
    end
  end

  # Represents the `self` keyword.
  #
  #     self
  #     ^^^^
  class SelfNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_self_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> SelfNode
    def copy(**params)
      SelfNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :self_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :self_node
    end
  end

  # Represents a singleton class declaration involving the `class` keyword.
  #
  #     class << self end
  #     ^^^^^^^^^^^^^^^^^
  class SingletonClassNode < Node
    # attr_reader locals: Array[Symbol]
    attr_reader :locals

    # attr_reader class_keyword_loc: Location
    attr_reader :class_keyword_loc

    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader expression: Node
    attr_reader :expression

    # attr_reader body: Node?
    attr_reader :body

    # attr_reader end_keyword_loc: Location
    attr_reader :end_keyword_loc

    # def initialize: (locals: Array[Symbol], class_keyword_loc: Location, operator_loc: Location, expression: Node, body: Node?, end_keyword_loc: Location, location: Location) -> void
    def initialize(locals, class_keyword_loc, operator_loc, expression, body, end_keyword_loc, location)
      @locals = locals
      @class_keyword_loc = class_keyword_loc
      @operator_loc = operator_loc
      @expression = expression
      @body = body
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_singleton_class_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [expression, body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << expression
      compact << body if body
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [class_keyword_loc, operator_loc, expression, *body, end_keyword_loc]
    end

    # def copy: (**params) -> SingletonClassNode
    def copy(**params)
      SingletonClassNode.new(
        params.fetch(:locals) { locals },
        params.fetch(:class_keyword_loc) { class_keyword_loc },
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:expression) { expression },
        params.fetch(:body) { body },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { locals: locals, class_keyword_loc: class_keyword_loc, operator_loc: operator_loc, expression: expression, body: body, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def class_keyword: () -> String
    def class_keyword
      class_keyword_loc.slice
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def end_keyword: () -> String
    def end_keyword
      end_keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── locals: #{locals.inspect}\n"
      inspector << "├── class_keyword_loc: #{inspector.location(class_keyword_loc)}\n"
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      inspector << "├── expression:\n"
      inspector << inspector.child_node(expression, "│   ")
      if (body = self.body).nil?
        inspector << "├── body: ∅\n"
      else
        inspector << "├── body:\n"
        inspector << body.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :singleton_class_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :singleton_class_node
    end
  end

  # Represents the use of the `__ENCODING__` keyword.
  #
  #     __ENCODING__
  #     ^^^^^^^^^^^^
  class SourceEncodingNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_source_encoding_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> SourceEncodingNode
    def copy(**params)
      SourceEncodingNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :source_encoding_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :source_encoding_node
    end
  end

  # Represents the use of the `__FILE__` keyword.
  #
  #     __FILE__
  #     ^^^^^^^^
  class SourceFileNode < Node
    # attr_reader filepath: String
    attr_reader :filepath

    # def initialize: (filepath: String, location: Location) -> void
    def initialize(filepath, location)
      @filepath = filepath
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_source_file_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> SourceFileNode
    def copy(**params)
      SourceFileNode.new(
        params.fetch(:filepath) { filepath },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { filepath: filepath, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── filepath: #{filepath.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :source_file_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :source_file_node
    end
  end

  # Represents the use of the `__LINE__` keyword.
  #
  #     __LINE__
  #     ^^^^^^^^
  class SourceLineNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_source_line_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> SourceLineNode
    def copy(**params)
      SourceLineNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :source_line_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :source_line_node
    end
  end

  # Represents the use of the splat operator.
  #
  #     [*a]
  #      ^^
  class SplatNode < Node
    # attr_reader operator_loc: Location
    attr_reader :operator_loc

    # attr_reader expression: Node?
    attr_reader :expression

    # def initialize: (operator_loc: Location, expression: Node?, location: Location) -> void
    def initialize(operator_loc, expression, location)
      @operator_loc = operator_loc
      @expression = expression
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_splat_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [expression]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << expression if expression
      compact
    end

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

    # def copy: (**params) -> SplatNode
    def copy(**params)
      SplatNode.new(
        params.fetch(:operator_loc) { operator_loc },
        params.fetch(:expression) { expression },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { operator_loc: operator_loc, expression: expression, location: location }
    end

    # def operator: () -> String
    def operator
      operator_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n"
      if (expression = self.expression).nil?
        inspector << "└── expression: ∅\n"
      else
        inspector << "└── expression:\n"
        inspector << expression.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :splat_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :splat_node
    end
  end

  # Represents a set of statements contained within some scope.
  #
  #     foo; bar; baz
  #     ^^^^^^^^^^^^^
  class StatementsNode < Node
    # attr_reader body: Array[Node]
    attr_reader :body

    # def initialize: (body: Array[Node], location: Location) -> void
    def initialize(body, location)
      @body = body
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_statements_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*body]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*body]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*body]
    end

    # def copy: (**params) -> StatementsNode
    def copy(**params)
      StatementsNode.new(
        params.fetch(:body) { body },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { body: body, location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "└── body: #{inspector.list("#{inspector.prefix}    ", body)}"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :statements_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :statements_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader content_loc: Location
    attr_reader :content_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # attr_reader unescaped: String
    attr_reader :unescaped

    # def initialize: (flags: Integer, opening_loc: Location?, content_loc: Location, closing_loc: Location?, unescaped: String, location: Location) -> void
    def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location)
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_string_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*opening_loc, content_loc, *closing_loc]
    end

    # def copy: (**params) -> StringNode
    def copy(**params)
      StringNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:content_loc) { content_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:unescaped) { unescaped },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location }
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(StringFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(StringFlags::FORCED_BINARY_ENCODING)
    end

    # def frozen?: () -> bool
    def frozen?
      flags.anybits?(StringFlags::FROZEN)
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def content: () -> String
    def content
      content_loc.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("frozen" if frozen?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── content_loc: #{inspector.location(content_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "└── unescaped: #{unescaped.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :string_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :string_node
    end
  end

  # Represents the use of the `super` keyword with parentheses or arguments.
  #
  #     super()
  #     ^^^^^^^
  #
  #     super foo, bar
  #     ^^^^^^^^^^^^^^
  class SuperNode < Node
    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader lparen_loc: Location?
    attr_reader :lparen_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader rparen_loc: Location?
    attr_reader :rparen_loc

    # attr_reader block: Node?
    attr_reader :block

    # def initialize: (keyword_loc: Location, lparen_loc: Location?, arguments: ArgumentsNode?, rparen_loc: Location?, block: Node?, location: Location) -> void
    def initialize(keyword_loc, lparen_loc, arguments, rparen_loc, block, location)
      @keyword_loc = keyword_loc
      @lparen_loc = lparen_loc
      @arguments = arguments
      @rparen_loc = rparen_loc
      @block = block
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_super_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [arguments, block]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << arguments if arguments
      compact << block if block
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, *lparen_loc, *arguments, *rparen_loc, *block]
    end

    # def copy: (**params) -> SuperNode
    def copy(**params)
      SuperNode.new(
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:block) { block },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { keyword_loc: keyword_loc, lparen_loc: lparen_loc, arguments: arguments, rparen_loc: rparen_loc, block: block, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def lparen: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # def rparen: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n"
      if (block = self.block).nil?
        inspector << "└── block: ∅\n"
      else
        inspector << "└── block:\n"
        inspector << block.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :super_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :super_node
    end
  end

  # Represents a symbol literal or a symbol contained within a `%i` list.
  #
  #     :foo
  #     ^^^^
  #
  #     %i[foo]
  #        ^^^
  class SymbolNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location?
    attr_reader :opening_loc

    # attr_reader value_loc: Location?
    attr_reader :value_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # attr_reader unescaped: String
    attr_reader :unescaped

    # def initialize: (flags: Integer, opening_loc: Location?, value_loc: Location?, closing_loc: Location?, unescaped: String, location: Location) -> void
    def initialize(flags, opening_loc, value_loc, closing_loc, unescaped, location)
      @flags = flags
      @opening_loc = opening_loc
      @value_loc = value_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_symbol_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*opening_loc, *value_loc, *closing_loc]
    end

    # def copy: (**params) -> SymbolNode
    def copy(**params)
      SymbolNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:value_loc) { value_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:unescaped) { unescaped },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, value_loc: value_loc, closing_loc: closing_loc, unescaped: unescaped, location: location }
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(SymbolFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(SymbolFlags::FORCED_BINARY_ENCODING)
    end

    # def forced_us_ascii_encoding?: () -> bool
    def forced_us_ascii_encoding?
      flags.anybits?(SymbolFlags::FORCED_US_ASCII_ENCODING)
    end

    # def opening: () -> String?
    def opening
      opening_loc&.slice
    end

    # def value: () -> String?
    def value
      value_loc&.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── value_loc: #{inspector.location(value_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "└── unescaped: #{unescaped.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :symbol_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :symbol_node
    end
  end

  # Represents the use of the literal `true` keyword.
  #
  #     true
  #     ^^^^
  class TrueNode < Node
    # def initialize: (location: Location) -> void
    def initialize(location)
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_true_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      []
    end

    # def copy: (**params) -> TrueNode
    def copy(**params)
      TrueNode.new(
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { location: location }
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :true_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :true_node
    end
  end

  # Represents the use of the `undef` keyword.
  #
  #     undef :foo, :bar, :baz
  #     ^^^^^^^^^^^^^^^^^^^^^^
  class UndefNode < Node
    # attr_reader names: Array[Node]
    attr_reader :names

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # def initialize: (names: Array[Node], keyword_loc: Location, location: Location) -> void
    def initialize(names, keyword_loc, location)
      @names = names
      @keyword_loc = keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_undef_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*names]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      [*names]
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [*names, keyword_loc]
    end

    # def copy: (**params) -> UndefNode
    def copy(**params)
      UndefNode.new(
        params.fetch(:names) { names },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { names: names, keyword_loc: keyword_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── names: #{inspector.list("#{inspector.prefix}│   ", names)}"
      inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :undef_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :undef_node
    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
    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader predicate: Node
    attr_reader :predicate

    # attr_reader then_keyword_loc: Location?
    attr_reader :then_keyword_loc

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # attr_reader consequent: ElseNode?
    attr_reader :consequent

    # attr_reader end_keyword_loc: Location?
    attr_reader :end_keyword_loc

    # def initialize: (keyword_loc: Location, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> void
    def initialize(keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location)
      @keyword_loc = keyword_loc
      @predicate = predicate
      @then_keyword_loc = then_keyword_loc
      @statements = statements
      @consequent = consequent
      @end_keyword_loc = end_keyword_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_unless_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      predicate.set_newline_flag(newline_marked)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [predicate, statements, consequent]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << predicate
      compact << statements if statements
      compact << consequent if consequent
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, predicate, *then_keyword_loc, *statements, *consequent, *end_keyword_loc]
    end

    # def copy: (**params) -> UnlessNode
    def copy(**params)
      UnlessNode.new(
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:predicate) { predicate },
        params.fetch(:then_keyword_loc) { then_keyword_loc },
        params.fetch(:statements) { statements },
        params.fetch(:consequent) { consequent },
        params.fetch(:end_keyword_loc) { end_keyword_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { keyword_loc: keyword_loc, predicate: predicate, then_keyword_loc: then_keyword_loc, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def then_keyword: () -> String?
    def then_keyword
      then_keyword_loc&.slice
    end

    # def end_keyword: () -> String?
    def end_keyword
      end_keyword_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── predicate:\n"
      inspector << inspector.child_node(predicate, "│   ")
      inspector << "├── then_keyword_loc: #{inspector.location(then_keyword_loc)}\n"
      if (statements = self.statements).nil?
        inspector << "├── statements: ∅\n"
      else
        inspector << "├── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      if (consequent = self.consequent).nil?
        inspector << "├── consequent: ∅\n"
      else
        inspector << "├── consequent:\n"
        inspector << consequent.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :unless_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :unless_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # attr_reader predicate: Node
    attr_reader :predicate

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # def initialize: (flags: Integer, keyword_loc: Location, closing_loc: Location?, predicate: Node, statements: StatementsNode?, location: Location) -> void
    def initialize(flags, keyword_loc, closing_loc, predicate, statements, location)
      @flags = flags
      @keyword_loc = keyword_loc
      @closing_loc = closing_loc
      @predicate = predicate
      @statements = statements
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_until_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      predicate.set_newline_flag(newline_marked)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [predicate, statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << predicate
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, *closing_loc, predicate, *statements]
    end

    # def copy: (**params) -> UntilNode
    def copy(**params)
      UntilNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:predicate) { predicate },
        params.fetch(:statements) { statements },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, keyword_loc: keyword_loc, closing_loc: closing_loc, predicate: predicate, statements: statements, location: location }
    end

    # def begin_modifier?: () -> bool
    def begin_modifier?
      flags.anybits?(LoopFlags::BEGIN_MODIFIER)
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("begin_modifier" if begin_modifier?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "├── predicate:\n"
      inspector << inspector.child_node(predicate, "│   ")
      if (statements = self.statements).nil?
        inspector << "└── statements: ∅\n"
      else
        inspector << "└── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :until_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :until_node
    end
  end

  # Represents the use of the `when` keyword within a case statement.
  #
  #     case true
  #     when true
  #     ^^^^^^^^^
  #     end
  class WhenNode < Node
    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader conditions: Array[Node]
    attr_reader :conditions

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # def initialize: (keyword_loc: Location, conditions: Array[Node], statements: StatementsNode?, location: Location) -> void
    def initialize(keyword_loc, conditions, statements, location)
      @keyword_loc = keyword_loc
      @conditions = conditions
      @statements = statements
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_when_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [*conditions, statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact.concat(conditions)
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, *conditions, *statements]
    end

    # def copy: (**params) -> WhenNode
    def copy(**params)
      WhenNode.new(
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:conditions) { conditions },
        params.fetch(:statements) { statements },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { keyword_loc: keyword_loc, conditions: conditions, statements: statements, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│   ", conditions)}"
      if (statements = self.statements).nil?
        inspector << "└── statements: ∅\n"
      else
        inspector << "└── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :when_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :when_node
    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
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader closing_loc: Location?
    attr_reader :closing_loc

    # attr_reader predicate: Node
    attr_reader :predicate

    # attr_reader statements: StatementsNode?
    attr_reader :statements

    # def initialize: (flags: Integer, keyword_loc: Location, closing_loc: Location?, predicate: Node, statements: StatementsNode?, location: Location) -> void
    def initialize(flags, keyword_loc, closing_loc, predicate, statements, location)
      @flags = flags
      @keyword_loc = keyword_loc
      @closing_loc = closing_loc
      @predicate = predicate
      @statements = statements
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_while_node(self)
    end

    def set_newline_flag(newline_marked) # :nodoc:
      predicate.set_newline_flag(newline_marked)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [predicate, statements]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << predicate
      compact << statements if statements
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, *closing_loc, predicate, *statements]
    end

    # def copy: (**params) -> WhileNode
    def copy(**params)
      WhileNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:predicate) { predicate },
        params.fetch(:statements) { statements },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, keyword_loc: keyword_loc, closing_loc: closing_loc, predicate: predicate, statements: statements, location: location }
    end

    # def begin_modifier?: () -> bool
    def begin_modifier?
      flags.anybits?(LoopFlags::BEGIN_MODIFIER)
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def closing: () -> String?
    def closing
      closing_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("begin_modifier" if begin_modifier?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "├── predicate:\n"
      inspector << inspector.child_node(predicate, "│   ")
      if (statements = self.statements).nil?
        inspector << "└── statements: ∅\n"
      else
        inspector << "└── statements:\n"
        inspector << statements.inspect(inspector.child_inspector("    ")).delete_prefix(inspector.prefix)
      end
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :while_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :while_node
    end
  end

  # Represents an xstring literal with no interpolation.
  #
  #     `foo`
  #     ^^^^^
  class XStringNode < Node
    # attr_reader flags: Integer
    private attr_reader :flags

    # attr_reader opening_loc: Location
    attr_reader :opening_loc

    # attr_reader content_loc: Location
    attr_reader :content_loc

    # attr_reader closing_loc: Location
    attr_reader :closing_loc

    # attr_reader unescaped: String
    attr_reader :unescaped

    # def initialize: (flags: Integer, opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, location: Location) -> void
    def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location)
      @flags = flags
      @opening_loc = opening_loc
      @content_loc = content_loc
      @closing_loc = closing_loc
      @unescaped = unescaped
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_x_string_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      []
    end

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

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [opening_loc, content_loc, closing_loc]
    end

    # def copy: (**params) -> XStringNode
    def copy(**params)
      XStringNode.new(
        params.fetch(:flags) { flags },
        params.fetch(:opening_loc) { opening_loc },
        params.fetch(:content_loc) { content_loc },
        params.fetch(:closing_loc) { closing_loc },
        params.fetch(:unescaped) { unescaped },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location }
    end

    # def forced_utf8_encoding?: () -> bool
    def forced_utf8_encoding?
      flags.anybits?(EncodingFlags::FORCED_UTF8_ENCODING)
    end

    # def forced_binary_encoding?: () -> bool
    def forced_binary_encoding?
      flags.anybits?(EncodingFlags::FORCED_BINARY_ENCODING)
    end

    # def opening: () -> String
    def opening
      opening_loc.slice
    end

    # def content: () -> String
    def content
      content_loc.slice
    end

    # def closing: () -> String
    def closing
      closing_loc.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      flags = [("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?)].compact
      inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n"
      inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n"
      inspector << "├── content_loc: #{inspector.location(content_loc)}\n"
      inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n"
      inspector << "└── unescaped: #{unescaped.inspect}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :x_string_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :x_string_node
    end
  end

  # Represents the use of the `yield` keyword.
  #
  #     yield 1
  #     ^^^^^^^
  class YieldNode < Node
    # attr_reader keyword_loc: Location
    attr_reader :keyword_loc

    # attr_reader lparen_loc: Location?
    attr_reader :lparen_loc

    # attr_reader arguments: ArgumentsNode?
    attr_reader :arguments

    # attr_reader rparen_loc: Location?
    attr_reader :rparen_loc

    # def initialize: (keyword_loc: Location, lparen_loc: Location?, arguments: ArgumentsNode?, rparen_loc: Location?, location: Location) -> void
    def initialize(keyword_loc, lparen_loc, arguments, rparen_loc, location)
      @keyword_loc = keyword_loc
      @lparen_loc = lparen_loc
      @arguments = arguments
      @rparen_loc = rparen_loc
      @location = location
    end

    # def accept: (visitor: Visitor) -> void
    def accept(visitor)
      visitor.visit_yield_node(self)
    end

    # def child_nodes: () -> Array[nil | Node]
    def child_nodes
      [arguments]
    end

    # def compact_child_nodes: () -> Array[Node]
    def compact_child_nodes
      compact = []
      compact << arguments if arguments
      compact
    end

    # def comment_targets: () -> Array[Node | Location]
    def comment_targets
      [keyword_loc, *lparen_loc, *arguments, *rparen_loc]
    end

    # def copy: (**params) -> YieldNode
    def copy(**params)
      YieldNode.new(
        params.fetch(:keyword_loc) { keyword_loc },
        params.fetch(:lparen_loc) { lparen_loc },
        params.fetch(:arguments) { arguments },
        params.fetch(:rparen_loc) { rparen_loc },
        params.fetch(:location) { location },
      )
    end

    # def deconstruct: () -> Array[nil | Node]
    alias deconstruct child_nodes

    # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
    def deconstruct_keys(keys)
      { keyword_loc: keyword_loc, lparen_loc: lparen_loc, arguments: arguments, rparen_loc: rparen_loc, location: location }
    end

    # def keyword: () -> String
    def keyword
      keyword_loc.slice
    end

    # def lparen: () -> String?
    def lparen
      lparen_loc&.slice
    end

    # def rparen: () -> String?
    def rparen
      rparen_loc&.slice
    end

    # def inspect(inspector: NodeInspector) -> String
    def inspect(inspector = NodeInspector.new)
      inspector << inspector.header(self)
      inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
      inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n"
      if (arguments = self.arguments).nil?
        inspector << "├── arguments: ∅\n"
      else
        inspector << "├── arguments:\n"
        inspector << arguments.inspect(inspector.child_inspector("│   ")).delete_prefix(inspector.prefix)
      end
      inspector << "└── rparen_loc: #{inspector.location(rparen_loc)}\n"
      inspector.to_str
    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.
    #
    # def type: () -> Symbol
    def type
      :yield_node
    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.
    #
    # def self.type: () -> Symbol
    def self.type
      :yield_node
    end
  end

  # Flags for arguments nodes.
  module ArgumentsNodeFlags
    # if arguments contain keyword splat
    CONTAINS_KEYWORD_SPLAT = 1 << 0
  end

  # Flags for array nodes.
  module ArrayNodeFlags
    # if array contains splat nodes
    CONTAINS_SPLAT = 1 << 0
  end

  # Flags for call nodes.
  module CallNodeFlags
    # &. operator
    SAFE_NAVIGATION = 1 << 0

    # a call that could have been a local variable
    VARIABLE_CALL = 1 << 1

    # a call that is an attribute write, so the value being written should be returned
    ATTRIBUTE_WRITE = 1 << 2
  end

  # Flags for nodes that have unescaped content.
  module EncodingFlags
    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 0

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 1
  end

  # Flags for integer nodes that correspond to the base of the integer.
  module IntegerBaseFlags
    # 0b prefix
    BINARY = 1 << 0

    # 0d or no prefix
    DECIMAL = 1 << 1

    # 0o or 0 prefix
    OCTAL = 1 << 2

    # 0x prefix
    HEXADECIMAL = 1 << 3
  end

  # Flags for keyword hash nodes.
  module KeywordHashNodeFlags
    # a keyword hash which only has `AssocNode` elements all with static literal keys, which means the elements can be treated as keyword arguments
    STATIC_KEYS = 1 << 0
  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 << 0
  end

  # Flags for range and flip-flop nodes.
  module RangeFlags
    # ... operator
    EXCLUDE_END = 1 << 0
  end

  # Flags for regular expression and match last line nodes.
  module RegularExpressionFlags
    # i - ignores the case of characters when matching
    IGNORE_CASE = 1 << 0

    # x - ignores whitespace and allows comments in regular expressions
    EXTENDED = 1 << 1

    # m - allows $ to match the end of lines within strings
    MULTI_LINE = 1 << 2

    # o - only interpolates values into the regular expression once
    ONCE = 1 << 3

    # e - forces the EUC-JP encoding
    EUC_JP = 1 << 4

    # n - forces the ASCII-8BIT encoding
    ASCII_8BIT = 1 << 5

    # s - forces the Windows-31J encoding
    WINDOWS_31J = 1 << 6

    # u - forces the UTF-8 encoding
    UTF_8 = 1 << 7

    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 8

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 9

    # internal bytes forced the encoding to US-ASCII
    FORCED_US_ASCII_ENCODING = 1 << 10
  end

  # Flags for string nodes.
  module StringFlags
    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 0

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 1

    # frozen by virtue of a `frozen_string_literal` comment
    FROZEN = 1 << 2
  end

  # Flags for symbol nodes.
  module SymbolFlags
    # internal bytes forced the encoding to UTF-8
    FORCED_UTF8_ENCODING = 1 << 0

    # internal bytes forced the encoding to binary
    FORCED_BINARY_ENCODING = 1 << 1

    # internal bytes forced the encoding to US-ASCII
    FORCED_US_ASCII_ENCODING = 1 << 2
  end
end

Youez - 2016 - github.com/yon3zu
LinuXploit