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.
- 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
|