cauterize 0.0.1.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +24 -0
  2. data/.rspec +1 -0
  3. data/.travisci.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +152 -0
  7. data/Rakefile +38 -0
  8. data/bin/cauterize +53 -0
  9. data/c/src/cauterize.c +74 -0
  10. data/c/src/cauterize.h +46 -0
  11. data/c/src/cauterize_debug.h +29 -0
  12. data/c/src/cauterize_util.h +7 -0
  13. data/c/test/greatest.h +536 -0
  14. data/c/test/test.c +166 -0
  15. data/cauterize.gemspec +26 -0
  16. data/example/Cauterize +44 -0
  17. data/example/build.sh +4 -0
  18. data/lib/cauterize/base_type.rb +96 -0
  19. data/lib/cauterize/builders.rb +27 -0
  20. data/lib/cauterize/builders/c/buildable.rb +59 -0
  21. data/lib/cauterize/builders/c/composite.rb +55 -0
  22. data/lib/cauterize/builders/c/enumeration.rb +41 -0
  23. data/lib/cauterize/builders/c/fixed_array.rb +62 -0
  24. data/lib/cauterize/builders/c/group.rb +95 -0
  25. data/lib/cauterize/builders/c/scalar.rb +31 -0
  26. data/lib/cauterize/builders/c/variable_array.rb +90 -0
  27. data/lib/cauterize/c_builder.rb +63 -0
  28. data/lib/cauterize/cauterize.rb +33 -0
  29. data/lib/cauterize/composite.rb +50 -0
  30. data/lib/cauterize/enumeration.rb +77 -0
  31. data/lib/cauterize/fixed_array.rb +43 -0
  32. data/lib/cauterize/formatter.rb +59 -0
  33. data/lib/cauterize/group.rb +56 -0
  34. data/lib/cauterize/scalar.rb +38 -0
  35. data/lib/cauterize/snake_case.rb +21 -0
  36. data/lib/cauterize/variable_array.rb +56 -0
  37. data/lib/cauterize/version.rb +3 -0
  38. data/spec/base_type_spec.rb +167 -0
  39. data/spec/builders/c/buildable_spec.rb +25 -0
  40. data/spec/builders/c/composite_spec.rb +46 -0
  41. data/spec/builders/c/enumeration_spec.rb +32 -0
  42. data/spec/builders/c/fixed_array_spec.rb +36 -0
  43. data/spec/builders/c/group_spec.rb +112 -0
  44. data/spec/builders/c/scalar_spec.rb +8 -0
  45. data/spec/builders/c/variable_array_spec.rb +50 -0
  46. data/spec/builders_spec.rb +51 -0
  47. data/spec/c_builder_spec.rb +133 -0
  48. data/spec/cauterize_spec.rb +8 -0
  49. data/spec/composite_spec.rb +62 -0
  50. data/spec/enumeration_spec.rb +104 -0
  51. data/spec/fixed_array_spec.rb +62 -0
  52. data/spec/group_spec.rb +104 -0
  53. data/spec/scalar_spec.rb +36 -0
  54. data/spec/spec_helper.rb +115 -0
  55. data/spec/support/shared_examples_for_array_buildables.rb +22 -0
  56. data/spec/support/shared_examples_for_c_buildables.rb +91 -0
  57. data/spec/support/shared_examples_for_sane_c_buildables.rb +22 -0
  58. data/spec/support/shared_examples_for_stubbed_functions.rb +18 -0
  59. data/spec/test_main.c +13 -0
  60. data/spec/variable_array_spec.rb +92 -0
  61. metadata +212 -0
