sfrp 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags +3 -0
  3. data/.editorconfig +9 -0
  4. data/.gitignore +14 -0
  5. data/.rubocop.yml +629 -0
  6. data/.travis.yml +12 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +28 -0
  9. data/README.md +34 -0
  10. data/Rakefile +1 -0
  11. data/base-library/Base.sfrp +81 -0
  12. data/base-library/IO/AVR/ATMEGA8.c +9 -0
  13. data/base-library/IO/AVR/ATMEGA8.h +6 -0
  14. data/base-library/IO/AVR/ATMEGA8.sfrp +4 -0
  15. data/base-library/IO/STDIO.c +40 -0
  16. data/base-library/IO/STDIO.h +13 -0
  17. data/base-library/IO/STDIO.sfrp +10 -0
  18. data/bin/sfrp +7 -0
  19. data/lib/sfrp.rb +2 -0
  20. data/lib/sfrp/command.rb +73 -0
  21. data/lib/sfrp/compiler.rb +94 -0
  22. data/lib/sfrp/error.rb +4 -0
  23. data/lib/sfrp/file.rb +18 -0
  24. data/lib/sfrp/flat/dsl.rb +33 -0
  25. data/lib/sfrp/flat/elements.rb +90 -0
  26. data/lib/sfrp/flat/exception.rb +45 -0
  27. data/lib/sfrp/flat/expression.rb +125 -0
  28. data/lib/sfrp/flat/set.rb +61 -0
  29. data/lib/sfrp/input/exception.rb +16 -0
  30. data/lib/sfrp/input/parser.rb +417 -0
  31. data/lib/sfrp/input/set.rb +29 -0
  32. data/lib/sfrp/input/transformer.rb +219 -0
  33. data/lib/sfrp/low/dsl.rb +126 -0
  34. data/lib/sfrp/low/element.rb +126 -0
  35. data/lib/sfrp/low/set.rb +62 -0
  36. data/lib/sfrp/mono/dsl.rb +120 -0
  37. data/lib/sfrp/mono/environment.rb +26 -0
  38. data/lib/sfrp/mono/exception.rb +21 -0
  39. data/lib/sfrp/mono/expression.rb +124 -0
  40. data/lib/sfrp/mono/function.rb +86 -0
  41. data/lib/sfrp/mono/memory.rb +32 -0
  42. data/lib/sfrp/mono/node.rb +125 -0
  43. data/lib/sfrp/mono/pattern.rb +69 -0
  44. data/lib/sfrp/mono/set.rb +151 -0
  45. data/lib/sfrp/mono/type.rb +210 -0
  46. data/lib/sfrp/mono/vconst.rb +134 -0
  47. data/lib/sfrp/output/set.rb +33 -0
  48. data/lib/sfrp/poly/dsl.rb +171 -0
  49. data/lib/sfrp/poly/elements.rb +168 -0
  50. data/lib/sfrp/poly/exception.rb +42 -0
  51. data/lib/sfrp/poly/expression.rb +170 -0
  52. data/lib/sfrp/poly/monofier.rb +73 -0
  53. data/lib/sfrp/poly/set.rb +90 -0
  54. data/lib/sfrp/poly/typing.rb +197 -0
  55. data/lib/sfrp/raw/dsl.rb +41 -0
  56. data/lib/sfrp/raw/elements.rb +164 -0
  57. data/lib/sfrp/raw/exception.rb +40 -0
  58. data/lib/sfrp/raw/expression.rb +168 -0
  59. data/lib/sfrp/raw/namespace.rb +30 -0
  60. data/lib/sfrp/raw/set.rb +109 -0
  61. data/lib/sfrp/version.rb +3 -0
  62. data/sfrp.gemspec +40 -0
  63. data/spec/sfrp/Test.sfrp +4 -0
  64. data/spec/sfrp/compiler_spec.rb +17 -0
  65. data/spec/sfrp/flat/set_spec.rb +40 -0
  66. data/spec/sfrp/input/parse_test.sfrp +20 -0
  67. data/spec/sfrp/input/set_spec.rb +18 -0
  68. data/spec/sfrp/low/set_spec.rb +20 -0
  69. data/spec/sfrp/mono/expected.yml +295 -0
  70. data/spec/sfrp/mono/set_spec.rb +152 -0
  71. data/spec/sfrp/output/set_spec.rb +29 -0
  72. data/spec/sfrp/poly/set_spec.rb +290 -0
  73. data/spec/sfrp/raw/set_spec.rb +38 -0
  74. data/spec/spec_helper.rb +16 -0
  75. data/test/IntTest/Main.c +5 -0
  76. data/test/IntTest/Main.h +6 -0
  77. data/test/IntTest/Main.sfrp +10 -0
  78. data/test/IntTest/in.txt +3 -0
  79. data/test/IntTest/out.txt +4 -0
  80. data/test/MaybeTest/Main.sfrp +8 -0
  81. data/test/MaybeTest/SubDir/Lib.sfrp +9 -0
  82. data/test/MaybeTest/in.txt +6 -0
  83. data/test/MaybeTest/out.txt +6 -0
  84. data/test/Rakefile +15 -0
  85. metadata +290 -0
