sfrp 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ctags +3 -0
- data/.editorconfig +9 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +629 -0
- data/.travis.yml +12 -0
- data/Gemfile +2 -0
- data/LICENSE +28 -0
- data/README.md +34 -0
- data/Rakefile +1 -0
- data/base-library/Base.sfrp +81 -0
- data/base-library/IO/AVR/ATMEGA8.c +9 -0
- data/base-library/IO/AVR/ATMEGA8.h +6 -0
- data/base-library/IO/AVR/ATMEGA8.sfrp +4 -0
- data/base-library/IO/STDIO.c +40 -0
- data/base-library/IO/STDIO.h +13 -0
- data/base-library/IO/STDIO.sfrp +10 -0
- data/bin/sfrp +7 -0
- data/lib/sfrp.rb +2 -0
- data/lib/sfrp/command.rb +73 -0
- data/lib/sfrp/compiler.rb +94 -0
- data/lib/sfrp/error.rb +4 -0
- data/lib/sfrp/file.rb +18 -0
- data/lib/sfrp/flat/dsl.rb +33 -0
- data/lib/sfrp/flat/elements.rb +90 -0
- data/lib/sfrp/flat/exception.rb +45 -0
- data/lib/sfrp/flat/expression.rb +125 -0
- data/lib/sfrp/flat/set.rb +61 -0
- data/lib/sfrp/input/exception.rb +16 -0
- data/lib/sfrp/input/parser.rb +417 -0
- data/lib/sfrp/input/set.rb +29 -0
- data/lib/sfrp/input/transformer.rb +219 -0
- data/lib/sfrp/low/dsl.rb +126 -0
- data/lib/sfrp/low/element.rb +126 -0
- data/lib/sfrp/low/set.rb +62 -0
- data/lib/sfrp/mono/dsl.rb +120 -0
- data/lib/sfrp/mono/environment.rb +26 -0
- data/lib/sfrp/mono/exception.rb +21 -0
- data/lib/sfrp/mono/expression.rb +124 -0
- data/lib/sfrp/mono/function.rb +86 -0
- data/lib/sfrp/mono/memory.rb +32 -0
- data/lib/sfrp/mono/node.rb +125 -0
- data/lib/sfrp/mono/pattern.rb +69 -0
- data/lib/sfrp/mono/set.rb +151 -0
- data/lib/sfrp/mono/type.rb +210 -0
- data/lib/sfrp/mono/vconst.rb +134 -0
- data/lib/sfrp/output/set.rb +33 -0
- data/lib/sfrp/poly/dsl.rb +171 -0
- data/lib/sfrp/poly/elements.rb +168 -0
- data/lib/sfrp/poly/exception.rb +42 -0
- data/lib/sfrp/poly/expression.rb +170 -0
- data/lib/sfrp/poly/monofier.rb +73 -0
- data/lib/sfrp/poly/set.rb +90 -0
- data/lib/sfrp/poly/typing.rb +197 -0
- data/lib/sfrp/raw/dsl.rb +41 -0
- data/lib/sfrp/raw/elements.rb +164 -0
- data/lib/sfrp/raw/exception.rb +40 -0
- data/lib/sfrp/raw/expression.rb +168 -0
- data/lib/sfrp/raw/namespace.rb +30 -0
- data/lib/sfrp/raw/set.rb +109 -0
- data/lib/sfrp/version.rb +3 -0
- data/sfrp.gemspec +40 -0
- data/spec/sfrp/Test.sfrp +4 -0
- data/spec/sfrp/compiler_spec.rb +17 -0
- data/spec/sfrp/flat/set_spec.rb +40 -0
- data/spec/sfrp/input/parse_test.sfrp +20 -0
- data/spec/sfrp/input/set_spec.rb +18 -0
- data/spec/sfrp/low/set_spec.rb +20 -0
- data/spec/sfrp/mono/expected.yml +295 -0
- data/spec/sfrp/mono/set_spec.rb +152 -0
- data/spec/sfrp/output/set_spec.rb +29 -0
- data/spec/sfrp/poly/set_spec.rb +290 -0
- data/spec/sfrp/raw/set_spec.rb +38 -0
- data/spec/spec_helper.rb +16 -0
- data/test/IntTest/Main.c +5 -0
- data/test/IntTest/Main.h +6 -0
- data/test/IntTest/Main.sfrp +10 -0
- data/test/IntTest/in.txt +3 -0
- data/test/IntTest/out.txt +4 -0
- data/test/MaybeTest/Main.sfrp +8 -0
- data/test/MaybeTest/SubDir/Lib.sfrp +9 -0
- data/test/MaybeTest/in.txt +6 -0
- data/test/MaybeTest/out.txt +6 -0
- data/test/Rakefile +15 -0
- metadata +290 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'sfrp/error'
|
2
|
+
|
3
|
+
module SFRP
|
4
|
+
module Poly
|
5
|
+
class UndeterminableTypeError < CompileError
|
6
|
+
def initialize(identifier, typing)
|
7
|
+
@identifier = identifier
|
8
|
+
@typing = typing
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
"undeterminable type #{@typing}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class UnifyError < CompileError
|
17
|
+
def initialize(typing1, typing2)
|
18
|
+
@typing1 = typing1
|
19
|
+
@typing2 = typing2
|
20
|
+
end
|
21
|
+
|
22
|
+
def message
|
23
|
+
vars = @typing1.variables + @typing2.variables
|
24
|
+
"cannot unify #{@typing1.to_s(vars)} and #{@typing2.to_s(vars)}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class RecursiveError < CompileError
|
29
|
+
def initialize(node_strs)
|
30
|
+
@node_strs = node_strs
|
31
|
+
end
|
32
|
+
|
33
|
+
def chain_str
|
34
|
+
[*@node_strs, @node_strs[0]].join(' -> ')
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
"recursive node/function path: #{chain_str}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Poly
|
3
|
+
class MatchExp
|
4
|
+
Case = Struct.new(:pattern, :exp)
|
5
|
+
|
6
|
+
def initialize(left_exp, cases, id = nil)
|
7
|
+
@left_exp = left_exp
|
8
|
+
@cases = cases
|
9
|
+
@id = id
|
10
|
+
end
|
11
|
+
|
12
|
+
def typing(set, var_env)
|
13
|
+
raise if @typing
|
14
|
+
left_exp_typing = @left_exp.typing(set, var_env)
|
15
|
+
@typing = Typing.new do |t|
|
16
|
+
@cases.each do |c|
|
17
|
+
new_var_env = var_env.dup
|
18
|
+
left_exp_typing.unify(c.pattern.typing(set, new_var_env))
|
19
|
+
t.unify(c.exp.typing(set, new_var_env))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def clone
|
25
|
+
cloned_cases = @cases.map { |c| Case.new(c.pattern.clone, c.exp.clone) }
|
26
|
+
MatchExp.new(@left_exp.clone, cloned_cases, @id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def called_func_strs
|
30
|
+
[@left_exp, *@cases.map(&:exp)].flat_map(&:called_func_strs)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_mono(monofier)
|
34
|
+
raise UndeterminableTypeError.new(@id, @typing) unless @typing.mono?
|
35
|
+
mono_type_str = monofier.use_type(@typing)
|
36
|
+
M.match_e(mono_type_str, @left_exp.to_mono(monofier)) do |m|
|
37
|
+
@cases.each do |c|
|
38
|
+
m.case(c.pattern.to_mono(monofier)) { c.exp.to_mono(monofier) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class FuncCallExp
|
45
|
+
def initialize(func_str, arg_exps, id = nil)
|
46
|
+
@func_str = func_str
|
47
|
+
@arg_exps = arg_exps
|
48
|
+
@id = id
|
49
|
+
end
|
50
|
+
|
51
|
+
def typing(set, var_env)
|
52
|
+
raise if @typing
|
53
|
+
@ftyping = set.func(@func_str).ftyping(set).instance do |ft|
|
54
|
+
ft.params.zip(@arg_exps) { |t, e| e.typing(set, var_env).unify(t) }
|
55
|
+
end
|
56
|
+
@typing = @ftyping.body
|
57
|
+
end
|
58
|
+
|
59
|
+
def clone
|
60
|
+
FuncCallExp.new(@func_str, @arg_exps.map(&:clone), @id)
|
61
|
+
end
|
62
|
+
|
63
|
+
def called_func_strs
|
64
|
+
[@func_str, *@arg_exps.flat_map(&:called_func_strs)]
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_mono(monofier)
|
68
|
+
raise UndeterminableTypeError.new(@id, @typing) unless @typing.mono?
|
69
|
+
mono_func_str = monofier.use_func(@func_str, @ftyping)
|
70
|
+
args = @arg_exps.map { |e| e.to_mono(monofier) }
|
71
|
+
M.call_e(monofier.use_type(@typing), mono_func_str, *args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class VConstCallExp
|
76
|
+
def initialize(vconst_str, arg_exps, id = nil)
|
77
|
+
@vconst_str = vconst_str
|
78
|
+
@arg_exps = arg_exps
|
79
|
+
@id = id
|
80
|
+
end
|
81
|
+
|
82
|
+
def typing(set, var_env)
|
83
|
+
raise if @typing
|
84
|
+
@ftyping = set.vconst(@vconst_str).ftyping.instance do |ft|
|
85
|
+
ft.params.zip(@arg_exps) { |t, e| e.typing(set, var_env).unify(t) }
|
86
|
+
end
|
87
|
+
@typing = @ftyping.body
|
88
|
+
end
|
89
|
+
|
90
|
+
def clone
|
91
|
+
VConstCallExp.new(@vconst_str, @arg_exps.map(&:clone), @id)
|
92
|
+
end
|
93
|
+
|
94
|
+
def called_func_strs
|
95
|
+
@arg_exps.flat_map(&:called_func_strs)
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_mono(monofier)
|
99
|
+
raise UndeterminableTypeError.new(@id, @typing) unless @typing.mono?
|
100
|
+
mono_vconst_str = monofier.use_vconst(@vconst_str, @typing)
|
101
|
+
args = @arg_exps.map { |e| e.to_mono(monofier) }
|
102
|
+
M.vc_call_e(monofier.use_type(@typing), mono_vconst_str, *args)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class VarRefExp
|
107
|
+
def initialize(var_str, id = nil)
|
108
|
+
@var_str = var_str
|
109
|
+
@id = id
|
110
|
+
end
|
111
|
+
|
112
|
+
def typing(_set, var_env)
|
113
|
+
@typing = var_env[@var_str]
|
114
|
+
end
|
115
|
+
|
116
|
+
def clone
|
117
|
+
VarRefExp.new(@var_str, @id)
|
118
|
+
end
|
119
|
+
|
120
|
+
def called_func_strs
|
121
|
+
[]
|
122
|
+
end
|
123
|
+
|
124
|
+
def to_mono(monofier)
|
125
|
+
raise UndeterminableTypeError.new(@id, @typing) unless @typing.mono?
|
126
|
+
M.v_e(monofier.use_type(@typing), @var_str)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class Pattern
|
131
|
+
def initialize(vconst_str, ref_var_str, patterns, id = nil)
|
132
|
+
@vconst_str = vconst_str
|
133
|
+
@ref_var_str = ref_var_str
|
134
|
+
@patterns = patterns
|
135
|
+
@id = id
|
136
|
+
end
|
137
|
+
|
138
|
+
def typing(set, var_env)
|
139
|
+
raise if @typing
|
140
|
+
@typing = Typing.new do |t|
|
141
|
+
var_env[@ref_var_str] = t if @ref_var_str
|
142
|
+
if @vconst_str
|
143
|
+
set.vconst(@vconst_str).ftyping.instance do |ft|
|
144
|
+
@patterns.zip(ft.params) do |pat, param_typing|
|
145
|
+
pat.typing(set, var_env).unify(param_typing)
|
146
|
+
end
|
147
|
+
ft.body.unify(t)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def clone
|
154
|
+
Pattern.new(@vconst_str, @ref_var_str, @patterns.map(&:clone), @id)
|
155
|
+
end
|
156
|
+
|
157
|
+
def to_mono(monofier)
|
158
|
+
raise UndeterminableTypeError.new(@id, @typing) unless @typing.mono?
|
159
|
+
mono_type_str = monofier.use_type(@typing)
|
160
|
+
if @vconst_str
|
161
|
+
mono_vconst_str = monofier.use_vconst(@vconst_str, @typing)
|
162
|
+
ch = @patterns.map { |pat| pat.to_mono(monofier) }
|
163
|
+
M.pref(mono_type_str, mono_vconst_str, @ref_var_str, *ch)
|
164
|
+
else
|
165
|
+
M.pany(mono_type_str, @ref_var_str)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Poly
|
3
|
+
class Monofier
|
4
|
+
def initialize(src_set, dest_set, &block)
|
5
|
+
@src_set = src_set
|
6
|
+
@dest_set = dest_set
|
7
|
+
@type_str = {}
|
8
|
+
@func_str = {}
|
9
|
+
@vconst_str = {}
|
10
|
+
@node_str = {}
|
11
|
+
block.call(self) if block
|
12
|
+
end
|
13
|
+
|
14
|
+
def use_type(typing)
|
15
|
+
unique_type_str = typing.tconst_str + '/TYPE/' + typing.unique_str
|
16
|
+
if @type_str.key?(unique_type_str)
|
17
|
+
@type_str[unique_type_str]
|
18
|
+
else
|
19
|
+
@type_str[unique_type_str] = 'T' + md5(unique_type_str)
|
20
|
+
new_tconst = @src_set.tconst(typing.tconst_str).clone
|
21
|
+
new_tconst.typing.unify(typing)
|
22
|
+
@dest_set << new_tconst.to_mono(self)
|
23
|
+
@type_str[unique_type_str]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def use_func(func_str, ftyping)
|
28
|
+
unique_func_str = func_str + '/FUNC/' + ftyping.unique_str
|
29
|
+
if @func_str.key?(unique_func_str)
|
30
|
+
@func_str[unique_func_str]
|
31
|
+
else
|
32
|
+
new_func = @src_set.func(func_str).clone
|
33
|
+
mono_func_str = 'F' + md5(unique_func_str)
|
34
|
+
new_func.ftyping(@src_set).unify(ftyping)
|
35
|
+
@dest_set << new_func.to_mono(self, mono_func_str)
|
36
|
+
@func_str[unique_func_str] = mono_func_str
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def use_vconst(vconst_str, typing)
|
41
|
+
unique_vconst_str = vconst_str + '/VCONST/' + typing.unique_str
|
42
|
+
if @vconst_str.key?(unique_vconst_str)
|
43
|
+
@vconst_str[unique_vconst_str]
|
44
|
+
else
|
45
|
+
@vconst_str[unique_vconst_str] = 'V' + md5(unique_vconst_str)
|
46
|
+
new_vconst = @src_set.vconst(vconst_str).clone
|
47
|
+
new_vconst.ftyping.body.unify(typing)
|
48
|
+
@dest_set << new_vconst.to_mono(self)
|
49
|
+
@vconst_str[unique_vconst_str]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def use_node(node_str)
|
54
|
+
unique_node_str = node_str + '/NODE/'
|
55
|
+
if @node_str.key?(unique_node_str)
|
56
|
+
@node_str[unique_node_str]
|
57
|
+
else
|
58
|
+
@node_str[unique_node_str] = 'N' + md5(unique_node_str)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def md5(str)
|
65
|
+
require 'digest/md5'
|
66
|
+
@record ||= {}
|
67
|
+
hash_val = Digest::MD5.hexdigest(str).to_i(16).to_s(36)[0, 20]
|
68
|
+
raise "MD5: #{@record[hash_val]} and #{str}" if @record.key?(hash_val)
|
69
|
+
hash_val
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'sfrp/poly/exception'
|
2
|
+
require 'sfrp/poly/typing'
|
3
|
+
require 'sfrp/poly/elements'
|
4
|
+
require 'sfrp/poly/expression'
|
5
|
+
require 'sfrp/poly/monofier'
|
6
|
+
require 'sfrp/poly/dsl'
|
7
|
+
|
8
|
+
module SFRP
|
9
|
+
module Poly
|
10
|
+
class Set
|
11
|
+
def initialize(&block)
|
12
|
+
@func_h = {}
|
13
|
+
@node_h = {}
|
14
|
+
@tconst_h = {}
|
15
|
+
@vconst_h = {}
|
16
|
+
@output_node_strs = []
|
17
|
+
@init_func_strs = []
|
18
|
+
block.call(self) if block
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_mono
|
22
|
+
Mono::Set.new do |dest_set|
|
23
|
+
@func_h.values.each do |f|
|
24
|
+
f.check_recursion(self)
|
25
|
+
f.ftyping(self)
|
26
|
+
end
|
27
|
+
@node_h.values.each do |n|
|
28
|
+
n.check_recursion(self)
|
29
|
+
n.typing(self)
|
30
|
+
end
|
31
|
+
Monofier.new(self, dest_set) do |m|
|
32
|
+
@init_func_strs.each do |func_str|
|
33
|
+
mono_func_str = m.use_func(func_str, func(func_str).ftyping(self))
|
34
|
+
dest_set.append_init_func_str(mono_func_str)
|
35
|
+
end
|
36
|
+
@node_h.values.each do |node|
|
37
|
+
dest_set << node.to_mono(m)
|
38
|
+
end
|
39
|
+
@output_node_strs.each do |node_str|
|
40
|
+
dest_set.append_output_node_str(m.use_node(node_str))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def <<(element)
|
47
|
+
case element
|
48
|
+
when Function
|
49
|
+
@func_h[element.str] = element
|
50
|
+
when Node
|
51
|
+
@node_h[element.str] = element
|
52
|
+
when TConst
|
53
|
+
@tconst_h[element.str] = element
|
54
|
+
when VConst
|
55
|
+
@vconst_h[element.str] = element
|
56
|
+
else
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def append_output_node_str(node_str)
|
62
|
+
@output_node_strs << node_str
|
63
|
+
end
|
64
|
+
|
65
|
+
def append_init_func_str(init_func_str)
|
66
|
+
@init_func_strs << init_func_str
|
67
|
+
end
|
68
|
+
|
69
|
+
def func(func_str)
|
70
|
+
raise func_str unless @func_h.key?(func_str)
|
71
|
+
@func_h[func_str]
|
72
|
+
end
|
73
|
+
|
74
|
+
def node(node_str)
|
75
|
+
raise node_str unless @node_h.key?(node_str)
|
76
|
+
@node_h[node_str]
|
77
|
+
end
|
78
|
+
|
79
|
+
def tconst(tconst_str)
|
80
|
+
raise tconst_str unless @tconst_h.key?(tconst_str )
|
81
|
+
@tconst_h[tconst_str ]
|
82
|
+
end
|
83
|
+
|
84
|
+
def vconst(vconst_str)
|
85
|
+
raise vconst_str unless @vconst_h.key?(vconst_str)
|
86
|
+
@vconst_h[vconst_str]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module SFRP
|
2
|
+
module Poly
|
3
|
+
class Typing
|
4
|
+
def initialize(tconst_str = nil, arg_typings = [], &block)
|
5
|
+
@tconst_str = tconst_str
|
6
|
+
@arg_typings = arg_typings
|
7
|
+
@parent = nil
|
8
|
+
block.call(self) if block
|
9
|
+
end
|
10
|
+
|
11
|
+
def tconst_str
|
12
|
+
root == self ? @tconst_str : root.tconst_str
|
13
|
+
end
|
14
|
+
|
15
|
+
def unify(other)
|
16
|
+
return self if same?(other)
|
17
|
+
return root.unify(other) unless root == self
|
18
|
+
if variable? && other.variable?
|
19
|
+
@parent = other
|
20
|
+
elsif variable? && !other.variable?
|
21
|
+
raise UnifyError.new(self, other) if occur?(other)
|
22
|
+
@parent = other
|
23
|
+
elsif !variable? && other.variable?
|
24
|
+
other.unify(self)
|
25
|
+
else
|
26
|
+
unless tconst_str == other.tconst_str && argc == other.argc
|
27
|
+
raise UnifyError.new(self, other)
|
28
|
+
end
|
29
|
+
arg_typings.zip(other.arg_typings) { |a, b| a.unify(b) }
|
30
|
+
@parent = other
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def unique_str
|
35
|
+
raise unless mono?
|
36
|
+
"#{tconst_str}[#{arg_typings.map(&:unique_str).join(', ')}]"
|
37
|
+
end
|
38
|
+
|
39
|
+
def mono?
|
40
|
+
!variable? && arg_typings.all?(&:mono?)
|
41
|
+
end
|
42
|
+
|
43
|
+
def variables
|
44
|
+
return [self] if variable?
|
45
|
+
arg_typings.flat_map(&:variables)
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_type_annot(vars)
|
49
|
+
if variable?
|
50
|
+
idx = vars.index { |v| v.same?(self) }
|
51
|
+
raise unless idx
|
52
|
+
TypeAnnotationVar.new('a' + idx.to_s)
|
53
|
+
else
|
54
|
+
args = arg_typings.map { |t| t.to_type_annot(vars) }
|
55
|
+
TypeAnnotationType.new(tconst_str, args)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s(vars = nil)
|
60
|
+
vars ||= variables
|
61
|
+
to_type_annot(vars).to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def root
|
67
|
+
@parent ? (@parent = @parent.root) : self
|
68
|
+
end
|
69
|
+
|
70
|
+
def argc
|
71
|
+
arg_typings.size
|
72
|
+
end
|
73
|
+
|
74
|
+
def arg_typings
|
75
|
+
root == self ? @arg_typings : root.arg_typings
|
76
|
+
end
|
77
|
+
|
78
|
+
def variable?
|
79
|
+
tconst_str.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def same?(other)
|
83
|
+
return true if root == other.root
|
84
|
+
return false if variable? || other.variable?
|
85
|
+
return false unless tconst_str == other.tconst_str && argc == other.argc
|
86
|
+
arg_typings.zip(other.arg_typings).all? { |a, b| a.same?(b) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def occur?(other)
|
90
|
+
raise unless variable?
|
91
|
+
return true if same?(other)
|
92
|
+
arg_typings.any? { |t| occur?(t) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class FuncTyping
|
97
|
+
attr_reader :params, :body
|
98
|
+
|
99
|
+
def initialize(param_size, &block)
|
100
|
+
@params = Array.new(param_size) { Typing.new }
|
101
|
+
@body = Typing.new
|
102
|
+
block.call(self) if block
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_ftype_annot
|
106
|
+
vars = @body.variables + @params.flat_map(&:variables)
|
107
|
+
args = @params.map { |t| t.to_type_annot(vars) }
|
108
|
+
FuncTypeAnnotation.new(@body.to_type_annot(vars), args)
|
109
|
+
end
|
110
|
+
|
111
|
+
def unify(other)
|
112
|
+
raise unless @params.size == other.params.size
|
113
|
+
@params.zip(other.params) { |a, b| a.unify(b) }
|
114
|
+
@body.unify(other.body)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def instance(&block)
|
119
|
+
instance = to_ftype_annot.to_ftyping
|
120
|
+
block.call(instance) if block
|
121
|
+
instance
|
122
|
+
end
|
123
|
+
|
124
|
+
def unique_str
|
125
|
+
args = @params + [@body]
|
126
|
+
"Func#{@params.size}[#{args.map(&:unique_str).join(', ')}]"
|
127
|
+
end
|
128
|
+
|
129
|
+
def mono?
|
130
|
+
[@body, *@params].all?(&:mono?)
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_s
|
134
|
+
to_ftype_annot.to_s
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class FuncTypeAnnotation
|
139
|
+
def initialize(ret_type_annot, arg_type_annots)
|
140
|
+
@ret_type_annot = ret_type_annot
|
141
|
+
@arg_type_annots = arg_type_annots
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_ftyping(var_strs = nil)
|
145
|
+
var_strs ||= [@ret_type_annot, *@arg_type_annots].flat_map(&:var_strs)
|
146
|
+
tbl = Hash[var_strs.uniq.map { |s| [s, Typing.new] }]
|
147
|
+
FuncTyping.new(@arg_type_annots.size) do |ft|
|
148
|
+
ft.params.zip(@arg_type_annots) { |t, at| t.unify(at.to_typing(tbl)) }
|
149
|
+
ft.body.unify(@ret_type_annot.to_typing(tbl))
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_s
|
154
|
+
"(#{@arg_type_annots.map(&:to_s).join(', ')}) -> #{@ret_type_annot}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class TypeAnnotationType
|
159
|
+
def initialize(tconst_str, arg_type_annots)
|
160
|
+
@tconst_str = tconst_str
|
161
|
+
@arg_type_annots = arg_type_annots
|
162
|
+
end
|
163
|
+
|
164
|
+
def to_typing(tbl)
|
165
|
+
Typing.new(@tconst_str, @arg_type_annots.map { |ta| ta.to_typing(tbl) })
|
166
|
+
end
|
167
|
+
|
168
|
+
def var_strs
|
169
|
+
@arg_type_annots.flat_map(&:var_strs)
|
170
|
+
end
|
171
|
+
|
172
|
+
def to_s
|
173
|
+
return @tconst_str if @arg_type_annots.empty?
|
174
|
+
"#{@tconst_str}[#{@arg_type_annots.map(&:to_s).join(', ')}]"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class TypeAnnotationVar
|
179
|
+
def initialize(var_str)
|
180
|
+
@var_str = var_str
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_typing(tbl)
|
184
|
+
raise var_str unless tbl.key?(@var_str)
|
185
|
+
tbl[@var_str]
|
186
|
+
end
|
187
|
+
|
188
|
+
def var_strs
|
189
|
+
[@var_str]
|
190
|
+
end
|
191
|
+
|
192
|
+
def to_s
|
193
|
+
@var_str
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|