module Steep
module Index
class RBSIndex
class TypeEntry
attr_reader :type_name
attr_reader :declarations
attr_reader :references
def initialize(type_name:)
@type_name = type_name
@declarations = Set[]
@references = Set[]
end
def add_declaration(decl)
case decl
when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
declarations << decl
when RBS::AST::Declarations::Interface
declarations << decl
when RBS::AST::Declarations::Alias
declarations << decl
else
raise "Unexpected type declaration: #{decl}"
end
self
end
def add_reference(ref)
case ref
when RBS::AST::Members::MethodDefinition
references << ref
when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
references << ref
when RBS::AST::Members::InstanceVariable, RBS::AST::Members::ClassInstanceVariable, RBS::AST::Members::ClassVariable
references << ref
when RBS::AST::Members::Include, RBS::AST::Members::Extend
references << ref
when RBS::AST::Declarations::Module, RBS::AST::Declarations::Class
references << ref
when RBS::AST::Declarations::Constant, RBS::AST::Declarations::Global
references << ref
when RBS::AST::Declarations::Alias
references << ref
else
raise "Unexpected type reference: #{ref}"
end
self
end
end
class MethodEntry
attr_reader :method_name
attr_reader :declarations
attr_reader :references
def initialize(method_name:)
@method_name = method_name
@declarations = Set[]
@references = Set[]
end
def add_declaration(decl)
case decl
when RBS::AST::Members::MethodDefinition,
RBS::AST::Members::Alias,
RBS::AST::Members::AttrWriter,
RBS::AST::Members::AttrReader,
RBS::AST::Members::AttrAccessor
declarations << decl
else
raise "Unexpected method declaration: #{decl}"
end
self
end
end
class ConstantEntry
attr_reader :const_name
attr_reader :declarations
def initialize(const_name:)
@const_name = const_name
@declarations = Set[]
end
def add_declaration(decl)
case decl
when RBS::AST::Declarations::Constant
declarations << decl
else
raise
end
self
end
end
class GlobalEntry
attr_reader :global_name
attr_reader :declarations
def initialize(global_name:)
@global_name = global_name
@declarations = Set[]
end
def add_declaration(decl)
case decl
when RBS::AST::Declarations::Global
declarations << decl
else
raise
end
self
end
end
attr_reader :type_index
attr_reader :method_index
attr_reader :const_index
attr_reader :global_index
def initialize()
@type_index = {}
@method_index = {}
@const_index = {}
@global_index = {}
end
def entry(type_name: nil, method_name: nil, const_name: nil, global_name: nil)
case
when type_name
type_index[type_name] ||= TypeEntry.new(type_name: type_name)
when method_name
method_index[method_name] ||= MethodEntry.new(method_name: method_name)
when const_name
const_index[const_name] ||= ConstantEntry.new(const_name: const_name)
when global_name
global_index[global_name] ||= GlobalEntry.new(global_name: global_name)
else
raise
end
end
def each_entry(&block)
if block_given?
type_index.each_value(&block)
method_index.each_value(&block)
const_index.each_value(&block)
global_index.each_value(&block)
else
enum_for(:each_entry)
end
end
def add_type_declaration(type_name, declaration)
entry(type_name: type_name).add_declaration(declaration)
end
def add_method_declaration(method_name, member)
entry(method_name: method_name).add_declaration(member)
end
def add_constant_declaration(const_name, decl)
entry(const_name: const_name).add_declaration(decl)
end
def add_global_declaration(global_name, decl)
entry(global_name: global_name).add_declaration(decl)
end
def each_declaration(type_name: nil, method_name: nil, const_name: nil, global_name: nil, &block)
if block
entry = entry(type_name: type_name, method_name: method_name, const_name: const_name, global_name: global_name)
entry.declarations.each(&block)
else
enum_for(:each_declaration, type_name: type_name, method_name: method_name, const_name: const_name, global_name: global_name)
end
end
def add_type_reference(type_name, ref)
entry(type_name: type_name).add_reference(ref)
end
def each_reference(type_name: nil, &block)
if block
entry(type_name: type_name).references.each(&block)
else
enum_for(:each_reference, type_name: type_name)
end
end
class Builder
attr_reader :index
def initialize(index:)
@index = index
end
def member(type_name, member)
case member
when RBS::AST::Members::MethodDefinition
member.types.each do |method_type|
method_type.each_type do |type|
type_reference type, from: member
end
end
if member.instance?
method_name = InstanceMethodName.new(type_name: type_name, method_name: member.name)
index.add_method_declaration(method_name, member)
end
if member.singleton?
method_name = SingletonMethodName.new(type_name: type_name, method_name: member.name)
index.add_method_declaration(method_name, member)
end
when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
type_reference member.type, from: member
if member.is_a?(RBS::AST::Members::AttrReader) || member.is_a?(RBS::AST::Members::AttrAccessor)
method_name = case member.kind
when :instance
InstanceMethodName.new(type_name: type_name, method_name: member.name)
when :singleton
SingletonMethodName.new(type_name: type_name, method_name: member.name)
end
index.add_method_declaration(method_name, member)
end
if member.is_a?(RBS::AST::Members::AttrWriter) || member.is_a?(RBS::AST::Members::AttrAccessor)
method_name = case member.kind
when :instance
InstanceMethodName.new(type_name: type_name, method_name: "#{member.name}=".to_sym)
when :singleton
SingletonMethodName.new(type_name: type_name, method_name: "#{member.name}=".to_sym)
end
index.add_method_declaration(method_name, member)
end
when RBS::AST::Members::InstanceVariable, RBS::AST::Members::ClassVariable, RBS::AST::Members::ClassInstanceVariable
type_reference member.type, from: member
when RBS::AST::Members::Include, RBS::AST::Members::Extend
index.add_type_reference member.name, member
member.args.each do |type|
type_reference type, from: member
end
when RBS::AST::Members::Alias
if member.instance?
new_name = InstanceMethodName.new(type_name: type_name, method_name: member.new_name)
index.add_method_declaration(new_name, member)
end
if member.singleton?
new_name = SingletonMethodName.new(type_name: type_name, method_name: member.new_name)
index.add_method_declaration(new_name, member)
end
end
end
def type_reference(type, from:)
case type
when RBS::Types::ClassInstance, RBS::Types::ClassSingleton, RBS::Types::Alias, RBS::Types::Interface
index.add_type_reference(type.name, from)
end
type.each_type do |ty|
type_reference ty, from: from
end
end
def env(env)
env.class_decls.each do |name, decl|
decl.decls.each do |d|
index.add_type_declaration(name, d.decl)
case d.decl
when RBS::AST::Declarations::Class
if super_class = d.decl.super_class
index.add_type_reference(super_class.name, d.decl)
super_class.args.each do |type|
type_reference(type, from: d.decl)
end
end
when RBS::AST::Declarations::Module
d.decl.self_types.each do |self_type|
index.add_type_reference(self_type.name, d.decl)
self_type.args.each do |type|
type_reference(type, from: d.decl)
end
end
end
d.decl.members.each do |member|
member(name, member)
end
end
end
env.interface_decls.each do |name, decl|
index.add_type_declaration(name, decl.decl)
decl.decl.members.each do |member|
member(name, member)
end
end
env.alias_decls.each do |name, decl|
index.add_type_declaration(name, decl.decl)
type_reference decl.decl.type, from: decl.decl
end
env.constant_decls.each do |name, decl|
index.add_constant_declaration(name, decl.decl)
type_reference decl.decl.type, from: decl.decl
end
env.global_decls.each do |name, decl|
index.add_global_declaration(name, decl.decl)
type_reference decl.decl.type, from: decl.decl
end
end
end
end
end
end