lib/steep/ast/types/name.rb



module Steep
  module AST
    module Types
      module Name
        class Base
          attr_reader :location
          attr_reader :name

          def initialize(name:, location: nil)
            @location = location
            @name = name
          end

          include Helper::NoFreeVariables

          def subst(s)
            self
          end

          def level
            [0]
          end
        end

        class Applying < Base
          attr_reader :args

          def initialize(name:, args:, location: nil)
            super(name: name, location: location)
            @args = args
          end

          def ==(other)
            other.class == self.class &&
              other.name == name &&
              other.args == args
          end

          alias eql? ==

          def hash
            @hash ||= self.class.hash ^ name.hash ^ args.hash
          end

          def to_s
            if args.empty?
              "#{name}"
            else
              "#{name}[#{args.join(", ")}]"
            end
          end

          def with_location(new_location)
            self.class.new(name: name, args: args, location: new_location)
          end

          def subst(s)
            if free_variables.intersect?(s.domain)
              self.class.new(location: location,
                             name: name,
                             args: args.map {|a| a.subst(s) })
            else
              self
            end
          end

          def free_variables
            @fvs ||= Set.new().tap do |set|
              args.each do |type|
                set.merge(type.free_variables)
              end
            end
          end

          include Helper::ChildrenLevel

          def level
            [0] + level_of_children(args)
          end
        end

        class Singleton < Base
          def ==(other)
            other.class == self.class &&
              other.name == name
          end

          alias eql? ==

          def hash
            self.class.hash ^ name.hash
          end

          def to_s
            "singleton(#{name.to_s})"
          end

          def with_location(new_location)
            self.class.new(name: name, location: new_location)
          end
        end

        class Instance < Applying
          def to_module
            Singleton.new(name: name, location: location)
          end
        end

        class Interface < Applying
        end

        class Alias < Applying
        end
      end
    end
  end
end