cauterize 0.0.1.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|