rdl 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/rails_types.rb +1 -0
- data/lib/rdl.rb +56 -0
- data/lib/rdl/config.rb +121 -0
- data/lib/rdl/contracts/and.rb +29 -0
- data/lib/rdl/contracts/contract.rb +7 -0
- data/lib/rdl/contracts/flat.rb +31 -0
- data/lib/rdl/contracts/or.rb +25 -0
- data/lib/rdl/contracts/proc.rb +24 -0
- data/lib/rdl/switch.rb +20 -0
- data/lib/rdl/types/annotated_arg.rb +41 -0
- data/lib/rdl/types/finitehash.rb +81 -0
- data/lib/rdl/types/generic.rb +100 -0
- data/lib/rdl/types/intersection.rb +66 -0
- data/lib/rdl/types/lexer.rex +39 -0
- data/lib/rdl/types/lexer.rex.rb +148 -0
- data/lib/rdl/types/method.rb +219 -0
- data/lib/rdl/types/nil.rb +50 -0
- data/lib/rdl/types/nominal.rb +80 -0
- data/lib/rdl/types/optional.rb +54 -0
- data/lib/rdl/types/parser.racc +150 -0
- data/lib/rdl/types/parser.tab.rb +654 -0
- data/lib/rdl/types/singleton.rb +62 -0
- data/lib/rdl/types/structural.rb +72 -0
- data/lib/rdl/types/top.rb +50 -0
- data/lib/rdl/types/tuple.rb +61 -0
- data/lib/rdl/types/type.rb +24 -0
- data/lib/rdl/types/type_inferencer.rb +73 -0
- data/lib/rdl/types/union.rb +74 -0
- data/lib/rdl/types/var.rb +51 -0
- data/lib/rdl/types/vararg.rb +54 -0
- data/lib/rdl/types/wild.rb +26 -0
- data/lib/rdl/util.rb +56 -0
- data/lib/rdl/wrap.rb +505 -0
- data/lib/rdl_types.rb +2 -0
- data/types/other/chronic.rb +5 -0
- data/types/other/paperclip_attachment.rb +7 -0
- data/types/other/securerandom.rb +4 -0
- data/types/rails-4.2.1/fixnum.rb +3 -0
- data/types/rails-4.2.1/string.rb +3 -0
- data/types/rails-tmp/action_dispatch.rb +406 -0
- data/types/rails-tmp/active_record.rb +406 -0
- data/types/rails-tmp/devise_contracts.rb +216 -0
- data/types/ruby-2.2.0/_aliases.rb +4 -0
- data/types/ruby-2.2.0/abbrev.rb +5 -0
- data/types/ruby-2.2.0/array.rb +137 -0
- data/types/ruby-2.2.0/base64.rb +10 -0
- data/types/ruby-2.2.0/basic_object.rb +13 -0
- data/types/ruby-2.2.0/benchmark.rb +11 -0
- data/types/ruby-2.2.0/bigdecimal.rb +15 -0
- data/types/ruby-2.2.0/bigmath.rb +12 -0
- data/types/ruby-2.2.0/class.rb +17 -0
- data/types/ruby-2.2.0/complex.rb +42 -0
- data/types/ruby-2.2.0/coverage.rb +6 -0
- data/types/ruby-2.2.0/csv.rb +5 -0
- data/types/ruby-2.2.0/date.rb +6 -0
- data/types/ruby-2.2.0/dir.rb +38 -0
- data/types/ruby-2.2.0/encoding.rb +23 -0
- data/types/ruby-2.2.0/enumerable.rb +98 -0
- data/types/ruby-2.2.0/enumerator.rb +26 -0
- data/types/ruby-2.2.0/exception.rb +15 -0
- data/types/ruby-2.2.0/file.rb +124 -0
- data/types/ruby-2.2.0/fileutils.rb +6 -0
- data/types/ruby-2.2.0/fixnum.rb +45 -0
- data/types/ruby-2.2.0/float.rb +54 -0
- data/types/ruby-2.2.0/gem.rb +245 -0
- data/types/ruby-2.2.0/hash.rb +72 -0
- data/types/ruby-2.2.0/integer.rb +31 -0
- data/types/ruby-2.2.0/io.rb +103 -0
- data/types/ruby-2.2.0/kernel.rb +89 -0
- data/types/ruby-2.2.0/marshal.rb +5 -0
- data/types/ruby-2.2.0/matchdata.rb +26 -0
- data/types/ruby-2.2.0/math.rb +53 -0
- data/types/ruby-2.2.0/numeric.rb +46 -0
- data/types/ruby-2.2.0/object.rb +73 -0
- data/types/ruby-2.2.0/pathname.rb +106 -0
- data/types/ruby-2.2.0/process.rb +127 -0
- data/types/ruby-2.2.0/random.rb +15 -0
- data/types/ruby-2.2.0/range.rb +38 -0
- data/types/ruby-2.2.0/rational.rb +31 -0
- data/types/ruby-2.2.0/regexp.rb +30 -0
- data/types/ruby-2.2.0/set.rb +58 -0
- data/types/ruby-2.2.0/string.rb +145 -0
- data/types/ruby-2.2.0/strscan.rb +7 -0
- data/types/ruby-2.2.0/symbol.rb +29 -0
- data/types/ruby-2.2.0/time.rb +68 -0
- data/types/ruby-2.2.0/uri.rb +18 -0
- data/types/ruby-2.2.0/yaml.rb +5 -0
- metadata +131 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module RDL::Type
|
|
4
|
+
class SingletonType < Type
|
|
5
|
+
attr_reader :val
|
|
6
|
+
|
|
7
|
+
@@cache = {}
|
|
8
|
+
@@cache.compare_by_identity
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
alias :__new__ :new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.new(val)
|
|
15
|
+
t = @@cache[val]
|
|
16
|
+
return t if t
|
|
17
|
+
t = self.__new__ val
|
|
18
|
+
return (@@cache[val] = t) # assignment evaluates to t
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(val)
|
|
22
|
+
@val = val
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def eql?(other)
|
|
26
|
+
self == other
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ==(other)
|
|
30
|
+
return (other.instance_of? self.class) && (other.val.equal? @val)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def hash # :nodoc:
|
|
34
|
+
return @val.hash
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_s
|
|
38
|
+
if @val.instance_of? Symbol
|
|
39
|
+
":{@val}"
|
|
40
|
+
else
|
|
41
|
+
"Singleton(#{@val.to_s})"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def <=(other)
|
|
46
|
+
other.instance_of?(TopType) ||
|
|
47
|
+
(other.instance_of?(SingletonType) && other.val == @val) ||
|
|
48
|
+
(other.instance_of?(NominalType) && @val.class == other.klass) ||
|
|
49
|
+
(other.instance_of?(NominalType) && @val.is_a?(other.klass))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def member?(obj, *args)
|
|
53
|
+
t = RDL::Util.rdl_type obj
|
|
54
|
+
return t <= self if t
|
|
55
|
+
obj.nil? || obj.equal?(@val)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def instantiate(inst)
|
|
59
|
+
return self
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module RDL::Type
|
|
4
|
+
class StructuralType < Type
|
|
5
|
+
attr_reader :methods
|
|
6
|
+
|
|
7
|
+
@@cache = {}
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
alias :__new__ :new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.new(methods)
|
|
14
|
+
t = @@cache[methods]
|
|
15
|
+
return t if t
|
|
16
|
+
t = StructuralType.__new__(methods)
|
|
17
|
+
return (@@cache[methods] = t) # assignment evaluates to t
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Create a new StructuralType.
|
|
21
|
+
#
|
|
22
|
+
# [+methods+] Map from method names as symbols to their types.
|
|
23
|
+
def initialize(methods)
|
|
24
|
+
raise "methods can't be empty" if methods.empty?
|
|
25
|
+
methods.each { |m, t|
|
|
26
|
+
raise RuntimeError, "Method names in StructuralType must be symbols" unless m.instance_of? Symbol
|
|
27
|
+
raise RuntimeError, "Got #{t.class} where MethodType expected" unless t.instance_of? MethodType
|
|
28
|
+
# Note intersection types not allowed as subtyping would be tricky
|
|
29
|
+
}
|
|
30
|
+
@methods = methods
|
|
31
|
+
super()
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_s # :nodoc:
|
|
35
|
+
"[ " + @methods.each_pair.map { |m, t| "#{m.to_s}: #{t.to_s}" }.sort.join(", ") + " ]"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def <=(other)
|
|
39
|
+
return true if other.instance_of? TopType
|
|
40
|
+
# in theory a StructuralType could contain all the methods of a NominalType or GenericType,
|
|
41
|
+
# but it seems unlikely in practice, so disallow this case.
|
|
42
|
+
return RuntimeError, "Structural subtype can't be subtype of #{other.class}" unless other.instance_of? StructuralType
|
|
43
|
+
# allow width subtyping
|
|
44
|
+
other.methods.each_pair { |m, t|
|
|
45
|
+
return false unless @methods.has_key?(m) && @methods[m] <= t
|
|
46
|
+
}
|
|
47
|
+
return true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def member?(obj, *args)
|
|
51
|
+
t = RDL::Util.rdl_type obj
|
|
52
|
+
return t <= self if t
|
|
53
|
+
return NominalType.new(obj.class) <= self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def instantiate(inst)
|
|
57
|
+
StructuralType.new(Hash[*@methods.each_pair.map { |m, t| [m, t.instantiate(inst)] }.flatten])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def eql?(other)
|
|
61
|
+
self == other
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def ==(other) # :nodoc:
|
|
65
|
+
return (other.instance_of? StructuralType) && (other.methods == @methods)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def hash # :nodoc:
|
|
69
|
+
@methods.hash
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module RDL::Type
|
|
4
|
+
class TopType < Type
|
|
5
|
+
@@cache = nil
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
alias :__new__ :new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.new
|
|
12
|
+
@@cache = TopType.__new__ unless @@cache
|
|
13
|
+
return @@cache
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
"%any"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def eql?(other)
|
|
25
|
+
self == other
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def ==(other)
|
|
29
|
+
other.instance_of? TopType
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def <=(other)
|
|
33
|
+
other.instance_of? TopType
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def member?(obj, *args)
|
|
37
|
+
t = RDL::Util.rdl_type obj
|
|
38
|
+
return t <= self if t
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def instantiate(inst)
|
|
43
|
+
return self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def hash
|
|
47
|
+
17
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module RDL::Type
|
|
4
|
+
# A specialized GenericType for tuples, i.e., fixed-sized arrays
|
|
5
|
+
class TupleType < Type
|
|
6
|
+
attr_reader :params
|
|
7
|
+
|
|
8
|
+
@@cache = {}
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
alias :__new__ :new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.new(*params)
|
|
15
|
+
t = @@cache[params]
|
|
16
|
+
return t if t
|
|
17
|
+
raise RuntimeError, "Attempt to create generic type with non-type param" unless params.all? { |p| p.is_a? Type }
|
|
18
|
+
t = TupleType.__new__(params)
|
|
19
|
+
return (@@cache[params] = t) # assignment evaluates to t
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def initialize(params)
|
|
23
|
+
@params = params
|
|
24
|
+
super()
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_s
|
|
28
|
+
"[#{@params.map { |t| t.to_s }.join(', ')}]"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def eql?(other)
|
|
32
|
+
self == other
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ==(other) # :nodoc:
|
|
36
|
+
return (other.instance_of? TupleType) && (other.params == @params)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def <=(other)
|
|
40
|
+
return true if other.instance_of? TopType
|
|
41
|
+
return self == other
|
|
42
|
+
# Subtyping with Array not allowed
|
|
43
|
+
# All positions of Tuple are invariant since tuples are mutable
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def member?(obj, *args)
|
|
47
|
+
t = RDL::Util.rdl_type obj
|
|
48
|
+
return t <= self if t
|
|
49
|
+
return false unless obj.instance_of?(Array) && obj.size == @params.size
|
|
50
|
+
return @params.zip(obj).all? { |formal, actual| formal.member?(actual, *args) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def instantiate(inst)
|
|
54
|
+
TupleType.new(*@params.map { |t| t.instantiate(inst) })
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def hash
|
|
58
|
+
h = 73 * @params.hash
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module RDL::Type
|
|
2
|
+
# Abstract base class for all types. This class
|
|
3
|
+
# should never be instantiated directly.
|
|
4
|
+
|
|
5
|
+
class TypeError < StandardError; end
|
|
6
|
+
|
|
7
|
+
class Type
|
|
8
|
+
|
|
9
|
+
@@contract_cache = {}
|
|
10
|
+
|
|
11
|
+
def to_contract
|
|
12
|
+
c = @@contract_cache[self]
|
|
13
|
+
return c if c
|
|
14
|
+
|
|
15
|
+
slf = self # Bind self to slf since contracts are executed in scope of associated method
|
|
16
|
+
c = RDL::Contract::FlatContract.new(to_s) { |obj|
|
|
17
|
+
raise TypeError, "Expecting #{to_s}, got object of class #{RDL::Util.rdl_type_or_class(obj)}" unless slf.member?(obj)
|
|
18
|
+
true
|
|
19
|
+
}
|
|
20
|
+
return (@@contract_cache[self] = c) # assignment evaluates to c
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module RDL
|
|
2
|
+
class TypeInferencer
|
|
3
|
+
def self.infer_type(it)
|
|
4
|
+
current_types = Set.new
|
|
5
|
+
it_types = it.map {|t| t.rdl_type}
|
|
6
|
+
it_types = it_types.to_set
|
|
7
|
+
|
|
8
|
+
it_types.each {|t|
|
|
9
|
+
subtype = current_types.any? {|ct| t.le(ct)}
|
|
10
|
+
current_types.add(t) if not subtype
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if current_types.size == 1
|
|
14
|
+
current_types.to_a[0]
|
|
15
|
+
elsif current_types.size == 0
|
|
16
|
+
RDL::Type::NilType.new
|
|
17
|
+
else
|
|
18
|
+
RDL::Type::UnionType.new(*self.unify_param_types(current_types))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def self.extract_types(param_type)
|
|
25
|
+
param_type.instance_of?(RDL::Type::UnionType) ? param_type.types.to_a : [param_type]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Unifies i.e. #<Set: {Array<String>, Array<Array<String>>}> into
|
|
29
|
+
# Array<(Array<String> or String)>
|
|
30
|
+
# If this step is not called, then infer_type for
|
|
31
|
+
# [["a", "b"], [["c"]]].rdl_type would return
|
|
32
|
+
# (Array<Array<String>> or Array<String>) instead of
|
|
33
|
+
# (Array<(Array<String> or String)>)
|
|
34
|
+
def self.unify_param_types(type_set)
|
|
35
|
+
non_param_classes = []
|
|
36
|
+
parameterized_classes = {}
|
|
37
|
+
|
|
38
|
+
type_set.each {|member_type|
|
|
39
|
+
if member_type.instance_of? RDL::Type::GenericType
|
|
40
|
+
nominal_type = member_type.base
|
|
41
|
+
|
|
42
|
+
tparam_set = parameterized_classes.fetch(nominal_type) {|n_type|
|
|
43
|
+
cls = eval(n_type.name.to_s)
|
|
44
|
+
type_parameters = cls.instance_variable_get :@__cls_params
|
|
45
|
+
[].fill([], 0, type_parameters.size)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
cls = eval(nominal_type.name.to_s)
|
|
49
|
+
type_parameters = cls.instance_variable_get :@__cls_params
|
|
50
|
+
((0..(type_parameters.size - 1)).map {|tparam_index|
|
|
51
|
+
extract_types(member_type.params[tparam_index])
|
|
52
|
+
}).each_with_index {|type_parameter,index|
|
|
53
|
+
tparam_set[index]+=type_parameter
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
parameterized_classes[nominal_type] = tparam_set
|
|
57
|
+
else
|
|
58
|
+
non_param_classes << member_type
|
|
59
|
+
end
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
parameterized_classes.each {|nominal, type_set|
|
|
63
|
+
t = type_set.map {|unioned_type_parameter|
|
|
64
|
+
RDL::Type::UnionType.new(*unify_param_types(unioned_type_parameter))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
non_param_classes << RDL::Type::GenericType.new(nominal, *t)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
non_param_classes
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module RDL::Type
|
|
4
|
+
class UnionType < Type
|
|
5
|
+
attr_reader :types
|
|
6
|
+
|
|
7
|
+
@@cache = {}
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
alias :__new__ :new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.new(*types)
|
|
14
|
+
ts = []
|
|
15
|
+
types.each { |t|
|
|
16
|
+
if t.instance_of? NilType
|
|
17
|
+
next
|
|
18
|
+
elsif t.instance_of? TopType
|
|
19
|
+
ts = [t]
|
|
20
|
+
break
|
|
21
|
+
elsif t.instance_of? UnionType
|
|
22
|
+
ts.concat t.types
|
|
23
|
+
else
|
|
24
|
+
raise RuntimeError, "Attempt to create union type with non-type" unless t.is_a? Type
|
|
25
|
+
ts << t
|
|
26
|
+
end
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
ts.sort! { |a,b| a.object_id <=> b.object_id }
|
|
30
|
+
ts.uniq!
|
|
31
|
+
|
|
32
|
+
return NilType.new if ts.size == 0
|
|
33
|
+
return ts[0] if ts.size == 1
|
|
34
|
+
|
|
35
|
+
t = @@cache[ts]
|
|
36
|
+
return t if t
|
|
37
|
+
t = UnionType.__new__(ts)
|
|
38
|
+
return (@@cache[ts] = t) # assignment evaluates to t
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def initialize(types)
|
|
42
|
+
@types = types
|
|
43
|
+
super()
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_s # :nodoc:
|
|
47
|
+
"#{@types.map { |t| t.to_s }.join(' or ')}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def eql?(other)
|
|
51
|
+
self == other
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def ==(other) # :nodoc:
|
|
55
|
+
return (other.instance_of? UnionType) && (other.types == @types)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def <=(other)
|
|
59
|
+
@types.all? { |t| t <= other }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def member?(obj, *args)
|
|
63
|
+
@types.any? { |t| t.member?(obj, *args) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def instantiate(inst)
|
|
67
|
+
return UnionType.new(*(@types.map { |t| t.instantiate(inst) }))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def hash # :nodoc:
|
|
71
|
+
41 + @types.hash
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module RDL::Type
|
|
4
|
+
class VarType < Type
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
7
|
+
@@cache = {}
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
alias :__new__ :new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.new(name)
|
|
14
|
+
name = name.to_s.to_sym
|
|
15
|
+
t = @@cache[name]
|
|
16
|
+
return t if t
|
|
17
|
+
t = self.__new__ name
|
|
18
|
+
return (@@cache[name] = t) # assignment evaluates to t
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(name)
|
|
22
|
+
@name = name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s # :nodoc:
|
|
26
|
+
return @name.to_s
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def eql?(other)
|
|
30
|
+
self == other
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ==(other)
|
|
34
|
+
return (other.instance_of? self.class) && (other.name.to_s == @name.to_s)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def hash # :nodoc:
|
|
38
|
+
return @name.to_s.hash
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def member?(obj, vars_wild: false)
|
|
42
|
+
return true if vars_wild
|
|
43
|
+
raise TypeError, "Unbound type variable #{@name}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def instantiate(inst)
|
|
47
|
+
return inst[@name] if inst[@name]
|
|
48
|
+
return self
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|