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.
- data/.gitignore +24 -0
- data/.rspec +1 -0
- data/.travisci.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +38 -0
- data/bin/cauterize +53 -0
- data/c/src/cauterize.c +74 -0
- data/c/src/cauterize.h +46 -0
- data/c/src/cauterize_debug.h +29 -0
- data/c/src/cauterize_util.h +7 -0
- data/c/test/greatest.h +536 -0
- data/c/test/test.c +166 -0
- data/cauterize.gemspec +26 -0
- data/example/Cauterize +44 -0
- data/example/build.sh +4 -0
- data/lib/cauterize/base_type.rb +96 -0
- data/lib/cauterize/builders.rb +27 -0
- data/lib/cauterize/builders/c/buildable.rb +59 -0
- data/lib/cauterize/builders/c/composite.rb +55 -0
- data/lib/cauterize/builders/c/enumeration.rb +41 -0
- data/lib/cauterize/builders/c/fixed_array.rb +62 -0
- data/lib/cauterize/builders/c/group.rb +95 -0
- data/lib/cauterize/builders/c/scalar.rb +31 -0
- data/lib/cauterize/builders/c/variable_array.rb +90 -0
- data/lib/cauterize/c_builder.rb +63 -0
- data/lib/cauterize/cauterize.rb +33 -0
- data/lib/cauterize/composite.rb +50 -0
- data/lib/cauterize/enumeration.rb +77 -0
- data/lib/cauterize/fixed_array.rb +43 -0
- data/lib/cauterize/formatter.rb +59 -0
- data/lib/cauterize/group.rb +56 -0
- data/lib/cauterize/scalar.rb +38 -0
- data/lib/cauterize/snake_case.rb +21 -0
- data/lib/cauterize/variable_array.rb +56 -0
- data/lib/cauterize/version.rb +3 -0
- data/spec/base_type_spec.rb +167 -0
- data/spec/builders/c/buildable_spec.rb +25 -0
- data/spec/builders/c/composite_spec.rb +46 -0
- data/spec/builders/c/enumeration_spec.rb +32 -0
- data/spec/builders/c/fixed_array_spec.rb +36 -0
- data/spec/builders/c/group_spec.rb +112 -0
- data/spec/builders/c/scalar_spec.rb +8 -0
- data/spec/builders/c/variable_array_spec.rb +50 -0
- data/spec/builders_spec.rb +51 -0
- data/spec/c_builder_spec.rb +133 -0
- data/spec/cauterize_spec.rb +8 -0
- data/spec/composite_spec.rb +62 -0
- data/spec/enumeration_spec.rb +104 -0
- data/spec/fixed_array_spec.rb +62 -0
- data/spec/group_spec.rb +104 -0
- data/spec/scalar_spec.rb +36 -0
- data/spec/spec_helper.rb +115 -0
- data/spec/support/shared_examples_for_array_buildables.rb +22 -0
- data/spec/support/shared_examples_for_c_buildables.rb +91 -0
- data/spec/support/shared_examples_for_sane_c_buildables.rb +22 -0
- data/spec/support/shared_examples_for_stubbed_functions.rb +18 -0
- data/spec/test_main.c +13 -0
- data/spec/variable_array_spec.rb +92 -0
- metadata +212 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
# enumeration.rb
|
2
|
+
#
|
3
|
+
# Enumerations correspond exactly to C enumerations.
|
4
|
+
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
module Cauterize
|
8
|
+
module_function
|
9
|
+
def enumeration(name)
|
10
|
+
e = enumerations[name] || enumerations[name] = Enumeration.new(name)
|
11
|
+
yield e if block_given?
|
12
|
+
return e
|
13
|
+
end
|
14
|
+
|
15
|
+
def enumeration!(name, &blk)
|
16
|
+
if enumerations[name]
|
17
|
+
raise Exception.new("Enumeration with name #{name} already exists.")
|
18
|
+
else
|
19
|
+
enumeration(name, &blk)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def enumerations
|
24
|
+
@enumerations ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
class EnumerationValue
|
28
|
+
attr_reader :name, :value
|
29
|
+
|
30
|
+
def initialize(name, value)
|
31
|
+
@name = name
|
32
|
+
@value = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Enumeration < BaseType
|
37
|
+
attr_reader :values
|
38
|
+
|
39
|
+
def initialize(name)
|
40
|
+
super
|
41
|
+
@values = {}
|
42
|
+
@value_id = 0
|
43
|
+
@used_ids = Set.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def value(name, id=nil)
|
47
|
+
if @values[name]
|
48
|
+
raise Exception.new("Cannot duplicate name #{name}.")
|
49
|
+
end
|
50
|
+
|
51
|
+
next_id = value_id(id)
|
52
|
+
@used_ids << next_id
|
53
|
+
@values[name] = EnumerationValue.new(name, next_id)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def value_id(next_id=nil)
|
59
|
+
if next_id
|
60
|
+
@value_id = next_id
|
61
|
+
end
|
62
|
+
|
63
|
+
v = @value_id
|
64
|
+
|
65
|
+
if @used_ids.include? v
|
66
|
+
raise Exception.new("Cannot duplicate constant #{v}.")
|
67
|
+
end
|
68
|
+
|
69
|
+
loop do
|
70
|
+
@value_id += 1
|
71
|
+
break unless @used_ids.include? @value_id
|
72
|
+
end
|
73
|
+
|
74
|
+
return v
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def fixed_array(name)
|
5
|
+
a = fixed_arrays[name] || fixed_arrays[name] = FixedArray.new(name)
|
6
|
+
yield a if block_given?
|
7
|
+
return a
|
8
|
+
end
|
9
|
+
|
10
|
+
def fixed_array!(name, &blk)
|
11
|
+
if fixed_arrays[name]
|
12
|
+
raise Exception.new("FixedArray with name #{name} already exists.")
|
13
|
+
else
|
14
|
+
fixed_array(name, &blk)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def fixed_arrays
|
19
|
+
@fixed_ararys ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
class FixedArray < BaseType
|
23
|
+
def initialize(name)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def array_type(t = nil)
|
28
|
+
if t
|
29
|
+
@array_type = BaseType.find_type!(t)
|
30
|
+
else
|
31
|
+
@array_type
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def array_size(s = nil)
|
36
|
+
if s
|
37
|
+
@array_size = s
|
38
|
+
else
|
39
|
+
@array_size
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
def default_formatter
|
2
|
+
Formatter.new
|
3
|
+
end
|
4
|
+
|
5
|
+
class Formatter
|
6
|
+
def initialize
|
7
|
+
@indent_level = 0
|
8
|
+
@indent_str = " "
|
9
|
+
@lines = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def indent(line)
|
13
|
+
(@indent_str * @indent_level) + line
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(line)
|
17
|
+
@lines << indent(line)
|
18
|
+
end
|
19
|
+
|
20
|
+
# indent back one level
|
21
|
+
def backdent(line)
|
22
|
+
@indent_level -= 1
|
23
|
+
@lines << indent(line)
|
24
|
+
@indent_level += 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def append(text)
|
28
|
+
if @lines.length == 0
|
29
|
+
@lines << ""
|
30
|
+
end
|
31
|
+
|
32
|
+
@lines[-1] += text
|
33
|
+
end
|
34
|
+
|
35
|
+
def braces
|
36
|
+
self << "{"
|
37
|
+
indented { yield self } if block_given?
|
38
|
+
self << "}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def blank_line
|
42
|
+
@lines << ""
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s(extra_indent = 0)
|
46
|
+
@indent_level += extra_indent
|
47
|
+
s = @lines.map {|l| indent(l) }.join("\n")
|
48
|
+
@indent_level -= extra_indent
|
49
|
+
return s
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def indented
|
55
|
+
@indent_level += 1
|
56
|
+
yield self
|
57
|
+
@indent_level -= 1
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def group(name)
|
5
|
+
a = groups[name] || groups[name] = Group.new(name)
|
6
|
+
yield a if block_given?
|
7
|
+
return a
|
8
|
+
end
|
9
|
+
|
10
|
+
def group!(name, &blk)
|
11
|
+
if groups[name]
|
12
|
+
raise Exception.new("Group with name #{name} already exists.")
|
13
|
+
else
|
14
|
+
group(name, &blk)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def groups
|
19
|
+
@groups ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
class GroupField
|
23
|
+
attr_reader :name, :type
|
24
|
+
|
25
|
+
def initialize(name, type)
|
26
|
+
@name = name
|
27
|
+
@type = BaseType.find_type!(type)
|
28
|
+
end
|
29
|
+
|
30
|
+
def enum_sym
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Group < BaseType
|
35
|
+
attr_reader :fields, :tag_enum
|
36
|
+
|
37
|
+
def initialize(name)
|
38
|
+
super
|
39
|
+
@fields = {}
|
40
|
+
@tag_enum = Cauterize.enumeration!("group_#{name}_type".to_sym)
|
41
|
+
end
|
42
|
+
|
43
|
+
def field(name, type)
|
44
|
+
if @fields[name]
|
45
|
+
raise Exception.new("Field name #{name} already used.")
|
46
|
+
else
|
47
|
+
@fields[name] = GroupField.new(name, type)
|
48
|
+
@tag_enum.value(enum_sym(name))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def enum_sym(fname)
|
53
|
+
"group_#{@name}_type_#{fname}".up_snake.to_sym
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# scalar.rb
|
2
|
+
#
|
3
|
+
# scalars are types that, in C, can be updated with assignment. This includes
|
4
|
+
# native types in C and typedefs around these native types.
|
5
|
+
#
|
6
|
+
# scalars are not structs, enumerations, unions, or arrays.
|
7
|
+
|
8
|
+
module Cauterize
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def scalar(name)
|
12
|
+
a = scalars[name] || scalars[name] = Scalar.new(name)
|
13
|
+
yield a if block_given?
|
14
|
+
return a
|
15
|
+
end
|
16
|
+
|
17
|
+
def scalar!(name, &blk)
|
18
|
+
if scalars[name]
|
19
|
+
raise Exception.new("Scalar with name #{name} already exists.")
|
20
|
+
else
|
21
|
+
scalar(name, &blk)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def scalars
|
26
|
+
@scalars ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def flush_scalars
|
30
|
+
@scalars = {}
|
31
|
+
end
|
32
|
+
|
33
|
+
class Scalar < BaseType
|
34
|
+
def initialize(name)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class String
|
2
|
+
def snake
|
3
|
+
self.gsub(/::/, '/').
|
4
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
5
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
6
|
+
tr("-", "_")
|
7
|
+
end
|
8
|
+
|
9
|
+
def up_snake
|
10
|
+
snake.upcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def down_snake
|
14
|
+
snake.downcase
|
15
|
+
end
|
16
|
+
|
17
|
+
def camel
|
18
|
+
return self.capitalize if self !~ /_/ && self =~ /[A-z]+.*/
|
19
|
+
split('_').map{|e| e.capitalize}.join
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def variable_array(name)
|
5
|
+
a = variable_arrays[name] || variable_arrays[name] = VariableArray.new(name)
|
6
|
+
yield a if block_given?
|
7
|
+
return a
|
8
|
+
end
|
9
|
+
|
10
|
+
def variable_array!(name, &blk)
|
11
|
+
if variable_arrays[name]
|
12
|
+
raise Exception.new("VariableArray with name #{name} already exists.")
|
13
|
+
else
|
14
|
+
variable_array(name, &blk)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def variable_arrays
|
19
|
+
@variable_ararys ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
class VariableArray < BaseType
|
23
|
+
def intialize(name)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def array_type(t = nil)
|
28
|
+
if t
|
29
|
+
@array_type = BaseType.find_type!(t)
|
30
|
+
else
|
31
|
+
@array_type
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def array_size(s = nil)
|
36
|
+
if s
|
37
|
+
@array_size = s
|
38
|
+
else
|
39
|
+
@array_size
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def size_type(t = nil)
|
44
|
+
if t
|
45
|
+
_t = BaseType.find_type!(t)
|
46
|
+
if _t.is_scalar?
|
47
|
+
@size_type = _t
|
48
|
+
else
|
49
|
+
raise Exception.new("The type #{t} is not an scalar")
|
50
|
+
end
|
51
|
+
else
|
52
|
+
@size_type
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
include Cauterize
|
2
|
+
|
3
|
+
describe Cauterize do
|
4
|
+
before {
|
5
|
+
BaseType.class_variable_set(:@@next_id, {})
|
6
|
+
BaseType.class_variable_set(:@@instances, {})
|
7
|
+
}
|
8
|
+
|
9
|
+
describe BaseType do
|
10
|
+
describe :id do
|
11
|
+
it { has_a_unique_id_for_each_instance(BaseType) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :type_str do
|
15
|
+
it "is the hexadecimal representation of type" do
|
16
|
+
f = enumeration(:foo) do |e|
|
17
|
+
e.value :a, 1
|
18
|
+
end
|
19
|
+
b = enumeration(:bar) do |e|
|
20
|
+
e.value :a, 1
|
21
|
+
end
|
22
|
+
|
23
|
+
b.type_str.should == "0x2001"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe :tag do
|
28
|
+
it { is_tagged_as(Scalar, 0) }
|
29
|
+
it { is_tagged_as(Enumeration, 1) }
|
30
|
+
it { is_tagged_as(Composite, 2) }
|
31
|
+
it { is_tagged_as(FixedArray, 3) }
|
32
|
+
it { is_tagged_as(VariableArray, 4) }
|
33
|
+
it { is_tagged_as(Group, 5) }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe :next_id do
|
37
|
+
it "is an incrementing value starting at 0" do
|
38
|
+
# the .new consumes the 0.
|
39
|
+
BaseType.new(:foo).instance_exec do
|
40
|
+
next_id.should == 1
|
41
|
+
next_id.should == 2
|
42
|
+
next_id.should == 3
|
43
|
+
next_id.should == 4
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should not allow derived class ids to interact" do
|
48
|
+
a1 = Scalar.new(:foo)
|
49
|
+
a2 = Scalar.new(:bar)
|
50
|
+
e1 = Enumeration.new(:zoop)
|
51
|
+
e2 = Enumeration.new(:nih)
|
52
|
+
|
53
|
+
a1.id.should == 0
|
54
|
+
a2.id.should == 1
|
55
|
+
e1.id.should == 0
|
56
|
+
e2.id.should == 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "bit stuff" do
|
61
|
+
it "is consistent" do
|
62
|
+
BaseType.class_exec do
|
63
|
+
(tag_bit_width + id_bit_width).should == type_bit_width
|
64
|
+
(tag_bit_mask >> id_bit_width).should == 0x7
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe :register_instance do
|
70
|
+
it "adds an instance to the instance list" do
|
71
|
+
class X < BaseType
|
72
|
+
def initialize(name); end
|
73
|
+
end
|
74
|
+
x = X.new(:foo)
|
75
|
+
|
76
|
+
x.instance_exec do
|
77
|
+
register_instance(x)
|
78
|
+
end
|
79
|
+
|
80
|
+
BaseType.all_instances[0].should be x
|
81
|
+
BaseType.all_instances.length.should == 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe :instances do
|
86
|
+
# Two things are being tested here.
|
87
|
+
# 1. That instances works.
|
88
|
+
# 2. That super() is called in each .new
|
89
|
+
it "is every instance of a BaseType-derived class" do
|
90
|
+
BaseType.all_instances.should == []
|
91
|
+
|
92
|
+
a = Scalar.new(:foo)
|
93
|
+
e = Enumeration.new(:emoo)
|
94
|
+
c = Composite.new(:cooo)
|
95
|
+
f = FixedArray.new(:moo)
|
96
|
+
v = VariableArray.new(:quack)
|
97
|
+
g = Group.new(:goo)
|
98
|
+
|
99
|
+
lst = [a, e, c, f, v, g]
|
100
|
+
|
101
|
+
instances = BaseType.all_instances
|
102
|
+
instances.length.should == lst.length + 1 # +1 because groups make an enum as well
|
103
|
+
|
104
|
+
# Check that each of our instances shows up in the list returned from
|
105
|
+
# all_instances. Do it this way in case there are other types created
|
106
|
+
# (like the enumeration for Group).
|
107
|
+
lst.all? do |l|
|
108
|
+
instances.any? {|i| i.equal? l}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe :find_type do
|
114
|
+
it "returns the instance with the provided name" do
|
115
|
+
f = scalar(:foo)
|
116
|
+
b = scalar(:bar)
|
117
|
+
|
118
|
+
BaseType.find_type(:bar).should be b
|
119
|
+
BaseType.find_type(:foo).should be f
|
120
|
+
end
|
121
|
+
|
122
|
+
it "is nil on an unknown name" do
|
123
|
+
BaseType.find_type(:xxxxxxxxxxxxxxxxxx).should be_nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe :find_type! do
|
128
|
+
it "returns the instance with the provided name" do
|
129
|
+
f = scalar(:foo)
|
130
|
+
b = scalar(:bar)
|
131
|
+
|
132
|
+
BaseType.find_type!(:bar).should be b
|
133
|
+
BaseType.find_type!(:foo).should be f
|
134
|
+
end
|
135
|
+
|
136
|
+
it "errors on an unknown name" do
|
137
|
+
lambda { BaseType.find_type!(:foo) }.should raise_error /name foo does not/
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "is_[type]?" do
|
142
|
+
it "supports scalar" do
|
143
|
+
scalar(:foo).is_scalar?.should be_true
|
144
|
+
end
|
145
|
+
|
146
|
+
it "supports enumeration" do
|
147
|
+
enumeration(:foo).is_enumeration?.should be_true
|
148
|
+
end
|
149
|
+
|
150
|
+
it "supports composite" do
|
151
|
+
composite(:foo).is_composite?.should be_true
|
152
|
+
end
|
153
|
+
|
154
|
+
it "supports fixed_array" do
|
155
|
+
fixed_array(:foo).is_fixed_array?.should be_true
|
156
|
+
end
|
157
|
+
|
158
|
+
it "supports variable_array" do
|
159
|
+
variable_array(:foo).is_variable_array?.should be_true
|
160
|
+
end
|
161
|
+
|
162
|
+
it "supports group" do
|
163
|
+
group(:foo).is_group?.should be_true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|