123456789_123456789_123456789_123456789_123456789_

Class: RBS::Environment

Relationships & Source Files
Namespace Children
Modules:
Classes:
Inherits: Object
Defined in: lib/rbs/environment.rb

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.newEnvironment

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 105

def initialize
  @buffers = []
  @declarations = []

  @class_decls = {}
  @interface_decls = {}
  @alias_decls = {}
  @constant_decls = {}
  @global_decls = {}
end

Class Method Details

.from_loader(loader)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 127

def self.from_loader(loader)
  self.new.tap do |env|
    loader.load(env: env)
  end
end

Instance Attribute Details

#alias_decls (readonly)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 7

attr_reader :alias_decls

#class_decls (readonly)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 5

attr_reader :class_decls

#constant_decls (readonly)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 8

attr_reader :constant_decls

#declarations (readonly)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 3

attr_reader :declarations

#global_decls (readonly)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 9

attr_reader :global_decls

#interface_decls (readonly)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 6

attr_reader :interface_decls

Instance Method Details

#<<(decl)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 200

def <<(decl)
  declarations << decl
  insert_decl(decl, outer: [], namespace: Namespace.root)
  self
end

#absolute_type(resolver, type, context:)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 436

def absolute_type(resolver, type, context:)
  type.map_type_name do |name, _, _|
    absolute_type_name(resolver, name, context: context)
  end
end

#absolute_type_name(resolver, type_name, context:)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 432

def absolute_type_name(resolver, type_name, context:)
  resolver.resolve(type_name, context: context) || type_name
end

#buffers

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 447

def buffers
  buffers_decls.keys.compact
end

#buffers_decls

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 451

def buffers_decls
  # @type var hash: Hash[Buffer, Array[AST::Declarations::t]]
  hash = {}

  declarations.each do |decl|
    location = decl.location or next
    (hash[location.buffer] ||= []) << decl
  end

  hash
end

#cache_name(cache, name:, decl:, outer:)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 133

def cache_name(cache, name:, decl:, outer:)
  if cache.key?(name)
    raise DuplicatedDeclarationError.new(_ = name, _ = decl, _ = cache[name].decl)
  end

  cache[name] = SingleEntry.new(name: name, decl: decl, outer: outer)
end

#initialize_copy(other)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 116

def initialize_copy(other)
  @buffers = other.buffers.dup
  @declarations = other.declarations.dup

  @class_decls = other.class_decls.dup
  @interface_decls = other.interface_decls.dup
  @alias_decls = other.alias_decls.dup
  @constant_decls = other.constant_decls.dup
  @global_decls = other.global_decls.dup
end

#insert_decl(decl, outer:, namespace:)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 141

def insert_decl(decl, outer:, namespace:)
  case decl
  when AST::Declarations::Class, AST::Declarations::Module
    name = decl.name.with_prefix(namespace)

    if constant_decls.key?(name)
      raise DuplicatedDeclarationError.new(name, decl, constant_decls[name].decl)
    end

    unless class_decls.key?(name)
      case decl
      when AST::Declarations::Class
        class_decls[name] ||= ClassEntry.new(name: name)
      when AST::Declarations::Module
        class_decls[name] ||= ModuleEntry.new(name: name)
      end
    end

    existing_entry = class_decls[name]

    case
    when decl.is_a?(AST::Declarations::Module) && existing_entry.is_a?(ModuleEntry)
      # @type var existing_entry: ModuleEntry
      # @type var decl: AST::Declarations::Module
      existing_entry.insert(decl: decl, outer: outer)
    when decl.is_a?(AST::Declarations::Class) && existing_entry.is_a?(ClassEntry)
      # @type var existing_entry: ClassEntry
      # @type var decl: AST::Declarations::Class
      existing_entry.insert(decl: decl, outer: outer)
    else
      raise DuplicatedDeclarationError.new(name, decl, existing_entry.decls[0].decl)
    end

    prefix = outer + [decl]
    ns = name.to_namespace
    decl.each_decl do |d|
      insert_decl(d, outer: prefix, namespace: ns)
    end

  when AST::Declarations::Interface
    cache_name interface_decls, name: decl.name.with_prefix(namespace), decl: decl, outer: outer

  when AST::Declarations::Alias
    cache_name alias_decls, name: decl.name.with_prefix(namespace), decl: decl, outer: outer

  when AST::Declarations::Constant
    name = decl.name.with_prefix(namespace)

    if class_decls.key?(name)
      raise DuplicatedDeclarationError.new(name, decl, class_decls[name].decls[0].decl)
    end

    cache_name constant_decls, name: name, decl: decl, outer: outer

  when AST::Declarations::Global
    cache_name global_decls, name: decl.name, decl: decl, outer: outer
  end
