rbplusplus 0.8 → 0.9

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 (80) hide show
  1. data/Rakefile +13 -13
  2. data/TODO +9 -41
  3. data/lib/rbplusplus/builders/allocation_strategy.rb +57 -0
  4. data/lib/rbplusplus/builders/base.rb +115 -212
  5. data/lib/rbplusplus/builders/class.rb +129 -115
  6. data/lib/rbplusplus/builders/const.rb +30 -0
  7. data/lib/rbplusplus/builders/const_converter.rb +52 -0
  8. data/lib/rbplusplus/builders/constructor.rb +19 -0
  9. data/lib/rbplusplus/builders/director.rb +149 -0
  10. data/lib/rbplusplus/builders/director_method.rb +20 -0
  11. data/lib/rbplusplus/builders/enumeration.rb +19 -26
  12. data/lib/rbplusplus/builders/extension.rb +42 -54
  13. data/lib/rbplusplus/builders/global_function.rb +18 -0
  14. data/lib/rbplusplus/builders/helpers/class.rb +74 -0
  15. data/lib/rbplusplus/builders/helpers/enumeration.rb +28 -0
  16. data/lib/rbplusplus/builders/helpers/module.rb +22 -0
  17. data/lib/rbplusplus/builders/include.rb +32 -0
  18. data/lib/rbplusplus/builders/instance_variable.rb +36 -0
  19. data/lib/rbplusplus/builders/method.rb +14 -0
  20. data/lib/rbplusplus/builders/method_base.rb +136 -0
  21. data/lib/rbplusplus/builders/module.rb +37 -51
  22. data/lib/rbplusplus/builders/module_function.rb +16 -0
  23. data/lib/rbplusplus/builders/static_method.rb +14 -0
  24. data/lib/rbplusplus/extension.rb +140 -28
  25. data/lib/rbplusplus/logger.rb +45 -0
  26. data/lib/rbplusplus/module.rb +55 -1
  27. data/lib/rbplusplus/transformers/class.rb +116 -35
  28. data/lib/rbplusplus/transformers/function.rb +14 -16
  29. data/lib/rbplusplus/transformers/method.rb +26 -1
  30. data/lib/rbplusplus/transformers/namespace.rb +12 -0
  31. data/lib/rbplusplus/transformers/node.rb +47 -54
  32. data/lib/rbplusplus/transformers/node_cache.rb +5 -9
  33. data/lib/rbplusplus/writers/multiple_files_writer.rb +290 -88
  34. data/lib/rbplusplus/writers/single_file_writer.rb +36 -14
  35. data/lib/rbplusplus.rb +44 -18
  36. data/test/allocation_strategies_test.rb +33 -0
  37. data/test/class_methods_encapsulate_test.rb +59 -0
  38. data/test/class_methods_test.rb +2 -35
  39. data/test/classes_test.rb +72 -2
  40. data/test/compiling_test.rb +13 -0
  41. data/test/constructors_test.rb +9 -18
  42. data/test/custom_code_test.rb +53 -0
  43. data/test/default_arguments_test.rb +69 -0
  44. data/test/director_test.rb +173 -0
  45. data/test/enumerations_test.rb +29 -0
  46. data/test/extension_test.rb +7 -2
  47. data/test/file_writers_test.rb +11 -4
  48. data/test/function_pointer_test.rb +56 -0
  49. data/test/function_pointers_classes_test.rb +27 -0
  50. data/test/generated/extconf.rb +2 -2
  51. data/test/headers/Adder.cpp +8 -0
  52. data/test/headers/Adder.h +31 -1
  53. data/test/headers/alloc_strats.h +26 -0
  54. data/test/headers/class_methods.h +30 -0
  55. data/test/headers/code/custom_to_from_ruby.cpp +11 -0
  56. data/test/headers/code/custom_to_from_ruby.hpp +13 -0
  57. data/test/headers/constructors.h +8 -20
  58. data/test/headers/default_arguments.h +49 -0
  59. data/test/headers/director.h +148 -0
  60. data/test/headers/enums.h +33 -0
  61. data/test/headers/function_pointers.h +32 -0
  62. data/test/headers/function_pointers_class.h +26 -0
  63. data/test/headers/needs_code.h +10 -0
  64. data/test/headers/overload.h +0 -3
  65. data/test/headers/subclass.h +10 -0
  66. data/test/headers/to_from_ruby.h +6 -4
  67. data/test/headers/ugly_interface.h +4 -7
  68. data/test/modules_test.rb +11 -6
  69. data/test/overloading_test.rb +6 -2
  70. data/test/subclass_test.rb +20 -10
  71. data/test/test_helper.rb +6 -1
  72. data/test/to_from_ruby_test.rb +0 -2
  73. data/test/wrap_as_test.rb +28 -37
  74. metadata +89 -57
  75. data/lib/rbplusplus/builders/types_manager.rb +0 -93
  76. data/lib/rbplusplus/transformers/constructor.rb +0 -4
  77. data/lib/rbplusplus/transformers/module.rb +0 -71
  78. data/lib/rbplusplus/transformers/node_reference.rb +0 -30
  79. data/test/headers/ugly_helper.h +0 -18
  80. data/test/object_persistence_test.rb +0 -44
