autoc 1.1 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,104 @@
1
+ require "set"
2
+ require "forwardable"
1
3
  require "autoc/code"
2
4
 
3
5
 
4
6
  module AutoC
5
7
 
6
8
 
9
+ # @private
10
+ class Dispatcher
11
+
12
+ # @private
13
+ class ParameterArray < Array
14
+ def self.coerce(*params)
15
+ out = []
16
+ i = 0
17
+ params.each do |t|
18
+ i += 1
19
+ out << (t.is_a?(Array) ? t.collect {|x| x.to_s} : [t.to_s, "_#{i}"])
20
+ end
21
+ self.new(out)
22
+ end
23
+ # Test for parameter list compatibility
24
+ def ===(other) other.is_a?(ParameterArray) && types == other.types end
25
+ def types; collect {|x| x.first} end
26
+ def names; collect {|x| x.last} end
27
+ def pass; names.join(',') end
28
+ def declaration; types.join(',') end
29
+ def definition; collect {|x| "#{x.first} #{x.last}"}.join(',') end
30
+ end # ParameterArray
31
+
32
+ # def call(*params)
33
+
34
+ def dispatch(*params)
35
+ if params.empty?
36
+ self
37
+ else
38
+ params = [] if params.size == 1 && params.first.nil?
39
+ call(*params)
40
+ end
41
+ end
42
+
43
+ end # Dispatcher
44
+
45
+
46
+ # @private
47
+ class Statement < Dispatcher
48
+
49
+ attr_reader :parameters
50
+
51
+ def initialize(params = [])
52
+ @parameters = ParameterArray.coerce(*params)
53
+ end
54
+
55
+ end # Statement
56
+
57
+
58
+ # @private
59
+ class Function < Dispatcher
60
+
61
+ # @private
62
+ class Signature
63
+
64
+ attr_reader :parameters, :result
65
+
66
+ def initialize(params = [], result = nil)
67
+ @parameters = Dispatcher::ParameterArray.coerce(*params)
68
+ @result = (result.nil? ? :void : result).to_s
69
+ end
70
+
71
+ end # Signature
72
+
73
+ extend Forwardable
74
+
75
+ def_delegators :@signature,
76
+ :parameters, :result
77
+
78
+ attr_reader :name, :signature
79
+
80
+ def initialize(name, a = [], b = nil)
81
+ @name = AutoC.c_id(name)
82
+ @signature = a.is_a?(Signature) ? a : Signature.new(a, b)
83
+ end
84
+
85
+ def to_s; name end
86
+
87
+ def call(*params)
88
+ "#{name}(#{params.join(',')})"
89
+ end
90
+
91
+ def definition
92
+ "#{result} #{name}(#{parameters.definition})"
93
+ end
94
+
95
+ def declaration
96
+ "#{result} #{name}(#{parameters.declaration})"
97
+ end
98
+
99
+ end # Function
100
+
101
+
7
102
  class Type < Code
8
103
 
9
104
  # @private
@@ -50,60 +145,83 @@ class Type < Code
50
145
  end
51
146
  end.new
52
147
 
53
- attr_reader :type
148
+ def self.coerce(type)
149
+ type.is_a?(Type) ? type : UserDefinedType.new(type)
150
+ end
151
+
152
+ def hash; self.class.hash ^ type.hash end
153
+
154
+ def ==(other) self.class == other.class && type == other.type end
54
155
 
55
- def entities; [CommonCode] end
156
+ alias :eql? :==
157
+
158
+ def entities; super << CommonCode end
56
159
 
160
+ attr_reader :type, :type_ref
161
+
162
+ def prefix
163
+ # Lazy evaluator for simple types like char* which do not actually use
164
+ # this method and hence do not require the prefix to be valid C identifier
165
+ AutoC.c_id(type)
166
+ end
167
+
57
168
  def initialize(type, visibility = :public)
58
169
  @type = type.to_s
170
+ @type_ref = "#{self.type}*"
59
171
  @visibility = [:public, :private, :static].include?(visibility) ? visibility : raise("unsupported visibility")
172
+ @capability = Set[:constructible, :destructible, :copyable, :comparable, :hashable, :orderable] # Can be used to disable specific capabilities for a type
173
+ # Canonic special method signatures
174
+ @ctor_signature = Function::Signature.new([type^:self])
175
+ @dtor_signature = Function::Signature.new([type^:self])
176
+ @copy_signature = Function::Signature.new([type^:dst, type^:src])
177
+ @equal_signature = Function::Signature.new([type^:lt, type^:rt], :int)
178
+ @identify_signature = Function::Signature.new([type^:self], :size_t)
179
+ @less_signature = Function::Signature.new([type^:lt, type^:rt], :int)
60
180
  end
61
181
 
