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.
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