fwi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 87be340eab8e5bf9eb089e92cff12a5334be00e7
4
+ data.tar.gz: 688dc30f47412cabbd679f6d8a2571e9a71980b8
5
+ SHA512:
6
+ metadata.gz: 7df2c8cdffdee78b64599afbddf8d04efad76f37ed20f0b32de2051988de2ccaa6015d46aa65dcaf1ab75e95389e7d5fa074da9236145f75940ca69263ef6481
7
+ data.tar.gz: 3593cba598bc3cf4a2b552cca783a58f02ad8aa3dcb7c0a0deba5d9327b19160a5e2b9d2ffea3ed5ee00c51bc279dbdf0aa7ba989697f51fc8cc24315bf271ee
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in waitress-core.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jaci R Brunning
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/bin/fwi ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fwi/compiler.rb'
@@ -0,0 +1,17 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "fwi"
6
+ spec.version = "1.0.0"
7
+ spec.authors = ["Jaci Brunning"]
8
+ spec.email = ["jaci.brunning@gmail.com"]
9
+
10
+ spec.summary = %q{Fixed-Width Data Interchange Compiler}
11
+ spec.homepage = "http://github.com/JacisNonsense/Fixed-Width-Interchange"
12
+
13
+ spec.bindir = "bin"
14
+ spec.files = Dir.glob("lib/**/*") + ['fwi.gemspec', 'Gemfile', 'LICENSE']
15
+ spec.executables = ["fwi"]
16
+ spec.require_paths = ["lib"]
17
+ end
@@ -0,0 +1,64 @@
1
+ require_relative 'cpp/compiler.rb'
2
+ require_relative 'parser.rb'
3
+ require 'optparse'
4
+
5
+ COMPILERS = {
6
+ "cpp" => CPPCompiler.new
7
+ };
8
+
9
+ options = {
10
+ :source_root => "."
11
+ }
12
+ optp = OptionParser.new do |opts|
13
+
14
+ opts.separator ""
15
+ opts.separator "Common options:"
16
+
17
+ opts.on("-h", "--help", "Show this message") do
18
+ puts opts
19
+ exit
20
+ end
21
+
22
+ opts.on("-l", "--language LANGUAGE", COMPILERS.map { |n, v| n },
23
+ "Select the language to compile down to. One of [#{COMPILERS.keys.join(", ")}]") do |lang|
24
+ options[:language] = lang
25
+ end
26
+
27
+ opts.on("-d", "--source-directory DIRECTORY", "Set the source directory to pull files from") do |directory|
28
+ options[:source_root] = directory
29
+ end
30
+
31
+ COMPILERS.each do |n,x|
32
+ opts.separator ""
33
+ opts.separator n
34
+ x.populate_options opts
35
+ end
36
+
37
+
38
+ end
39
+
40
+ begin
41
+ optp.parse!
42
+ mandatory = [:language]
43
+ missing = mandatory.select{ |param| options[param].nil? }
44
+ unless missing.empty?
45
+ raise OptionParser::MissingArgument.new(missing.join(', '))
46
+ end
47
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
48
+ puts $!.to_s
49
+ puts optp
50
+ exit
51
+ end
52
+
53
+ source_files = ARGV
54
+ COMPILERS.each { |n,x| x.after_parse }
55
+ selected_compiler = COMPILERS[options[:language]]
56
+
57
+ p = FWI::Parser.new
58
+
59
+ selected_compiler.on_selected
60
+ source_files.each do |file|
61
+ lex = p.lex(file, options[:source_root])
62
+ bitmap = p.bitmap(lex)
63
+ selected_compiler.compile file, lex, bitmap, options
64
+ end
@@ -0,0 +1,52 @@
1
+ require_relative 'gen.rb'
2
+ require 'fileutils'
3
+
4
+ class CPPCompiler
5
+ GEN = FWI::Generator::CPP.new
6
+
7
+ def populate_options o
8
+ @options = {
9
+ :hpp => ".", :cpp => ".",
10
+ :hpp_ext => ".hpp", :cpp_ext => ".cpp",
11
+ :hpp_only => false
12
+ };
13
+ o.on("--headers [DIRECTORY]", "Directory to put Generated C++ Header Files.") { |x| @options[:hpp] = x }
14
+ o.on("--sources [DIRECTORY]", "Directory to put Generated C++ Source Files.") { |x| @options[:cpp] = x }
15
+ o.separator ""
16
+ o.on("--header_ext [EXTENSION]", "Extension for Generated C++ Header Files. Default .hpp") { |x| @options[:hpp_ext] = x }
17
+ o.on("--source_ext [EXTENSION]", "Extension for Generated C++ Source Files. Default .cpp") { |x| @options[:cpp_ext] = x }
18
+ o.separator ""
19
+ o.on("--header-only", "Compile as header-only") { |x| @options[:hpp_only] = true }
20
+ end
21
+
22
+ def after_parse
23
+ end
24
+
25
+ def on_selected; end
26
+
27
+ def compile file, lex, bitmap, options
28
+ base = File.basename(file, File.extname(file))
29
+
30
+ hpp_ext = @options[:hpp_ext]
31
+ cpp_ext = @options[:cpp_ext]
32
+
33
+ compile_cpp = !@options[:hpp_only]
34
+
35
+ hpp = GEN.gen_hpp bitmap, hpp_ext, @options[:hpp_only]
36
+ hpp.each do |fn, contents|
37
+ f = File.join(@options[:hpp], fn)
38
+ FileUtils.mkdir_p File.expand_path("..", f)
39
+ File.write(f, contents)
40
+ end
41
+
42
+ if compile_cpp
43
+ cpp = GEN.gen_cpp bitmap, cpp_ext, hpp_ext
44
+ cpp.each do |fn, contents|
45
+ f = File.join(@options[:cpp], fn)
46
+ FileUtils.mkdir_p File.expand_path("..", f)
47
+ File.write(f, contents)
48
+ end
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,329 @@
1
+ module FWI
2
+ module Generator
3
+ class CPP
4
+ TYPE_MAP = {
5
+ :float64 => "double",
6
+ :float32 => "float",
7
+ :u64 => "uint64_t",
8
+ :u32 => "uint32_t",
9
+ :u16 => "uint16_t",
10
+ :u8 => "uint8_t",
11
+ :i64 => "int64_t",
12
+ :i32 => "int32_t",
13
+ :i16 => "int16_t",
14
+ :i8 => "int8_t",
15
+ :string => "char *",
16
+ :bool => "bool"
17
+ };
18
+
19
+ def append buffer, indent, string
20
+ string.split(/\n/).each { |y| buffer << ("\t" * indent) + y + "\n" }
21
+ end
22
+
23
+ def _write_fwd_child name, child, indent, buffer
24
+ if child[:type] == :namespace
25
+ _write_fwd name, child, indent, buffer
26
+ elsif child[:type] == :block
27
+ append(buffer, indent, "struct #{name};")
28
+ elsif child[:type] == :enum
29
+ type = child[:reltype]
30
+ append(buffer, indent, "enum class #{name} {")
31
+ indent += 1
32
+ append(buffer, indent, child[:members].map { |n| "#{n[:name]} = #{n[:val]}" }.join(",\n"))
33
+ indent -= 1
34
+ append(buffer, indent, "};")
35
+ end
36
+ end
37
+
38
+ def _write_fwd name, namespace, indent, buffer
39
+ append(buffer, indent, "namespace #{name} {")
40
+ indent += 1
41
+ namespace[:members].each do |name, child|
42
+ _write_fwd_child name, child, indent, buffer
43
+ end
44
+ indent -= 1
45
+ append(buffer, indent, "}")
46
+ end
47
+
48
+ def write_fwd_declarations str, root, indent
49
+ root[:members].each do |name, child|
50
+ _write_fwd_child name, child, indent, str
51
+ end
52
+ end
53
+
54
+ def _func_util mode, name, member, truncate=true, relative_types=true, fulltype=""
55
+ type = member[:type]
56
+ type_sym = relative_types ? :reltype : :element_name
57
+
58
+ ctype = TYPE_MAP[type]
59
+ ctype = member[type_sym] + (member[:element_type] == :block ? " *" : "") if (member[:type] == :reference)
60
+ ctype = member[:attribute_map]["ctype"] unless member[:attribute_map]["ctype"].nil?
61
+
62
+ param = member[:array].nil? ? "" : "int index#{mode == :setter ? ', ' : ''}"
63
+ custom_getter = member[:attribute_map]["getter"]
64
+ custom_setter = member[:attribute_map]["setter"]
65
+ custom_length = member[:attribute_map]["length_func"]
66
+ prefix = relative_types ? "" : (fulltype + "::")
67
+ func_name = prefix
68
+ func_sig = ""
69
+ if mode == :setter
70
+ func_name += custom_setter.nil? ? "set_#{name}" : custom_setter
71
+ func_sig = "void #{func_name}(#{param}#{ctype} value)"
72
+ elsif mode == :getter
73
+ func_name += custom_getter.nil? ? "get_#{name}" : custom_getter
74
+ func_sig = "#{ctype} #{func_name}(#{param})"
75
+ elsif mode == :length
76
+ func_name += custom_length.nil? ? "#{name}_length" : custom_length
77
+ func_sig = "int #{func_name}(#{param})"
78
+ end
79
+ func_sig += truncate ? ";" : ' {'
80
+ index = member[:index]
81
+ index = "#{index} + (#{member[:typesize]} * index)" unless member[:array].nil?
82
+ { :ctype => ctype, :prefix => prefix, :func_name => func_name, :func_sig => func_sig, :index => index }
83
+ end
84
+
85
+ def write_getter str, name, member, indent, truncate=true, relative_types=true, fulltype=""
86
+ return "" if member[:attributes].include? "no-getter"
87
+ util = _func_util :getter, name, member, truncate, relative_types, fulltype
88
+
89
+ append(str, indent, util[:func_sig])
90
+ unless truncate
91
+ type = member[:type]
92
+ ctype = util[:ctype]
93
+
94
+ indent += 1
95
+ if type == :reference
96
+ if member[:element_type] == :enum
97
+ append(str, indent, "return (#{ctype})(_store[#{util[:index]}]);")
98
+ else
99
+ if member[:array].nil?
100
+ append(str, indent, "return &_#{member[:name]};")
101
+ else
102
+ append(str, indent, "return &_#{member[:name]}[index];")
103
+ end
104
+ end
105
+ elsif type == :string
106
+ append(str, indent, "return (_store + #{util[:index]});")
107
+ elsif type == :bool
108
+ if member[:array].nil?
109
+ append(str, indent, "return FWI_IS_BIT_SET(_store[#{util[:index]}], #{member[:bit_index]});")
110
+ else
111
+ append(str, indent, "return FWI_IS_BIT_SET(_store[#{member[:index]} + index / 8], index % 8);")
112
+ end
113
+ else
114
+ append(str, indent, "return FWI_MEM_VAL(#{util[:ctype]}, _store, #{util[:index]});")
115
+ end
116
+ indent -= 1
117
+ append(str, indent, "}")
118
+ end
119
+ str
120
+ end
121
+
122
+ def write_setter str, name, member, indent, truncate=true, relative_types=true, fulltype=""
123
+ return "" if member[:attributes].include? "no-setter"
124
+ util = _func_util :setter, name, member, truncate, relative_types, fulltype
125
+
126
+ append(str, indent, util[:func_sig])
127
+ unless truncate
128
+ type = member[:type]
129
+ ctype = util[:ctype]
130
+
131
+ indent += 1
132
+ if type == :reference
133
+ append(str, indent, "_store[#{util[:index]}] = (char)value;")
134
+ elsif type == :bool
135
+ if member[:array].nil?
136
+ append(str, indent, "FWI_SET_BIT_TO(_store[#{util[:index]}], #{member[:bit_index]}, value ? 1 : 0);")
137
+ else
138
+ append(str, indent, "FWI_SET_BIT_TO(_store[#{member[:index]} + index / 8], index % 8, value ? 1 : 0);")
139
+ end
140
+ else
141
+ append(str, indent, "FWI_MEM_VAL(#{ctype}, _store, #{util[:index]}) = value;")
142
+ end
143
+ indent -= 1
144
+ append(str, indent, "}")
145
+ end
146
+ str
147
+ end
148
+
149
+ def write_length str, name, member, indent, truncate=true, relative_types=true, fulltype=""
150
+ return "" if member[:attributes].include? "no-len"
151
+ util = _func_util :length, name, member, truncate, relative_types, fulltype
152
+
153
+ append(str, indent, util[:func_sig])
154
+ unless truncate
155
+ indent += 1
156
+ append(str, indent, "return #{member[:size]};")
157
+ indent -= 1
158
+ append(str, indent, "}")
159
+ end
160
+ str
161
+ end
162
+
163
+ def write_ptr_update buffer, b_refs, indent, truncate=true, prefix=""
164
+ unless b_refs.empty?
165
+ virt = prefix.empty? ? "virtual " : ""
166
+ if truncate
167
+ append(buffer, indent, "#{virt}void #{prefix}_update_ptr();")
168
+ else
169
+ append(buffer, indent, "#{virt}void #{prefix}_update_ptr() {")
170
+ indent += 1
171
+ i_def = false
172
+ b_refs.each do |ref|
173
+ if ref[:array].nil?
174
+ append(buffer, indent, "_#{ref[:name]}.map_to(_store + #{ref[:index]});")
175
+ else
176
+ unless i_def
177
+ i_def = true
178
+ append(buffer, indent, "int i;")
179
+ end
180
+ append(buffer, indent, "for (i = 0; i < #{ref[:array]}; i++) {")
181
+ indent += 1
182
+ append(buffer, indent, "_#{ref[:name]}[i].map_to(_store + #{ref[:index]} + (#{ref[:typesize]} * i));")
183
+ indent -= 1
184
+ append(buffer, indent, "}")
185
+ end
186
+ end
187
+ indent -= 1
188
+ append(buffer, indent, "}")
189
+ end
190
+ end
191
+ end
192
+
193
+ def _get_for_file bitmap, file
194
+ map = { :members => {}, :type => :namespace }
195
+ bitmap[:members].each do |name, member|
196
+ if member[:type] == :namespace
197
+ ret = _get_for_file member, file
198
+ map[:members][name] = ret unless ret[:members].empty?
199
+ else
200
+ map[:members][name] = member if member[:file] == file
201
+ end
202
+ end
203
+ map
204
+ end
205
+
206
+ def gen_hpp_for buffer, indent, filtered, hpp_only
207
+ namespace, object = filtered[:members].partition { |n,x| x[:type] == :namespace }
208
+
209
+ object.select { |n,x| x[:type] == :block }.each do |name, block|
210
+ append(buffer, indent, "struct #{name} : public FWI::Block {")
211
+ indent += 1
212
+ append(buffer, indent, "static const int SIZE = #{block[:size]};")
213
+ b_refs, mems = block[:members].partition { |x| x[:type] == :reference && x[:element_type] == :block }
214
+ buffer << "\n"
215
+
216
+ trunc = !hpp_only
217
+
218
+ b_refs.each do |block_ref|
219
+ write_getter buffer, block_ref[:name], block_ref, indent, trunc, true
220
+ buffer << "\n"
221
+ end
222
+
223
+ mems.each do |member_ref|
224
+ write_getter buffer, member_ref[:name], member_ref, indent, trunc, true
225
+ if member_ref[:type] == :string
226
+ write_length buffer, member_ref[:name], member_ref, indent, trunc, true
227
+ else
228
+ write_setter buffer, member_ref[:name], member_ref, indent, trunc, true
229
+ end
230
+ buffer << "\n"
231
+ end
232
+
233
+ b_refs.each do |block_ref|
234
+ if block_ref[:array].nil?
235
+ append(buffer, indent, "#{block_ref[:reltype]} _#{block_ref[:name]};")
236
+ else
237
+ append(buffer, indent, "#{block_ref[:reltype]} _#{block_ref[:name]}[#{block_ref[:array]}];")
238
+ end
239
+ end
240
+
241
+ buffer << "\n"
242
+
243
+ write_ptr_update buffer, b_refs, indent, trunc
244
+
245
+ indent -= 1
246
+ append(buffer, indent, "}; // struct: #{name}")
247
+ end
248
+
249
+ namespace.each do |name, ns|
250
+ append(buffer, indent, "namespace #{name} {")
251
+ gen_hpp_for buffer, indent + 1, ns, hpp_only
252
+ append(buffer, indent, "} // namespace: #{name}")
253
+ end
254
+ end
255
+
256
+ def gen_cpp_for buffer, indent, blocks
257
+ blocks.each do |obj|
258
+ name = obj[:name]
259
+ block = obj[:block]
260
+
261
+ b_refs, mems = block[:members].partition { |x| x[:type] == :reference && x[:element_type] == :block }
262
+
263
+ b_refs.each do |block_ref|
264
+ write_getter buffer, block_ref[:name], block_ref, indent, false, false, block[:fulltype]
265
+ buffer << "\n"
266
+ end
267
+
268
+ mems.each do |member_ref|
269
+ write_getter buffer, member_ref[:name], member_ref, indent, false, false, block[:fulltype]
270
+ if member_ref[:type] == :string
271
+ write_length buffer, member_ref[:name], member_ref, indent, false, false, block[:fulltype]
272
+ else
273
+ write_setter buffer, member_ref[:name], member_ref, indent, false, false, block[:fulltype]
274
+ end
275
+ buffer << "\n"
276
+ end
277
+
278
+ buffer << "\n"
279
+
280
+ write_ptr_update(buffer, b_refs, indent, false, (block[:fulltype] + "::"))
281
+ end
282
+ end
283
+
284
+ def gen_hpp bitmap, hpp_ext, hpp_only
285
+ map = {}
286
+ bitmap[:files].each do |name, file|
287
+ filename = name.sub ".fwi", hpp_ext
288
+ contents = "#pragma once\n\n#include \"fwi.hpp\"\n"
289
+ file[:imports].each do |import|
290
+ append(contents, 0, "#include \"#{import.sub '.fwi', hpp_ext}\"")
291
+ end
292
+ contents << "\n" unless file[:imports].empty?
293
+
294
+ filtered_bitmap = _get_for_file(bitmap, name)
295
+
296
+ write_fwd_declarations contents, filtered_bitmap, 0
297
+ contents << "\n"
298
+ gen_hpp_for contents, 0, filtered_bitmap, hpp_only
299
+
300
+ map[filename] = contents
301
+ end
302
+ map
303
+ end
304
+
305
+ def gen_cpp bitmap, cpp_ext, hpp_ext
306
+ map = {}
307
+ bitmap[:files].each do |name, file|
308
+ filename = name.sub ".fwi", cpp_ext
309
+ contents = "#include \"#{name.sub '.fwi', hpp_ext}\"\n\n"
310
+
311
+ blocks = file[:blocks].map do |b|
312
+ ref = bitmap
313
+ name = ""
314
+ b.split("::").each do |c|
315
+ ref = ref[:members][c]
316
+ name = c
317
+ end
318
+ { :name => name, :block => ref }
319
+ end
320
+
321
+ gen_cpp_for contents, 0, blocks
322
+
323
+ map[filename] = contents
324
+ end
325
+ map
326
+ end
327
+ end
328
+ end
329
+ end
@@ -0,0 +1,323 @@
1
+ class ::Hash
2
+ def deep_merge(second)
3
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
4
+ self.merge(second.to_h, &merger)
5
+ end
6
+ end
7
+
8
+ module FWI
9
+ class Parser
10
+ TYPE_MAP = {
11
+ "float64" => :float64,
12
+ "float32" => :float32,
13
+ "u64" => :u64,
14
+ "u32" => :u32,
15
+ "u16" => :u16,
16
+ "u8" => :u8,
17
+ "i64" => :i64,
18
+ "i32" => :i32,
19
+ "i16" => :i16,
20
+ "i8" => :i8,
21
+ "string" => :string,
22
+ "bool" => :bool,
23
+
24
+ "blank" => :blank,
25
+
26
+ "float" => :float32,
27
+ "double" => :float64,
28
+ "ulong" => :u64,
29
+ "long" => :i64,
30
+ "uint" => :u32,
31
+ "int" => :i32,
32
+ "ushort" => :u16,
33
+ "short" => :i16,
34
+ "char" => :i8,
35
+ "uchar" => :u8,
36
+ "byte" => :i8,
37
+ "ubyte" => :u8,
38
+ "boolean" => :bool,
39
+ "bit" => :bool
40
+ };
41
+
42
+ TYPE_SIZES = {
43
+ :float64 => 8,
44
+ :u64 => 8,
45
+ :i64 => 8,
46
+
47
+ :float32 => 4,
48
+ :u32 => 4,
49
+ :i32 => 4,
50
+
51
+ :u16 => 2,
52
+ :i16 => 2,
53
+
54
+ :u8 => 1,
55
+ :i8 => 1
56
+ };
57
+
58
+ # Do the initial parsing on the file
59
+ def lex src_file, src_dir
60
+ src = File.read(File.join(src_dir, src_file))
61
+ hash = {
62
+ :members => {},
63
+ :files => {
64
+ src_file => {
65
+ :imports => [],
66
+ :enums => [],
67
+ :blocks => []
68
+ }
69
+ },
70
+ :block_order => []
71
+ }
72
+ file = hash[:files][src_file]
73
+
74
+ _blevel = []
75
+ hashobj = lambda do
76
+ hr = hash
77
+ _blevel.select { |n| n[:type] == :namespace }.each do |ns|
78
+ hr = hr[:members][ns[:name]]
79
+ end
80
+ hr
81
+ end
82
+
83
+ namespacedive = lambda do |fqn|
84
+ hr = hash
85
+ comp = fqn.split("::")
86
+ _blevel.select { |x| x[:type] == :namespace }.each do |b|
87
+ return nil if hr.nil?
88
+ hr = hr[:members][b[:name]]
89
+ end
90
+ comp.each do |c|
91
+ return nil if hr.nil?
92
+ hr = hr[:members][c]
93
+ end
94
+ hr
95
+ end
96
+
97
+ rootdive = lambda do |fqn|
98
+ hr = hash
99
+ comp = fqn.split("::")
100
+ comp.each do |a|
101
+ return nil if hr.nil?
102
+ hr = hr[:members][a]
103
+ end
104
+ hr
105
+ end
106
+
107
+ current_fqn = lambda do
108
+ _blevel.select { |n| n[:type] == :namespace }.map { |n| n[:name] }.join("::")
109
+ end
110
+
111
+ findtype = lambda do |tn|
112
+ return tn unless rootdive[tn].nil?
113
+ unless namespacedive[tn].nil?
114
+ return [current_fqn[], tn].join("::")
115
+ end
116
+ usings = _blevel.each_index.map { |x| Hash[x, _blevel[x]] if _blevel[x][:type] == :using }.reject(&:nil?)
117
+ usings.size.times do |time|
118
+ afqn = [usings.first(time + 1).map { |x| x.values[0][:name] }, tn].join("::")
119
+ return afqn unless rootdive[afqn].nil?
120
+ return [current_fqn[], afqn].join("::") unless namespacedive[afqn].nil?
121
+ end
122
+ nil
123
+ end
124
+
125
+ _enumidx = 0
126
+
127
+ src.each_line.map(&:strip).reject { |l| l.start_with?("//") || l.start_with?("#") }.each do |line|
128
+ tok = line.split(/\s+/).reject(&:empty?)
129
+ unless _blevel.empty? || tok[0] == "}"
130
+ cur = _blevel.last
131
+ b_name = cur[:name]
132
+ b_type = cur[:type]
133
+ h = hashobj[][:members][b_name]
134
+
135
+ if b_type == :block
136
+ type, vals = line.split(/\s+/, 2)
137
+
138
+ next if vals.nil?
139
+ vals.split(/\s*,\s*/).each do |splitcomma|
140
+ name, *attrib = splitcomma.split(/\s+/).reject(&:empty?)
141
+ array_match = /(.+)\[([0-9]+)\]/.match(name)
142
+ arrlen = 1
143
+
144
+ unless array_match.nil?
145
+ name = array_match[1]
146
+ arrlen = array_match[2].to_i
147
+ end
148
+
149
+ type_s = TYPE_MAP[type]
150
+ m = { :type => type_s, :name => name, :original_type => type }
151
+ m[:attributes] = attrib
152
+ m[:attribute_map] = Hash[attrib.select { |x| x.is_a?(String) && x.include?("=") }.map { |x| x.split(/\s*=\s*/, 2) }]
153
+
154
+ if m[:type].nil?
155
+ fqn = findtype[type]
156
+ throw "Can't find type: #{type}" if fqn.nil?
157
+ m[:type] = :reference
158
+ m[:element_name] = fqn
159
+ m[:element_type] = rootdive[fqn][:type]
160
+
161
+ spl = fqn.split("::")
162
+ spl_cu = current_fqn[].split("::")
163
+
164
+ min = spl - spl_cu
165
+ if min.empty?
166
+ m[:reltype] = fqn
167
+ else
168
+ m[:reltype] = min.join("::")
169
+ end
170
+ end
171
+
172
+ unless arrlen == 1
173
+ m[:array] = arrlen
174
+ end
175
+ h[:members] << m
176
+ end
177
+ elsif b_type == :enum
178
+ line.split(",").each do |ln|
179
+ a, b, c = ln.split(/\s+/).reject(&:empty?)
180
+
181
+ if !b.nil? && b == "="
182
+ _enumidx = c.to_i
183
+ end
184
+ h[:members] << { :name => a, :val => _enumidx}
185
+ _enumidx = _enumidx + 1
186
+ end
187
+ end
188
+ end
189
+
190
+ if tok[0] == "}"
191
+ _blevel.pop
192
+ elsif tok[0] == "namespace"
193
+ if tok[2] == "{"
194
+ hashobj[][:members][tok[1]] = { :type => :namespace, :members => {} }
195
+ _blevel << { :type => :namespace, :name => tok[1] }
196
+ else
197
+ tok[1].split("::").each do |ns|
198
+ hashobj[][:members][ns] = { :type => :namespace, :members => {} }
199
+ _blevel << { :type => :namespace, :name => ns }
200
+ end
201
+ end
202
+ elsif tok[0] == "block"
203
+ cur = current_fqn[]
204
+ fulltype = tok[1]
205
+ fulltype = cur + "::" + tok[1] unless cur.empty?
206
+
207
+ hashobj[][:members][tok[1]] = {
208
+ :type => :block,
209
+ :members => [],
210
+ :file => src_file,
211
+ :fulltype => fulltype
212
+ }
213
+
214
+ # Block Order is used by the bitmap generator to decide what order to process block sizes
215
+ # and references in. This means that declaration order matters
216
+ hash[:block_order] << fulltype
217
+ file[:blocks] << fulltype
218
+
219
+ _blevel << { :type => :block, :name => tok[1] }
220
+ elsif tok[0] == "enum"
221
+ cur = current_fqn[]
222
+ fulltype = tok[1]
223
+ fulltype = cur + "::" + tok[1] unless cur.empty?
224
+
225
+ hashobj[][:members][tok[1]] = {
226
+ :type => :enum,
227
+ :members => [],
228
+ :file => src_file,
229
+ :fulltype => fulltype
230
+ }
231
+ _enumidx = 0
232
+ _blevel << { :type => :enum, :name => tok[1] }
233
+
234
+ file[:enums] << fulltype
235
+ elsif tok[0] == "using" && tok[1] == "namespace"
236
+ if tok[3] == "{"
237
+ _blevel << { :type => :using, :name => tok[2] }
238
+ else
239
+ tok[2].split("::").each do |ns|
240
+ _blevel << { :type => :using, :name => ns }
241
+ end
242
+ end
243
+ elsif tok[0] == "import"
244
+ file[:imports] << tok[1]
245
+ hash = hash.deep_merge(lex(tok[1], src_dir))
246
+ end
247
+ end
248
+ hash
249
+ end
250
+
251
+ def bitmap lex
252
+ lex[:block_order].each do |block_name|
253
+ block = lex
254
+ block_name.split("::").each { |x| block = block[:members][x] }
255
+
256
+ bools, nonbools = block[:members].partition { |el| el[:type] == :bool && el[:array].nil? }
257
+ idx = 0
258
+
259
+ bools.each_slice(8) do |byte|
260
+ byte.each_with_index do |bitvalue, i|
261
+ bitvalue[:bit_index] = i
262
+ bitvalue[:index] = idx
263
+ end
264
+ idx += 1
265
+ end
266
+
267
+ nonbools.each do |member|
268
+ t = member[:type]
269
+ n = member[:name]
270
+
271
+ arraysize = 1
272
+ arraysize = member[:array] unless member[:array].nil?
273
+
274
+ if t == :bool
275
+ # It must be a boolean array.
276
+ total_size = (arraysize / 8.to_f).ceil
277
+ member[:index] = idx
278
+ member[:size] = total_size
279
+ idx += total_size
280
+ elsif t == :blank
281
+ idx += arraysize
282
+ elsif t == :string
283
+ typesize = member[:attributes][0].to_i
284
+ len = typesize * arraysize
285
+ member[:index] = idx
286
+ member[:size] = len
287
+ member[:typesize] = typesize
288
+ idx += len
289
+ elsif t == :reference
290
+ if member[:element_type] == :block
291
+ referenced = lex
292
+ member[:element_name].split("::").each { |a| referenced = referenced[:members][a] }
293
+
294
+ size = referenced[:size] * arraysize
295
+ member[:size] = size
296
+ member[:index] = idx
297
+ member[:typesize] = referenced[:size]
298
+ idx += size
299
+ elsif member[:element_type] == :enum
300
+ member[:size] = arraysize
301
+ member[:typesize] = 1
302
+ member[:index] = idx
303
+ idx += arraysize
304
+ end
305
+ else
306
+ size = TYPE_SIZES[t] * arraysize
307
+ member[:size] = size
308
+ member[:index] = idx
309
+ member[:typesize] = TYPE_SIZES[t]
310
+ idx += TYPE_SIZES[t]
311
+ end
312
+ end
313
+
314
+ # Remove :blank types
315
+ block[:members].each_index.select { |i| block[:members][i][:type] == :blank }.each { |x| block[:members].delete_at(x) }
316
+
317
+ # Final Size
318
+ block[:size] = idx
319
+ end
320
+ lex
321
+ end
322
+ end
323
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fwi
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jaci Brunning
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - jaci.brunning@gmail.com
16
+ executables:
17
+ - fwi
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - Gemfile
22
+ - LICENSE
23
+ - bin/fwi
24
+ - fwi.gemspec
25
+ - lib/fwi/compiler.rb
26
+ - lib/fwi/cpp/compiler.rb
27
+ - lib/fwi/cpp/gen.rb
28
+ - lib/fwi/parser.rb
29
+ homepage: http://github.com/JacisNonsense/Fixed-Width-Interchange
30
+ licenses: []
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.4.5
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Fixed-Width Data Interchange Compiler
52
+ test_files: []