data/c/test/test.c ADDED
@@ -0,0 +1,166 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+
4
+ #include "cauterize.h"
5
+ #include "greatest.h"
6
+
7
+ GREATEST_MAIN_DEFS();
8
+
9
+ TEST t_CauterizeInitAppend_works() {
10
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
11
+ struct Cauterize m;
12
+ uint8_t buffer[64] = { 0 };
13
+
14
+ s = CauterizeInitAppend(&m, buffer, sizeof(buffer));
15
+
16
+ ASSERT_EQ(CA_OK, s);
17
+ ASSERT_EQ(m.size, 64);
18
+ ASSERT_EQ(m.used, 0);
19
+ ASSERT_EQ(m.pos, 0);
20
+
21
+ PASS();
22
+ }
23
+
24
+ TEST t_CauterizeInitRead_works() {
25
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
26
+ struct Cauterize m;
27
+ uint8_t buffer[64] = { 0 };
28
+
29
+ s = CauterizeInitRead(&m, buffer, 13);
30
+
31
+ ASSERT_EQ(CA_OK, s);
32
+ ASSERT_EQ(m.size, 13);
33
+ ASSERT_EQ(m.used, 13);
34
+ ASSERT_EQ(m.pos, 0);
35
+
36
+ PASS();
37
+ }
38
+
39
+ TEST t_CauterizeAppend_works() {
40
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
41
+ struct Cauterize m;
42
+ uint8_t buffer[64] = { 0 };
43
+ char data[] = "Hello World";
44
+
45
+ s = CauterizeInitAppend(&m, buffer, sizeof(buffer));
46
+ ASSERT_EQ(CA_OK, s);
47
+
48
+ s = CauterizeAppend(&m, (uint8_t*)data, sizeof(data));
49
+ ASSERT_EQ(CA_OK, s);
50
+ ASSERT_EQ(m.used, sizeof(data));
51
+ ASSERT_STR_EQ(data, (char*)m.buffer);
52
+
53
+ PASS();
54
+ }
55
+
56
+ TEST t_CauterizeAppend_works_again() {
57
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
58
+ struct Cauterize m;
59
+ uint8_t buffer[64] = { 0 };
60
+
61
+ char data_1[3] = "ABC";
62
+ char data_2[] = "DEF";
63
+
64
+ s = CauterizeInitAppend(&m, buffer, sizeof(buffer));
65
+ ASSERT_EQ(CA_OK, s);
66
+
67
+ ASSERT_EQ(CA_OK, CauterizeAppend(&m, (uint8_t*)data_1, sizeof(data_1)));
68
+ ASSERT_EQ(CA_OK, CauterizeAppend(&m, (uint8_t*)data_2, sizeof(data_2)));
69
+
70
+ ASSERT_EQ(sizeof(data_1) + sizeof(data_2), m.used);
71
+ ASSERT_STR_EQ("ABCDEF", (char*)m.buffer);
72
+
73
+ PASS();
74
+ }
75
+
76
+ TEST t_CauterizeAppend_checks_space_needs() {
77
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
78
+ struct Cauterize m;
79
+ uint8_t buffer[64] = { 0 };
80
+ char data[] = "Hello World";
81
+
82
+ s = CauterizeInitAppend(&m, buffer, sizeof(data) - 5);
83
+ ASSERT_EQ(CA_OK, s);
84
+
85
+ s = CauterizeAppend(&m, (uint8_t*)data, sizeof(data));
86
+ ASSERT_EQ(CA_ERR_NOT_ENOUGH_SPACE, s);
87
+ ASSERT_EQ(m.used, 0);
88
+
89
+ PASS();
90
+ }
91
+
92
+ TEST t_CauterizeRead_works() {
93
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
94
+ struct Cauterize m;
95
+ struct Cauterize n;
96
+ uint8_t buffer[64] = { 0 };
97
+ char data[] = "Hello World";
98
+
99
+ ASSERT_EQ(CA_OK, CauterizeInitAppend(&m, buffer, sizeof(buffer)));
100
+ ASSERT_EQ(CA_OK, CauterizeAppend(&m, (uint8_t*)data, sizeof(data)));
101
+
102
+ ASSERT_EQ(CA_OK, CauterizeInitRead(&n, buffer, m.used));
103
+
104
+ char dest[64] = {0};
105
+
106
+ s = CauterizeRead(&n, (uint8_t*)dest, 5);
107
+ ASSERT_EQ(CA_OK, s);
108
+ ASSERT_EQ(5, n.pos);
109
+ ASSERT_STR_EQ("Hello", dest);
110
+
111
+ PASS();
112
+ }
113
+
114
+ TEST t_CauterizeRead_works_again() {
115
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
116
+ struct Cauterize m;
117
+ struct Cauterize n;
118
+ uint8_t buffer[64] = { 0 };
119
+ char data[] = "Hello World";
120
+
121
+ ASSERT_EQ(CA_OK, CauterizeInitAppend(&m, buffer, sizeof(buffer)));
122
+ ASSERT_EQ(CA_OK, CauterizeAppend(&m, (uint8_t*)data, sizeof(data)));
123
+
124
+ char dest[64] = {0};
125
+
126
+ ASSERT_EQ(CA_OK, CauterizeInitRead(&n, buffer, m.used));
127
+ ASSERT_EQ(CA_OK, CauterizeRead(&n, (uint8_t*)dest, 5));
128
+
129
+ s = CauterizeRead(&n, (uint8_t*)dest, 6);
130
+ ASSERT_EQ(CA_OK, s);
131
+ ASSERT_EQ(11, n.pos);
132
+ ASSERT_STR_EQ(" World", dest);
133
+
134
+ PASS();
135
+ }
136
+
137
+ TEST t_CauterizeRead_checks_data_needs() {
138
+ CAUTERIZE_STATUS_T s = CA_ERR_GENERAL;
139
+ struct Cauterize m;
140
+ struct Cauterize n;
141
+ uint8_t buffer[32] = { 0 };
142
+ char data[] = "Hello World";
143
+
144
+ ASSERT_EQ(CA_OK, CauterizeInitAppend(&m, buffer, sizeof(buffer)));
145
+ ASSERT_EQ(CA_OK, CauterizeAppend(&m, (uint8_t*)data, sizeof(data)));
146
+
147
+ char dest[64] = {0};
148
+
149
+ ASSERT_EQ(CA_OK, CauterizeInitRead(&n, buffer, m.used));
150
+ s = CauterizeRead(&n, (uint8_t*)dest, sizeof(dest));
151
+ ASSERT_EQ(CA_ERR_NOT_ENOUGH_DATA, s);
152
+ ASSERT_EQ(0, n.pos);
153
+
154
+ PASS();
155
+ }
156
+
157
+ GREATEST_SUITE(marshal) {
158
+ /* test_suite.c is generated programatically by the Rakefile */
159
+ #include "test_suite.c"
160
+ }
161
+
162
+ int main(int argc, char * argv[]) {
163
+ GREATEST_MAIN_BEGIN();
164
+ RUN_SUITE(marshal);
165
+ GREATEST_MAIN_END();
166
+ }
data/cauterize.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cauterize/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "cauterize"
8
+ gem.version = Cauterize::VERSION
9
+ gem.authors = ["John Van Enk"]
10
+ gem.email = ["vanenkj@gmail.com"]
11
+ gem.summary = %q{Tools to generate structures and mashalers suitable for static-memory environments.}
12
+ gem.description = %q{Tools to generate C structures and marshalers with a Ruby DSL.}
13
+ gem.homepage = "https://github.com/sw17ch/cauterize"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'rake', '>= 0.9.2.0'
21
+ gem.add_dependency 'thor', '>= 0.16.0'
22
+ gem.add_dependency 'require_all', '>= 1.2.1'
23
+
24
+ gem.add_development_dependency 'rspec', '>= 2.12.0'
25
+ gem.add_development_dependency 'mocha', '>= 0.13.0'
26
+ end
data/example/Cauterize ADDED
@@ -0,0 +1,44 @@
1
+ set_name("example_project")
2
+
3
+ scalar(:int8_t)
4
+ scalar(:int16_t)
5
+ scalar(:int32_t)
6
+ scalar(:int64_t)
7
+ scalar(:uint8_t)
8
+ scalar(:uint16_t)
9
+ scalar(:uint32_t)
10
+ scalar(:uint64_t)
11
+
12
+ enumeration(:color) do |e|
13
+ e.value :red
14
+ e.value :blue
15
+ e.value :green
16
+ end
17
+
18
+ fixed_array(:color_list) do |a|
19
+ a.array_type :color
20
+ a.array_size 4
21
+ end
22
+
23
+ variable_array(:numbers) do |a|
24
+ a.size_type :uint8_t
25
+ a.array_type :int32_t
26
+ a.array_size 128
27
+ end
28
+
29
+ composite(:nonsensical) do |c|
30
+ c.field :color, :color
31
+ c.field :color_list, :color_list
32
+ c.field :numbers, :numbers
33
+ end
34
+
35
+ composite(:crazy) do |c|
36
+ c.field :first_numbers, :numbers
37
+ c.field :second_numbers, :numbers
38
+ c.field :third_numbers, :numbers
39
+ end
40
+
41
+ group(:insanity) do |g|
42
+ g.field :nonsensical, :nonsensical
43
+ g.field :crazy, :crazy
44
+ end
data/example/build.sh ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+
3
+ rm -rf cauterize_output
4
+ ../bin/cauterize generate c cauterize_output
@@ -0,0 +1,96 @@
1
+ require 'set'
2
+
3
+ module Cauterize
4
+ class BaseType
5
+ attr_reader :name, :id
6
+ @@next_id = {}
7
+ @@instances = {}
8
+ @@used_names = Set.new
9
+
10
+ def initialize(name)
11
+ if @@used_names.include?(name)
12
+ raise Exception.new("A type with the name #{name} already exists.")
13
+ else
14
+ @@used_names << name
15
+ end
16
+
17
+ @name = name
18
+ @id = next_id
19
+ register_instance(self)
20
+ end
21
+
22
+ def type
23
+ tag_part = ((tag << BaseType.id_bit_width) & BaseType.tag_bit_mask)
24
+ id_part = (id & BaseType.id_bit_mask)
25
+ (tag_part | id_part) & BaseType.type_bit_mask
26
+ end
27
+
28
+ def type_str
29
+ "0x%04X" % type
30
+ end
31
+
32
+ def tag
33
+ cname = self.class.name
34
+ case cname
35
+ when "Cauterize::Scalar"; 0
36
+ when "Cauterize::Enumeration"; 1
37
+ when "Cauterize::Composite"; 2
38
+ when "Cauterize::FixedArray"; 3
39
+ when "Cauterize::VariableArray"; 4
40
+ when "Cauterize::Group"; 5
41
+ else
42
+ raise Exception.new("Tag not defined for #{cname}.")
43
+ end
44
+ end
45
+
46
+ def self.tag_bit_mask; 0xE000 end
47
+ def self.tag_bit_width; 3 end
48
+ def self.id_bit_mask; 0x1FFF end
49
+ def self.id_bit_width; 13 end
50
+ def self.type_bit_mask; 0xFFFF end
51
+ def self.type_bit_width; tag_bit_width + id_bit_width end
52
+ def self.all_instances; @@instances.values end
53
+
54
+ def self.find_type(name)
55
+ @@instances[name]
56
+ end
57
+
58
+ def self.find_type!(name)
59
+ unless t = find_type(name)
60
+ raise Exception.new("The name #{name} does not correspond to a type.")
61
+ else
62
+ return t
63
+ end
64
+ end
65
+
66
+ alias :orig_method_missing :method_missing
67
+
68
+ def method_missing(sym, *args)
69
+ m = sym.to_s.match /is_([^\?]+)\?/
70
+ if m
71
+ return ("Cauterize::#{m[1].camel}" == self.class.name)
72
+ else
73
+ orig_method_missing(sym, *args)
74
+ end
75
+ end
76
+
77
+ protected
78
+
79
+ def register_instance(inst)
80
+ if @@instances[inst.name]
81
+ raise Exception.new("Type with name #{inst.name} already defined.")
82
+ end
83
+
84
+ @@instances[inst.name] = inst
85
+ end
86
+
87
+ def next_id
88
+ cname = self.class.name
89
+ @@next_id[cname] ||= 0
90
+
91
+ an_id = @@next_id[cname]
92
+ @@next_id[cname] += 1
93
+ return an_id
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,27 @@
1
+ module Cauterize
2
+ module Builders
3
+ class UnregisteredException < Exception; end
4
+ class DuplicateException < Exception; end
5
+
6
+ module_function
7
+
8
+ def register(language, description_class, builder_class)
9
+ @builders ||= {}
10
+ @builders[language] ||= {}
11
+
12
+ if @builders[language][description_class]
13
+ raise DuplicateException.new("A builder for #{description_class} is already registered for language #{language}.")
14
+ else
15
+ @builders[language][description_class] = builder_class
16
+ end
17
+ end
18
+
19
+ def get(language, description_instance)
20
+ if @builders and @builders[language]
21
+ @builders[language][description_instance.class].new(description_instance)
22
+ else
23
+ raise UnregisteredException.new("The builder for #{description_instance.class} in #{language} is unregistered.")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,59 @@
1
+ module Cauterize
2
+ module Builders
3
+ module C
4
+ # sym - symbol - the lexical symbol associated with the generated entity
5
+ # sig - signature - the C signature associated with the entity
6
+ # proto - prototype - the C prototype associated with the entity
7
+ # defn - definition - the C definition associated with the entity
8
+ REQUIRED_METHODS = [
9
+ :render,
10
+ :declare,
11
+ :packer_sym, :packer_sig, :packer_proto, :packer_defn,
12
+ :unpacker_sym, :unpacker_sig, :unpacker_proto, :unpacker_defn,
13
+ :struct_proto, :struct_defn,
14
+ :enumeration,
15
+ ]
16
+
17
+ class BuildableException < Exception; end
18
+
19
+ class Buildable
20
+ def initialize(blueprint)
21
+ @blueprint = blueprint
22
+ end
23
+
24
+ alias_method :orig_method_missing, :method_missing
25
+
26
+ def method_missing(sym, *args)
27
+ sym_required = REQUIRED_METHODS.include?(sym)
28
+
29
+ if sym_required
30
+ raise BuildableException.new("Classes deriving Buildable must implement the method #{sym}.")
31
+ else
32
+ orig_method_missing(sym, *args)
33
+ end
34
+ end
35
+
36
+ # Things below here are tested in shared_examples_for_c_buildables #
37
+ ####################################################################
38
+
39
+ # Methods that are pretty much the same for everyone.
40
+ def packer_sym; "Pack_#{@blueprint.name}" end
41
+ def packer_sig; "CAUTERIZE_STATUS_T #{packer_sym}(struct Cauterize * dst, #{render} * src)" end
42
+ def packer_proto(formatter)
43
+ formatter << packer_sig + ";"
44
+ end
45
+
46
+ def unpacker_sym; "Unpack_#{@blueprint.name}" end
47
+ def unpacker_sig; "CAUTERIZE_STATUS_T #{unpacker_sym}(struct Cauterize * src, #{render} * dst)" end
48
+ def unpacker_proto(formatter)
49
+ formatter << unpacker_sig + ";"
50
+ end
51
+
52
+ # These are only different in a few type varieties.
53
+ def struct_proto(formatter); nil end
54
+ def struct_defn(formatter); nil end
55
+ def enum_defn(formatter); nil end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,55 @@
1
+ module Cauterize
2
+ module Builders
3
+ module C
4
+ class Composite < Buildable
5
+ def render
6
+ "struct #{@blueprint.name.to_s}"
7
+ end
8
+
9
+ def declare(formatter, sym)
10
+ formatter << "#{render} #{sym};"
11
+ end
12
+
13
+ def packer_defn(formatter)
14
+ formatter << packer_sig
15
+ formatter.braces do
16
+ formatter << "CAUTERIZE_STATUS_T err;"
17
+ @blueprint.fields.values.each do |field|
18
+ p_sym = Builders.get(:c, field.type).packer_sym
19
+ formatter << "if (CA_OK != (err = #{p_sym}(dst, &src->#{field.name}))) { return err; }"
20
+ end
21
+ formatter << "return CA_OK;"
22
+ end
23
+ end
24
+
25
+ def unpacker_defn(formatter)
26
+ formatter << unpacker_sig
27
+ formatter.braces do
28
+ formatter << "CAUTERIZE_STATUS_T err;"
29
+ @blueprint.fields.values.each do |field|
30
+ u_sym = Builders.get(:c, field.type).unpacker_sym
31
+ formatter << "if (CA_OK != (err = #{u_sym}(src, &dst->#{field.name}))) { return err; }"
32
+ end
33
+ formatter << "return CA_OK;"
34
+ end
35
+ end
36
+
37
+ def struct_proto(formatter)
38
+ formatter << (render + ";")
39
+ end
40
+
41
+ def struct_defn(formatter)
42
+ formatter << render
43
+ formatter.braces do
44
+ @blueprint.fields.values.each do |field|
45
+ Builders.get(:c, field.type).declare(formatter, field.name)
46
+ end
47
+ end
48
+ formatter.append(";")
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ Cauterize::Builders.register(:c, Cauterize::Composite, Cauterize::Builders::C::Composite)