62
182
  def method_missing(method, *args)
63
183
  str = method.to_s
64
- func = @type + str[0,1].capitalize + str[1..-1] # Ruby 1.8 compatible
184
+ str = str.sub(/[\!\?]$/, '') # Strip trailing ? or !
185
+ fn = prefix + str[0,1].capitalize + str[1..-1] # Ruby 1.8 compatible
65
186
  if args.empty?
66
- func # Emit bare function name
187
+ fn # Emit bare function name
67
188
  elsif args.size == 1 && args.first == nil
68
- func + "()" # Use sole nil argument to emit function call with no arguments
189
+ fn + '()' # Use sole nil argument to emit function call with no arguments
69
190
  else
70
- func + "(" + args.join(", ") + ")" # Emit normal function call with supplied arguments
191
+ fn + '(' + args.join(',') + ')' # Emit normal function call with supplied arguments
71
192
  end
72
193
  end
73
194
 
74
195
  def write_intf(stream)
75
- case @visibility
76
- when :public
77
- write_exported_types(stream)
78
- write_exported_declarations(stream, extern, inline)
196
+ if public?
197
+ write_intf_types(stream)
198
+ write_intf_decls(stream, extern, inline)
79
199
  end
80
200
  end
81
201
 
82
202
  def write_decls(stream)
83
- case @visibility
84
- when :private
85
- write_exported_types(stream)
86
- write_exported_declarations(stream, extern, inline)
87
- when :static
88
- write_exported_types(stream)
89
- write_exported_declarations(stream, static, inline)
203
+ if private?
204
+ write_intf_types(stream)
205
+ write_intf_decls(stream, extern, inline)
206
+ elsif static?
207
+ write_intf_types(stream)
208
+ write_intf_decls(stream, static, inline)
90
209
  end
91
210
  end
92
211
 
93
212
  def write_defs(stream)
94
- case @visibility
95
- when :public, :private
96
- write_implementations(stream, nil)
97
- when :static
98
- write_implementations(stream, static)
213
+ if public? || private?
214
+ write_impls(stream, nil)
215
+ elsif static?
216
+ write_impls(stream, static)
99
217
  end
100
218
  end
101
219
 
102
- def write_exported_types(stream) end
220
+ # def write_intf_types(stream)
103
221
 
104
- def write_exported_declarations(stream, declare, define) end
222
+ # def write_intf_decls(stream, declare, define)
105
223
 
106
- def write_implementations(stream, define) end
224
+ # def write_impls(stream, define)
107
225
 
108
226
  def extern; "AUTOC_EXTERN" end
109
227
 
@@ -121,78 +239,225 @@ class Type < Code
121
239
 
122
240
  def abort; "abort" end
123
241
 
124
- protected
125
-
126
242
  def public?; @visibility == :public end
127
243
 
128
244
  def private?; @visibility == :private end
129
245
 
130
246
  def static?; @visibility == :static end
131
247
 
248
+ def constructible?; @capability.include?(:constructible) end
249
+
250
+ def destructible?; @capability.include?(:destructible) end
251
+
252
+ def copyable?; @capability.include?(:copyable) end
253
+
254
+ def comparable?; @capability.include?(:comparable) end
255
+
256
+ def orderable?; @capability.include?(:orderable) && comparable? end
257
+
258
+ def hashable?; @capability.include?(:hashable) && comparable? end
259
+
260
+ # Create forwarding readers which take arbitrary number of arguments
261
+ [:ctor, :dtor, :copy, :equal, :identify, :less].each do |name|
262
+ class_eval %$
263
+ def #{name}(*args)
264
+ @#{name}.dispatch(*args)
265
+ end
266
+ $
267
+ end
268
+
269
+ private
270
+
271
+ def define_function(name, signature)
272
+ Function.new(method_missing(name), signature)
273
+ end
274
+
132
275
  end # Type
133
276
 
134
277
 
278
+ =begin
279
+
280
+ UserDefinedType represents a user-defined custom type.
281
+
282
+ =end
135
283
  class UserDefinedType < Type
136
284
 
137
285
  # @private
138
286
  class PublicDeclaration < Code
139
- def entities; super + [Type::CommonCode] end
287
+ def entities; super << Type::CommonCode end
140
288
  def initialize(forward) @forward = forward.to_s end
141
289
  def hash; @forward.hash end
142
- def eql?(other) self.class == other.class && @forward == other.instance_variable_get(:@forward) end
290
+ def ==(other) self.class == other.class && @forward == other.instance_variable_get(:@forward) end
291
+ alias :eql? :==
143
292
  def write_intf(stream)
144
- stream << "\n"
145
- stream << @forward
146
- stream << "\n"
293
+ stream << "\n#{@forward}\n"
147
294
  end
148
295
  end # PublicDeclaration