@@ -1,77 +1,70 @@
1
1
  module RbGCCXML
2
- class Node
3
- # Specifies to not export this node
2
+ class Node
3
+
4
+ # Specify to Rb++ that this node is not to be wrapped
4
5
  def ignore
5
- @ignored = true
6
+ cache[:ignored] = true
7
+ end
8
+
9
+ # Un-ignore this node, useful if there's a glob ignore and the wrapper
10
+ # just wants a few of the classes
11
+ def unignore
12
+ cache[:ignored] = false
6
13
  end
7
-
8
- # Returns true if this node is ignored in exporting
14
+
15
+ # Has this node been previously declared to not be wrapped?
9
16
  def ignored?
10
- @ignored || false
17
+ !!cache[:ignored]
11
18
  end
12
19
 
13
20
  # Specifies that this node has been included somewhere else
14
- def moved=(val)
15
- @moved = val
21
+ def moved_to=(val)
22
+ cache[:moved_to] = val
16
23
  end
17
-
24
+
18
25
  # Change what the name of this node will be when wrapped into Ruby
19
26
  def wrap_as(name)
20
- @renamed = name
27
+ cache[:wrap_as] = name
21
28
  self
22
29
  end
23
-
24
- # Returns true if the node has been moved
25
- def moved?
26
- @moved || false
30
+
31
+ # Where has this node moved to?
32
+ def moved_to
33
+ cache[:moved_to]
27
34
  end
28
-
35
+
29
36
  # Has this node been renamed
30
37
  def renamed?
31
- (@renamed.nil? ? false : true)
38
+ !!cache[:wrap_as]
32
39
  end
33
40
 
34
- alias_method :rbgccxml_namespaces, :namespaces
35
- def namespaces(*args) #:nodoc:
36
- nodes = rbgccxml_namespaces(*args)
37
- return cache(nodes)
41
+ alias_method :rbgccxml_name, :name
42
+ def name #:nodoc:
43
+ cache[:wrap_as] || rbgccxml_name
38
44
  end
39
-
40
- alias_method :rbgccxml_classes, :classes
41
- def classes(*args) #:nodoc:
42
- nodes = rbgccxml_classes(*args)
43
- return cache(nodes)
45
+
46
+ def cpp_name
47
+ rbgccxml_name
44
48
  end
