cgen 0.16.0

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