149
296
 
150
- def entities; super + @deps end
297
+ def entities; super.concat(@deps) end
298
+
299
+ def prefix; @prefix.nil? ? super : @prefix end
151
300
 
152
301
  def initialize(opt)
153
- @deps = []
154
- v = :public
155
- if [Symbol, String].include?(opt.class)
156
- t = opt
157
- elsif opt.is_a?(Hash)
158
- t = opt[:type].nil? ? raise("type is not specified") : opt[:type]
159
- [:ctor, :dtor, :copy, :equal, :less, :identify].each do |key|
160
- instance_variable_set("@#{key}".to_sym, opt[key].to_s) unless opt[key].nil?
161
- end
162
- @deps << PublicDeclaration.new(opt[:forward]) unless opt[:forward].nil?
163
- optv = opt[:visibility]
164
- v = optv.nil? ? :public : optv
302
+ opt = {:type => opt} if opt.is_a?(Symbol) || opt.is_a?(String)
303
+ if opt.is_a?(Hash)
304
+ t = opt[:type].nil? ? raise("type is not specified") : opt[:type].to_s
165
305
  else
166
- raise "failed to decode the argument"
306
+ raise "argument must be a Symbol, String or Hash"
167
307
  end
168
- super(t, v)
308
+ super(t)
309
+ @prefix = AutoC.c_id(opt[:prefix]) unless opt[:prefix].nil?
310
+ @deps = []; @deps << PublicDeclaration.new(opt[:forward]) unless opt[:forward].nil?
311
+ opt.default = :unset # This allows to use nil as a value to indicate that the specific method is not avaliable
312
+ opt[:ctor].nil? ? @capability.subtract([:constructible]) : define_callable(:ctor, opt) {def call(obj) "((#{obj}) = 0)" end}
313
+ opt[:dtor].nil? ? @capability.subtract([:destructible]) : define_callable(:dtor, opt) {def call(obj) end}
314
+ opt[:copy].nil? ? @capability.subtract([:copyable]) : define_callable(:copy, opt) {def call(dst, src) "((#{dst}) = (#{src}))" end}
315
+ opt[:equal].nil? ? @capability.subtract([:comparable]) : define_callable(:equal, opt) {def call(lt, rt) "((#{lt}) == (#{rt}))" end}
316
+ opt[:less].nil? ? @capability.subtract([:orderable]) : define_callable(:less, opt) {def call(lt, rt) "((#{lt}) < (#{rt}))" end}
317
+ opt[:identify].nil? ? @capability.subtract([:hashable]) : define_callable(:identify, opt) {def call(obj) "((size_t)(#{obj}))" end}
318
+ # Handle specific requirements
319
+ @capability.subtract([:constructible]) if @ctor.parameters.size > 1 # Constructible type must not have extra parameters besides self
169
320
  end
170
321
 
171
- def ctor(obj)
172
- @ctor.nil? ? "(#{obj} = 0)" : "#{@ctor}(#{obj})"
173
- end
322
+ private
174
323
 
175
- def dtor(obj)
176
- @dtor.nil? ? nil : "#{@dtor}(#{obj})"
324
+ # Default methods creator
325
+ def define_callable(name, opt, &code)
326
+ iv = "@#{name}"
327
+ ivs = "@#{name}_signature"
328
+ c = if opt[name] == :unset
329
+ # Synthesize statement block with default (canonic) parameter list
330
+ Class.new(Statement, &code).new(instance_variable_get(ivs).parameters)
331
+ elsif opt[name].is_a?(Function)
332
+ opt[name] # If a Function instance is given, pass it through
333
+ else
334
+ # If only a name is specified, assume it is the function name with default signature
335
+ Function.new(opt[name], instance_variable_get(ivs))
336
+ end
337
+ instance_variable_set(iv, c)
177
338
  end
178
339
 
