class Spoom::Model

def [](full_name)

: (String full_name) -> Symbol
Raises an error if the symbol is not found

Get a symbol by it's full name
def [](full_name)
  symbol = @symbols[full_name]
  raise Error, "Symbol not found: #{full_name}" unless symbol
  symbol
end

def compute_symbols_hierarchy!

: -> void
def compute_symbols_hierarchy!
  @symbols.dup.each do |_full_name, symbol|
    symbol.definitions.each do |definition|
      next unless definition.is_a?(Namespace)
      @symbols_hierarchy.add_element(symbol)
      if definition.is_a?(Class)
        superclass_name = definition.superclass_name
        if superclass_name
          superclass = resolve_symbol(superclass_name, context: symbol)
          @symbols_hierarchy.add_direct_edge(symbol, superclass)
        end
      end
      definition.mixins.each do |mixin|
        next if mixin.is_a?(Extend)
        target = resolve_symbol(mixin.name, context: symbol)
        @symbols_hierarchy.add_direct_edge(symbol, target)
      end
    end
  end
end

def finalize!

: -> void
def finalize!
  compute_symbols_hierarchy!
end

def initialize

: -> void
def initialize
  @symbols = {} #: Hash[String, Symbol]
  @symbols_hierarchy = Poset.new #: Poset[Symbol]
end

def register_symbol(full_name)

: (String full_name) -> Symbol
If the symbol already exists, it will be returned.

Register a new symbol by it's full name
def register_symbol(full_name)
  @symbols[full_name] ||= Symbol.new(full_name)
end

def resolve_symbol(full_name, context:)

: (String full_name, context: Symbol) -> Symbol
def resolve_symbol(full_name, context:)
  if full_name.start_with?("::")
    full_name = full_name.delete_prefix("::")
    return @symbols[full_name] ||= UnresolvedSymbol.new(full_name)
  end
  target = @symbols[full_name] #: Symbol?
  return target if target
  parts = context.full_name.split("::")
  until parts.empty?
    target = @symbols["#{parts.join("::")}::#{full_name}"]
    return target if target
    parts.pop
  end
  @symbols[full_name] = UnresolvedSymbol.new(full_name)
end

def subtypes(symbol)

: (Symbol symbol) -> Array[Symbol]
def subtypes(symbol)
  poe = @symbols_hierarchy[symbol]
  poe.descendants
end

def supertypes(symbol)

: (Symbol symbol) -> Array[Symbol]
def supertypes(symbol)
  poe = @symbols_hierarchy[symbol]
  poe.ancestors
end