end

#inspect

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 442

def inspect
  ivars = %i[@declarations @class_decls @interface_decls @alias_decls @constant_decls @global_decls]
  "\#<RBS::Environment #{ivars.map { |iv| "#{iv}=(#{instance_variable_get(iv).size} items)"}.join(' ')}>"
end

#reject

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 463

def reject
  env = Environment.new

  declarations.each do |decl|
    unless yield(decl)
      env << decl
    end
  end

  env
end

#resolve_declaration(resolver, decl, outer:, prefix:)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 227

def resolve_declaration(resolver, decl, outer:, prefix:)
  if decl.is_a?(AST::Declarations::Global)
    # @type var decl: AST::Declarations::Global
    return AST::Declarations::Global.new(
      name: decl.name,
      type: absolute_type(resolver, decl.type, context: [Namespace.root]),
      location: decl.location,
      comment: decl.comment
    )
  end

  context = (outer + [decl]).each.with_object([Namespace.root]) do |decl, array|
    head = array.first or raise
    array.unshift(head + decl.name.to_namespace)
  end

  case decl
  when AST::Declarations::Class
    outer_ = outer + [decl]
    prefix_ = prefix + decl.name.to_namespace
    AST::Declarations::Class.new(
      name: decl.name.with_prefix(prefix),
      type_params: decl.type_params,
      super_class: decl.super_class&.yield_self do |super_class|
        AST::Declarations::Class::Super.new(
          name: absolute_type_name(resolver, super_class.name, context: context),
          args: super_class.args.map {|type| absolute_type(resolver, type, context: context) },
          location: super_class.location
        )
      end,
      members: decl.members.map do |member|
        case member
        when AST::Members::Base
          resolve_member(resolver, member, context: context)
        when AST::Declarations::Base
          resolve_declaration(
            resolver,
            member,
            outer: outer_,
            prefix: prefix_
          )
        else
          raise
        end
      end,
      location: decl.location,
      annotations: decl.annotations,
      comment: decl.comment
    )
  when AST::Declarations::Module
    outer_ = outer + [decl]
    prefix_ = prefix + decl.name.to_namespace
    AST::Declarations::Module.new(
      name: decl.name.with_prefix(prefix),
      type_params: decl.type_params,
      self_types: decl.self_types.map do |module_self|
        AST::Declarations::Module::Self.new(
          name: absolute_type_name(resolver, module_self.name, context: context),
          args: module_self.args.map {|type| absolute_type(resolver, type, context: context) },
          location: module_self.location
        )
      end,
      members: decl.members.map do |member|
        case member
        when AST::Members::Base
          resolve_member(resolver, member, context: context)
        when AST::Declarations::Base
          resolve_declaration(
            resolver,
            member,
            outer: outer_,
            prefix: prefix_
          )
        else
          raise
        end
      end,
      location: decl.location,
      annotations: decl.annotations,
      comment: decl.comment
    )
  when AST::Declarations::Interface
    AST::Declarations::Interface.new(
      name: decl.name.with_prefix(prefix),
      type_params: decl.type_params,
      members: decl.members.map do |member|
        resolve_member(resolver, member, context: context)
      end,
      comment: decl.comment,
      location: decl.location,
      annotations: decl.annotations
    )
  when AST::Declarations::Alias
    AST::Declarations::Alias.new(
      name: decl.name.with_prefix(prefix),
      type: absolute_type(resolver, decl.type, context: context),
      location: decl.location,
      annotations: decl.annotations,
      comment: decl.comment
    )

  when AST::Declarations::Constant
    AST::Declarations::Constant.new(
      name: decl.name.with_prefix(prefix),
      type: absolute_type(resolver, decl.type, context: context),
      location: decl.location,
      comment: decl.comment
    )
  end
