cgen 0.16.0

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 (52) hide show
  1. data/.gitignore +5 -0
  2. data/History.txt +199 -0
  3. data/README.txt +34 -0
  4. data/examples/bench.rb +14 -0
  5. data/examples/complex.rb +63 -0
  6. data/examples/complex2.rb +48 -0
  7. data/examples/cshadow-example.rb +55 -0
  8. data/examples/cshadow-point.rb +58 -0
  9. data/examples/ctest.rb +34 -0
  10. data/examples/ctest2.rb +32 -0
  11. data/examples/ctest3.rb +179 -0
  12. data/examples/ctest4.rb +18 -0
  13. data/examples/ctest5.rb +27 -0
  14. data/examples/example-ruby-talk-30April2004.rb +65 -0
  15. data/examples/fixed-array.rb +221 -0
  16. data/examples/inherit-example.rb +26 -0
  17. data/examples/inherit-example.txt +80 -0
  18. data/examples/instance-eval.rb +66 -0
  19. data/examples/ivset.rb +55 -0
  20. data/examples/marshal-test.rb +19 -0
  21. data/examples/matrix.rb +91 -0
  22. data/examples/modular-def.rb +87 -0
  23. data/examples/objattr.rb +46 -0
  24. data/examples/opaque-struct-test.rb +36 -0
  25. data/examples/sample.rb +184 -0
  26. data/examples/struct.rb +103 -0
  27. data/examples/test.rb +24 -0
  28. data/examples/yaml.rb +56 -0
  29. data/install.rb +1015 -0
  30. data/lib/cgen/attribute.rb +414 -0
  31. data/lib/cgen/cgen.rb +2041 -0
  32. data/lib/cgen/cshadow.rb +1037 -0
  33. data/lib/cgen/inherit.rb +46 -0
  34. data/rakefile +42 -0
  35. data/tasks/ann.rake +80 -0
  36. data/tasks/bones.rake +20 -0
  37. data/tasks/gem.rake +201 -0
  38. data/tasks/git.rake +40 -0
  39. data/tasks/notes.rake +27 -0
  40. data/tasks/post_load.rake +34 -0
  41. data/tasks/rdoc.rake +51 -0
  42. data/tasks/rubyforge.rake +55 -0
  43. data/tasks/setup.rb +292 -0
  44. data/tasks/spec.rake +54 -0
  45. data/tasks/svn.rake +47 -0
  46. data/tasks/test.rake +40 -0
  47. data/tasks/zentest.rake +36 -0
  48. data/test/test-attribute.rb +430 -0
  49. data/test/test-cgen.rb +127 -0
  50. data/test/test-cshadow.rb +289 -0
  51. data/test/test.rb +17 -0
  52. metadata +123 -0