45
-
46
- alias_method :rbgccxml_functions, :functions
47
- def functions(*args) #:nodoc:
48
- nodes = rbgccxml_functions(*args)
49
- return cache(nodes)
49
+
50
+ # In some cases, the automatic typedef lookup of rb++ can end up
51
+ # doing the wrong thing (for example, it can take a normal class
52
+ # and end up using the typedef for stl::container<>::value_type).
53
+ # Flag a given class as ignoring this typedef lookup if this
54
+ # situation happens.
55
+ def disable_typedef_lookup
56
+ cache[:disable_typedef_lookup] = true
50
57
  end
51
-
52
- alias_method :rbgccxml_methods, :functions
53
- def methods(*args) #:nodoc:
54
- nodes = rbgccxml_methods(*args)
55
- return cache(nodes)
56
- end
57
-
58
- alias_method :rbgccxml_name, :name
59
- def name #:nodoc:
60
- @renamed || rbgccxml_name
58
+
59
+ def _disable_typedef_lookup? #:nodoc:
60
+ !!cache[:disable_typedef_lookup]
61
61
  end
62
-
63
- private
64
- # Looks up the objects in the node cache.
65
- def cache(nodes)
66
- if nodes.is_a?(QueryResult)
67
- retv = QueryResult.new
68
- nodes.each do |node|
69
- retv << RbPlusPlus::NodeCache.instance.get(node)
70
- end
71
- return retv
72
- else
73
- return RbPlusPlus::NodeCache.instance.get(nodes)
74
- end
62
+
63
+ protected
64
+
65
+ # Get this node's settings cache
66
+ def cache
67
+ NodeCache.get(self)
75
68
  end
76
- end
69
+ end
77
70
  end
@@ -1,18 +1,14 @@
1
1
  module RbPlusPlus
2
2
  class NodeCache #:nodoc:
3
- include Singleton
4
- # Retrieves a node from the cache based on the node's qualified name
5
- def get(node)
6
- demangled = node.attributes['demangled']
3
+ # Retrieves or initializes a node's information cache
4
+ def self.get(node)
5
+ demangled = node.attributes['id']
7
6
  @@nodes ||= {}
8
- if @@nodes[demangled].nil?
9
- @@nodes[demangled] = node
10
- end
11
- return @@nodes[demangled]
7
+ @@nodes[demangled] ||= {}
12
8
  end
13
9
 
14
10
  # Clears out the cache
15
- def clear
11
+ def self.clear
16
12
  @@nodes = {}
17
13
  end
18
14
  end
@@ -4,120 +4,322 @@ module RbPlusPlus
4
4
  # multiple files.
5
5
  class MultipleFilesWriter < Base
6
6
 
7
+ # Writing out a multiple-file built is a multi-stage process. This writer
8
+ # first builds a [working_dir]/.build directory, where new code initially goes.
9
+ # Once the writing is complete, each file in .build/ is diff-checked by the files
10
+ # in [working_dir]. If the files are different, the new file is copied into place.
11
+ # Then, the .build dir is removed.
12
+ #
13
+ # We do this to allow for easy and quick-ish work on large wrapping projects. Because
14
+ # Rice code takes so long to compile, the fewer files one has to compile per change
15
+ # the better.
7
16
  def write
8
- @to_from_include = ""
9
- write_to_from_ruby
10
- _write_node(builder)
17
+ build_working_dir
18
+ write_files
19
+ process_diffs
20
+ cleanup
21
+ end
22
+
23
+ private
24
+
25
+ def build_working_dir
26
+ @build_dir = File.join(working_dir, ".build")
27
+
28
+ # Build our temp dir
29
+ FileUtils.mkdir_p @build_dir
30
+ end
31
+
32
+ # Go through each file in @build_dir and check them against
33
+ # the files in @working_dir, copying over only the ones
34
+ # that differ
35
+ def process_diffs
36
+ Dir["#{@build_dir}/*.{cpp,hpp}"].each do |file|
37
+ FileUtils.cp file, working_dir if files_differ(file)
38
+ end
39
+ end
40
+
41
+ def files_differ(file)
42
+ filename = File.basename(file)
43
+ existing = File.expand_path(File.join(working_dir, filename))
44
+ new = File.expand_path(File.join(@build_dir, filename))
45
+ return true if !File.exists?(existing)
46
+
47
+ !system("diff #{existing} #{new} > #{@build_dir}/diff_info 2>&1")
11
48
  end
