sfrp 1.1.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 +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
|