finitio 0.7.0 → 0.8.0
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 +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
|