lib/steep/ast/types/name.rb



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

          def initialize(name:)
            @name = name
          end

          include Helper::NoFreeVariables

          def subst(s)
            self
          end

          def level
            [0]
          end

          def map_type(&block)
            self
          end
        end

        class Applying < Base
          attr_reader :args

          def initialize(name:, args:)
            super(name: name)
            @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 subst(s)
            if free_variables.intersect?(s.domain)
              _ = self.class.new(
                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

          def each_child(&block)
            if block
              args.each(&block)
            else
              args.each
            end
          end

          include Helper::ChildrenLevel

          def level
            [0] + level_of_children(args)
          end

          def map_type(&block)
            args = self.args.map(&block)

            _ = self.class.new(name: self.name, args: self.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

          include Helper::NoChild
        end

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

        class Interface < Applying
        end

        class Alias < Applying
        end
      end
    end
  end
end