cauterize 0.0.1.pre1

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 (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)