123456789_123456789_123456789_123456789_123456789_

Class: RBS::Resolver::TypeNameResolver

Relationships & Source Files
Inherits: Object
Defined in: lib/rbs/resolver/type_name_resolver.rb

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(*args)

See additional method definition at line 10.

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 16

def initialize(all_names, aliases)
  @all_names = all_names
  @aliases = aliases
  @cache = {}
end

Class Method Details

.build(env)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 24

def self.build(env)
  all_names = Set.new #: Set[TypeName]

  all_names.merge(env.class_decls.keys)
  all_names.merge(env.interface_decls.keys)
  all_names.merge(env.type_alias_decls.keys)

  aliases = {} #: Hash[TypeName, [TypeName, context]]

  env.class_alias_decls.each do |name, entry|
    aliases[name] = [entry.decl.old_name, entry.context]
  end

  new(all_names, aliases)
end

Instance Attribute Details

#aliases (readonly)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 8

attr_reader :aliases

#all_names (readonly)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 6

attr_reader :all_names

#cache (readonly)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 7

attr_reader :cache

Instance Method Details

#aliased_name?(type_name) ⇒ Boolean

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 90

def aliased_name?(type_name)
  if aliases.key?(type_name)
    type_name
  end
end

#has_type_name?(full_name) ⇒ Boolean

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 84

def has_type_name?(full_name)
  if all_names.include?(full_name)
    full_name
  end
end

#normalize_namespace(type_name, rhs, context, visited)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 129

def normalize_namespace(type_name, rhs, context, visited)
  if visited.include?(type_name)
    # Cycle detected
    return false
  end

  visited << type_name

  begin
    resolve_namespace0(rhs, context, visited)
  ensure
    visited.delete(type_name)
  end
end

#resolve(type_name, context:)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 47

def resolve(type_name, context:)
  if type_name.absolute? && has_type_name?(type_name)
    return type_name
  end

  try_cache([type_name, context]) do
    if type_name.class?
      resolve_namespace0(type_name, context, Set.new) || nil
    else
      namespace = type_name.namespace

      if namespace.empty?
        resolve_type_name(type_name.name, context)
      else
        if namespace = resolve_namespace0(namespace.to_type_name, context, Set.new)
          type_name = TypeName.new(name: type_name.name, namespace: namespace.to_namespace)
          has_type_name?(type_name)
        end
      end
    end
  end
end

#resolve_head_namespace(head, context)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 112

def resolve_head_namespace(head, context)
  if context
    outer, inner = context
    case inner
    when false
      resolve_head_namespace(head, outer)
    when TypeName
      has_type_name?(inner) or raise "Context must be normalized: #{inner.inspect}"
      type_name = TypeName.new(name: head, namespace: inner.to_namespace)
      has_type_name?(type_name) || aliased_name?(type_name) || resolve_head_namespace(head, outer)
    end
  else
    type_name = TypeName.new(name: head, namespace: Namespace.root)
    has_type_name?(type_name) || aliased_name?(type_name)
  end
end

#resolve_namespace(type_name, context:)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 70

def resolve_namespace(type_name, context:)
  if type_name.absolute? && has_type_name?(type_name)
    return type_name
  end

  unless type_name.class?
    raise "Type name must be a class name: #{type_name}"
  end

  try_cache([type_name, context]) do
    ns = resolve_namespace0(type_name, context, Set.new) or return ns
  end
end

#resolve_namespace0(type_name, context, visited)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 144

def resolve_namespace0(type_name, context, visited)
  head, *tail = [*type_name.namespace.path, type_name.name]

  head = head #: Symbol

  head =
    if type_name.absolute?
      root_name = TypeName.new(name: head, namespace: Namespace.root)
      has_type_name?(root_name) || aliased_name?(root_name)
    else
      resolve_head_namespace(head, context)
    end

  if head
    if (rhs, context = aliases.fetch(head, nil))
      head = normalize_namespace(head, rhs, context, visited) or return head
    end

    tail.inject(head) do |namespace, name|
      type_name = TypeName.new(name: name, namespace: namespace.to_namespace)
      case
      when has_type_name?(type_name)
        type_name
      when (rhs, context = aliases.fetch(type_name, nil))
        m = normalize_namespace(type_name, rhs, context, visited) or return m
      else
        return nil
      end
    end
  end
end

#resolve_type_name(type_name, context)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 96

def resolve_type_name(type_name, context)
  if context
    outer, inner = context
    case inner
    when false
      resolve_type_name(type_name, outer)
    else
      has_type_name?(inner) or raise "Context must be normalized: #{inner.inspect}"
      has_type_name?(TypeName.new(name: type_name, namespace: inner.to_namespace)) || resolve_type_name(type_name, outer)
    end
  else
    type_name = TypeName.new(name: type_name, namespace: Namespace.root)
    has_type_name?(type_name)
  end
end

#try_cache(query)

[ GitHub ]

  
# File 'lib/rbs/resolver/type_name_resolver.rb', line 40

def try_cache(query)
  cache.fetch(query) do
    result = yield
    cache[query] = result
  end
end