end

#resolve_member(resolver, member, context:)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 338

def resolve_member(resolver, member, context:)
  case member
  when AST::Members::MethodDefinition
    AST::Members::MethodDefinition.new(
      name: member.name,
      kind: member.kind,
      types: member.types.map do |type|
        type.map_type {|ty| absolute_type(resolver, ty, context: context) }
      end,
      comment: member.comment,
      overload: member.overload?,
      annotations: member.annotations,
      location: member.location
    )
  when AST::Members::AttrAccessor
    AST::Members::AttrAccessor.new(
      name: member.name,
      type: absolute_type(resolver, member.type, context: context),
      kind: member.kind,
      annotations: member.annotations,
      comment: member.comment,
      location: member.location,
      ivar_name: member.ivar_name
    )
  when AST::Members::AttrReader
    AST::Members::AttrReader.new(
      name: member.name,
      type: absolute_type(resolver, member.type, context: context),
      kind: member.kind,
      annotations: member.annotations,
      comment: member.comment,
      location: member.location,
      ivar_name: member.ivar_name
    )
  when AST::Members::AttrWriter
    AST::Members::AttrWriter.new(
      name: member.name,
      type: absolute_type(resolver, member.type, context: context),
      kind: member.kind,
      annotations: member.annotations,
      comment: member.comment,
      location: member.location,
      ivar_name: member.ivar_name
    )
  when AST::Members::InstanceVariable
    AST::Members::InstanceVariable.new(
      name: member.name,
      type: absolute_type(resolver, member.type, context: context),
      comment: member.comment,
      location: member.location
    )
  when AST::Members::ClassInstanceVariable
    AST::Members::ClassInstanceVariable.new(
      name: member.name,
      type: absolute_type(resolver, member.type, context: context),
      comment: member.comment,
      location: member.location
    )
  when AST::Members::ClassVariable
    AST::Members::ClassVariable.new(
      name: member.name,
      type: absolute_type(resolver, member.type, context: context),
      comment: member.comment,
      location: member.location
    )
  when AST::Members::Include
    AST::Members::Include.new(
      name: absolute_type_name(resolver, member.name, context: context),
      args: member.args.map {|type| absolute_type(resolver, type, context: context) },
      comment: member.comment,
      location: member.location,
      annotations: member.annotations
    )
  when AST::Members::Extend
    AST::Members::Extend.new(
      name: absolute_type_name(resolver, member.name, context: context),
      args: member.args.map {|type| absolute_type(resolver, type, context: context) },
      comment: member.comment,
      location: member.location,
      annotations: member.annotations
    )
  when AST::Members::Prepend
    AST::Members::Prepend.new(
      name: absolute_type_name(resolver, member.name, context: context),
      args: member.args.map {|type| absolute_type(resolver, type, context: context) },
      comment: member.comment,
      location: member.location,
      annotations: member.annotations
    )
  else
    member
  end
end

#resolve_type_names(only: nil)

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 212

def resolve_type_names(only: nil)
  resolver = TypeNameResolver.from_env(self)
  env = Environment.new()

  declarations.each do |decl|
    if only && !only.member?(decl)
      env << decl
    else
      env << resolve_declaration(resolver, decl, outer: [], prefix: Namespace.root)
    end
  end

  env
end

#validate_type_params

[ GitHub ]

  
# File 'lib/rbs/environment.rb', line 206

def validate_type_params
  class_decls.each_value do |decl|
    decl.primary
  end
end