179
- def copy(dst, src)
180
- @copy.nil? ? "(#{dst} = #{src})" : "#{@copy}(#{dst}, #{src})"
340
+ end # UserDefinedType
341
+
342
+
343
+ =begin
344
+
345
+ Reference represents a managed counted reference for any type.
346
+ It can be used with any type, including AutoC collections themselves.
347
+
348
+ == Generated C interface
349
+
350
+ === Type management
351
+
352
+ [cols="2*"]
353
+ |===
354
+ |*_Type_* * ~type~New(...)
355
+ |
356
+ Create and return a reference to *_Type_* with reference count set to one.
357
+
358
+ The storage for the returned instance is malloc()'ed. The instance is constructed with the type's constructor ~type~Ctor(...).
359
+
360
+ NOTE: The generated method borrows the second and subsequent arguments from the respective constructor.
361
+
362
+ |*_Type_* * ~type~Ref(*_Type_* * self)
363
+ |
364
+ Increment the +self+'s reference count and return +self+.
365
+
366
+ |*_void_* ~type~Free(*_Type_* * self)
367
+ |
368
+ Decrement the +self+'s reference count.
369
+ If the reference count reaches zero, free the storage and destroy the instance with the type's destructor ~type~Dtor().
370
+
371
+ =end
372
+ class Reference < Type
373
+
374
+ extend Forwardable
375
+
376
+ def_delegators :@target,
377
+ :prefix,
378
+ :public?, :private?, :static?,
379
+ :constructible?, :destructible?, :copyable?, :comparable?, :orderable?, :hashable?
380
+
381
+ def initialize(target)
382
+ @target = Type.coerce(target)
383
+ super(@target.type_ref) # NOTE : the type of the Reference instance itself is actually a pointer type
384
+ @ctor_params = Dispatcher::ParameterArray.new(@target.ctor.parameters[1..-1]) # Capture extra parameters from the target type constructor
385
+ define_callable(:ctor, @ctor_params) {def call(obj, *params) "((#{obj}) = #{@ref.new?}(#{params.join(',')}))" end}
386
+ define_callable(:dtor, [type]) {def call(obj) "#{@ref.free?}(#{obj})" end}
387
+ define_callable(:copy, [type, type]) {def call(dst, src) "((#{dst}) = #{@ref.ref?}(#{src}))" end}
388
+ define_callable(:equal, [type, type]) {def call(lt, rt) @target.equal("*#{lt}", "*#{rt}") end}
389
+ define_callable(:less, [type, type]) {def call(lt, rt) @target.less("*#{lt}", "*#{rt}") end}
390
+ define_callable(:identify, [type]) {def call(obj) @target.identify("*#{obj}") end}
181
391
  end
182
392
 
183
- def equal(lt, rt)
184
- @equal.nil? ? "(#{lt} == #{rt})" : "#{@equal}(#{lt}, #{rt})"
393
+ def ==(other) @target == other.instance_variable_get(:@target) end
394
+
395
+ alias :eql? :==
396
+
397
+ def entities; super << @target end
398
+
399
+ def write_intf_decls(stream, declare, define)
400
+ stream << %$
401
+ /***
402
+ **** <#{type}> (#{self.class})
403
+ ***/
404
+ #{declare} #{type} #{new?}(#{@ctor_params.declaration});
405
+ #{declare} #{type} #{ref?}(#{type});
406
+ #{declare} void #{free?}(#{type});
407
+ $
185
408
  end
186
409
 
187
- def less(lt, rt)
188
- @less.nil? ? "(#{lt} < #{rt})" : "#{@less}(#{lt}, #{rt})"
410
+ def write_impls(stream, define)
411
+ stream << %$
412
+ #define AUTOC_COUNTER(p) (*(size_t*)((char*)(p) + sizeof(#{@target.type})))
413
+ #{define} #{type} #{new?}(#{@ctor_params.definition}) {
414
+ #{type} self = (#{type})#{malloc}(sizeof(#{@target.type}) + sizeof(size_t)); #{assert}(self);
415
+ #{@target.ctor("*self", *@ctor_params.names)};
416
+ AUTOC_COUNTER(self) = 1;
417
+ return self;
418
+ }
419
+ #{define} #{type} #{ref?}(#{type} self) {
420
+ #{assert}(self);
421
+ ++AUTOC_COUNTER(self);
422
+ return self;
423
+ }
424
+ #{define} void #{free?}(#{type} self) {
425
+ #{assert}(self);
426
+ if(--AUTOC_COUNTER(self) == 0) {
427
+ #{@target.dtor("*self")};
428
+ #{free}(self);
429
+ }
430
+ }
431
+ #undef AUTOC_COUNTER
432
+ $
189
433
  end
190
434
 
191
- def identify(obj)
192
- @identify.nil? ? "(size_t)(#{obj})" : "#{@identify}(#{obj})"
435
+ private
436
+
437
+ # @private
438
+ class BoundStatement < Statement
439
+ def initialize(ref, target, params)
440
+ super(params)
441
+ @ref = ref
442
+ @target = target
443
+ end
444
+ end # BoundStatement
445
+
446
+ def define_callable(name, params, &code)
447
+ instance_variable_set("@#{name}", Class.new(BoundStatement, &code).new(self, @target, params))
193
448
  end
194
449
 
195
- end # UserDefinedType
450
+ end # Reference
451
+
452
+
453
+ # Class adjustments for the function signature definition DSL
454
+ [Symbol, String, Type].each do |type|
455
+ type.class_eval do
456
+ def ^(name)
457
+ [self, name]
458
+ end
459
+ end
460
+ end
196
461
 
197
462
 
198
463
  end # AutoC