finitio 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +40 -41
- data/lib/finitio/generation.rb +106 -0
- data/lib/finitio/generation/ad_type.rb +10 -0
- data/lib/finitio/generation/alias_type.rb +9 -0
- data/lib/finitio/generation/any_type.rb +11 -0
- data/lib/finitio/generation/builtin_type.rb +9 -0
- data/lib/finitio/generation/hash_based_type.rb +15 -0
- data/lib/finitio/generation/heuristic.rb +8 -0
- data/lib/finitio/generation/heuristic/constant.rb +30 -0
- data/lib/finitio/generation/heuristic/random.rb +52 -0
- data/lib/finitio/generation/rel_based_type.rb +13 -0
- data/lib/finitio/generation/seq_type.rb +13 -0
- data/lib/finitio/generation/set_type.rb +13 -0
- data/lib/finitio/generation/sub_type.rb +9 -0
- data/lib/finitio/generation/union_type.rb +10 -0
- data/lib/finitio/inference.rb +51 -0
- data/lib/finitio/support.rb +18 -0
- data/lib/finitio/support/attribute.rb +8 -0
- data/lib/finitio/support/compilation.rb +18 -18
- data/lib/finitio/support/contract.rb +8 -0
- data/lib/finitio/support/fetch_scope.rb +19 -0
- data/lib/finitio/support/heading.rb +36 -1
- data/lib/finitio/syntax.rb +1 -1
- data/lib/finitio/syntax/lexer.citrus +1 -1
- data/lib/finitio/syntax/type.rb +2 -0
- data/lib/finitio/syntax/type/high_order_type_instantiation.rb +29 -0
- data/lib/finitio/syntax/type/high_order_vars.rb +16 -0
- data/lib/finitio/syntax/type/type_def.rb +11 -1
- data/lib/finitio/syntax/types.citrus +14 -1
- data/lib/finitio/system.rb +11 -1
- data/lib/finitio/type.rb +19 -0
- data/lib/finitio/type/ad_type.rb +8 -0
- data/lib/finitio/type/alias_type.rb +8 -0
- data/lib/finitio/type/any_type.rb +12 -0
- data/lib/finitio/type/builtin_type.rb +4 -0
- data/lib/finitio/type/collection_type.rb +15 -0
- data/lib/finitio/type/heading_based_type.rb +17 -0
- data/lib/finitio/type/high_order_type.rb +39 -0
- data/lib/finitio/type/multi_relation_type.rb +4 -0
- data/lib/finitio/type/multi_tuple_type.rb +4 -0
- data/lib/finitio/type/proxy_type.rb +10 -20
- data/lib/finitio/type/relation_type.rb +4 -0
- data/lib/finitio/type/seq_type.rb +1 -1
- data/lib/finitio/type/struct_type.rb +8 -0
- data/lib/finitio/type/sub_type.rb +8 -0
- data/lib/finitio/type/tuple_type.rb +4 -0
- data/lib/finitio/type/union_type.rb +19 -0
- data/lib/finitio/version.rb +1 -1
- data/spec/generation/test_generation.rb +169 -0
- data/spec/heading/test_looks_similar.rb +45 -0
- data/spec/heading/test_suppremum.rb +56 -0
- data/spec/inference/test_inference.rb +42 -0
- data/spec/spec_helper.rb +31 -6
- data/spec/support/test_compare_attrs.rb +67 -0
- data/spec/syntax/test_compile.rb +57 -0
- data/spec/type/ad_type/test_initialize.rb +1 -8
- data/spec/type/relation_type/test_suppremum.rb +104 -0
- data/spec/type/seq_type/test_suppremum.rb +54 -0
- data/spec/type/set_type/test_suppremum.rb +54 -0
- data/spec/type/test_suppremum.rb +49 -0
- data/spec/type/test_unconstrained.rb +150 -0
- data/spec/type/tuple_type/test_suppremum.rb +119 -0
- data/spec/type/union_type/test_suppremum.rb +51 -0
- data/tasks/test.rake +1 -1
- metadata +183 -144
- data/spec/type/proxy_type/test_delegation.rb +0 -37
- data/spec/type/proxy_type/test_resolve.rb +0 -29
@@ -0,0 +1,51 @@
|
|
1
|
+
module Finitio
|
2
|
+
class Inference
|
3
|
+
|
4
|
+
def initialize(system, options = {})
|
5
|
+
@system = system
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
attr_reader :system
|
9
|
+
|
10
|
+
def call(input)
|
11
|
+
infer_type(input)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def infer_type(value)
|
17
|
+
case value
|
18
|
+
when Hash
|
19
|
+
attrs = value.map{|k,v|
|
20
|
+
Attribute.new(k.to_sym, infer_type(v))
|
21
|
+
}
|
22
|
+
heading = Heading.new(attrs)
|
23
|
+
TupleType.new(heading)
|
24
|
+
when Array
|
25
|
+
infered = value.inject(nil){|sup, value|
|
26
|
+
value_type = infer_type(value)
|
27
|
+
sup.nil? ? value_type : sup.suppremum(value_type)
|
28
|
+
}
|
29
|
+
SeqType.new(infered.nil? ? ANY_TYPE : infered)
|
30
|
+
else
|
31
|
+
found = self.system.types.values.find{|t|
|
32
|
+
try_dress(t, value)
|
33
|
+
}
|
34
|
+
found ? found : ANY_TYPE
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def try_dress(t, value)
|
39
|
+
raise "Type expected, got #{t}" unless t.is_a?(Type)
|
40
|
+
t.dress(value)
|
41
|
+
true
|
42
|
+
rescue Finitio::Error => ex
|
43
|
+
#puts %Q{[#{ex.class}] #{ex.message}}
|
44
|
+
nil
|
45
|
+
rescue => ex
|
46
|
+
puts %Q{[#{ex.class}] #{ex.message}\n#{ex.backtrace.join("\n")}}
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class Inference
|
51
|
+
end # module Finitio
|
data/lib/finitio/support.rb
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
module Finitio
|
2
|
+
module Support
|
3
|
+
|
4
|
+
def compare_attrs(h1, h2, &bl)
|
5
|
+
mine, yours = if bl
|
6
|
+
[h1.map(&bl), h2.map(&bl)]
|
7
|
+
elsif h1.is_a?(Hash)
|
8
|
+
[h1.keys, h2.keys]
|
9
|
+
else
|
10
|
+
[h1, h2]
|
11
|
+
end
|
12
|
+
[ mine & yours, mine - yours, yours - mine ]
|
13
|
+
end
|
14
|
+
module_function :compare_attrs
|
15
|
+
|
16
|
+
end # module Support
|
17
|
+
end # module Finitio
|
1
18
|
require_relative 'support/proc_with_code'
|
2
19
|
require_relative 'support/metadata'
|
3
20
|
require_relative 'support/attribute'
|
@@ -6,4 +23,5 @@ require_relative 'support/contract'
|
|
6
23
|
require_relative 'support/heading'
|
7
24
|
require_relative 'support/dress_helper'
|
8
25
|
require_relative 'support/type_factory'
|
26
|
+
require_relative 'support/fetch_scope'
|
9
27
|
require_relative 'support/compilation'
|
@@ -55,5 +55,13 @@ module Finitio
|
|
55
55
|
name.hash ^ type.hash ^ required.hash
|
56
56
|
end
|
57
57
|
|
58
|
+
def resolve_proxies(system)
|
59
|
+
Attribute.new(name, type.resolve_proxies(system), required, metadata)
|
60
|
+
end
|
61
|
+
|
62
|
+
def unconstrained
|
63
|
+
Attribute.new(name, type.unconstrained, required, metadata)
|
64
|
+
end
|
65
|
+
|
58
66
|
end # class Attribute
|
59
67
|
end # module Finitio
|
@@ -1,19 +1,19 @@
|
|
1
1
|
module Finitio
|
2
2
|
class Compilation
|
3
3
|
|
4
|
-
def initialize(system = System.new, factory = TypeFactory.new, source = nil)
|
4
|
+
def initialize(system = System.new, factory = TypeFactory.new, scope = nil, source = nil)
|
5
5
|
@system = system
|
6
6
|
@factory = factory
|
7
|
-
@
|
7
|
+
@scope = scope || FetchScope.new(system, {})
|
8
8
|
@source = source
|
9
9
|
end
|
10
|
-
attr_reader :system, :factory, :
|
10
|
+
attr_reader :system, :factory, :scope, :source
|
11
11
|
|
12
12
|
def self.coerce(arg, source = nil)
|
13
13
|
case arg
|
14
|
-
when NilClass then new(System.new, TypeFactory.new, source)
|
15
|
-
when System then new(arg, arg.factory, source)
|
16
|
-
when TypeFactory then new(System.new, arg, source)
|
14
|
+
when NilClass then new(System.new, TypeFactory.new, nil, source)
|
15
|
+
when System then new(arg, arg.factory, nil, source)
|
16
|
+
when TypeFactory then new(System.new, arg, nil, source)
|
17
17
|
else
|
18
18
|
raise ArgumentError, "Unable to coerce `#{arg}`"
|
19
19
|
end
|
@@ -48,11 +48,8 @@ module Finitio
|
|
48
48
|
Pathname.new(file)
|
49
49
|
end
|
50
50
|
|
51
|
-
def resolve_proxies
|
52
|
-
|
53
|
-
p.resolve(system)
|
54
|
-
end
|
55
|
-
self
|
51
|
+
def resolve_proxies
|
52
|
+
system.resolve_proxies
|
56
53
|
end
|
57
54
|
|
58
55
|
# Delegation to Factory
|
@@ -63,17 +60,10 @@ module Finitio
|
|
63
60
|
}
|
64
61
|
end
|
65
62
|
|
66
|
-
def proxy(*args, &bl)
|
67
|
-
proxy = factory.proxy(*args, &bl)
|
68
|
-
proxies << proxy
|
69
|
-
proxy
|
70
|
-
end
|
71
|
-
|
72
63
|
# Delegation to System
|
73
64
|
|
74
65
|
[
|
75
66
|
:add_type,
|
76
|
-
:fetch,
|
77
67
|
:main,
|
78
68
|
].each do |meth|
|
79
69
|
define_method(meth) do |*args, &bl|
|
@@ -81,5 +71,15 @@ module Finitio
|
|
81
71
|
end
|
82
72
|
end
|
83
73
|
|
74
|
+
# Delegation to FetchScope
|
75
|
+
|
76
|
+
def fetch(type_name, &bl)
|
77
|
+
scope.fetch(type_name, &bl)
|
78
|
+
end
|
79
|
+
|
80
|
+
def with_scope(overrides)
|
81
|
+
Compilation.new(system, factory, scope.with(overrides), source)
|
82
|
+
end
|
83
|
+
|
84
84
|
end # class Compilation
|
85
85
|
end # module Finitio
|
@@ -44,5 +44,13 @@ module Finitio
|
|
44
44
|
end
|
45
45
|
alias :eql? :==
|
46
46
|
|
47
|
+
def resolve_proxies(system)
|
48
|
+
Contract.new(infotype.resolve_proxies(system), dresser, undresser, name, metadata)
|
49
|
+
end
|
50
|
+
|
51
|
+
def unconstrained
|
52
|
+
Contract.new(infotype.unconstrained, dresser, undresser, name, metadata)
|
53
|
+
end
|
54
|
+
|
47
55
|
end # class Contract
|
48
56
|
end # module Finitio
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Finitio
|
2
|
+
class FetchScope
|
3
|
+
|
4
|
+
def initialize(parent, overrides)
|
5
|
+
@parent, @overrides = parent, overrides
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(name, &bl)
|
9
|
+
@overrides.fetch(name) do
|
10
|
+
@parent.fetch(name, &bl)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def with(overrides)
|
15
|
+
FetchScope.new(self, overrides)
|
16
|
+
end
|
17
|
+
|
18
|
+
end # class FetchScope
|
19
|
+
end # module Finitio
|
@@ -61,6 +61,32 @@ module Finitio
|
|
61
61
|
name
|
62
62
|
end
|
63
63
|
|
64
|
+
def looks_similar?(other)
|
65
|
+
return self if other == self
|
66
|
+
shared, mine, yours = Support.compare_attrs(attributes, other.attributes)
|
67
|
+
shared.length >= mine.length && shared.length >= yours.length
|
68
|
+
end
|
69
|
+
|
70
|
+
def suppremum(other)
|
71
|
+
raise ArgumentError unless other.is_a?(Heading)
|
72
|
+
return self if other == self
|
73
|
+
options = { allow_extra: allow_extra? || other.allow_extra? }
|
74
|
+
shared, mine, yours = Support.compare_attrs(attributes, other.attributes)
|
75
|
+
attributes = shared.map{|attr|
|
76
|
+
a1, o1 = self[attr], other[attr]
|
77
|
+
Attribute.new(attr, a1.type.suppremum(o1.type), a1.required && o1.required)
|
78
|
+
}
|
79
|
+
attributes += mine.map{|attrname|
|
80
|
+
attr = self[attrname]
|
81
|
+
Attribute.new(attr.name, attr.type, false)
|
82
|
+
}
|
83
|
+
attributes += yours.map{|attrname|
|
84
|
+
attr = other[attrname]
|
85
|
+
Attribute.new(attr.name, attr.type, false)
|
86
|
+
}
|
87
|
+
Heading.new(attributes, options)
|
88
|
+
end
|
89
|
+
|
64
90
|
def ==(other)
|
65
91
|
return nil unless other.is_a?(Heading)
|
66
92
|
attributes == other.attributes && options == other.options
|
@@ -73,6 +99,15 @@ module Finitio
|
|
73
99
|
attr_reader :attributes, :options
|
74
100
|
protected :attributes, :options
|
75
101
|
|
102
|
+
def resolve_proxies(system)
|
103
|
+
as = attributes.map{|k,a| a.resolve_proxies(system) }
|
104
|
+
Heading.new(as, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
def unconstrained
|
108
|
+
Heading.new(attributes.values.map{|a| a.unconstrained }, options)
|
109
|
+
end
|
110
|
+
|
76
111
|
private
|
77
112
|
|
78
113
|
def normalize_attributes(attrs)
|
@@ -83,7 +118,7 @@ module Finitio
|
|
83
118
|
attributes = {}
|
84
119
|
attrs.each do |attr|
|
85
120
|
unless attr.is_a?(Attribute)
|
86
|
-
raise ArgumentError, "Enumerable[Attribute] expected"
|
121
|
+
raise ArgumentError, "Enumerable[Attribute] expected, got a `#{attr.inspect}`"
|
87
122
|
end
|
88
123
|
if attributes[attr.name]
|
89
124
|
raise ArgumentError, "Attribute names must be unique"
|
data/lib/finitio/syntax.rb
CHANGED
data/lib/finitio/syntax/type.rb
CHANGED
@@ -19,9 +19,11 @@ require_relative 'type/relation_type'
|
|
19
19
|
require_relative 'type/union_type'
|
20
20
|
require_relative 'type/type_ref'
|
21
21
|
require_relative 'type/ad_type'
|
22
|
+
require_relative 'type/high_order_type_instantiation'
|
22
23
|
require_relative 'type/contract'
|
23
24
|
require_relative 'type/inline_pair'
|
24
25
|
require_relative 'type/external_pair'
|
25
26
|
require_relative 'type/lambda_expr'
|
26
27
|
require_relative 'type/metadata'
|
27
28
|
require_relative 'type/metadata_attr'
|
29
|
+
require_relative 'type/high_order_vars'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Finitio
|
2
|
+
module Syntax
|
3
|
+
module HighOrderTypeInstantiation
|
4
|
+
include Node
|
5
|
+
|
6
|
+
capture :high
|
7
|
+
capture :vars
|
8
|
+
|
9
|
+
def compile(system)
|
10
|
+
target = system.fetch(high.to_s){
|
11
|
+
raise Error, "No such type `#{high.to_s}`"
|
12
|
+
}
|
13
|
+
raise "#{high} is not a high order type" unless target.is_a?(HighOrderType)
|
14
|
+
|
15
|
+
subs = vars.compile(system).map{|low|
|
16
|
+
system.fetch(low.to_s) {
|
17
|
+
raise Error, "No such type `#{low.to_s}`"
|
18
|
+
}
|
19
|
+
}
|
20
|
+
target.instantiate(system, subs)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_ast
|
24
|
+
[:high_order_type_instantiation, high.to_s, lows.to_s]
|
25
|
+
end
|
26
|
+
|
27
|
+
end # module HighOrderTypeInstantiation
|
28
|
+
end # module Syntax
|
29
|
+
end # module Finitio
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Finitio
|
2
|
+
module Syntax
|
3
|
+
module HighOrderVars
|
4
|
+
include Node
|
5
|
+
|
6
|
+
def compile(system)
|
7
|
+
captures[:type_name].map{|c| c.to_s }
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_ast(var_name)
|
11
|
+
[ :high_order_vars, captures[:type_name].map{|c| c.to_s } ]
|
12
|
+
end
|
13
|
+
|
14
|
+
end # module HighOrderVars
|
15
|
+
end # module Syntax
|
16
|
+
end # module Finitio
|
@@ -5,9 +5,19 @@ module Finitio
|
|
5
5
|
|
6
6
|
capture :type
|
7
7
|
capture :type_name
|
8
|
+
capture :vars
|
8
9
|
|
9
10
|
def compile(system)
|
10
|
-
|
11
|
+
if vars
|
12
|
+
vs = vars.compile(system)
|
13
|
+
overrides = Hash[vs.map{|v|
|
14
|
+
[ v.to_s, ProxyType.new(v) ]
|
15
|
+
}]
|
16
|
+
t = type.compile(system.with_scope(overrides))
|
17
|
+
t = HighOrderType.new(vs, t)
|
18
|
+
else
|
19
|
+
t = type.compile(system)
|
20
|
+
end
|
11
21
|
n = type_name && type_name.to_str
|
12
22
|
m = metadata
|
13
23
|
system.add_type(t, n, m)
|
@@ -6,10 +6,15 @@ grammar Finitio::Syntax::Types
|
|
6
6
|
include Finitio::Syntax::Literals
|
7
7
|
|
8
8
|
rule type_def
|
9
|
-
(metadata? type_name equal type)
|
9
|
+
(metadata? type_name ('<' vars:high_order_vars '>')? equal type)
|
10
10
|
<Finitio::Syntax::TypeDef>
|
11
11
|
end
|
12
12
|
|
13
|
+
rule high_order_vars
|
14
|
+
(type_name (comma type_name)*)
|
15
|
+
<Finitio::Syntax::HighOrderVars>
|
16
|
+
end
|
17
|
+
|
13
18
|
rule main_type
|
14
19
|
(metadata? type)
|
15
20
|
<Finitio::Syntax::MainType>
|
@@ -58,6 +63,7 @@ grammar Finitio::Syntax::Types
|
|
58
63
|
rule rel_type
|
59
64
|
relation_type
|
60
65
|
| tuple_type
|
66
|
+
| high_order_type_instantiation
|
61
67
|
| collection_type
|
62
68
|
end
|
63
69
|
|
@@ -110,6 +116,13 @@ grammar Finitio::Syntax::Types
|
|
110
116
|
<Finitio::Syntax::StructType>
|
111
117
|
end
|
112
118
|
|
119
|
+
# high-order types
|
120
|
+
|
121
|
+
rule high_order_type_instantiation
|
122
|
+
(high:type_name '<' vars:high_order_vars '>')
|
123
|
+
<Finitio::Syntax::HighOrderTypeInstantiation>
|
124
|
+
end
|
125
|
+
|
113
126
|
# terminal forms
|
114
127
|
|
115
128
|
rule term_type
|
data/lib/finitio/system.rb
CHANGED
@@ -10,7 +10,7 @@ module Finitio
|
|
10
10
|
end
|
11
11
|
|
12
12
|
attr_reader :types, :imports
|
13
|
-
private :
|
13
|
+
private :imports
|
14
14
|
|
15
15
|
def add_import(system)
|
16
16
|
@imports << system
|
@@ -89,6 +89,16 @@ module Finitio
|
|
89
89
|
Syntax.compile(source, self.dup)
|
90
90
|
end
|
91
91
|
|
92
|
+
def resolve_proxies(recurse = true)
|
93
|
+
rebuilt = {}
|
94
|
+
scope = FetchScope.new(self, rebuilt)
|
95
|
+
types.each_with_object(rebuilt) do |(name,type),memo|
|
96
|
+
rebuilt[name] = type.resolve_proxies(scope)
|
97
|
+
end
|
98
|
+
resolved = System.new(rebuilt, imports)
|
99
|
+
recurse ? resolved.resolve_proxies(false) : resolved
|
100
|
+
end
|
101
|
+
|
92
102
|
def inspect
|
93
103
|
@types.each_pair.map{|k,v| "#{k} = #{v}" }.join("\n")
|
94
104
|
end
|