12
49
 
13
- # Write out files that include the auto-generated to_/from_ruby constructs.
14
- def write_to_from_ruby
15
- # Ignore this if there's nothing to write out
16
- return if Builders::TypesManager.body.length == 0
50
+ def cleanup
51
+ FileUtils.rm_rf @build_dir
52
+ end
53
+
54
+ # Given our builder, go through nodes and write out files
55
+ def write_files
56
+ # Couple of steps here:
57
+ # - Split up the code into files according to Modules and Classes
58
+ # - Header files need a register_#{name} prototype, source needs
59
+ # register_#{name}(#{parent}) method definition
60
+ # - All includes for this node go in the header.
61
+ # - Source gets an include for the related header
62
+ # - Save up all data from global_children and at the end write out
63
+ # our rbpp_custom files, making sure all header files include
64
+ # rbpp_custom.hpp
65
+
66
+ @file_writers = []
67
+ @global_writer = RbppCustomFileWriter.new
68
+ @globals_handled = []
17
69
 
18
- hpp_file = File.join(working_dir, "_to_from_ruby.rb.hpp")
19
- cpp_file = File.join(working_dir, "_to_from_ruby.rb.cpp")
70
+ new_file_for(self.builder)
71
+ process_globals(self.builder)
20
72
 
21
- @to_from_include = "#include \"#{hpp_file}\""
73
+ @global_writer.with_includes(self.builder.additional_includes)
74
+ @global_writer.write(@build_dir)
22
75
 
23
- include_guard = "__RICE_GENERATED_TO_FROM_RUBY_HPP__"
76
+ # Write out from the bottom up, makes sure that children file writers
77
+ # update their parents as needed
78
+ @file_writers.each do |fw|
79
+ fw.write(@build_dir)
80
+ end
81
+ end
24
82
 
25
- File.open(hpp_file, "w+") do |f|
26
- f.puts "#ifndef #{include_guard}"
27
- f.puts "#define #{include_guard}"
28
- f.puts ""
29
- f.puts Builders::TypesManager.includes.uniq.join("\n")
30
- f.puts ""
31
- f.puts Builders::TypesManager.prototypes.join("\n")
32
- f.puts ""
33
- f.puts "#endif // #{include_guard}"
83
+ def process_globals(node)
84
+ # Process the globals
85
+ node.global_nodes.each do |g|
86
+ next if @globals_handled.include?(g.qualified_name)
87
+ @globals_handled << g.qualified_name
88
+ @global_writer << g
34
89
  end
35
90
 
36
- File.open(cpp_file, "w+") do |f|
37
- f.puts @to_from_include
38
- f.puts ""
39
- f.puts Builders::TypesManager.body.join("\n");
91
+ node.nodes.each do |b|
92
+ process_globals(b)
40
93
  end
41
94
  end
42
95
 
