csquare 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/Gemfile +8 -0
- data/History.txt +12 -0
- data/Manifest.txt +21 -0
- data/README.rdoc +63 -0
- data/Rakefile +39 -0
- data/lib/csquare.rb +1089 -0
- data/lib/csquare/base.rb +36 -0
- data/lib/csquare/cerb.rb +82 -0
- data/lib/csquare/function.rb +175 -0
- data/lib/csquare/generator.rb +374 -0
- data/lib/csquare/generator/assign_op.rb +53 -0
- data/lib/csquare/generator/binary_op.rb +72 -0
- data/lib/csquare/generator/blueprint.rb +357 -0
- data/lib/csquare/generator/boolean_op.rb +32 -0
- data/lib/csquare/generator/enum.rb +99 -0
- data/lib/csquare/generator/enum/namer.rb +13 -0
- data/lib/csquare/generator/enum/op_namer.rb +34 -0
- data/lib/csquare/generator/enum/sparse_op_namer.rb +7 -0
- data/lib/csquare/generator/index.rb +340 -0
- data/lib/csquare/generator/op.rb +102 -0
- data/lib/csquare/generator/type.rb +62 -0
- metadata +140 -0
@@ -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,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,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
|