@@ -0,0 +1,414 @@
1
+ module CShadow
2
+
3
+ AttributeTypes = []
4
+
5
+ # This is the base class for all plug-in attribute classes used with the
6
+ # CShadow module. Each subclass provides information which CShadow uses to
7
+ # manage some of the housekeeping for the attribute:
8
+ #
9
+ # * declaration of the attribute in the shadow struct,
10
+ #
11
+ # * accessor code (which CShadow wraps in methods),
12
+ #
13
+ # * type conversion for the write accessor,
14
+ #
15
+ # * type checking for the write accessor,
16
+ #
17
+ # * the 'mark' function, if the attribute refers to Ruby objects,
18
+ #
19
+ # * the 'free' function, if the attribute refers to C data,
20
+ #
21
+ # * initialization (usually, this is left to the class's #initialize method),
22
+ #
23
+ # * serialization methods for the attribute.(*)
24
+ #
25
+ # (*) For Ruby versions before 1.7, requires a patch using the marshal.patch
26
+ # file (the patch is explained in marshal.txt).
27
+ #
28
+ # The subclass hierarchy has two branches: ObjectAttribute and
29
+ # CNativeAttribute. The former is a reference to a Ruby object (in other
30
+ # words, a struct member of type +VALUE+. The latter has subclasses for
31
+ # various C data types, such as +double+ and <tt>char *</tt>.
32
+ #
33
+ # ==Adding new attribute classes
34
+ #
35
+ # Each attribute class must define a class method called 'match' which returns
36
+ # true if the right hand side of the ':name => ...' expression is recognized
37
+ # as defining an attribute of the class. The class should have an initialize
38
+ # method to supply custom code for readers, writers, type checking, memory
39
+ # management, and serialization. (If serialization methods are omitted, the
40
+ # attribute will be ignored during +dump+/+load+.) The easiest way is to
41
+ # follow the examples. For many purposes, most of the work can be done by
42
+ # subclassing existing classes.
43
+ #
44
+ # The +dump+ and +load+ methods require a bit of explanation. Each attribute
45
+ # provides code to dump and load itself in a very generic way. The dump code
46
+ # must operate on a ruby array called result. It must push _one_ piece of ruby
47
+ # data (which may itself be an array, hash, etc.) onto this array. Similarly,
48
+ # the load code operates on a ruby array called from_array. It must shift
49
+ # _one_ piece of ruby data from this array. (Probably it would have been more
50
+ # efficient to use LIFO rather than FIFO. Oh, well.)
51
+ #
52
+ # ==To do:
53
+ #
54
+ # * Type checking and conversion should to to_str, to_ary, etc. first if
55
+ # appropriate.
56
+ #
57
+ # * Consider changing '[Foo]' to 'shadow(Foo)' and using [Foo, Bar, Baz],
58
+ # [Foo]*20, and [Foo .. Foo] to signify structs, fixed-length arrays, and
59
+ # var-length arrays of (VALUE *) ?
60
+ #
61
+ # * More attribute classes: floats, unsigned, fixed length arrays, bitfields,
62
+ # etc.
63
+ #
64
+ # * substructs?
65
+ #
66
+ # * Make classes more generic, so that there aren't so many classes. (Factory
67
+ # classes, like ArrayAttribute(PointerAttribute(:char)) ?)
68
+ #
69
+ # * Support for #freeze, #taint, etc.
70
+ #
71
+ # ==Limitations:
72
+ #
73
+ # * IntAttribute: No attempt to handle Bignums.
74
+ #
75
+ class Attribute
76
+
77
+ def Attribute.inherited subclass
78
+ AttributeTypes << subclass
79
+ end
80
+
81
+ def Attribute.match decl
82
+ false
83
+ end
84
+
85
+ attr_reader :var, :cvar, :cdecl,
86
+ :init, :reader, :check, :writer,
87
+ :mark, :free, :dump, :load,
88
+ :persists, :owner_class
89
+
90
+ def initialize owner_class, var, match, persists = true
91
+ @owner_class = owner_class
92
+ @var, @match = var, match
93
+ @persists = persists
94
+ end
95
+
96
+ def inspect
97
+ %{<#{self.class} #{@cvar} => #{@cdecl.inspect}>}
98
+ end
99
+ end
100
+
101
+ # There are two kinds of object attributes. Both refer to Ruby objects and can
102
+ # be typed or untyped. This one is less optimized but cat refer to arbitrary
103
+ # ruby objects.
104
+ #
105
+ # The syntax for adding an object attribute to a class is simple. The
106
+ # following code adds three object attributes, one untyped and two typed:
107
+ #
108
+ # class A
109
+ # include CShadow
110
+ # shadow_attr_accessor :obj => Object, :sym => Symbol, :ary => Array
111
+ # end
112
+ #
113
+ # (See CShadow for variations on #shadow_attr_accessor.)
114
+ #
115
+ # Assignment to +obj+ performs no type checking. Assignment to +sym+ raises a
116
+ # TypeError unless the object assigned is a +Symbol+ or +nil+. Similarly +ary+
117
+ # must always be an +Array+ or +nil+. Type checking always allows +nil+ in
118
+ # addition to the specified type. In each case, the attribute is initialized
119
+ # to +nil+.
120
+ #
121
+ # The referenced Ruby object is marked to protect it from the garbage
122
+ # collector.
123
+ #
124
+ class ObjectAttribute < Attribute
125
+
126
+ def ObjectAttribute.match decl
127
+ decl if decl.is_a? Class
128
+ end
129
+
130
+ def target_class; @class; end
131
+
132
+ def initialize(*args)
133
+ super
134
+ @class = @match
135
+
136
+ @cvar = @var
137
+ @cdecl = "VALUE #{@cvar}; // #{@class}"
138
+
139
+ @init = "shadow->#{@cvar} = Qnil" # otherwise, it's Qfalse == 0
140
+ @reader = "result = shadow->#{@cvar}"
141
+ @writer = "shadow->#{@cvar} = arg"
142
+ @check = @class unless @class == Object
143
+ @mark = "rb_gc_mark(shadow->#{@cvar})"
144
+
145
+ @dump = "rb_ary_push(result, shadow->#{@cvar})"
146
+ @load = "shadow->#{@cvar} = rb_ary_shift(from_array)"
147
+ end
148
+
149
+ def inspect
150
+ %{<#{self.class} #{@cvar} => #{@class.inspect}>}
151
+ end
152
+
153
+ end
154
+
155
+ # There are two kinds of object attributes. Both refer to Ruby objects and can
156
+ # be typed or untyped. This one is a slightly optimized variation that is
157
+ # restricted to references to other shadow objects.
158
+ #
159
+ # ShadowObjectAttribute is a restricted variant of ObjectAttribute in which
160
+ # the object referred to must belong to a class that includes CShadow. The
161
+ # actual pointer is to the shadow struct itself, rather than a +VALUE+. This
162
+ # difference is transparent to Ruby code. The syntax for this variant differs
163
+ # only in the use of brackets around the type. For example, using the class
164
+ # +A+ defined above:
165
+ #
166
+ # class B
167
+ # include CShadow
168
+ # shadow_attr_accessor :a => [A]
169
+ #
170
+ # def initialize
171
+ # self.a = A.new
172
+ # a.sym = :something
173
+ # end
174
+ # end
175
+ #
176
+ # Note that a shadow struct always has a +self+ pointer, so a
177
+ # ShadowObjectAttribute contains essentially the same information as an
178
+ # ObjectAttribute. It is included for situation in which the efficiency of a
179
+ # direct reference to the shadow struct is desirable. Note that only
180
+ # ObjectAttributes can refer to general Ruby objects which may or may not
181
+ # include the CShadow module.
182
+ #
183
+ # The accessors work just as with ObjectAttribute, with type checking
184
+ # performed by the writer. From Ruby, these two kinds of attributes are
185
+ # indistinguishable in all respects except their declaration syntax.
186
+ #
187
+ # The referenced Ruby object is marked to protect it from the garbage
188
+ # collector.
189
+ #
190
+ class ShadowObjectAttribute < Attribute
191
+
192
+ def ShadowObjectAttribute.match decl
193
+ decl[0] if decl.is_a? Array and decl.size == 1 and decl[0].is_a? Class
194
+ end
195
+
196
+ def target_class; @class; end
197
+
198
+ def initialize(*args)
199
+ super
200
+ @class = @match
201
+
202
+ ssn = @class.shadow_struct.name
203
+
204
+ @cvar = @var
205
+ if @class < CShadow
206
+ @cdecl = "struct #{ssn} *#{@cvar}"
207
+ else
208
+ raise ScriptError, "Class #{@class} doesn't include CShadow."
209
+ end
210
+
211
+ @reader = "result = shadow->#{@cvar} ? shadow->#{@cvar}->self : Qnil"
212
+ @writer = %{
213
+ if (arg != Qnil) {
214
+ Data_Get_Struct(arg, #{ssn}, shadow->#{@cvar});
215
+ } else
216
+ shadow->#{@cvar} = 0;
217
+ }
218
+ @check = @class unless @class == Object
219
+ @mark = %{\
220
+ if (shadow->#{@cvar})
221
+ rb_gc_mark(shadow->#{@cvar}->self);\
222
+ }
223
+
224
+ @dump =
225
+ "rb_ary_push(result, shadow->#{@cvar} ? shadow->#{@cvar}->self : 0)"
226
+ @load = %{
227
+ tmp = rb_ary_shift(from_array);
228
+ if (tmp) {
229
+ Data_Get_Struct(tmp, #{ssn}, shadow->#{@cvar});
230
+ } else
231
+ shadow->#{@cvar} = 0;
232
+ }
233
+ end
234
+
235
+ def inspect
236
+ %{<#{self.class} #{@cvar} => [#{@class.inspect}]>}
237
+ end
238
+ end
239
+
240
+ # CNativeAttribute and its subclasses handle all but the two special cases
241
+ # described above. The general form for declarations of such attributes is:
242
+ #
243
+ # shadow_attr_accessor ruby_var => c_declaration
244
+ #
245
+ # where +ruby_var+ is the name (symbol or string) which will access the data
246
+ # from Ruby, and +c_declaration+ is the string used to declare the data. For
247
+ # example:
248
+ #
249
+ # shadow_attr_accessor :x => "double x", :y => "int yyy"
250
+ #
251
+ # Note that the symbol and C identifier need not be the same.
252
+ #
253
+ # Native attributes fall into two categories: those that embed data within the
254
+ # struct, and those that point to a separately allocated block. Embedded
255
+ # attributes are limited in that they are of fixed size. Pointer attributes do
256
+ # not have this limitation. But programmers should be wary of treating them as
257
+ # separate objects: the lifespan of the referenced data block is the same as
258
+ # the lifespan of the Ruby object. If the Ruby object and its shadow are
259
+ # garbage collected while the data is in use, the data will be freed and no
260
+ # longer valid.
261
+ #
262
+ # When using a separately allocated data block, it is a good practice is to
263
+ # use "copy" semantics, so that there can be no other references to the data.
264
+ # See CharPointerAttribute, for example. Reading or writing to such an
265
+ # attribute has copy semantics, in the following sense. On assignment, the
266
+ # Ruby string argument is copied into an allocated block; later references to
267
+ # this attribute generate a new Ruby string which is a copy of that array of
268
+ # char.
269
+ #
270
+ # Some CNativeAttribute classes are included for int, long, double, double *,
271
+ # char *, etc.
272
+ #
273
+ # Uninitialized numeric members are 0. Accessors for uninitialized strings
274
+ # return +nil+.
275
+ #
276
+ class CNativeAttribute < Attribute
277
+
278
+ attr_reader :ctype
279
+
280
+ @pattern = nil
281
+
282
+ def CNativeAttribute.match decl
283
+ if decl.is_a? String and @pattern and @pattern =~ decl
284
+ Regexp.last_match
285
+ else
286
+ false
287
+ end
288
+ end
289
+
290
+ def initialize(*args)
291
+ super
292
+ @cdecl = @match[0]
293
+ @ctype = @match[1]
294
+ @cvar = @match[2]
295
+ end
296
+
297
+ end
298
+
299
+ class IntAttribute < CNativeAttribute
300
+ @pattern = /\A(int)\s+(\w+)\z/
301
+ def initialize(*args)
302
+ super
303
+ @reader = "result = INT2NUM(shadow->#{@cvar})"
304
+ @writer = "shadow->#{@cvar} = NUM2INT(arg)" # type check and conversion
305
+ @dump = "rb_ary_push(result, INT2NUM(shadow->#{@cvar}))"
306
+ @load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2INT(tmp)"
307
+ end
308
+ end
309
+
310
+ # Does not check for overflow.
311
+ class ShortAttribute < IntAttribute
312
+ @pattern = /\A(short)\s+(\w+)\z/
313
+ def initialize(*args)
314
+ super
315
+ @reader = "result = INT2NUM(shadow->#{@cvar})"
316
+ @writer = "shadow->#{@cvar} = NUM2INT(arg)" # type check and conversion
317
+ @dump = "rb_ary_push(result, INT2NUM(shadow->#{@cvar}))"
318
+ @load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2INT(tmp)"
319
+ end
320
+ end
321
+
322
+ class LongAttribute < CNativeAttribute
323
+ @pattern = /\A(long)\s+(\w+)\z/
324
+ def initialize(*args)
325
+ super
326
+ @reader = "result = INT2NUM(shadow->#{@cvar})"
327
+ @writer = "shadow->#{@cvar} = NUM2LONG(arg)" # type check and conversion
328
+ @dump = "rb_ary_push(result, INT2NUM(shadow->#{@cvar}))"
329
+ @load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2LONG(tmp)"
330
+ end
331
+ end
332
+
333
+ class DoubleAttribute < CNativeAttribute
334
+ @pattern = /\A(double)\s+(\w+)\z/
335
+ def initialize(*args)
336
+ super
337
+ @reader = "result = rb_float_new(shadow->#{@cvar})"
338
+ @writer = "shadow->#{@cvar} = NUM2DBL(arg)" # type check and conversion
339
+ @dump = "rb_ary_push(result, rb_float_new(shadow->#{@cvar}))"
340
+ @load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2DBL(tmp)"
341
+ end
342
+ end
343
+
344
+ class PointerAttribute < CNativeAttribute
345
+ @pattern = nil
346
+ def initialize(*args)
347
+ super
348
+ @free = "free(shadow->#{@cvar})"
349
+ end
350
+ end
351
+
352
+ # Stores a null-terminated string
353
+ class CharPointerAttribute < PointerAttribute
354
+ @pattern = /\A(char)\s*\*\s*(\w+)\z/
355
+ def initialize(*args)
356
+ super
357
+ @reader =
358
+ "result = shadow->#{@cvar} ? rb_str_new2(shadow->#{@cvar}) : Qnil"
359
+ @writer = %{
360
+ {
361
+ int len;
362
+ char *str;
363
+
364
+ free(shadow->#{@cvar});
365
+
366
+ if (arg == Qnil)
367
+ shadow->#{@cvar} = 0;
368
+ else {
369
+ StringValueCStr(arg);
370
+ len = RSTRING(arg)->len;
371
+ str = RSTRING(arg)->ptr;
372
+ shadow->#{@cvar} = ALLOC_N(char, len + 1);
373
+
374
+ if (str)
375
+ memcpy(shadow->#{@cvar}, str, len);
376
+
377
+ shadow->#{@cvar}[len] = '\\0';
378
+ }
379
+ }
380
+ }
381
+ @dump = %{
382
+ rb_ary_push(result,
383
+ shadow->#{@cvar} ? rb_str_new2(shadow->#{@cvar}) : 0);
384
+ }
385
+ @load = %{
386
+ {
387
+ VALUE arg = rb_ary_shift(from_array);
388
+ int len;
389
+ char *str;
390
+
391
+ if (arg == Qnil)
392
+ shadow->#{@cvar} = 0;
393
+ else {
394
+ len = RSTRING(arg)->len;
395
+ str = RSTRING(arg)->ptr;
396
+ shadow->#{@cvar} = ALLOC_N(char, len + 1);
397
+
398
+ if (str)
399
+ memcpy(shadow->#{@cvar}, str, len);
400
+
401
+ shadow->#{@cvar}[len] = '\\0';
402
+ }
403
+ }
404
+ }
405
+ end
406
+ end
407
+
408
+ # can be used for variable length arrays--see examples/matrix.rb.
409
+ class DoublePointerAttribute < PointerAttribute
410
+ @pattern = /\A(double)\s*\*\s*(\w+)\z/
411
+ # can't do anything else in general
412
+ end
413
+
414
+ end
@@ -0,0 +1,2041 @@
1
+ require 'rbconfig'
2
+ require 'cgen/inherit'
3
+
4
+ # ==Overview
5
+ #
6
+ # The CGenerator module is a framework for dynamically generating C
7
+ # extensions. It is a bit like Perl's +inline+ but intended for a different
8
+ # purpose: managing incremental, structured additions to C source files, and
9
+ # compiling the code and loading the library just in time for execution. Whereas
10
+ # +inline+ helps you write a C extension, CGenerator helps you write a Ruby
11
+ # program that generates C extensions. To put it another way, this is a Ruby
12
+ # interface to the Ruby C API.
13
+ #
14
+ # The original use of CGenerator was as the back end of a compiler for
15
+ # mathematical expressions in C-like syntax involving limited Ruby
16
+ # subexpressions. In that case, CGenerator allowed the compiler to think
17
+ # about the syntax and semantics of the input expressions without having to
18
+ # worry about the high-level structure of the generated .c and .h files.
19
+ #
20
+ # One potential use is quick-turnaround development and testing of C code,
21
+ # possibly using Ruby as a driver environment; the library under construction
22
+ # needn't be Ruby-specific. If SWIG didn't support Ruby, this framework could be
23
+ # the starting point for a program that generates wrapper code for existing
24
+ # libraries. Finally, a Ruby package that includes C extensions could benefit
25
+ # from being able to use Ruby code to dynamically specify the contents and
26
+ # control the build process during installation.
27
+ #
28
+ # The CGenerator framework consists of two base classes, Accumulator and
29
+ # Template. Think of accumulators as blanks in a form and templates as the form
30
+ # around the blanks, except that accumulators and templates can nest within each
31
+ # other. The base classes have subclasses which hierarchically decompose the
32
+ # information managed by the framework. This hierarchy is achieved by
33
+ # inheritance along the +parent+ attribute, which is secondary to subclass
34
+ # inheritance.
35
+ #
36
+ # ==Templates
37
+ #
38
+ # The main template in the CGenerator module is Library. It has accumulators for
39
+ # such constructs as including header files, declaring variables, declaring Ruby
40
+ # symbols, declaring classes, defining functions, and defining structs. Some
41
+ # accumulators, such as those for adding function and struct definitions, return
42
+ # a new template each time they are called. Those templates, in turn, have their
43
+ # own accumulators for structure members, function arguments, declarations,
44
+ # initialization, scope, etc.
45
+ #
46
+ # ===Library templates
47
+ #
48
+ # A Library corresponds to one main C source file and one shared C library (.so
49
+ # or .dll). It manages the +Init_library+ code (including registration of
50
+ # methods), as well as user-specified declaration and initialization in the
51
+ # scope of the .c file and its corresponding .h file. All files generated in the
52
+ # process of building the library are kept in a directory with the same name as
53
+ # the library. Additional C files in this directory will be compiled and linked
54
+ # to the library.
55
+ #
56
+ # Each library is the root of a template containment hierarchy, and it alone has
57
+ # a #commit method. After client code has sent all desired fragments to the
58
+ # accumulators, calling the commit method uses the structure imposed by the
59
+ # sub-templates of the library to joins the fragments into two strings, one for
60
+ # the .h file and one for the .c file. Then each string is written to the
61
+ # corresponding file (only if the string is different from the current file
62
+ # contents), and the library is compiled (if necessary) and loaded.
63
+ #
64
+ # ===Function templates
65
+ #
66
+ # Function templates are used to define the functions in a Library. The base
67
+ # class, CGenerator::Function, generates a function (by default, static) in the
68
+ # library without registering it with Ruby in any way.
69
+ #
70
+ # The CGenerator::RubyFunction templates define the function as above and also
71
+ # register the function as an instance method, module function, or singleton
72
+ # method of a specified class or module, or as a global function (a private
73
+ # method of +Kernel+).
74
+ #
75
+ # Client code does not instantiate these templates directly, but instead uses
76
+ # the library's #define accumulator methods, which return the new template.
77
+ #
78
+ # The function template for the library's initialization function can be
79
+ # accessed using the library's #init_library_function method, although direct
80
+ # access to this template is typically not needed. (Use the library's #setup
81
+ # method to write code to the #init_library_function.)
82
+ #
83
+ # ===Struct templates
84
+ #
85
+ # A struct template generates a typedef for a C struct. It can be external, in
86
+ # which case it is written to the .h file. It has a #declare accumulator for
87
+ # adding data members.
88
+ #
89
+ # ==Accumulators
90
+ #
91
+ # Accumulators are a way of defining a hierarchical structure and populating it
92
+ # with data in such a way that the data can be serialized to a string at any
93
+ # point during the process without side effects. Templates are Accumulators
94
+ # which contain other accumulators and have convenience methods for accessing
95
+ # them from client code.
96
+ #
97
+ # Accumulators can be fairly unstructured--they just accumulate in sequence
98
+ # whatever is sent to them, possibly with some filtering, which may include
99
+ # other accumulators. Templates are usually more more structured. In general,
100
+ # only Templates can be parents; other accumulators set the #parent of each
101
+ # accumulated item to be the accumulator's #parent, simplifying the #parent
102
+ # hierarchy.
103
+ #
104
+ # Accumulators are responsible for the format of each accumulated item, for
105
+ # joining the items to form a string when requested to do so, and for doing any
106
+ # necessary preprocessing on the items (e.g., discarding duplicates).
107
+ #
108
+ # From the point of view of client code, accumulators are methods for "filling
109
+ # in the blanks" in templates. Client code doesn't access the accumulator object
110
+ # directly, only through a method on the template. For example:
111
+ #
112
+ # lib.declare :global_int_array =>
113
+ # 'int global_int_array[100]',
114
+ # :name =>
115
+ # 'char *name'
116
+ #
117
+ # is used to access the "declare" accumulator of the library (which is actually
118
+ # delegated to a file template).
119
+ #
120
+ # Providing a key for each declaration (in the example, the keys are symbols,
121
+ # but they can be any hash keys) helps CGenerator reject repeated declarations.
122
+ # (Redundancy checking by simple string comparison is inadequate, because it
123
+ # would allow two declarations of different types, but the same name, or two
124
+ # declarations with insignificant whitespace differences.)
125
+ #
126
+ # The basic Accumulator class adds fragments to an array in sequence. When
127
+ # converted to a string with #to_s, it joins the fragments with newline
128
+ # separators. These behaviors change as needed in the subclasses. <b>Note that
129
+ # the accumulated items need not all be strings, they need only respond to
130
+ # +to_s+.</b>
131
+ #
132
+ # Return values of accumulators are not very consistent: in general, an
133
+ # accumulator returns whatever is needed for the caller to continue working with
134
+ # the thing that was just accumulated. It might be a template which supports
135
+ # some other accumulators, or it might be a string which can be inserted in C
136
+ # code.
137
+ #
138
+ # Some accumulators take existing Ruby objects as an argument. These
139
+ # accumulators typically return, as a Ruby symbol, the C identifier that has
140
+ # been defined or declared to refer to that Ruby object. This can be
141
+ # interpolated into C code to refer to the Ruby object from C.
142
+ #
143
+ # <b>Note about argument order:</b> Since hashes are unordered, passing a hash
144
+ # of key-value pairs to #declare or similar methods will not preserve the
145
+ # textual ordering. Internally, cgen sorts this hash into an array of pairs so
146
+ # that at least the result is deterministic, reducing recompilation. One can
147
+ # force an argument order by using an array of pairs.
148
+ #
149
+ # lib.declare [[:global_int_array,
150
+ # 'int global_int_array[100]'],
151
+ # [:name =>
152
+ # 'char *name']
153
+ #
154
+ # Alternately, simply break the declaration into multiple declares.
155
+ #
156
+ # ==C code output
157
+ #
158
+ # ===Format
159
+ #
160
+ # Some effort is made to generate readable code. Relative tabbing within code
161
+ # fragments is preserved. One goal of CGenerator is producing Ruby extensions
162
+ # that can be saved and distributed with little or no modification (as opposed
163
+ # to just created and loaded on the fly).
164
+ #
165
+ # ===Use of C identifiers
166
+ #
167
+ # CGenerator attempts to generate C identifiers in non-conflicting ways...
168
+ # (prove some nice property)
169
+ #
170
+ # ==Usage
171
+ #
172
+ # Create a library with:
173
+ #
174
+ # lib = CGenerator::Library.new "my_lib_name"
175
+ #
176
+ # The name must be an identifier: +/[A-Za-z0-9_]*/+.
177
+ #
178
+ # It is useful to keep a reference to +lib+ around to send define and declare
179
+ # messages to.
180
+ #
181
+ # ===Templates
182
+ #
183
+ # All templates respond to #library and #file methods, which return the library
184
+ # or file object which contains the template. (The library itself does not
185
+ # respond to #file.) They also respond to #name and #parent.
186
+ #
187
+ # ===Library
188
+ #
189
+ # ---Library#use_work_dir dir_name
190
+ #
191
+ # Changes into +dir_name+, creating it first if necessary. Does nothing if
192
+ # alread in a diredctory of that name. Often used with +"tmp"+.
193
+ #
194
+ # ---Library#commit
195
+ #
196
+ # Writes the files to disk, and makes and loads the library.
197
+ #
198
+ # Note that #commit must be called after all C code definitions for the library,
199
+ # but before instantiation of any objects that use those definitions. If a
200
+ # definition occurs after commit, or if instantiation occurs before commit, then
201
+ # a CGenerator::Library::CommitError is raised, with an appropriate message.
202
+ # Sometimes, this forces you to use many small libraries, each committed just in
203
+ # time for use. See examples/fixed-array.rb.
204
+ #
205
+ # ---Library#committed?
206
+ #
207
+ # True if the library has been committed.
208
+ #
209
+ # ---Library#before_commit(&block)
210
+ # ---Library#after_commit(&block)
211
+ #
212
+ # Schedules block to run before or after Library#commit. The before blocks are
213
+ # run in the same order in which they were scheduled; the after blocks run in
214
+ # the reverse order (analogously with +BEGIN+/+END+). Each block is evaluated in
215
+ # the context in which it was created (instance_eval is *not* used), and it is
216
+ # passed the library as an argument.
217
+ #
218
+ # ---Library#empty?
219
+ #
220
+ # True if no content has been added to the library.
221
+ #
222
+ # ---Library#add_file name
223
+ #
224
+ # Creates templates for two files, a source (.c) file and an include (.h) file
225
+ # that will be generated in the same dir as the library. The base file name is
226
+ # taken from the argument. Returns an array containing the include file template
227
+ # and the source file template, in that order.
228
+ #
229
+ # Functions can be added to the source file by calling #define_method and
230
+ # similar methods on the source file template. Their +rb_init+ calls are done in
231
+ # #init_library_function in the main library source file. The new source file
232
+ # automatically #includes the library's main header file, as well as its own
233
+ # header file, and the library's main source file also #includes the new header
234
+ # file. Declarations can be added to the header file by calling #declare on it,
235
+ # but in many cases this is taken care of automatically.
236
+ #
237
+ # ---Library#extconf
238
+ #
239
+ # Override #extconf if you want to do more than just #create_makefile. Note that
240
+ # #create_makefile recognizes all .c files in the library directory, and
241
+ # generates a makefile that compiles them and links them into the dynamic
242
+ # library.
243
+ #
244
+ # ---Library#write
245
+ # ---Library#makedepend
246
+ # ---Library#mkmf
247
+ # ---Library#make arg = nil
248
+ #
249
+ # Internal methods called, in sequence, by #commit:
250
+ #
251
+ # * #write dumps each file template to disk, if needed
252
+ # * #makedepend executes +makedepend+
253
+ # * #mkmf calls Library#extconf
254
+ # * #make executes the system's +make+ program.
255
+ #
256
+ # These methods can be overridden, but are more typically called directly. The
257
+ # argument to #make is interpolated into the system call as a command line
258
+ # argument to the +make+ program. If the argument is 'clean' or 'distclean' then
259
+ # the make log is deleted; if the argument is 'distclean' then all .c and .h
260
+ # files generated by #write are deleted (additional user-supplied .c and .h
261
+ # files in the library dir are not affected).
262
+ #
263
+ # ---Library#update_file f, template
264
+ #
265
+ # Called by write on each .c and .h file to actually write +template+ to the
266
+ # open file +f+. The default behavior is to compare the existing data with the
267
+ # generated data, and leave the file untouched if nothing changed. Subclasses
268
+ # may have more efficient ways of doing this. (For instance, check a version
269
+ # indicator in the file on disk, perhaps stored using the file's preamble
270
+ # accumulator. It is even possible to defer some entries in the template until
271
+ # after this check has been made: code that only needs to be regenerated if some
272
+ # specification has changed)
273
+ #
274
+ # ---Library#purge_source_dir
275
+ # ---Library#purge_source_dir= flag
276
+ #
277
+ # Access the #purge_source_dir attribute of a library, which controls what
278
+ # happens to .c, .h, and .o files in the source dir of the library that are not
279
+ # among those generated as part of the library. If this is set to +:delete+,
280
+ # then those files are deleted. Other true values cause the .c, .h, and .o files
281
+ # to be renamed with the .hide extension. (Note that this makes it difficult to
282
+ # keep manually written C files in the same dir.) False +flag+ values (the
283
+ # default) cause CGen to leave the files untouched.
284
+ #
285
+ # Note that, regardless of this setting, #mkmf will construct a Makefile which
286
+ # lists all .c files that are in the source dir. If you do not delete obsolete
287
+ # files, they will be compiled into your library!
288
+ #
289
+ # ---Library#init_library_function
290
+ #
291
+ # Returns a Function template object; see below. This function is called when
292
+ # the library is loaded. Method definitions put stuff here to register methods
293
+ # with Ruby. Usually, there is no need to bother this guy directly. Use
294
+ # Library#setup instead.
295
+ #
296
+ # ---Library#setup key => "statements", ...
297
+ #
298
+ # Inserts code in the #init_library_function, which is called when the library
299
+ # is loaded. The +key+ is used for redundancy checking, as in the #declare
300
+ # accumulators. Note that hashes are unordered, so constructs like
301
+ #
302
+ # setup :x => "...", :y => "..."
303
+ #
304
+ # can result in unpredictable order. To avoid this, use several #setup calls.
305
+ #
306
+ # ---Library#source_file ---Library#include_file
307
+ #
308
+ # Returns the template for the main source or include file of the library.
309
+ # Usually, there is no need to access these directly.
310
+ #
311
+ # ---Library#define_c_function name, type
312
+ #
313
+ # Defines a plain ol' C function. Returns a Function template (see below), or a
314
+ # template of the specified +type+, if given.
315
+ #
316
+ # ---Library#define_c_method mod, name, subclass
317
+ # ---Library#define_c_module_function mod, name, subclass
318
+ # ---Library#define_c_global_function name, subclass
319
+ # ---Library#define_c_singleton_method mod, name, subclass
320
+ # ---Library#define_c_class_method mod, name, subclass
321
+ #
322
+ # Defines a function of the specified name and type in the given class/module
323
+ # (or in the global scope), and returns the function template (often used with
324
+ # #instance_eval to add arguments, code, etc.). The +subclass+ argument is
325
+ # optional and allows the template to belong to a subclass of the function
326
+ # template it would normally belong to.
327
+ #
328
+ # For example,
329
+ #
330
+ # define_c_method String, "reverse"
331
+ #
332
+ # The arguments accepted by the method automatically include +self+. By default,
333
+ # arguments are passed as individual C arguments, but the can be passed in a
334
+ # Ruby or C array. The latter has the advantage of argument parsing (based on
335
+ # rb_scan_args), defaults, and typechecking. See Method#c_array_args.
336
+ # #define_c_class_method is just an alias for #define_c_singleton_method.
337
+ #
338
+ # ---Library#include "file1.h", "<file2.h>", ...
339
+ #
340
+ # Insert the include statement(s) at the top of the library's main .c file. For
341
+ # convenience, <ruby.h> is included automatically, as is the header file of the
342
+ # library itself.
343
+ #
344
+ # ---Library#declare :x => "int x", ... ---Library#declare_extern :x => "int x",
345
+ # ...
346
+ #
347
+ # Puts the string in the declaration area of the .c or .h file, respectively.
348
+ # The declaration area is before the function definitions, and after the
349
+ # structure declarations.
350
+ #
351
+ # ---Library#declare_struct name, attributes=nil
352
+ # ---Library#declare_extern_struct name, attributes=nil
353
+ #
354
+ # Returns a Structure template, which generates to a typedefed C struct in the
355
+ # .c or .h file. The #declare method of this template is used to add members.
356
+ #
357
+ # ---Library#declare_class cl ---Library#declare_module mod
358
+ # ---Library#declare_symbol sym
359
+ #
360
+ # Define a C variable which will be initialized to refer to the class, module,
361
+ # or symbol. These accumulators return the name of the C variable which will be
362
+ # generated and initialized to the ID of the symbol, and this return value can
363
+ # be interpolated into C calls to the Ruby API. (The arguments are the actual
364
+ # Ruby objects.) This is very useful in #rb_ivar_get/#rb_ivar_set calls, and it
365
+ # avoids doing the lookup more than once:
366
+ #
367
+ # ...
368
+ # declare :my_ivar => "VALUE my_ivar"
369
+ # body %{
370
+ # my_ivar = rb_ivar_get(shadow->self, #{declare_symbol :@my_ivar});
371
+ # rb_ivar_set(shadow->self, #{declare_symbol :@my_ivar}, Qnil);
372
+ # }
373
+ #
374
+ # The second declaration notices that the library already has a variable that
375
+ # will be initialized to the ID of the symbol, and uses it.
376
+ #
377
+ # ---Library#literal_symbol sym
378
+ #
379
+ # Like Library#declare_symbol, but converts the ID to a VALUE at library
380
+ # initialization time. Useful for looking up hash values keyed by symbol
381
+ # objects, for example. +sym+ is a string or symbol.
382
+ #
383
+ # ---Library#show_times message
384
+ #
385
+ # If the attribute #show_times_flag is set to true, print the user and system
386
+ # times (and child user and child system on some platforms) and real time for
387
+ # each major step of the commit process. Display +message+.
388
+ #
389
+ # ===File
390
+ #
391
+ # File templates are managed by the Library, and most users do not need to
392
+ # interact with them directly. They are structured into four sections: includes,
393
+ # structure declarations, variable and function declarations, and function
394
+ # definitions. Each source file automatically includes its corresponding header
395
+ # file and the main header file for the library (which includes ruby.h). The
396
+ # main source file for the library includes each additional header file.
397
+ #
398
+ # ---File#define_c_method
399
+ # ---File#define_c_module_function
400
+ # ---File#define_c_global_function
401
+ # ---File#define_c_singleton_method
402
+ #
403
+ # As for the Library, but can be used on any source file within the library.
404
+ # Used to break large projects up into many files.
405
+ #
406
+ # ---File#preamble
407
+ #
408
+ # An accumulator that wraps its input in C comments and places it at the head of
409
+ # the source file.
410
+ #
411
+ # ===Function
412
+ #
413
+ # ---Funtion#scope :static ---Funtion#scope :extern ---Funtion#arguments 'int
414
+ # x', 'double y', 'VALUE obj', ... ---Funtion#return_type 'void'
415
+ #
416
+ # These accumulators affect the prototype of the function, which will be placed
417
+ # in the declaration section of either the .h or the .c file, depending on the
418
+ # scope setting. The default scope is static. The default return type is 'void'.
419
+ #
420
+ # For the Method subclasses of Function, argument and return types can be
421
+ # omitted, in which case they default to 'VALUE'.
422
+ #
423
+ # ---Funtion#declare :x => "static double x", ... ---Funtion#init "x = 0", ...
424
+ # ---Funtion#setup 'x' => "x += 1", ... ---Funtion#body 'y = sin(x);
425
+ # printf("%d\n", y)', ...
426
+ #
427
+ # These four accumulators determine the contents of the function between the
428
+ # opening and closing braces. The #init code is executed once when the function
429
+ # first runs; it's useful for initializing static data. The #setup code runs
430
+ # each time the function is called, as does the #body. Distinguishing #setup
431
+ # from #body is useful for two reasons: first, #setup is guaranteed to execute
432
+ # before #body, and, second, one can avoid setting up the same variable twice,
433
+ # because of the key.
434
+ #
435
+ # ---Funtion#returns "2*x"
436
+ #
437
+ # Specifies the string used in the final return statement of the function.
438
+ # Subsequent uses of this method clobber the previous value. Alternately, one
439
+ # can simply insert a "return" manually in the body.
440
+ #
441
+ # ===Method ===ModuleFunction ===GlobalFunction ===SingletonMethod
442
+ #
443
+ # These subclasses of the Function template are designed for coding Ruby
444
+ # methods. The necessary registration (+rb_define_method+, etc.) is handled
445
+ # automatically. Defaults are different from Function: +'VALUE self'+ is
446
+ # automatically an argument, and argument and return types are assumed to be
447
+ # +'VALUE'+ and can be omitted by the caller. The return value is +nil+ by
448
+ # default.
449
+ #
450
+ # ---Method#arguments :arg1, :arg2, ...
451
+ #
452
+ # The default way of specifying arguments. Allows a fixed number of VALUE
453
+ # arguments.
454
+ #
455
+ # ---Method#c_array_args argc_name = 'argc', argv_name = 'argv', &block
456
+ # ---Method#rb_array_args args_name = 'args'
457
+ #
458
+ # Specifies that arguments are to be collected and passed in a C or Ruby array,
459
+ # instead of individually (which is the default). In each case, the array of
460
+ # actual arguments will be bound to a C parameter with the name specified. See
461
+ # the Ruby API documentation for details.
462
+ #
463
+ # If a block is given to Method#c_array_args, it will be used to specify a call
464
+ # to the API function +rb_scan_args+ and to declare the associated variables.
465
+ # For example:
466
+ #
467
+ # c_array_args('argc', 'argv') {
468
+ # required :arg0, :arg1
469
+ # optional :arg2, :arg3, :arg4
470
+ # rest :rest
471
+ # block :block
472
+ # }
473
+ #
474
+ # declares all the listed symbols as variables of type +VALUE+ in function
475
+ # scope, and arranges for the following to be called in the #setup clause (i.e.,
476
+ # before the #body):
477
+ #
478
+ # rb_scan_args(argc, argv, "23*&", &arg0, &arg1, &arg2, &arg3, &arg4, &rest, &block);
479
+ #
480
+ # The <tt>'argc', 'argv'</tt> are the default values and are usually omitted.
481
+ #
482
+ # The lines in the block can occur in any order, and any line can be omitted.
483
+ # However, only one line of each kind should be used. In addition, each optional
484
+ # argument can be associated with a fragment of C code that will be executed to
485
+ # assign it a default value, if needed. For example, one can add the following
486
+ # lines to the above block:
487
+ #
488
+ # default :arg3 => "INT2NUM(7)",
489
+ # :arg4 => "INT2NUM(NUM2INT(arg2) + NUM2INT(arg3))"
490
+ #
491
+ # Otherwise, optional arguments are assigned nil.
492
+ #
493
+ # In this case, if +arg4+ is not provided by +argv+, then it is initialized
494
+ # using the code given. If, in addition, +arg3+ is not provided, then it too is
495
+ # initialized. These initializations happen in the #setup clause of the Function
496
+ # template and are executed in the same order as the arguments are given in the
497
+ # +optional+ line.
498
+ #
499
+ # Finally, argument types can be checked automatically:
500
+ #
501
+ # typecheck :arg2 => Numeric, :arg3 => Numeric
502
+ #
503
+ # The value passed to the function must either be +nil+ or match the type. Note
504
+ # that type checking happens *before* default assignment, so that default
505
+ # calculation code can assume types are correct. No typechecking code is
506
+ # generated if the type is Object.
507
+ #
508
+ # ===Structure
509
+ #
510
+ # ---Structure#declare :x => "int x"
511
+ #
512
+ # Adds the specified string to define a structure member.
513
+ #
514
+ # ===Utility functions
515
+ #
516
+ # ---CGenerator.make_c_name s
517
+ #
518
+ # Geenrates a unique C itentifier from the given Ruby identifier, which may
519
+ # include +/[@$?!]/+, +'::'+, and even +'.'+. (Some special globals are not yet
520
+ # supported: +$:+ and +$-I+, for example.)
521
+ #
522
+ # It is unique in the sense that distinct Ruby identifiers map to distinct C
523
+ # identifiers. (Not completely checked. Might fail for some really obscure
524
+ # cases.)
525
+ #
526
+ # ---String.tab n
527
+ #
528
+ # Tabs left or right by n chars, using spaces.
529
+ #
530
+ # ---String.tabto n
531
+ #
532
+ # The first non-empty line is adjusted to have n spaces before the first
533
+ # nonspace. Additional lines are changed to preserve relative tabbing.
534
+ #
535
+ # ---String.taballto n
536
+ #
537
+ # Aligns each line to have n spaces before the first non-space.
538
+ #
539
+ # (These routines probably don't work well, if at all, with "hard" tabs.)
540
+ #
541
+ # ==Example
542
+ #
543
+ # require 'cgen'
544
+ #
545
+ # lib = CGenerator::Library.new "sample_lib"
546
+ #
547
+ # class Point; end
548
+ #
549
+ # lib.declare_extern_struct(:point).instance_eval {
550
+ # # make it extern so we can see it from another lib
551
+ # declare :x => "double x"
552
+ # declare :y => "double y"
553
+ # }
554
+ #
555
+ # lib.define_c_global_function(:new_point).instance_eval {
556
+ # arguments "x", "y" # 'VALUE' is assumed
557
+ # declare :p => "point *p"
558
+ # declare :result => "VALUE result"
559
+ # # semicolons are added automatically
560
+ # body %{
561
+ # result = Data_Make_Struct(#{lib.declare_class Point}, point, 0, free, p);
562
+ # p->x = NUM2DBL(x);
563
+ # p->y = NUM2DBL(y);
564
+ #
565
+ # // might want to do something like this, too:
566
+ # // rb_funcall(result, #{lib.declare_symbol :initialize}, 0);
567
+ # }
568
+ # returns "result"
569
+ # # can put a return statement in the body, if preferred
570
+ # }
571
+ #
572
+ # for var in [:x, :y] # metaprogramming in C!
573
+ # lib.define_c_method(Point, var).instance_eval {
574
+ # declare :p => "point *p"
575
+ # body %{
576
+ # Data_Get_Struct(self, point, p);
577
+ # }
578
+ # returns "rb_float_new(p->#{var})"
579
+ # }
580
+ # end
581
+ #
582
+ # # A utility function, available to other C files
583
+ # lib.define_c_function("distance").instance_eval {
584
+ # arguments "point *p1", "point *p2"
585
+ # return_type "double"
586
+ # scope :extern
587
+ # returns "sqrt(pow(p1->x - p2->x, 2) + pow(p1->y - p2->y, 2))"
588
+ # include "<math.h>"
589
+ # # The include accumulator call propagates up the parent
590
+ # # hierarchy until something handles it. In this case,
591
+ # # the Library lib handles it by adding an include
592
+ # # directive to the .c file. This allows related, but
593
+ # # separate aspects of the C source to be handled in
594
+ # # the same place in the Ruby code. We could also have
595
+ # # called include directly on lib.
596
+ # }
597
+ #
598
+ # lib.define_c_method(Point, :distance).instance_eval {
599
+ # # no name conflict between this "distance" and the previous one,
600
+ # # because "method" and "Point" are both part of the C identifier
601
+ # # for this method
602
+ # arguments "other"
603
+ # declare :p => "point *p"
604
+ # declare :q => "point *q"
605
+ # body %{
606
+ # Data_Get_Struct(self, point, p);
607
+ # Data_Get_Struct(other, point, q);
608
+ # }
609
+ # returns "rb_float_new(distance(p, q))"
610
+ # }
611
+ #
612
+ # lib.commit # now you can use the new definitions
613
+ #
614
+ # p1 = new_point(1, 2)
615
+ # puts "p1: x is #{p1.x}, y is #{p1.y}"
616
+ #
617
+ # p2 = new_point(5, 8)
618
+ # puts "p2: x is #{p2.x}, y is #{p2.y}"
619
+ #
620
+ # puts "distance from p1 to p2 is #{p1.distance p2}"
621
+ #
622
+ # Output is:
623
+ #
624
+ # p1: x is 1.0, y is 2.0
625
+ # p2: x is 5.0, y is 8.0
626
+ # distance from p1 to p2 is 7.211102551
627
+ #
628
+ # That's a lot of code to do a simple operation, compared with an Inline-style
629
+ # construct. CGenerator's value shows up with more complex tasks. The
630
+ # +sample.rb+ file extends this example.
631
+ #
632
+ # ==Notes
633
+ #
634
+ # * My first Ruby extension was built with this module. That speaks well of the
635
+ # elegance, simplicity, and utter coolness of Ruby and its extension
636
+ # architecture. Thanks matz!
637
+ #
638
+ # * Some accumulators, like declare_symbol and declare_class, operate by default
639
+ # on the file scope, even if called on a method definition, so the declarations
640
+ # are shared across the library. This reduces redundancy with no disadvantage.
641
+ # (In general, accumulator calls propagate first thru the inheritance hierarchy
642
+ # and then thru the parent Template hierarchy.)
643
+ #
644
+ # * Note that accumulators can nest within accumulators, because #to_s is
645
+ # applied recursively. This is *very* useful (see Library#initialize for
646
+ # example). This defines a many-to-one dataflow pattern among accumulators. A
647
+ # one-to-many dataflow pattern arises when a method calls several accumulators,
648
+ # as in #define_c_method and kin.
649
+ #
650
+ # * CGenerator makes no attempt to check for C syntax errors in code supplied to
651
+ # the accumulators.
652
+ #
653
+ # * It may help to think of templates as heterogeneous collections, like
654
+ # structs, and accumulators as homogeneous collections, like arrays.
655
+ #
656
+ # * The containment hierarchy is represented by the #parent accessor in
657
+ # Accumulators and Templates. It provides a secondary inheritance of calls to
658
+ # accumulators. (As a result, doing #include at the function level adds an
659
+ # #include directive at the file level.)
660
+ #
661
+ # * The basic Template and Accumulator class are more general than C source, or
662
+ # even strings. The Module#inherit method is also reusable.
663
+ #
664
+ # * CGenerator does not allow more than one C function with the same name. This
665
+ # could be changed fairly easily.
666
+ #
667
+ # * You can subclass Library and override #extconf to do more complex processing
668
+ # than just #create_makefile.
669
+ #
670
+ # * Calling a #to_s method on an accumulator more than once has no unexpected
671
+ # side effects. It can be called at any time for a snapshot of the whole library
672
+ # or of a subtemplate.
673
+ #
674
+ # * CGenerator is probably not very efficient, so it may not be useful with
675
+ # large amounts of C code.
676
+ #
677
+ # * Library#commit will try to commit even if already comitted (in which case it
678
+ # raises a CommitError) or if the lib is empty. Use #committed? and #empty? to
679
+ # check for these cases. (Should these checks, or just the latter, be
680
+ # automatic?)
681
+ #
682
+ # * Library#commit first reads the .c and .h file and checks for changes. If
683
+ # there are none, it doesn't write to the file. If neither file gets written to,
684
+ # make won't need to compile them...
685
+ #
686
+ # * CGenerator generates header file entries for any non-static functions or
687
+ # data. This can be used for communication between files in the library without
688
+ # using Ruby calls, and to provide an API for other C libraries and executables.
689
+ #
690
+ # * Accumulator#inspect is a nice hierarchy-aware inspector.
691
+ #
692
+ # ==To do
693
+ #
694
+ # * Automatically generate inner and outer functions as in Michael Neumann's
695
+ # cplusruby. Similarly, should there be another field to refer to a struct of
696
+ # function pointers, so that C code can call the inner functions without
697
+ # funcall?
698
+ #
699
+ # * Try CFLAGS for optimization: with gcc, -march, -O3, -fomit-frame-pointer
700
+ #
701
+ # * Rename to something less generic (cgen --> "sagehen"?)
702
+ #
703
+ # * Option to target ruby/ext dir: generate MANIFEST file, but no Makefile. What
704
+ # about depend? how to generate it in installation-independent format?
705
+ #
706
+ # * Let user set dir to build in, rather than rely on chdir, which is not thread
707
+ # safe.
708
+ #
709
+ # * Instead of using an external program to makedepend, do it manually based on
710
+ # include operations? (Might have to do this anyway on mswin.)
711
+ #
712
+ # * Investigate Tiny C--Linux only, but fast, and libtcc allows dynamic codegen.
713
+ # Maybe best used in "develop" mode, rather than for production code (no -O).
714
+ #
715
+ # * Option in define_c_method to make method private/protected (see
716
+ # rb_define_private/protected_method in intern.h).
717
+ #
718
+ # * Optimization: declare_symbol and declare_module should do less work if the
719
+ # declaration has already neen done.
720
+ #
721
+ # * Macros, e.g. something for rb_funcall that does the declare_class for you.
722
+ #
723
+ # * Extend c_array_args features to rb_array_args and fixed length arglists.
724
+ #
725
+ # * Exception if modify descendant of Library after committed. Accumulators
726
+ # always notify parent before admitting any changes.
727
+ #
728
+ # * Freeze data structures after commit?
729
+ #
730
+ # * More wrappers: define_class, globals (in C and in Ruby), funcalls,
731
+ # iterators, argument type conversion, etc. Really, all of Chapter 17 of Thomas
732
+ # & Hunt.
733
+ #
734
+ # * Make commit happen automatically when the first call is made to a method in
735
+ # the library. (Use alias, maybe, since method_missing won't work--won't let you
736
+ # override.)
737
+ #
738
+ # * Finer granularity in accumulators. For example, #init could take a (lvalue,
739
+ # rvalue) pair, which would allow it to detect initialization of the same var
740
+ # with different values.
741
+ #
742
+ # * make this into Inline for ruby:
743
+ #
744
+ # Module#define_c_method ("name") { ... }
745
+ #
746
+ # (use instance_eval, so that accumulators can be used in the block?) The main
747
+ # drawback is that no Library is specified, so where does it go? (Actually,
748
+ # CShadow solves this problem, if you don't mind having a struct as overhead.)
749
+ #
750
+ # * investigate unloading a .so/.dll. Or: maybe rb_define_* can be called again,
751
+ # but in a different library (append version number to the lib name, but not to
752
+ # the dir name). See Ruby/DL in RAA. (See dln.c, eval.c, ruby.c in ruby source.
753
+ # It all seems possible, but a bit of work.)
754
+ #
755
+ # * parser/generator for (at first) simple ruby code, like '@x.y': one option
756
+ # would be to use init to define a Proc and use setup to call the Proc
757
+ #
758
+ # * check ANSI, check w/ other compilers
759
+ #
760
+ # * Improve space recognition in the tab routines (check for \t and handle
761
+ # intelligently, etc.).
762
+ #
763
+ # * Formalize the relation between templates and accumulators. Make it easier
764
+ # for client code to use its own templates and accumulators.
765
+ #
766
+ # * Double-ended accumulators (add_at_end vs. add_at_beginning, or push vs.
767
+ # unshift).
768
+ #
769
+ # * Automatically load/link other dynamic or static libs in the same dir. For
770
+ # static, use 'have_library' in #extconf; see p.185 of pickaxe. For dynamic, use
771
+ # Ruby/DL from RAA, or just require. (Currently, this can be done manually by
772
+ # subclassing and overriding extconf.)
773
+ #
774
+ # * More thorough checking for assert_uncommitted. Currently, just a few
775
+ # top-level methods (Library#commit and some of the define methods) check if the
776
+ # library has already been committed. Ideally, #commit would freeze all
777
+ # accumulators. But then the problem is how to report a freeze exception in a
778
+ # way that makes clear that the problem is really with commit.
779
+ module CGenerator
780
+
781
+ VERSION = '0.16.0'
782
+
783
+ class Accumulator ## should be a mixin? "Cumulative"?
784
+
785
+ ## should delegate Accs into two objects with two inheritance hierarchies,
786
+ ## one for adding items, one for generating strings
787
+ ##OR:
788
+ ## two hierarchies of modules that get included into Template subclasses
789
+
790
+ attr_reader :name, :parent
791
+
792
+ def initialize name, parent = nil
793
+ @name = name; @parent = parent
794
+ @pile = []
795
+ end
796
+
797
+ def accept? item
798
+ true
799
+ end
800
+
801
+ def add_one_really item
802
+ @pile << item
803
+ end
804
+
805
+ def add_one item
806
+ add_one_really item if accept? item
807
+ end
808
+
809
+ def add(*items)
810
+ for item in items
811
+ add_one item
812
+ end
813
+ end
814
+
815
+ def output_one item
816
+ item
817
+ end
818
+
819
+ def output items
820
+ items.collect { |item|
821
+ output_one item
822
+ }.select { |item|
823
+ item && item != ""
824
+ }
825
+ end
826
+
827
+ def separator; "\n"; end
828
+
829
+ def to_s
830
+ output(@pile).join(separator)
831
+ end
832
+
833
+ def inspect
834
+ eol = "\n" if @pile.size > 0
835
+ s = "s" if @pile.size != 1
836
+ %{<#{self.class} "#{@name}": #{@pile.size} item#{s}>#{eol}} +
837
+ @pile.collect { |item| inspect_one item }.join("\n").tabto(2)
838
+ end
839
+
840
+ def inspect_one item
841
+ item.inspect
842
+ end
843
+
844
+ end # class Accumulator
845
+
846
+ module SetAccumulator
847
+ def accept? item
848
+ not @pile.include? item
849
+ end
850
+ end
851
+
852
+ module KeyAccumulator
853
+ def initialize(*args)
854
+ super
855
+ @hash = {} # @pile maintains ordered list of keys for @hash
856
+ end
857
+
858
+ def add_one item
859
+ ## why not do this?
860
+ # unless item.is_a? Hash
861
+ # raise ArgumentError,
862
+ # "Tried to add non-hash '#{item}' to KeyAccumulator."
863
+ # end
864
+
865
+ item = item.sort_by {|k,v| k.to_s} unless item.is_a?(Array)
866
+
867
+ for key, value in item
868
+ if not @hash.has_key? key
869
+ super key
870
+ end
871
+ @hash[key] = value_filter(value)
872
+ end
873
+ end
874
+
875
+ def value_filter(value)
876
+ value
877
+ end
878
+
879
+ def output_one item
880
+ super @hash[item]
881
+ end
882
+
883
+ def inspect_one item
884
+ @hash[item].inspect
885
+ end
886
+
887
+ def [](item)
888
+ @hash[item]
889
+ end
890
+ end
891
+
892
+ class Template < Accumulator
893
+
894
+ def initialize name = "", parent = nil, &block
895
+ super
896
+ instance_eval(&block) if block
897
+ ## not very useful: users call an accumulator, rather than Template#new
898
+ end
899
+
900
+ def Template.accumulator(*names)
901
+ kind = if block_given? then yield else Accumulator end
902
+
903
+ for name in names
904
+
905
+ module_eval %{
906
+ def #{name}(*items)
907
+ #{name}!.add(*items)
908
+ end
909
+ def #{name}!
910
+ @#{name} ||= #{kind}.new(:#{name}, self)
911
+ end
912
+ }
913
+
914
+ unless Template.respond_to? name
915
+ Template.inherit :@parent, name
916
+ end
917
+
918
+ end
919
+
920
+ end
921
+
922
+ end # class Template
923
+
924
+
925
+ class Library < Template
926
+
927
+ class CommitError < RuntimeError; end
928
+
929
+ attr_reader :init_library_function, :include_file, :source_file
930
+ attr_accessor :purge_source_dir, :show_times_flag
931
+
932
+ def initialize name
933
+ super name
934
+
935
+ @show_times_flag = @purge_source_dir = false
936
+ @committed = false
937
+ @source_file = nil
938
+
939
+ @rtime = Time.now.to_f
940
+ @ptime = process_times
941
+
942
+ unless name =~ /\A[A-Za-z_]\w*\z/
943
+ raise NameError,
944
+ "\n Not a valid library name: '#{name}'." +
945
+ "\n Name must be a C identifier."
946
+ end
947
+
948
+ @include_file, @source_file = add_file name
949
+ @include_file.include '<ruby.h>'
950
+
951
+ @init_library_function = define_c_function "Init_" + name
952
+ @init_library_function.scope :extern
953
+
954
+ @init_library_function.body \
955
+ rb_define_method!,
956
+ rb_define_module_function!,
957
+ rb_define_global_function!,
958
+ rb_define_singleton_method!
959
+ ## odd, putting an accum inside
960
+ ## a template which is not the parent
961
+ end
962
+
963
+ def use_work_dir dir_name
964
+ if File.basename(Dir.pwd) == dir_name
965
+ yield
966
+ else
967
+ require 'fileutils'
968
+ FileUtils.makedirs dir_name
969
+ Dir.chdir dir_name do
970
+ yield
971
+ end
972
+ end
973
+ end
974
+
975
+ def add_file name, opts = {}
976
+ pair = @pile.detect {|p| p[0].name == name + ".h"}
977
+
978
+ if not pair
979
+ new_include_file = CFile.new name + ".h", self
980
+ new_source_file = CFile.new name + ".c", self, new_include_file
981
+
982
+ if @source_file
983
+ new_source_file.include @include_file unless opts[:independent]
984
+ @source_file.include new_include_file
985
+ end
986
+ new_source_file.include new_include_file
987
+
988
+ pair = [new_include_file, new_source_file]
989
+ add pair # for inspect and commit
990
+ end
991
+
992
+ return pair
993
+ end
994
+
995
+ def assert_uncommitted
996
+ if @committed
997
+ raise CommitError, "\nLibrary #{@name} has already been committed."
998
+ end
999
+ end
1000
+
1001
+ def committed?
1002
+ @committed
1003
+ end
1004
+
1005
+ def empty?
1006
+ @init_library_function.empty? ## is this enough?
1007
+ end
1008
+
1009
+ def before_commit(&block)
1010
+ (@before_commit ||= []) << block
1011
+ end
1012
+
1013
+ def after_commit(&block)
1014
+ (@after_commit ||= []) << block
1015
+ end
1016
+
1017
+ def commit(build = true)
1018
+ assert_uncommitted
1019
+
1020
+ while @before_commit
1021
+ bc = @before_commit; @before_commit = nil
1022
+ bc.each {|block| block[self]}
1023
+ end
1024
+
1025
+ @committed = true
1026
+
1027
+ if build
1028
+ @logname ||= "make.log"
1029
+
1030
+ show_times "precommit"
1031
+ show_times "write" do write end
1032
+ show_times "makedepend" do makedepend end
1033
+ show_times "mkmf" do mkmf end
1034
+ show_times "make" do make end
1035
+ end
1036
+
1037
+ show_times "loadlib" do loadlib end
1038
+
1039
+ while @after_commit
1040
+ ac = @after_commit; @after_commit = nil
1041
+ ac.reverse.each {|block| block[self]}
1042
+ end
1043
+ end
1044
+
1045
+ def process_times
1046
+ RUBY_VERSION.to_f >= 1.7 ? Process.times : Time.times
1047
+ end
1048
+
1049
+ def show_times message
1050
+ yield if block_given?
1051
+ if @show_times_flag
1052
+ unless @show_times_started
1053
+ printf "\n%20s %6s %6s %6s %6s %7s\n",
1054
+ "__step__", "utime", "stime", "cutime", "cstime", "real"
1055
+ @show_times_started = true
1056
+ end
1057
+ ptime = self.process_times
1058
+ rtime = Time.now.to_f
1059
+ printf "%20s %6.2f %6.2f %6.2f %6.2f %7.3f\n", message,
1060
+ ptime.utime - @ptime.utime, ptime.stime - @ptime.stime,
1061
+ ptime.cutime - @ptime.cutime, ptime.cstime - @ptime.cstime,
1062
+ rtime - @rtime
1063
+ @ptime = ptime
1064
+ @rtime = rtime
1065
+ end
1066
+ end
1067
+
1068
+ def write
1069
+ build_wrapper do
1070
+ templates = @pile.flatten.sort_by { |t| t.name }
1071
+
1072
+ if @purge_source_dir
1073
+ # hide or delete files not listed in templates
1074
+ files = Dir["*.{c,h,o}"]
1075
+ template_files = templates.map { |t| t.name }
1076
+ template_files +=
1077
+ template_files.grep(/\.c$/).map { |f| f.sub(/\.c$/, ".o") }
1078
+ for file in files - template_files
1079
+ if @purge_source_dir == :delete
1080
+ File.delete(file) rescue SystemCallError
1081
+ else
1082
+ File.rename(file, file + ".hide") rescue SystemCallError
1083
+ end
1084
+ end
1085
+ end
1086
+
1087
+ for template in templates do
1088
+ begin
1089
+ File.open(template.name, 'r+') {|f| update_file f, template}
1090
+ rescue SystemCallError
1091
+ File.open(template.name, 'w+') {|f| update_file f, template}
1092
+ end
1093
+ end
1094
+ end
1095
+ end
1096
+
1097
+ def update_file f, template
1098
+ template_str = template.to_s
1099
+ file_data = f.gets(nil) ## sysread is faster?
1100
+ unless file_data == template_str
1101
+ if defined?($CGEN_VERBOSE) and $CGEN_VERBOSE
1102
+ print_update_reason(template, template_str, file_data)
1103
+ end
1104
+ f.rewind
1105
+ f.print template_str
1106
+ f.truncate f.pos
1107
+ end
1108
+ end
1109
+
1110
+ def print_update_reason template, template_str, file_data
1111
+ puts "\nUpdating file #{template.name}"
1112
+
1113
+ if file_data == nil
1114
+ puts "File on disk is empty"
1115
+ return
1116
+ end
1117
+
1118
+ s = file_data
1119
+ t = template_str
1120
+ slines = s.split "\n"
1121
+ tlines = t.split "\n"
1122
+ i = 0
1123
+ sline = slines[i]
1124
+ tline = tlines[i]
1125
+ catch :done do
1126
+ while sline and tline
1127
+ if sline != tline
1128
+ puts "Line #{i+1}",
1129
+ "On disk: #{sline.inspect}",
1130
+ "In memory: #{tline.inspect}",
1131
+ ""
1132
+ throw :done
1133
+ end
1134
+ i += 1
1135
+ sline = slines[i]
1136
+ tline = tlines[i]
1137
+ end
1138
+ if sline == nil and tline == nil
1139
+ puts "Very strange, no difference found!"
1140
+ else
1141
+ if slines.size > tlines.size
1142
+ puts "file on disk is longer"
1143
+ else
1144
+ puts "file in memory is longer"
1145
+ end
1146
+ end
1147
+ end
1148
+ end
1149
+
1150
+ def makedepend
1151
+ return if /mswin/i =~ RUBY_PLATFORM ## what else can we do?
1152
+ build_wrapper do
1153
+ cfg = Config::CONFIG
1154
+ dirs = [cfg["sitearchdir"], cfg["archdir"], cfg["includedir"]]
1155
+ result = system %{
1156
+ touch depend
1157
+ makedepend -fdepend *.c -I#{dirs.join " -I"} >#{@logname} 2>&1
1158
+ } ## what about "gcc -MM" as in step 6 in README.EXT ?
1159
+ unless result
1160
+ log_data = File.read(@logname) rescue nil
1161
+ msg = "\n makedepend failed for #{@name}."
1162
+ if log_data
1163
+ msg <<
1164
+ "\n Transcript is saved in #{@name}/#{@logname} and follows:" +
1165
+ "\n " + "_" * 60 +
1166
+ "\n" + log_data.tabto(3).gsub(/^ /, " |") +
1167
+ " " + "_" * 60 + "\n"
1168
+ else
1169
+ msg <<
1170
+ "\n No log available.\n"
1171
+ end
1172
+ raise CommitError, msg
1173
+ end
1174
+ end
1175
+ end
1176
+
1177
+ def mkmf
1178
+ need_to_make_clean = false
1179
+
1180
+ # Need to do this in a separate process because mkmf.rb pollutes
1181
+ # the global namespace.
1182
+ build_wrapper do
1183
+ require 'rbconfig'
1184
+ ruby = Config::CONFIG["RUBY_INSTALL_NAME"]
1185
+
1186
+ old_contents = File.read("extconf.rb") rescue nil
1187
+ contents = extconf
1188
+ require 'stringio'
1189
+ s = StringIO.new
1190
+ s.puts(contents)
1191
+ s.rewind
1192
+ contents = s.read
1193
+
1194
+ if old_contents != contents
1195
+ File.open("extconf.rb", "w") do |f|
1196
+ f.puts contents
1197
+ end
1198
+ need_to_make_clean = true
1199
+ end
1200
+
1201
+ system %{
1202
+ #{ruby} extconf.rb > #{@logname}
1203
+ }
1204
+ end
1205
+
1206
+ make "clean" if need_to_make_clean
1207
+ end
1208
+
1209
+ ## use -j and -l make switches for multiprocessor builds (man sysconf)
1210
+ ## see http://www.gnu.org/manual/make/html_chapter/make_5.html#SEC47
1211
+ def make arg = nil
1212
+ build_wrapper do
1213
+ unless system "#{make_program} #{arg} >>#{@logname} 2>&1"
1214
+ raise CommitError,
1215
+ "\n Make #{arg} failed for #{@name}." +
1216
+ "\n Transcript is saved in #{@name}/#{@logname} and follows:" +
1217
+ "\n " + "_" * 60 +
1218
+ "\n" + File.read(@logname).tabto(3).gsub(/^ /, " |") +
1219
+ " " + "_" * 60 + "\n"
1220
+ end
1221
+
1222
+ if arg == 'clean' or arg == 'distclean'
1223
+ File.delete(@logname) rescue SystemCallError
1224
+ if arg == 'distclean'
1225
+ for template in @pile.flatten do
1226
+ File.delete(template.name) rescue SystemCallError
1227
+ end
1228
+ end
1229
+ end
1230
+ end
1231
+ end
1232
+
1233
+ def make_program
1234
+ case RUBY_PLATFORM
1235
+ when /mswin/i
1236
+ "nmake"
1237
+ when /mingw/i
1238
+ "make"
1239
+ # "mingw32-make" is the MSYS-independent, MSVC native version
1240
+ # which is supposedly less useful
1241
+ else
1242
+ "make"
1243
+ end
1244
+ end
1245
+
1246
+ def build_wrapper
1247
+ if File.exists? @name
1248
+ unless File.directory? @name
1249
+ raise CommitError, "Library #{@name}: Can't mkdir; file exists."
1250
+ end
1251
+ else
1252
+ Dir.mkdir @name
1253
+ end
1254
+
1255
+ Dir.chdir @name do yield end
1256
+ ### this is fragile--should record abs path when Lib is created
1257
+ end
1258
+
1259
+ # Yields the array of lines being constructed so that additional configuration
1260
+ # can be added. See the ruby documentation on mkmf.
1261
+ def extconf # :yields: lines_array
1262
+ a = []
1263
+ a << "require 'mkmf'"
1264
+ a << "$CFLAGS = \"#$CFLAGS\"" if defined?($CFLAGS)
1265
+ yield a if block_given?
1266
+ a << "create_makefile '#{@name}'"
1267
+ end
1268
+
1269
+ def loadlib
1270
+ require File.join(".", @name, @name)
1271
+ rescue ScriptError, StandardError => e
1272
+ raise e.class, "\nCgen: problem loading library:\n" + e.message
1273
+ end
1274
+
1275
+ class RbDefineAccumulator < Accumulator
1276
+ def add spec
1277
+ c_name = spec[:c_name]
1278
+ mod = spec[:mod]
1279
+ rb_name = spec[:rb_name]
1280
+
1281
+ meth_rec =
1282
+ if c_name
1283
+ @pile.find { |s| s[:c_name] == c_name }
1284
+ else
1285
+ @pile.find { |s| s[:mod] == mod and s[:rb_name] == rb_name }
1286
+ end
1287
+
1288
+ if meth_rec
1289
+ meth_rec.update spec
1290
+ else
1291
+ meth_rec = spec
1292
+
1293
+ unless rb_name
1294
+ raise ArgumentError, "define: must provide method name."
1295
+ end
1296
+
1297
+ kind = @name.to_s.sub(/\Arb_define_/, "")
1298
+ if mod
1299
+ meth_rec[:mod_c_name] ||= @parent.declare_module(mod) ## @parent ?
1300
+ meth_rec[:c_name] ||=
1301
+ ("#{CGenerator::make_c_name rb_name}" +
1302
+ "_#{meth_rec[:mod_c_name]}_#{kind}").intern
1303
+ else
1304
+ meth_rec[:c_name] ||=
1305
+ "#{CGenerator::make_c_name rb_name}_#{kind}".intern
1306
+ end
1307
+ meth_rec[:argc] ||= 0
1308
+ @pile << meth_rec
1309
+ end
1310
+
1311
+ meth_rec[:c_name]
1312
+ end
1313
+
1314
+ def to_s
1315
+ @pile.collect { |m|
1316
+ rb_name = m[:rb_name]
1317
+ c_name = m[:c_name]
1318
+ argc = m[:argc]
1319
+ if m[:mod]
1320
+ mod_c_name = m[:mod_c_name]
1321
+ "#{@name}(#{mod_c_name}, \"#{rb_name}\", #{c_name}, #{argc});"
1322
+ else
1323
+ "#{@name}(\"#{rb_name}\", #{c_name}, #{argc});"
1324
+ end
1325
+ }.join "\n"
1326
+ end
1327
+
1328
+ end # class RbDefineAccumulator
1329
+
1330
+ accumulator(:rb_define_method,
1331
+ :rb_define_module_function,
1332
+ :rb_define_global_function,
1333
+ :rb_define_singleton_method) {RbDefineAccumulator}
1334
+
1335
+ def define_c_method(*args)
1336
+ @source_file.define_c_method(*args)
1337
+ end
1338
+
1339
+ def define_c_module_function(*args)
1340
+ @source_file.define_c_module_function(*args)
1341
+ end
1342
+
1343
+ def define_c_global_function(*args)
1344
+ @source_file.define_c_global_function(*args)
1345
+ end
1346
+
1347
+ def define_c_singleton_method(*args)
1348
+ @source_file.define_c_singleton_method(*args)
1349
+ end
1350
+ alias define_c_class_method define_c_singleton_method
1351
+
1352
+ def include(*args)
1353
+ @source_file.include(*args)
1354
+ end
1355
+
1356
+ def declare(*args)
1357
+ @source_file.declare(*args)
1358
+ end
1359
+ alias declare_static declare
1360
+
1361
+ def declare_extern(*args)
1362
+ @include_file.declare(*args)
1363
+ end
1364
+
1365
+ def declare_struct struct_name, *rest
1366
+ @source_file.declare_struct struct_name, *rest
1367
+ end
1368
+ alias declare_static_struct declare_struct
1369
+
1370
+ def declare_extern_struct struct_name, *rest
1371
+ @include_file.declare_struct struct_name, *rest
1372
+ end
1373
+
1374
+ def define(*args)
1375
+ @source_file.define(*args)
1376
+ end
1377
+ alias define_c_function define
1378
+
1379
+ def declare_module mod
1380
+ c_name = "module_#{CGenerator::make_c_name mod.to_s}"
1381
+ declare mod => "VALUE #{c_name}"
1382
+ declare_extern mod => "extern VALUE #{c_name}"
1383
+ setup mod => "#{c_name} = rb_path2class(\"#{mod}\")"
1384
+ c_name.intern
1385
+ end
1386
+ alias declare_class declare_module
1387
+
1388
+ def declare_symbol sym
1389
+ c_name = "ID_#{CGenerator::make_c_name sym}"
1390
+ declare sym => "ID #{c_name}"
1391
+ declare_extern sym => "extern ID #{c_name}"
1392
+ setup sym => "#{c_name} = rb_intern(\"#{sym}\")"
1393
+ c_name.intern
1394
+ end
1395
+
1396
+ def literal_symbol sym
1397
+ c_name = "SYM_#{CGenerator::make_c_name sym}"
1398
+ declare sym => "VALUE #{c_name}"
1399
+ declare_extern sym => "extern VALUE #{c_name}"
1400
+ setup sym => "#{c_name} = ID2SYM(rb_intern(\"#{sym}\"))"
1401
+ c_name.intern
1402
+ end
1403
+
1404
+ def setup(*args)
1405
+ @init_library_function.setup(*args)
1406
+ end
1407
+
1408
+ Template.inherit :parent,
1409
+ :declare_module, :declare_symbol,
1410
+ :declare_static, :declare_extern,
1411
+ :declare_class, :declare_module,
1412
+ :literal_symbol,
1413
+ :library, :file,
1414
+ :assert_uncommitted
1415
+
1416
+ def library
1417
+ self
1418
+ end
1419
+
1420
+ end # class Library
1421
+
1422
+
1423
+ class CFragment < Template
1424
+
1425
+ class StatementAccumulator < Accumulator
1426
+ def add_one_really item
1427
+ if item.kind_of? String
1428
+ super item.tabto(0)
1429
+ else
1430
+ super
1431
+ end
1432
+ end
1433
+
1434
+ def output_one item
1435
+ str = item.to_s
1436
+ # if str =~ /(?:\A|[;}])\s*\z/
1437
+ if str.empty? or str =~ /[\s;}]\z/ or str =~ /\A\s*(?:\/\/|#)/
1438
+ str
1439
+ else
1440
+ str + ';'
1441
+ end
1442
+ end
1443
+ end
1444
+
1445
+ class StatementKeyAccumulator < StatementAccumulator
1446
+ include KeyAccumulator
1447
+ def value_filter(value)
1448
+ if value.kind_of? String
1449
+ super value.tabto(0)
1450
+ else
1451
+ super
1452
+ end
1453
+ end
1454
+ end
1455
+
1456
+ class BlockAccumulator < StatementAccumulator
1457
+ def add(*args)
1458
+ super
1459
+ return self
1460
+ end
1461
+ def to_s
1462
+ ["{", super.tabto(4), "}"].join "\n"
1463
+ end
1464
+ end
1465
+
1466
+ class SingletonAccumulator < Accumulator
1467
+ def add_one item
1468
+ @pile = [item]
1469
+ end
1470
+ end
1471
+
1472
+ end # class CFragment
1473
+
1474
+
1475
+ class CFile < CFragment
1476
+
1477
+ attr_reader :include_file
1478
+
1479
+ def initialize name, library, include_file = nil
1480
+ super name, library
1481
+ @include_file = include_file
1482
+ if include_file
1483
+ add preamble!, include!, declare!, define!
1484
+ else
1485
+ ## it's a little hacky to decide in this way that this is a .h file
1486
+ sym = name.gsub(/\W/, '_')
1487
+ add "#ifndef #{sym}\n#define #{sym}",
1488
+ preamble!, include!, declare!, define!,
1489
+ "#endif"
1490
+ end
1491
+ end
1492
+
1493
+ def separator
1494
+ "\n\n"
1495
+ end
1496
+
1497
+ class FunctionAccumulator < Accumulator
1498
+
1499
+ def add name, kind = Function
1500
+ @parent.assert_uncommitted
1501
+ name = name.intern if name.is_a? String
1502
+
1503
+ if kind.is_a? Symbol or kind.is_a? String
1504
+ kind = eval "CGenerator::#{kind}"
1505
+ end
1506
+
1507
+ unless kind <= Function
1508
+ raise ArgumentError,
1509
+ "#{kind.class} #{kind} is not a subclass of CGenerator::Function."
1510
+ end
1511
+
1512
+ fn = @pile.find { |f| f.name == name }
1513
+ unless fn
1514
+ fn = kind.new name, @parent
1515
+ super fn
1516
+ end
1517
+ fn
1518
+ end
1519
+
1520
+ def separator
1521
+ "\n\n"
1522
+ end
1523
+
1524
+ end
1525
+
1526
+ class IncludeAccumulator < Accumulator
1527
+ include SetAccumulator
1528
+ def output_one item
1529
+ item = item.name unless item.is_a? String
1530
+ "#include " +
1531
+ if item =~ /\A<.*>\z/
1532
+ item
1533
+ else
1534
+ '"' + item + '"'
1535
+ end
1536
+ end
1537
+ end
1538
+
1539
+ class CommentAccumulator < Accumulator
1540
+ def to_s
1541
+ str = super
1542
+ if str.length > 0
1543
+ str.gsub(/^(?!\/\/)/, "// ")
1544
+ else
1545
+ str
1546
+ end
1547
+ end
1548
+ end
1549
+
1550
+ accumulator(:preamble) {CommentAccumulator}
1551
+ accumulator(:include) {IncludeAccumulator}
1552
+ accumulator(:declare) {StatementKeyAccumulator}
1553
+ accumulator(:define) {FunctionAccumulator}
1554
+
1555
+ def define_c_function c_name, subclass = Function
1556
+ define c_name, subclass
1557
+ end
1558
+
1559
+ def define_c_method mod, name, subclass = Method
1560
+ unless subclass <= Method ## should use assert
1561
+ raise "#{subclass.name} is not <= Method"
1562
+ end
1563
+ c_name = library.rb_define_method :mod => mod, :rb_name => name
1564
+ define c_name, subclass
1565
+ end
1566
+
1567
+ def define_c_module_function mod, name, subclass = ModuleFunction
1568
+ raise unless subclass <= ModuleFunction
1569
+ c_name = library.rb_define_module_function :mod => mod, :rb_name => name
1570
+ define c_name, subclass
1571
+ end
1572
+
1573
+ def define_c_global_function name, subclass = GlobalFunction
1574
+ raise unless subclass <= GlobalFunction
1575
+ c_name = library.rb_define_global_function :rb_name => name
1576
+ define c_name, subclass
1577
+ end
1578
+
1579
+ def define_c_singleton_method mod, name, subclass = SingletonMethod
1580
+ raise unless subclass <= SingletonMethod
1581
+ c_name = library.rb_define_singleton_method :mod => mod, :rb_name => name
1582
+ define c_name, subclass
1583
+ end
1584
+ alias define_c_class_method define_c_singleton_method
1585
+
1586
+ # For ruby 1.7/1.8 after 20Dec2002
1587
+ def define_alloc_func klass
1588
+ klass_c_name = declare_class klass
1589
+ c_name = "alloc_func_#{klass_c_name}"
1590
+ library.init_library_function.body \
1591
+ %{rb_define_alloc_func(#{klass_c_name}, #{c_name})}
1592
+ define c_name, Function
1593
+ end
1594
+
1595
+ def declare_struct struct_name, *rest
1596
+ struct = CGenerator::Structure.new struct_name, self, *rest
1597
+ declare struct_name => ["\n", struct, ";\n"]
1598
+ struct
1599
+ end
1600
+
1601
+ def declare_extern_struct struct_name, *rest
1602
+ @include_file.declare_struct struct_name, *rest
1603
+ end
1604
+
1605
+ alias declare_static declare
1606
+
1607
+ def declare_extern(*args)
1608
+ if @include_file
1609
+ @include_file.declare(*args)
1610
+ else
1611
+ declare(*args)
1612
+ end
1613
+ end
1614
+
1615
+ def to_s
1616
+ super + "\n"
1617
+ end
1618
+
1619
+ def file
1620
+ self
1621
+ end
1622
+
1623
+ end # class CFile
1624
+
1625
+
1626
+ class Prototype < CFragment
1627
+
1628
+ class ArgumentAccumulator < Accumulator
1629
+ include SetAccumulator
1630
+ def to_s
1631
+ if @pile.size > 0
1632
+ "(" + @pile.join(", ") + ")"
1633
+ else
1634
+ '(void)'
1635
+ end
1636
+ end
1637
+
1638
+ def size
1639
+ @pile.size
1640
+ end
1641
+ end
1642
+
1643
+ accumulator(:scope,
1644
+ :return_type) {SingletonAccumulator}
1645
+ accumulator(:arguments) {ArgumentAccumulator}
1646
+
1647
+ def initialize name, parent
1648
+ super
1649
+ add scope!, return_type!, " ", name, arguments!
1650
+ end
1651
+
1652
+ def separator; ""; end
1653
+
1654
+ def argc
1655
+ arguments!.size
1656
+ end
1657
+
1658
+ end # class Prototype
1659
+
1660
+ class Function < CFragment
1661
+
1662
+ def initialize name, parent
1663
+ super
1664
+
1665
+ scope :static
1666
+ return_type 'void'
1667
+
1668
+ add prototype,
1669
+ block(declare!, init!, setup!, body!, returns!)
1670
+ end
1671
+
1672
+ def empty?
1673
+ block!.to_s =~ /\A\{\s*\}\z/m
1674
+ end
1675
+
1676
+ def prototype
1677
+ @prototype ||= Prototype.new(name, self)
1678
+ end
1679
+
1680
+ def scope s
1681
+ scope_str = s.to_s
1682
+ unless defined?(@scope) and scope_str == @scope
1683
+ @scope = scope_str
1684
+ case scope_str
1685
+ when "static"
1686
+ prototype.scope "static " ## this is kludgy
1687
+ declare_static @name => prototype
1688
+ declare_extern @name => nil
1689
+ when "extern"
1690
+ prototype.scope "" ## would be too much work to do "extern "
1691
+ declare_extern @name => prototype
1692
+ declare_static @name => nil
1693
+ end
1694
+ end
1695
+ end
1696
+
1697
+ class ReturnAccumulator < SingletonAccumulator
1698
+ def to_s
1699
+ if @pile.size > 0
1700
+ "return #{@pile.join};"
1701
+ else
1702
+ ""
1703
+ end
1704
+ end
1705
+ end
1706
+
1707
+ class InitAccumulator < BlockAccumulator
1708
+ def add_one_really(*args)
1709
+ super
1710
+ @parent.declare :first_time => "static int first_time = 1"
1711
+ end
1712
+
1713
+ def to_s
1714
+ if @pile.size > 0
1715
+ ["\nif (first_time)", super].join(" ") +
1716
+ "\nif (first_time) first_time = 0;\n"
1717
+ else
1718
+ ""
1719
+ end
1720
+ end
1721
+ end
1722
+
1723
+ accumulator(:block) {BlockAccumulator}
1724
+ accumulator(:declare) {StatementKeyAccumulator}
1725
+ accumulator(:init) {InitAccumulator}
1726
+ accumulator(:setup) {StatementKeyAccumulator}
1727
+ accumulator(:body) {StatementAccumulator}
1728
+ accumulator(:returns) {ReturnAccumulator}
1729
+
1730
+ def return_type(*args)
1731
+ prototype.return_type(*args)
1732
+ end
1733
+
1734
+ def arguments(*args)
1735
+ prototype.arguments(*args)
1736
+ end
1737
+
1738
+ end # class Function
1739
+
1740
+
1741
+ class MethodPrototype < Prototype
1742
+
1743
+ class MethodArgumentAccumulator < ArgumentAccumulator
1744
+ def add_one item
1745
+ item = item.to_s
1746
+ unless item =~ /\AVALUE /
1747
+ item = "VALUE " + item
1748
+ end
1749
+ super
1750
+ end
1751
+ def reset
1752
+ @pile = []
1753
+ end
1754
+ end
1755
+
1756
+ class RbScanArgsSpec
1757
+ def initialize bl
1758
+ @required = @optional = @typecheck = @default = @rest = @block = nil
1759
+ if bl
1760
+ instance_eval(&bl)
1761
+ end
1762
+ end
1763
+
1764
+ def required(*args); @required = args; end
1765
+ def optional(*args); @optional = args; end
1766
+ def typecheck(arg); @typecheck = arg; end
1767
+ def default(arg); @default = arg; end
1768
+ def rest(arg); @rest = arg; end
1769
+ def block(arg); @block = arg; end
1770
+
1771
+ def get_required; @required; end
1772
+ def get_optional; @optional; end
1773
+ def get_typecheck; @typecheck; end
1774
+ def get_default; @default; end
1775
+ def get_rest; @rest; end
1776
+ def get_block; @block; end
1777
+ end
1778
+
1779
+ accumulator(:arguments) {MethodArgumentAccumulator}
1780
+
1781
+ def c_array_args(argc_name = 'argc', argv_name = 'argv', &bl)
1782
+ arguments!.reset
1783
+ arguments!.add_one_really "int #{argc_name}"
1784
+ arguments!.add "*#{argv_name}", "self"
1785
+ @pile.freeze
1786
+
1787
+ scan_spec = RbScanArgsSpec.new(bl)
1788
+
1789
+ fmt_str = '"'
1790
+ arg_list = [fmt_str]
1791
+
1792
+ required = scan_spec.get_required
1793
+ count_required = required ? required.size : 0
1794
+ if count_required > 0
1795
+ fmt_str << "#{required.size}"
1796
+ for arg in required
1797
+ arg_list << arg
1798
+ declare arg => "VALUE #{arg}"
1799
+ end
1800
+ end
1801
+
1802
+ optional = scan_spec.get_optional
1803
+
1804
+ count_optional = optional ? optional.size : 0
1805
+ if count_optional > 0
1806
+ fmt_str << "0" unless count_required > 0
1807
+ fmt_str << "#{optional.size}"
1808
+ for arg in optional
1809
+ arg_list << arg
1810
+ declare arg => "VALUE #{arg}"
1811
+ end
1812
+ end
1813
+
1814
+ rest = scan_spec.get_rest
1815
+ if rest
1816
+ fmt_str << "*"
1817
+ arg_list << rest
1818
+ declare rest => "VALUE #{rest}"
1819
+ end
1820
+
1821
+ block = scan_spec.get_block
1822
+ if block
1823
+ fmt_str << "&"
1824
+ arg_list << block
1825
+ declare block => "VALUE #{block}"
1826
+ end
1827
+
1828
+ fmt_str << '"'
1829
+ arg_str = arg_list.join ", &"
1830
+
1831
+ unless arg_str == '""'
1832
+ setup :rb_scan_args => %{
1833
+ rb_scan_args(#{argc_name}, #{argv_name}, #{arg_str});
1834
+ }.tabto(0)
1835
+
1836
+ typecheck = scan_spec.get_typecheck
1837
+ if typecheck
1838
+ for arg, argtype in typecheck
1839
+ next unless argtype and argtype != Object
1840
+ ## this could be a function call
1841
+ setup "#{arg} typecheck" => %{\
1842
+ if (!NIL_P(#{arg}) &&
1843
+ rb_obj_is_kind_of(#{arg}, #{declare_class argtype}) != Qtrue)
1844
+ rb_raise(#{declare_class TypeError},
1845
+ "argument #{arg} declared #{argtype} but passed %s.",
1846
+ STR2CSTR(rb_funcall(
1847
+ rb_funcall(#{arg}, #{declare_symbol :class}, 0),
1848
+ #{declare_symbol :to_s}, 0)));
1849
+ }.tabto(0)
1850
+ end
1851
+ end
1852
+
1853
+ default = scan_spec.get_default
1854
+ if default and default.size > 0
1855
+ cases =
1856
+ (0..count_optional-1).map { |i|
1857
+ "case #{i}:" +
1858
+ if default[optional[i]]
1859
+ " #{optional[i]} = #{default[optional[i]]};"
1860
+ else
1861
+ ""
1862
+ end
1863
+ }.join("\n")
1864
+
1865
+ setup :rb_scan_args_defaults => %{\
1866
+ switch (argc - #{count_required}) {\n#{cases}
1867
+ }
1868
+ }.tabto(0)
1869
+ end
1870
+ end
1871
+ end
1872
+
1873
+ def rb_array_args args_name = 'args'
1874
+ arguments "#{args_name}"
1875
+ @pile.freeze
1876
+ end
1877
+
1878
+ end # class MethodPrototype
1879
+
1880
+ class RubyFunction < Function
1881
+
1882
+ def initialize name, parent
1883
+ super
1884
+ return_type 'VALUE'
1885
+ arguments 'self'
1886
+ returns 'Qnil'
1887
+ end
1888
+
1889
+ def prototype
1890
+ @prototype ||= MethodPrototype.new(name, self)
1891
+ end
1892
+
1893
+ def c_array_args(*args, &bl)
1894
+ prototype.c_array_args(*args, &bl)
1895
+ register_args :c_name => @name, :argc => -1 # code used by Ruby C API
1896
+ end
1897
+
1898
+ def rb_array_args(*args, &bl)
1899
+ prototype.rb_array_args(*args, &bl)
1900
+ register_args :c_name => @name, :argc => -2 # code used by Ruby C API
1901
+ end
1902
+
1903
+ def arguments(*args, &bl)
1904
+ prototype.arguments(*args, &bl)
1905
+ register_args :c_name => @name, :argc => prototype.argc - 1
1906
+ end
1907
+
1908
+ end
1909
+
1910
+
1911
+ class Method < RubyFunction
1912
+ def register_args(*args)
1913
+ rb_define_method(*args)
1914
+ end
1915
+ end
1916
+
1917
+ class ModuleFunction < RubyFunction
1918
+ def register_args(*args)
1919
+ rb_define_module_function(*args)
1920
+ end
1921
+ end
1922
+
1923
+ class GlobalFunction < RubyFunction
1924
+ def register_args(*args)
1925
+ rb_define_global_function(*args)
1926
+ end
1927
+ end
1928
+
1929
+ class SingletonMethod < RubyFunction
1930
+ def register_args(*args)
1931
+ rb_define_singleton_method(*args)
1932
+ end
1933
+ end
1934
+
1935
+
1936
+ class Structure < CFragment
1937
+
1938
+ class InheritAccumulator < Accumulator; include SetAccumulator; end
1939
+
1940
+ accumulator(:block) {BlockAccumulator}
1941
+ accumulator(:inherit) {InheritAccumulator}
1942
+ accumulator(:declare) {StatementKeyAccumulator}
1943
+
1944
+ def initialize name, parent, attribute = nil
1945
+ super(name, parent)
1946
+ if attribute
1947
+ add "typedef struct #{name}", block!, "#{attribute} #{name}"
1948
+ else
1949
+ add "typedef struct #{name}", block!, name
1950
+ end
1951
+ block inherit!, declare!
1952
+ end
1953
+
1954
+ def separator; " "; end
1955
+
1956
+ end # class Structure
1957
+
1958
+
1959
+ OpName= {
1960
+ '<' => :op_lt,
1961
+ '<=' => :op_le,
1962
+ '>' => :op_gt,
1963
+ '>=' => :op_ge,
1964
+ '==' => :op_eqeq
1965
+ }
1966
+
1967
+ def CGenerator.make_c_name s
1968
+ s = s.to_s
1969
+ OpName[s] || translate_ruby_identifier(s)
1970
+ end
1971
+
1972
+ def CGenerator.translate_ruby_identifier(s)
1973
+ # For uniqueness, we use a single '_' to indicate our subs
1974
+ # and translate pre-existing '_' to '__'
1975
+ # It should be possible to write another method which
1976
+ # converts the output back to the original.
1977
+ c_name = s.gsub(/_/, '__')
1978
+
1979
+
1980
+ # Ruby identifiers can include prefix $, @, or @@, or suffix ?, !, or =
1981
+ # and they can be [] or []=
1982
+ c_name.gsub!(/\$/, 'global_')
1983
+ c_name.gsub!(/@/, 'attr_')
1984
+ c_name.gsub!(/\?/, '_query')
1985
+ c_name.gsub!(/!/, '_bang')
1986
+ c_name.gsub!(/=/, '_equals')
1987
+ c_name.gsub!(/::/, '_')
1988
+ c_name.gsub!(/\[\]/, '_brackets')
1989
+
1990
+ # so that some Ruby expressions can be associated with a name,
1991
+ # we allow '.' in the str. Eventually, handle more Ruby exprs.
1992
+ c_name.gsub!(/\./, '_dot_')
1993
+
1994
+ # we should also make an attempt to encode special globals
1995
+ # like $: and $-I
1996
+
1997
+ unless c_name =~ /\A[A-Za-z_]\w*\z/
1998
+ raise SyntaxError,
1999
+ "Cgen's encoding cannot handle #{s.inspect}; " +
2000
+ "best try is #{c_name.inspect}."
2001
+ end
2002
+
2003
+ c_name.intern
2004
+ end
2005
+
2006
+ end # module CGenerator
2007
+
2008
+
2009
+ ##class Array
2010
+ ## def join_nonempty str
2011
+ ## map { |x|. x.to_s }.reject { |s| s == "" }.join(str)
2012
+ ## end
2013
+ ##end
2014
+
2015
+ class String
2016
+
2017
+ # tabs left or right by n chars, using spaces
2018
+ def tab n
2019
+ if n >= 0
2020
+ gsub(/^/, ' ' * n)
2021
+ else
2022
+ gsub(/^ {0,#{-n}}/, "")
2023
+ end
2024
+ end
2025
+
2026
+ # preserves relative tabbing
2027
+ # the first non-empty line ends up with n spaces before nonspace
2028
+ def tabto n
2029
+ if self =~ /^( *)\S/
2030
+ tab(n - $1.length)
2031
+ else
2032
+ self
2033
+ end
2034
+ end
2035
+
2036
+ # aligns each line
2037
+ def taballto n
2038
+ gsub(/^ */, ' ' * n)
2039
+ end
2040
+
2041
+ end # class String