csquare 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ class CSquare::Generator::BooleanOp < CSquare::Generator::BinaryOp
2
+
3
+ def decorated args_types, return_type, default_type_symbol
4
+ result = super(args_types, return_type, default_type_symbol)
5
+ return nil if result.nil?
6
+
7
+ # Boolean operations always return booleans
8
+ [result[0], :boolean]
9
+ end
10
+
11
+ # Determine which pattern to apply
12
+ def select_pattern args_types, return_type
13
+ args = args_types.keys
14
+ types = args_types.values
15
+
16
+ # If the exact arg has a pattern, prefer to use that
17
+ if self.has_key?(args[1]) # look for exact arg
18
+ self[args[1]]
19
+ elsif types[1].is_a?(Symbol) # look for type symbol
20
+ self[types[1]]
21
+ else # look for TYPE or LONG_TYPE or :cast
22
+
23
+ if types[0] == types[1]
24
+ self[blueprint.key]
25
+ else
26
+ self[:cast] || self[blueprint.long_key]
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+ end
@@ -0,0 +1,99 @@
1
+ class CSquare::Generator::Enum
2
+ def initialize name, opts = {}
3
+ @name = name
4
+ @prefix = opts[:prefix]
5
+
6
+ @on = opts.has_key?(:ops) ? :ops : :types
7
+
8
+ @selector = opts[@on]
9
+
10
+ # Don't need to use a namer if a hash was given; hash provides the names instead.
11
+ if @selector.is_a?(Array)
12
+ namer = opts[:with]
13
+ namer ||= @on == :ops ? :OpNamer : :Namer
14
+
15
+ namer_klass = begin
16
+ CSquare::Generator::Enum.const_get(namer)
17
+ rescue NameError
18
+ Kernel.const_get(namer)
19
+ end
20
+
21
+ # Create a namer object with the specified prefix (if any)
22
+ @namer = namer_klass.send :new, @prefix
23
+ end
24
+ end
25
+
26
+ attr_reader :selector, :name, :on
27
+
28
+ # Local symbols upon which we should enumerate. If types, this will be the type symbols (e.g., i8, i16, i32).
29
+ # If ops, this will be operations, like :'+', :'-', etc. Returns an array.
30
+ def enumerees
31
+ @selector.is_a?(Hash) ? @selector.values : @selector
32
+ end
33
+
34
+
35
+ def enumerate_for_index
36
+ ary = []
37
+ enumerees_and_c_values = enumerate.values
38
+ enumerees_and_c_values.sort_by{ |ecv| ecv[1] }.each do |enumeree_and_c_value|
39
+ ary <<[enumeree_and_c_value[0], enumeree_and_c_value[1]]
40
+ end
41
+ ary
42
+ end
43
+
44
+
45
+ # Pre-set/retrieve all the enum values (e.g., OP_ADD => '+'.ord) for
46
+ # the specified ops or dtypes (an Array).
47
+ def enumerate
48
+ h = {}
49
+
50
+ nums_used = Set.new
51
+
52
+ autos = []
53
+
54
+ if @selector.is_a?(Hash)
55
+ @selector.each_pair do |name, enumeree|
56
+ prefixed_name = [@prefix, name].compact.join('_')
57
+ autos << [enumeree, prefixed_name]
58
+ end
59
+ else
60
+ @selector.each do |enumeree|
61
+ num = @namer.num(enumeree)
62
+ name = @namer.name(enumeree)
63
+
64
+ next if name.nil? # don't bother if we couldn't determine a name
65
+
66
+ if num == :auto
67
+ autos << [enumeree, name]
68
+ else
69
+ h[name] = [enumeree, num]
70
+ nums_used.add(num) unless num == :auto
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ count = 0
77
+ # Now go back and re-number everything marked :auto
78
+ autos.each do |enumeree_and_name|
79
+ enumeree, name = enumeree_and_name
80
+
81
+ # Find the next unused number
82
+ count += 1 while nums_used.include?(count)
83
+
84
+ nums_used.add(count)
85
+ h[name] = [enumeree, count]
86
+ end
87
+
88
+ h
89
+ end
90
+
91
+
92
+ def to_c
93
+ ary = []
94
+ enumerate.each_pair do |c_symbol, enumeree_and_c_value|
95
+ ary << "\t#{c_symbol} = #{enumeree_and_c_value[1]}"
96
+ end
97
+ "enum #{@name} {\n\t" + ary.join(",\n\t") + "\n};\n"
98
+ end
99
+ end
@@ -0,0 +1,13 @@
1
+ class CSquare::Generator::Enum::Namer
2
+ def initialize prefix
3
+ @prefix = prefix
4
+ end
5
+
6
+ def name arg
7
+ @prefix.nil? ? arg.to_s.upcase : "#{@prefix.upcase}_#{arg.to_s.upcase}"
8
+ end
9
+
10
+ def num arg
11
+ :auto
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ class CSquare::Generator::Enum::OpNamer < CSquare::Generator::Enum::Namer
2
+ OP_TO_SUFFIX = {
3
+ :'<' => 'LT',
4
+ :'<=' => 'LTE',
5
+ :'>=' => 'GTE',
6
+ :'>' => 'GT',
7
+ :'==' => 'EQEQ',
8
+ :'!=' => 'NEQ',
9
+ :'-@' => 'NEG',
10
+ :'!@' => 'BANG',
11
+ :'+' => 'ADD',
12
+ :'-' => 'SUB',
13
+ :'*' => 'MUL',
14
+ :'/' => 'DIV',
15
+ :'%' => 'MOD',
16
+ :'&' => 'AND',
17
+ :'|' => 'OR',
18
+ :'^' => 'XOR',
19
+ :'<<' => 'LSH',
20
+ :'>>' => 'RSH',
21
+ :'~' => 'NOT'
22
+ }
23
+
24
+ def name op_symbol
25
+ OP_TO_SUFFIX.has_key?(op_symbol) ? super(OP_TO_SUFFIX[op_symbol]) : nil
26
+ end
27
+
28
+ # Use the character values if operations are single-character
29
+ def num op_symbol
30
+ op_string = op_symbol.to_s
31
+ op_string.size == 1 ? op_string.ord : :auto
32
+ end
33
+
34
+ end
@@ -0,0 +1,7 @@
1
+ class CSquare::Generator::Enum::SparseOpNamer < CSquare::Generator::Enum::OpNamer
2
+
3
+ def num op_symbol
4
+ :auto
5
+ end
6
+
7
+ end
@@ -0,0 +1,340 @@
1
+ class CSquare::Generator::Index
2
+
3
+ def initialize parent, index_name, options_and_mappings = {}
4
+ @parent = parent
5
+ @basename = index_name
6
+ @inline_sources = {}
7
+
8
+ on = options_and_mappings.delete(:on) # which enums
9
+ @with = options_and_mappings.delete(:with) # which function template to call
10
+ @default = options_and_mappings.delete(:default) # error function to call
11
+ @on = {}
12
+
13
+ # STDERR.puts "@with=#{@with.inspect}, name=#{name.inspect}"
14
+
15
+ # Find enumerators
16
+ if on.is_a?(Array)
17
+ on.each do |enum_id|
18
+ @on[enum_id] = generator.enumerators[enum_id]
19
+ end
20
+ else
21
+ @on[on || @basename] = generator.enumerators[on || @basename]
22
+ end
23
+
24
+ @signatures = map_from_index_options(options_and_mappings).merge(map_from_enums(options_and_mappings))
25
+ @mappings = options_and_mappings # save what remains
26
+ end
27
+
28
+
29
+ #def common_signature type_id=nil
30
+ # common_sig = nil
31
+ #
32
+ # # First pass: Find the longest, make that the common sig
33
+ # @signatures.each_value do |sig|
34
+ # common_sig = sig.clone if common_sig.nil? || sig.params.size > common_sig.params.size
35
+ # end
36
+ #
37
+ # # Second pass: walk through arguments of common sig and see if the current
38
+ # # sig is simpler.
39
+ # @signatures.each_value do |sig|
40
+ # # Start with return type
41
+ # common_sig.type = simplify_type common_sig.type, sig.type
42
+ #
43
+ # # Now do params
44
+ # sig.params.each_index do |i|
45
+ # common_sig.params[i] = simplify_type common_sig.params[i], sig.params[i]
46
+ # end
47
+ # end
48
+ #
49
+ # if @signatures.size == 1
50
+ # common_sig.params.each_index do |i|
51
+ # common_sig.params[i] = simplify_type common_sig.params[i], common_sig.params[i]
52
+ # end
53
+ # end
54
+ #
55
+ # common_sig.replace_types!(@parent.params(type_id)) unless type_id.nil?
56
+ #
57
+ # common_sig
58
+ #end
59
+
60
+ def decorated_signature type_id, enumeree_stack=[]
61
+ stack = [type_id].concat(enumeree_stack).compact
62
+ name = @mappings[type_id || enumeree_stack.first]
63
+ sig = @signatures[name].clone
64
+
65
+ blueprint = @parent.is_a?(CSquare::Generator::Blueprint) ? @parent : @parent.blueprint_for(stack.first)
66
+
67
+ require 'pry'
68
+ binding.pry if sig.nil? || blueprint.nil?
69
+
70
+ sig.replace_types!(blueprint.params(stack.first))
71
+
72
+ sig
73
+ end
74
+
75
+
76
+ def common_signature type_id=nil, enumeree_stack=[], on=nil
77
+ on ||= @on
78
+
79
+ ary = []
80
+
81
+ if on.values.first.on == :ops # index by ops instead of by type
82
+ ary = @signatures.values.compact
83
+ else
84
+
85
+ dim_enum_id, dim_enum = on.first
86
+ next_dim_on = on.select { |k,v| k != dim_enum_id }
87
+ next_dim_enum = next_dim_on.first.last unless next_dim_on.size == 0
88
+
89
+ if next_dim_on.size == 0
90
+
91
+ dim_enum.enumerees.each do |enumeree|
92
+ next if enumeree.nil?
93
+ curr_enumeree_stack = stacked_enumerees(enumeree_stack, enumeree)
94
+ ary << decorated_signature(type_id, curr_enumeree_stack)
95
+ end
96
+
97
+ else
98
+
99
+ dim_enum.enumerees.each do |enumeree|
100
+ next if enumeree.nil?
101
+ curr_enumeree_stack = stacked_enumerees(enumeree_stack, enumeree)
102
+ ary << common_signature(type_id, curr_enumeree_stack, next_dim_on)
103
+ end
104
+ end
105
+
106
+ ary = ary.compact
107
+ end
108
+
109
+ common_sig = nil
110
+
111
+ ary.each do |sig|
112
+ common_sig = sig.clone if common_sig.nil? || sig.params.size > common_sig.params.size
113
+ end
114
+
115
+ # Second pass: walk through arguments of common sig and see if the current
116
+ # sig is simpler.
117
+ ary.each do |sig|
118
+
119
+ # Start with return type
120
+ common_sig.type = simplify_type common_sig.type, sig.type
121
+
122
+ # Now do params
123
+ sig.params.each_index do |i|
124
+ common_sig.params[i] = simplify_type common_sig.params[i], sig.params[i]
125
+ end
126
+ end
127
+
128
+ common_sig.replace_types!(@parent.params(type_id)) unless type_id.nil?
129
+
130
+ common_sig
131
+ end
132
+
133
+
134
+
135
+ # Returns the template typename (e.g., TYPE) for this function pointer array.
136
+ def return_typename
137
+ common_rtn = nil
138
+
139
+ @signatures.each_value do |sig|
140
+ common_rtn ||= sig.type.clone
141
+ simplify_type common_rtn, sig.type
142
+ end
143
+
144
+ common_rtn
145
+ end
146
+
147
+
148
+ # Return the function pointer array declaration. Count is optional.
149
+ def declaration type_id=nil
150
+ # Figure out the function pointer type
151
+ sig = common_signature(type_id)
152
+
153
+ unnamed_params = sig.params.map { |p| p.name = nil; p.to_s }.join(", ")
154
+
155
+ # Figure out how many [][][] to include and what values to enclose in them
156
+ array_portion = begin
157
+ str = ""
158
+ @on.each_pair do |enum_id, enum_obj|
159
+ str += "[#{enum_obj.enumerees.size}]"
160
+ end
161
+ str
162
+ end
163
+
164
+ "#{sig.type.to_s} (*#{decorated_basename(type_id)}#{array_portion})(#{unnamed_params.to_s})"
165
+ end
166
+
167
+
168
+ def default_name type_ids=[]
169
+ type_ids ||= []
170
+ type_ids = [type_ids] unless type_ids.is_a?(Array)
171
+ return 'NULL' if @default.nil?
172
+ decorated_name(@default, type_ids)
173
+ end
174
+
175
+
176
+ def decorated_name type_ids=[]
177
+ type_ids = [type_ids] unless type_ids.is_a?(Array)
178
+ type_ids.empty? ? name : [name].concat(type_ids).compact.join('_')
179
+ end
180
+
181
+
182
+ def name
183
+ @with || @basename
184
+ end
185
+
186
+
187
+ def decorated_basename type_id=nil
188
+ type_id.nil? ? @basename : "#{@basename}_#{type_id}"
189
+ end
190
+
191
+
192
+ def stacked_enumerees stack, enumeree
193
+ @parent.is_a?(CSquare::Generator::Blueprint) ? stack : stack.clone.push(enumeree)
194
+ end
195
+
196
+
197
+ def use_decorated? stack, enumeree
198
+ return false if !@mappings.has_key?(enumeree) || enumeree.nil?
199
+ return false if stack.include?(nil)
200
+ true
201
+ end
202
+
203
+
204
+ def decorated_calls universal_type_id, enumeree_stack=[], on=nil
205
+ on ||= @on
206
+
207
+ ary = []
208
+ count = 0
209
+
210
+ dim_enum_id, dim_enum = on.first
211
+ next_dim_on = on.select { |k,v| k != dim_enum_id }
212
+ next_dim_enum = next_dim_on.first.last unless next_dim_on.size == 0
213
+
214
+ if next_dim_on.size == 0
215
+
216
+ dim_enum.enumerate_for_index.each do |enumeree, c_value|
217
+
218
+ while c_value > count
219
+ ary << default_name
220
+ count += 1
221
+ end
222
+
223
+ if use_decorated?(enumeree_stack, enumeree)
224
+ curr_enumeree_stack = stacked_enumerees(enumeree_stack, enumeree)
225
+ ary << [@mappings[enumeree], universal_type_id].concat(curr_enumeree_stack).compact.map{|i| i.to_s}.join('_')
226
+ else
227
+ ary << default_name
228
+ end
229
+
230
+ count += 1
231
+ end
232
+
233
+ else
234
+
235
+ dim_enum.enumerate_for_index.each do |enumeree, c_value|
236
+
237
+ while c_value > count
238
+ ary << (next_dim_enum.nil? ? default_name : "{ #{[default_name]*next_dim_enum.enumerate_for_index.size} }")
239
+ count += 1
240
+ end
241
+
242
+ curr_enumeree_stack = stacked_enumerees(enumeree_stack, enumeree)
243
+
244
+ ary << decorated_calls(universal_type_id, curr_enumeree_stack, next_dim_on)
245
+ count += 1
246
+ end
247
+ end
248
+
249
+ ary
250
+ end
251
+
252
+
253
+ def to_c type_id=nil # arg only gets used when type_ids are constant (not set by enum)
254
+ "#{declaration(type_id)} = {\n #{to_c_internal(decorated_calls(type_id))}\n};\n"
255
+ end
256
+
257
+
258
+ protected
259
+
260
+ def to_c_internal calls, level=0
261
+ calls.map do |call|
262
+ call.is_a?(Array) ? "{ #{to_c_internal(call, level+1)} }" : call
263
+ end.join(level == 0 ? ",\n " : ', ')
264
+ end
265
+
266
+
267
+ def simplify_type common, other
268
+ common_type = common.Parameter? ? common.type : common
269
+ other_type = other.Parameter? ? other.type : other
270
+
271
+ if common_type.Pointer? != other_type.Pointer?
272
+ raise(SyntaxError, "pointer mismatch between functions:\n = #{common.inspect}\n = #{other.inspect}")
273
+ end
274
+
275
+ if common_type.Pointer? # both are pointers
276
+ common_type.type = C::Void.new(:const => (common_type.type.const? || other_type.type.const?))
277
+ elsif common_type.name != other_type.name
278
+ raise(SyntaxError, "typename mismatch between functions:\n = #{common.inspect}\n = #{other.inspect}")
279
+ elsif common_type.longness != other_type.longness
280
+ raise(SyntaxError, "longness mismatch between functions:\n = #{common.inspect}\n = #{other.inspect}")
281
+ end
282
+
283
+ # De-constify
284
+ if common_type.const? != other_type.const?
285
+ common_type.const = false
286
+ end
287
+
288
+ # De-unsigned-ify
289
+ if common_type.unsigned? != other_type.unsigned?
290
+ common_type.unsigned = false
291
+ end
292
+
293
+ common.Parameter? ? C::Parameter.new(:type => common_type) : common_type
294
+ end
295
+
296
+ def map_from_enums mappings
297
+ return {} if @with.nil?
298
+
299
+ f = @parent.read_and_parse_source(@with)
300
+
301
+ signatures = {}
302
+
303
+ @on.each_pair do |enum_id, enum_obj|
304
+ enum_obj.enumerees.each do |enumeree|
305
+ with = @with.clone
306
+ mappings[enumeree] ||= with unless enumeree.nil?
307
+ signatures[with] ||= f.entity.type
308
+ end
309
+ end
310
+
311
+ signatures
312
+ end
313
+
314
+
315
+ def map_from_index_options mappings
316
+ signatures = {}
317
+
318
+ # First get function signatures for the user-supplied hash of enumerees-to-functions
319
+ mappings.each_pair do |enumeree, function_name|
320
+ if function_name == :inline
321
+ real_name = @parent.inline_op_function_name(enumeree)
322
+ f = @parent.declare_inline_source(enumeree)
323
+ signatures[real_name] = f.entity.type
324
+ mappings[enumeree] = real_name
325
+ else
326
+ signatures[function_name] = @parent.read_and_parse_source(function_name).entity.type
327
+ end
328
+ end
329
+
330
+ signatures
331
+ end
332
+
333
+
334
+ def generator
335
+ @parent.is_a?(CSquare::Generator) ? @parent : @parent.generator
336
+ end
337
+
338
+
339
+
340
+ end