class Prism::Node
  abstract!

  sig { returns(Prism::Source) }
  def source; end

  sig { returns(Integer) }
  def node_id; end

  sig { returns(Prism::Location) }
  def location; end

  sig{ returns(Integer) }
  def flags; end

  sig { returns(T::Boolean) }
  def newline?; end

  sig { returns(T::Boolean) }
  def static_literal?; end

  sig { returns(Integer) }
  def start_offset; end

  sig { returns(Integer) }
  def end_offset; end

  sig { returns(T::Array[String]) }
  def source_lines; end

  sig { returns(T::Array[String]) }
  def script_lines; end

  sig { returns(String) }
  def slice; end

  sig { returns(String) }
  def slice_lines; end

  sig { params(q: T.untyped).void }
  def pretty_print(q); end

  sig { returns(String) }
  def to_dot; end

  sig { params(line: Integer, column: Integer).returns(T::Array[Prism::Node]) }
  def tunnel(line, column); end

  sig { params(block: T.proc.params(node: Prism::Node).returns(T::Boolean)).returns(T.nilable(Prism::Node)) }
  def breadth_first_search(&block); end

  sig { abstract.params(visitor: Prism::Visitor).returns(T.untyped) }
  def accept(visitor); end

  sig { abstract.returns(T::Array[T.nilable(Prism::Node)]) }
  def child_nodes; end

  sig { abstract.returns(T::Array[T.nilable(Prism::Node)]) }
  def deconstruct; end

  sig { abstract.returns(T::Array[Prism::Node]) }
  def compact_child_nodes; end

  sig { abstract.returns(T::Array[T.any(Prism::Node, Prism::Location)]) }
  def comment_targets; end

  sig { abstract.returns(T::Array[Prism::Reflection::Field]) }
  def fields; end

  sig { abstract.returns(Symbol) }
  def type; end

  sig { abstract.returns(String) }
  def inspect; end
end
<%- nodes.each do |node| -%>

<%- node.each_comment_line do |line| -%>
#<%= line %>
<%- end -%>
class Prism::<%= node.name -%> < Prism::Node
  <%- if (node_flags = node.flags) -%>
  <%- node_flags.values.each do |value| -%>
  sig { returns(T::Boolean) }
  def <%= value.name.downcase %>?; end

  <%- end -%>
  <%- end -%>
  <%- node.fields.each do |field| -%>
  sig { returns(<%= field.rbi_class %>) }
  def <%= field.name %>; end

  <%- end -%>
  sig { params(<%= ["source: Prism::Source", "node_id: Integer", "location: Prism::Location", "flags: Integer", *node.fields.map { |field| "#{field.name}: #{field.rbi_class}" }].join(", ") %>).void }
  def initialize(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>); end

  sig { override.params(visitor: Prism::Visitor).returns(T.untyped) }
  def accept(visitor); end

  sig { override.returns(T::Array[T.nilable(Prism::Node)]) }
  def child_nodes; end

  sig { override.returns(T::Array[T.nilable(Prism::Node)]) }
  def deconstruct; end

  sig { override.returns(T::Array[Prism::Node]) }
  def compact_child_nodes; end

  sig { override.returns(T::Array[T.any(Prism::Node, Prism::Location)]) }
  def comment_targets; end

  sig { params(<%= (["node_id: Integer", "location: Prism::Location", "flags: Integer"] + node.fields.map { |field| "#{field.name}: #{field.rbi_class}" }).join(", ") %>).returns(Prism::<%= node.name %>) }
  def copy(<%= (["node_id", "location", "flags"] + node.fields.map(&:name)).map { |field| "#{field}: self.#{field}" }.join(", ") %>); end

  sig { params(keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, T.untyped]) }
  def deconstruct_keys(keys); end
  <%- node.fields.each do |field| -%>
  <%- case field -%>
  <%- when Prism::Template::LocationField -%>
  <%- raise unless field.name.end_with?("_loc") -%>
  <%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>

  sig { returns(String) }
  def <%= field.name.delete_suffix("_loc") %>; end
  <%- when Prism::Template::OptionalLocationField -%>
  <%- raise unless field.name.end_with?("_loc") -%>
  <%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>

  sig { returns(T.nilable(String)) }
  def <%= field.name.delete_suffix("_loc") %>; end
  <%- end -%>
  <%- end -%>

  sig { override.returns(T::Array[Prism::Reflection::Field]) }
  def fields; end

  sig { override.returns(String) }
  def inspect; end

  sig { override.returns(Symbol) }
  def type; end
end
<%- end -%>
<%- flags.each do |flag| -%>

# <%= flag.comment %>
module Prism::<%= flag.name %>
  <%- flag.values.each_with_index do |value, index| -%>
  # <%= value.comment %>
  <%= value.name %> = T.let(1 << <%= index + Prism::Template::COMMON_FLAGS_COUNT %>, Integer)
  <%- end -%>
end
<%- end -%>

# The flags that are common to all nodes.
module Prism::NodeFlags
  # A flag to indicate that the node is a candidate to emit a :line event
  # through tracepoint when compiled.
  NEWLINE = T.let(1, Integer)

  # A flag to indicate that the value that the node represents is a value that
  # can be determined at parse-time.
  STATIC_LITERAL = T.let(2, Integer)
end
