csquare 0.1.0

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