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 Class < Base attr_reader :constructor def initialize(name:, constructor:, location: nil) raise "Name should be a module name: #{name.inspect}" unless name.is_a?(Names::Module) super(name: name, location: location) @constructor = constructor end def ==(other) other.class == self.class && other.name == name && other.constructor == constructor end alias eql? == def hash self.class.hash ^ name.hash ^ constructor.hash end def to_s k = case constructor when true " constructor" when false " noconstructor" when nil "" end "singleton(#{name.to_s})" end def with_location(new_location) self.class.new(name: name, constructor: constructor, location: new_location) end def to_instance(*args) Instance.new(name: name, args: args) end NOTHING = ::Object.new def updated(constructor: NOTHING) if NOTHING == constructor constructor = self.constructor end self.class.new(name: name, constructor: constructor, location: location) end end class Module < 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_class(constructor:) Class.new(name: name, location: location, constructor: constructor) end def to_module Module.new(name: name, location: location) end end class Interface < Applying end class Alias < Applying end end end end end