@@ -0,0 +1,134 @@
1
+ module SFRP
2
+ module Mono
3
+ class VConst
4
+ attr_reader :str
5
+
6
+ def initialize(str, type_str, arg_type_strs, native_str = nil)
7
+ @str = str
8
+ @type_str = type_str
9
+ @arg_type_strs = arg_type_strs
10
+ @native_str = native_str
11
+ end
12
+
13
+ def comp
14
+ [@str, @type_str, @arg_type_strs, @native_str]
15
+ end
16
+
17
+ def ==(other)
18
+ comp == other.comp
19
+ end
20
+
21
+ # Return max memory size to hold an instance of this vconst.
22
+ def memory(set)
23
+ @arg_type_strs.reduce(Memory.empty) do |m, t_str|
24
+ m.and(set.type(t_str).memory(set))
25
+ end
26
+ end
27
+
28
+ # Is this vconst expressed in native C value?
29
+ def native?
30
+ @native_str
31
+ end
32
+
33
+ def native_args?(set)
34
+ @arg_type_strs.all? { |s| set.type(s).native? }
35
+ end
36
+
37
+ def all_pattern_examples(set)
38
+ return [Pattern::PatternExample.new(@str, [])] if @arg_type_strs.empty?
39
+ head, *tail = @arg_type_strs.map do |type_str|
40
+ set.type(type_str).all_pattern_examples(set)
41
+ end
42
+ head.product(*tail).map do |args|
43
+ Pattern::PatternExample.new(@str, args)
44
+ end
45
+ end
46
+
47
+ # Generate a struct-element of term for this vconst.
48
+ def gen_term_definition(set, term_id, terms)
49
+ return if native?
50
+ terms << L.member_structure('struct', "term#{term_id}") do |term|
51
+ @arg_type_strs.each_with_index do |t_str, idx|
52
+ low_type_str = set.type(t_str).low_type_str
53
+ term << L.member("#{low_type_str} member#{idx}")
54
+ end
55
+ end
56
+ end
57
+
58
+ # Do elements of this vconst need marking?
59
+ def param_needing_mark?(set)
60
+ @arg_type_strs.any? { |type_str| set.type(type_str).need_mark?(set) }
61
+ end
62
+
63
+ # Generate constructor-function in C.
64
+ def gen_constructor(src_set, term_id, dest_set)
65
+ return if native?
66
+ type = src_set.type(@type_str)
67
+ dest_set << L.function(low_constructor_str, type.low_type_str) do |f|
68
+ @arg_type_strs.each_with_index.map do |t_str, mem_idx|
69
+ f.append_param(src_set.type(t_str).low_type_str, "member#{mem_idx}")
70
+ end
71
+ if type.static?
72
+ f << L.stmt("#{type.low_type_str} x")
73
+ else
74
+ f << L.stmt("#{type.low_type_str} x = #{type.low_allocator_str}(0)")
75
+ end
76
+ if type.has_meta_in_struct?
77
+ f << L.stmt("#{type.meta_access_str('x')}.term_id = #{term_id}")
78
+ end
79
+ @arg_type_strs.size.times do |mem_idx|
80
+ terms = type.terms_access_str('x')
81
+ m = "member#{mem_idx}"
82
+ f << L.stmt("#{terms}.term#{term_id}.#{m} = #{m}")
83
+ end
84
+ f << L.stmt('return x')
85
+ end
86
+ end
87
+
88
+ # return low-expression to make a new instance by this vconst
89
+ def low_constructor_call_exp(low_arg_exps)
90
+ return @native_str if native?
91
+ "#{low_constructor_str}(#{low_arg_exps.join(', ')})"
92
+ end
93
+
94
+ # Return conditional-low-exps to match this vconst and receiver-exp.
95
+ def low_compare_exps(set, receiver_exp)
96
+ type = set.type(@type_str)
97
+ return [] if type.single_vconst?
98
+ return ["#{receiver_exp} == #{@native_str}"] if native?
99
+ meta = type.meta_access_str(receiver_exp)
100
+ term_id = type.term_id(@str)
101
+ ["#{meta}.term_id == #{term_id}"]
102
+ end
103
+
104
+ # name of constructor-function in C for this vconst
105
+ def low_constructor_str
106
+ 'VC_' + @str
107
+ end
108
+
109
+ # Return alias of the constructor of this vconst.
110
+ def low_macro_for_alias(alias_str)
111
+ arg = ('a'..'z').take(@arg_type_strs.size).join(', ')
112
+ L.macro("#{alias_str}(#{arg}) #{low_constructor_str}(#{arg})")
113
+ end
114
+
115
+ # Return low-exp to mark elements of this vconst.
116
+ def low_mark_element_exps(set, term_id, receiver_str)
117
+ types = @arg_type_strs.map { |t_str| set.type(t_str) }
118
+ types_needing_mark = types.select { |t| t.need_mark?(set) }
119
+ types_needing_mark.each_with_index.map do |type, mem_idx|
120
+ term_access = "#{type.terms_access_str(receiver_str)}.term#{term_id}"
121
+ "#{type.low_mark_func_str}(#{term_access}.member#{mem_idx})"
122
+ end
123
+ end
124
+
125
+ def low_member_pointers(type, receiver_str)
126
+ term_id = type.term_id(@str)
127
+ terms_access = "#{type.terms_access_str(receiver_str)}.term#{term_id}"
128
+ @arg_type_strs.each_with_index.map do |_, mem_idx|
129
+ "&#{terms_access}.member#{mem_idx}"
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,33 @@
1
+ require 'sfrp/file'
2
+ require 'fileutils'
3
+
4
+ module SFRP
5
+ module Output
6
+ class Set
7
+ attr_reader :virtual_files
8
+
9
+ def initialize(&block)
10
+ @virtual_files = []
11
+ block.call(self) if block
12
+ end
13
+
14
+ def generate!(output_dir_path, other_virtual_files = [])
15
+ unless File.directory?(output_dir_path)
16
+ FileUtils.mkdir_p(output_dir_path)
17
+ end
18
+ FileUtils.cd(output_dir_path) do
19
+ (@virtual_files + other_virtual_files).each do |vf|
20
+ relative_path = vf.fmodule_uri.gsub('.', '/') + '.' + vf.file_ext
21
+ dirname = File.dirname(relative_path)
22
+ FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
23
+ File.open(relative_path, 'w') { |f| f.write(vf.content) }
24
+ end
25
+ end
26
+ end
27
+
28
+ def create_file(relative_position, file_ext, content)
29
+ @virtual_files << VirtualFile.new(relative_position, file_ext, content)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,171 @@
1
+ module SFRP
2
+ module Poly
3
+ module DSL
4
+ extend SFRP::P = self
5
+
6
+ def tconst(tconst_str, var_strs, static, native_str, infinite, &block)
7
+ tp = TConstProxy.new(tconst_str, var_strs, infinite)
8
+ block.call(tp) if block
9
+ argc = var_strs.size
10
+ TConst.new(tconst_str, argc, tp.vconst_strs, static, native_str)
11
+ end
12
+
13
+ def func(func_str, ret_type_annot = nil, &block)
14
+ fp = FuncProxy.new(func_str, ret_type_annot)
15
+ block.call(fp) if block
16
+ fp.to_func
17
+ end
18
+
19
+ def node(node_str, type_annot = nil, &block)
20
+ np = NodeProxy.new(node_str, type_annot)
21
+ block.call(np) if block
22
+ np.to_node
23
+ end
24
+
25
+ def t(tconst_str, *args)
26
+ TypeAnnotationType.new(tconst_str, args)
27
+ end
28
+
29
+ def tv(var_str)
30
+ TypeAnnotationVar.new(var_str)
31
+ end
32
+
33
+ def match_e(left_exp, &block)
34
+ cp = CaseProxy.new
35
+ block.call(cp) if block
36
+ MatchExp.new(left_exp, cp.to_a)
37
+ end
38
+
39
+ def call_e(func_str, *arg_exps)
40
+ FuncCallExp.new(func_str, arg_exps)
41
+ end
42
+
43
+ def vc_call_e(vconst_str, *arg_exps)
44
+ VConstCallExp.new(vconst_str, arg_exps)
45
+ end
46
+
47
+ def v_e(var_str)
48
+ VarRefExp.new(var_str)
49
+ end
50
+
51
+ def pat(vconst_str, *arg_patterns)
52
+ Pattern.new(vconst_str, nil, arg_patterns)
53
+ end
54
+
55
+ def pref(vconst_str, ref_var_str, *arg_patterns)
56
+ Pattern.new(vconst_str, ref_var_str, arg_patterns)
57
+ end
58
+
59
+ def pany(ref_var_str = nil)
60
+ Pattern.new(nil, ref_var_str, [])
61
+ end
62
+
63
+ class TConstProxy
64
+ def initialize(tconst_str, var_strs, infinite)
65
+ args = var_strs.map { |v| TypeAnnotationVar.new(v) }
66
+ @ret_type_annot = TypeAnnotationType.new(tconst_str, args)
67
+ @var_strs = var_strs
68
+ @infinite = infinite
69
+ @vconst_strs = []
70
+ end
71
+
72
+ def vconst(vconst_str, arg_type_annots, native_str = nil)
73
+ ftype_annot = FuncTypeAnnotation.new(@ret_type_annot, arg_type_annots)
74
+ @vconst_strs << vconst_str
75
+ VConst.new(vconst_str, @var_strs, ftype_annot, native_str)
76
+ end
77
+
78
+ def vconst_strs
79
+ @infinite ? nil : @vconst_strs
80
+ end
81
+ end
82
+
83
+ class FuncProxy
84
+ def initialize(func_str, ret_type_annot = nil)
85
+ @func_str = func_str
86
+ @ret_type_annot = ret_type_annot || DSL.tv('%a0')
87
+ @param_strs = []
88
+ @type_annots = []
89
+ end
90
+
91
+ def param(param_str, type_annot = nil)
92
+ @param_strs << param_str
93
+ @type_annots << (type_annot || DSL.tv('%a' + @param_strs.size.to_s))
94
+ end
95
+
96
+ def ffi_str(str)
97
+ @ffi_str = str
98
+ end
99
+
100
+ def exp(&block)
101
+ @exp = block.call
102
+ end
103
+
104
+ def to_func
105
+ ftype_annot = FuncTypeAnnotation.new(@ret_type_annot, @type_annots)
106
+ Function.new(@func_str, @param_strs, ftype_annot, @exp, @ffi_str)
107
+ end
108
+ end
109
+
110
+ class NodeProxy
111
+ def initialize(node_str, type_annot)
112
+ @node_str = node_str
113
+ @type_annot = type_annot || TypeAnnotationVar.new('%a0')
114
+ @node_refs = []
115
+ @type_annots = []
116
+ end
117
+
118
+ def c(node_str)
119
+ dep(node_str, false)
120
+ end
121
+
122
+ def l(node_str)
123
+ dep(node_str, true)
124
+ end
125
+
126
+ def dep(node_str, last)
127
+ @node_refs << Node::NodeRef.new(node_str, last)
128
+ @type_annots << TypeAnnotationVar.new('%a' + @node_refs.size.to_s)
129
+ end
130
+
131
+ def eval_func(func_str, ret_type_annot = nil, &block)
132
+ @eval_func_str = func_str
133
+ DSL.func(func_str, ret_type_annot, &block)
134
+ end
135
+
136
+ def init_func(func_str, ret_type_annot = nil, &block)
137
+ @init_func_str = func_str
138
+ DSL.func(func_str, ret_type_annot, &block)
139
+ end
140
+
141
+ def eval_func_str(func_str)
142
+ @eval_func_str = func_str
143
+ end
144
+
145
+ def init_func_str(func_str)
146
+ @init_func_str = func_str
147
+ end
148
+
149
+ def to_node
150
+ a = @node_refs.size.times.map { |i| TypeAnnotationVar.new("a#{i}") }
151
+ annot = FuncTypeAnnotation.new(@type_annot, a)
152
+ Node.new(@node_str, @node_refs, annot, @eval_func_str, @init_func_str)
153
+ end
154
+ end
155
+
156
+ class CaseProxy
157
+ def initialize
158
+ @cases = []
159
+ end
160
+
161
+ def case(pattern, &exp_block)
162
+ @cases << MatchExp::Case.new(pattern, exp_block.call)
163
+ end
164
+
165
+ def to_a
166
+ @cases
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,168 @@
1
+ module SFRP
2
+ module Poly
3
+ class Function
4
+ attr_reader :str
5
+
6
+ def initialize(str, param_strs, ftype_annot, exp = nil, ffi_str = nil)
7
+ raise ArgumentError if exp.nil? && ffi_str.nil?
8
+ @str = str
9
+ @param_strs = param_strs
10
+ @ftype_annot = ftype_annot
11
+ @exp = exp
12
+ @ffi_str = ffi_str
13
+ end
14
+
15
+ def ftyping(set)
16
+ @ftyping ||= @ftype_annot.to_ftyping.instance do |ft|
17
+ var_env = {}
18
+ @param_strs.zip(ft.params) { |str, typing| var_env[str] = typing }
19
+ ft.body.unify(@exp.typing(set, var_env)) if @exp
20
+ end
21
+ end
22
+
23
+ def clone
24
+ exp = (@exp ? @exp.clone : nil)
25
+ Function.new(@str, @param_strs, @ftype_annot, exp, @ffi_str)
26
+ end
27
+
28
+ def check_recursion(set, path = [])
29
+ return if @exp == nil
30
+ if path.include?(@str)
31
+ raise RecursiveError.new(path.drop_while { |s| s != @str })
32
+ end
33
+ @exp.called_func_strs.each do |str|
34
+ set.func(str).check_recursion(set, path + [@str])
35
+ end
36
+ end
37
+
38
+ def to_mono(monofier, mono_func_str)
39
+ raise UndeterminableTypeError.new(@str, @ftyping) unless @ftyping.mono?
40
+ mono_type_str = monofier.use_type(@ftyping.body)
41
+ M.func(mono_type_str, mono_func_str) do |f|
42
+ @param_strs.zip(@ftyping.params) do |str, typing|
43
+ f.param(monofier.use_type(typing), str)
44
+ end
45
+ f.exp { @exp.to_mono(monofier) } if @exp
46
+ f.ffi_str(@ffi_str) if @ffi_str
47
+ end
48
+ end
49
+ end
50
+
51
+ class Node
52
+ attr_reader :str
53
+
54
+ NodeRef = Struct.new(:node_str, :last)
55
+
56
+ def initialize(
57
+ str, node_refs, ftype_annot, eval_func_str, init_func_str = nil
58
+ )
59
+ @str = str
60
+ @node_refs = node_refs
61
+ @ftype_annot = ftype_annot
62
+ @eval_func_str = eval_func_str
63
+ @init_func_str = init_func_str
64
+ end
65
+
66
+ def typing(set)
67
+ return @typing if @typing
68
+ @typing = Typing.new
69
+ @ftyping = set.func(@eval_func_str).ftyping(set).instance do |eval_ft|
70
+ @node_refs.zip(eval_ft.params) do |node_ref, typing|
71
+ set.node(node_ref.node_str).typing(set).unify(typing)
72
+ end
73
+ next unless @init_func_str
74
+ @init_ftyping = set.func(@init_func_str).ftyping(set).instance do |ft|
75
+ raise unless ft.params.empty?
76
+ ft.body.unify(eval_ft.body)
77
+ end
78
+ end
79
+ @ftyping.unify(@ftype_annot.to_ftyping).body.unify(@typing)
80
+ end
81
+
82
+ def check_recursion(set, path = [])
83
+ if path.include?(@str)
84
+ raise RecursiveError.new(path.drop_while { |s| s != @str })
85
+ end
86
+ @node_refs.each do |nr|
87
+ next if nr.last
88
+ set.node(nr.node_str).check_recursion(set, path + [@str])
89
+ end
90
+ end
91
+
92
+ def to_mono(monofier)
93
+ raise UndeterminableTypeError.new(@str, @typing) unless @typing.mono?
94
+ type_str = monofier.use_type(@typing)
95
+ node_str = monofier.use_node(@str)
96
+ eval_func_str = monofier.use_func(@eval_func_str, @ftyping)
97
+ if @init_func_str
98
+ init_func_str = monofier.use_func(@init_func_str, @init_ftyping)
99
+ else
100
+ init_func_str = nil
101
+ end
102
+ M.node(type_str, node_str, eval_func_str, init_func_str) do |n|
103
+ @node_refs.each do |node_ref|
104
+ node_str = monofier.use_node(node_ref.node_str)
105
+ node_ref.last ? n.l(node_str) : n.c(node_str)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ class TConst
112
+ attr_reader :str
113
+
114
+ def initialize(
115
+ str, paramc, vconst_strs = nil, static = false, native_str = nil
116
+ )
117
+ @str = str
118
+ @paramc = paramc
119
+ @vconst_strs = vconst_strs
120
+ @static = static
121
+ @native_str = native_str
122
+ end
123
+
124
+ def typing
125
+ @typing ||= Typing.new(@str, Array.new(@paramc) { Typing.new })
126
+ end
127
+
128
+ def clone
129
+ TConst.new(@str, @paramc, @vconst_strs, @static, @native_str)
130
+ end
131
+
132
+ def to_mono(monofier)
133
+ raise UndeterminableTypeError.new(@str, @typing) unless @typing.mono?
134
+ type_str = monofier.use_type(@typing)
135
+ return M.type(type_str, nil, @static, @native_str) unless @vconst_strs
136
+ vconst_strs = @vconst_strs.map { |s| monofier.use_vconst(s, @typing) }
137
+ M.type(type_str, vconst_strs, @static, @native_str)
138
+ end
139
+ end
140
+
141
+ class VConst
142
+ attr_reader :str
143
+
144
+ def initialize(str, annot_vars, ftype_annot, native_str = nil)
145
+ @str = str
146
+ @annot_vars = annot_vars
147
+ @ftype_annot = ftype_annot
148
+ @native_str = native_str
149
+ end
150
+
151
+ def ftyping
152
+ @ftyping ||= @ftype_annot.to_ftyping(@annot_vars)
153
+ end
154
+
155
+ def clone
156
+ VConst.new(@str, @annot_vars, @ftype_annot, @native_str)
157
+ end
158
+
159
+ def to_mono(monofier)
160
+ raise UndeterminableTypeError.new(@str, @ftyping) unless @ftyping.mono?
161
+ type_str = monofier.use_type(@ftyping.body)
162
+ vconst_str = monofier.use_vconst(@str, @ftyping.body)
163
+ arg_type_strs = @ftyping.params.map { |t| monofier.use_type(t) }
164
+ M.vconst(type_str, vconst_str, arg_type_strs, @native_str)
165
+ end
166
+ end
167
+ end
168
+ end