43
- # How this works:
44
- #
45
- # We'll recurse through the builder heirarchy, starting at the bottom.
46
- # This lets us to properly link up each file so that all classes / modules /
47
- # functions get properly exposed.
48
- def _write_node(node)
49
- node.builders.each do |b|
50
- _write_node(b)
51
- end
52
-
53
- filename = if node.parent
54
- "_"+node.qualified_name.gsub(/::/, "_")
55
- else
56
- node.name
57
- end
58
-
59
- #templated classes
60
- filename.gsub!(/[ ,<>]/,"_")
61
- #templates to pointers
62
- filename.gsub!("*","Ptr")
63
-
64
- cpp_file = File.join(working_dir, "#{filename}.rb.cpp")
65
-
66
- if node.parent
67
- hpp_file = File.join(working_dir, "#{filename}.rb.hpp")
68
- hpp_include = "#include \"#{hpp_file}\""
69
- register_func = "register_#{filename}"
70
-
71
- include_guard = "__RICE_GENERATED_#{filename}_HPP__"
72
-
73
- register_func_arg = ""
74
- register_func_prototype = ""
75
-
76
- if !node.parent.is_a?(Builders::ExtensionBuilder)
77
- register_func_arg = node.parent.rice_variable
78
- register_func_prototype = "#{node.parent.rice_variable_type} #{register_func_arg}"
96
+ def new_file_for(node, parent = nil)
97
+ file_writer = FileWriter.new(node, parent)
98
+ @file_writers << file_writer
99
+
100
+ process_file(file_writer, node)
101
+ end
102
+
103
+ # Recursively run through this node's children
104
+ # adding them to the given file_writer or spawning
105
+ # off another file writer depending on the type
106
+ # of node we hit
107
+ def process_file(file_writer, node)
108
+ node.nodes.each do |child|
109
+ if child.is_a?(Builders::ModuleNode) || child.is_a?(Builders::ClassNode)
110
+ new_file_for(child, file_writer)
111
+ else
112
+ file_writer << child
113
+ process_file(file_writer, child) if child.has_children?
79
114
  end
115
+ end
116
+ end
117
+
118
+ # For every file to write out, we build an instance of a FileWriter here.
119
+ # This class needs to be given all the nodes it will be writing out to a file
120
+ #
121
+ # To handle parents calling register_#{name}() on their children, it's up to the
122
+ # children writers to inform the parents of their existence
123
+ class FileWriter
124
+
125
+ attr_reader :base_name, :node
126
+
127
+ def initialize(node, parent)
128
+ @node = node
129
+ @base_name = node.qualified_name.as_variable
130
+
131
+ @header = parent ? "_#{@base_name}.rb.hpp" : nil
132
+ @source = parent ? "_#{@base_name}.rb.cpp" : "#{@base_name}.rb.cpp"
133
+ @parent = parent
134
+
135
+ @require_custom = false
136
+
137
+ @needs_closing = true
138
+
139
+ register_with_parent if @parent
140
+
141
+ @nodes = [@node]
142
+ end
143
+
144
+ # Add a node to this file writer
145
+ def <<(node)
146
+ @nodes << node
147
+ end
148
+
149
+ def write(build_dir)
150
+ @build_dir = build_dir
151
+
152
+ build_source
153
+ write_header if @header
154
+ write_source
155
+ end
156
+
157
+ def rice_type
158
+ @node.rice_variable_type
159
+ end
160
+
161
+ def rice_variable
162
+ @node.rice_variable
163
+ end
164
+
165
+ def has_rice_variable?
166
+ !@node.rice_variable.nil?
167
+ end
80
168
 
81
- # Changes we need to make to the parent for everything to work across multiple
82
- # files
83
- #
84
- # * Add an include to the hpp file
85
- # * Add a call to the register method
86
- node.parent.includes << hpp_include
169
+ def add_register_method(node_name, header)
170
+ @register_methods ||= []
171
+ @register_includes ||= []
87
172
 
88
- # Register for proper flattening of the inheritance tree
89
- node.parent.register_node(node, "#{register_func}(#{register_func_arg});")
173
+ @register_includes << "#include \"#{header}\""
174
+ @register_methods << "register_#{node_name}(#{has_rice_variable? ? self.rice_variable : ""});"
175
+ end
176
+
177
+ protected
178
+
179
+ def register_with_parent
180
+ @register_method = "void register_#{@base_name}"
181
+ @parent.add_register_method @base_name, @header
182
+ end
183
+
184
+ def build_source
185
+ @includes = []
186
+ @declarations = []
187
+ @registrations = []
188
+
189
+ @nodes.each do |node|
190
+ node.write
191
+ @includes << node.includes
192
+ @declarations << node.declarations
193
+ @registrations << node.registrations
194
+ end
195
+ end
196
+
197
+ def parent_signature
198
+ if @parent && @parent.has_rice_variable?
199
+ "#{@parent.rice_type} #{@parent.rice_variable}"
200
+ else
201
+ ""
202
+ end
203
+ end
90
204
 
