fwi 1.0.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.
@@ -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: []