91
- # Modifications to this current node's code:
92
- #
93
- # * Add a register prototype to the header file
94
- # * Set include in node to the header file
95
- # * Wrap the body in a register method
205
+ def write_header
206
+ include_guard = "__RICE_GENERATED_#{@base_name}_HPP__"
96
207
 
97
- File.open(hpp_file, "w+") do |hpp|
208
+ File.open(File.join(@build_dir, @header), "w+") do |hpp|
98
209
  hpp.puts "#ifndef #{include_guard}"
99
210
  hpp.puts "#define #{include_guard}"
100
- hpp.puts ""
101
- hpp.puts @to_from_include
102
- hpp.puts ""
103
- hpp.puts "void #{register_func}(#{register_func_prototype});"
104
- hpp.puts "#endif"
105
- end
211
+ hpp.puts
212
+
213
+ custom_name = "_rbpp_custom.rb.hpp"
214
+ hpp.puts "#include \"#{custom_name}\"" if File.exists?(File.join(@build_dir, custom_name))
106
215
 
107
- node.includes << hpp_include
216
+ if @register_method
217
+ hpp.puts "#{@register_method}(#{parent_signature});"
218
+ end
108
219
 
109
- node.body = [
110
- "void #{register_func}(#{register_func_prototype}) {",
111
- node.body,
112
- "}"
113
- ]
220
+ hpp.puts
221
+ hpp.puts "#endif // #{include_guard}"
222
+ end
114
223
  end
115
224
 
116
- File.open(cpp_file, "w+") do |cpp|
117
- cpp.puts node.to_s
225
+ def write_source
226
+ File.open(File.join(@build_dir, @source), "w+") do |cpp|
227
+ if (incls = @includes.flatten.compact).any?
228
+ cpp.puts "", incls.uniq.sort.reverse.join("\n"), ""
229
+ end
230
+
231
+ if @register_method
232
+ cpp.puts "", "#include \"#{@header}\"", ""
233
+ end
234
+
235
+ if @require_custom
236
+ custom_name = "_rbpp_custom.rb.hpp"
237
+ cpp.puts "#include \"#{custom_name}\"" if File.exists?(File.join(@build_dir, custom_name))
238
+ end
239
+
240
+ if @register_includes
241
+ @register_includes.each do |i|
242
+ cpp.puts i
243
+ end
244
+ end
245
+
246
+ if (decls = @declarations.flatten.compact).any?
247
+ cpp.puts "", decls.join("\n"), ""
248
+ end
249
+
250
+ if @register_method
251
+ cpp.puts "#{@register_method}(#{parent_signature}) {"
252
+ end
253
+
254
+ if (regs = @registrations.flatten.compact).any?
255
+ cpp.puts regs.join("\n")
256
+ end
257
+
258
+ if @register_methods
259
+ @register_methods.each do |m|
260
+ cpp.puts m
261
+ end
262
+ end
263
+
264
+ # I really need a better way of handling this
265
+ if @needs_closing
266
+ cpp.puts "}"
267
+ end
268
+ end
118
269
  end
270
+
119
271
  end
120
272
 
273
+ class RbppCustomFileWriter < FileWriter
274
+
275
+ def initialize
276
+ @base_name = "rbpp_custom"
277
+ @header = "_#{@base_name}.rb.hpp"
278
+ @source = "_#{@base_name}.rb.cpp"
279
+ @nodes = []
280
+ @needs_closing = false
281
+ @additional_includes = []
282
+ @require_custom = true
283
+ end
284
+
285
+ def with_includes(includes)
286
+ @additional_includes =
287
+ includes.flatten.inject([]) do |memo, incl|
288
+ memo << "#include \"#{incl}\""; memo
289
+ end
290
+ end
291
+
292
+ protected
293
+
294
+ def write_header
295
+ return unless @registrations.flatten.compact.any?
296
+
297
+ include_guard = "__RICE_GENERATED_#{@base_name}_HPP__"
298
+
299
+ File.open(File.join(@build_dir, @header), "w+") do |hpp|
300
+ hpp.puts "#ifndef #{include_guard}"
301
+ hpp.puts "#define #{include_guard}"
302
+
303
+ if (incls = [@includes, @additional_includes].flatten.compact).any?
304
+ hpp.puts "", incls.uniq.sort.reverse.join("\n"), ""
305
+ end
306
+
307
+ if (decls = @declarations.flatten.compact).any?
308
+ hpp.puts "", decls.join("\n"), ""
309
+ end
310
+ hpp.puts
311
+ hpp.puts "#endif // #{include_guard}"
312
+ end
313
+
314
+ @declarations = []
315
+ @includes = []
316
+ end
317
+
318
+ def write_source
319
+ super if @registrations.flatten.compact.any?
320
+ end
321
+
322
+ end
121
323
 
122
324
  end
123
325
  end
@@ -4,37 +4,59 @@ module RbPlusPlus
4
4
  # one single file
5
5
  class SingleFileWriter < Base
6
6
 
7
+ def initialize(builder, working_dir)
8
+ super
9
+
10
+ @includes = []
11
+ @declarations = []
12
+ @registrations = []
13
+
14
+ # Keep track of the code generated by the global nodes
15
+ @global_hpp = []
16
+ @global_cpp = []
17
+ end
18
+
7
19
  def write
8
20
  process_code(builder)
9
21
 
10
- if Builders::TypesManager.body.length > 0
11
- # Handle to_from_ruby constructions
12
- builder.declarations << Builders::TypesManager.body
13
- end
14
-
15
22
  filename = builder.name
16
23
  cpp_file = File.join(working_dir, "#{filename}.rb.cpp")
17
24
 
18
25
  File.open(cpp_file, "w+") do |cpp|
19
- cpp.puts builder.to_s
26
+
27
+ cpp.puts @includes.flatten.compact.uniq.sort.reverse.join("\n")
28
+ cpp.puts @global_hpp.flatten.compact.join("\n")
29
+ cpp.puts @declarations.flatten.compact.join("\n")
30
+ cpp.puts @global_cpp.flatten.compact.join("\n")
31
+ cpp.puts @registrations.flatten.compact.join("\n")
32
+ cpp.puts "}" # Yeah, need to figure this one out
33
+
20
34
  end
21
35
  end
22
36
 
23
37
  protected
24
38
 
25
39
  # What we do here is to go through the builder heirarchy
26
- # and push all the code from children up to the parent,
40
+ # and push all the code from children up to the parent,
27
41
  # ending up with all the code in the top-level builder
28
42
  def process_code(builder)
29
- builder.builders.each do |b|
30
- process_code(b)
31
- end
43
+ builder.write
32
44
 
33
- return unless builder.parent
45
+ @includes << builder.includes
46
+ @declarations << builder.declarations
47
+ @registrations << builder.registrations
34
48
 
35
- builder.parent.includes << builder.includes
36
- builder.parent.body << builder.body
37
- builder.parent.declarations << builder.declarations
49
+ # Process the globals
50
+ builder.global_nodes.each do |g|
51
+ g.write
52
+ @includes << g.includes
53
+ @global_hpp << g.declarations
54
+ @global_cpp << g.registrations
55
+ end
56
+
57
+ builder.nodes.each do |b|
58
+ process_code(b)
59
+ end
38
60
  end
39
61
 
40
62
  end