Class: CSquare::Generator::Blueprint
- Inherits:
-
Object
- Object
- CSquare::Generator::Blueprint
- Includes:
- Indexable
- Defined in:
- lib/csquare/generator/blueprint.rb
Instance Attribute Summary collapse
-
#externs(h = nil) ⇒ Object
readonly
Register symbols available to functions in this blueprint, and their template parameters.
-
#extra_templates_by_source ⇒ Object
readonly
Returns the value of attribute extra_templates_by_source.
-
#fields ⇒ Object
readonly
Returns the value of attribute fields.
-
#generator ⇒ Object
readonly
Returns the value of attribute generator.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#types ⇒ Object
readonly
Returns the value of attribute types.
Instance Method Summary collapse
-
#decorated_expression(type_symbol, op_id, args_and_types, should_return) ⇒ Object
Generate a C Abstract Syntax Tree based on a pattern given to generator/blueprint in configuration.
-
#expand_ops! ⇒ Object
Helper function called by Generator after all blueprints are declared.
- #extra_keys(source) ⇒ Object
- #has_op?(id) ⇒ Boolean
- #has_source?(f_name) ⇒ Boolean
- #indices ⇒ Object
-
#initialize(generator_obj, id, template_param, field_params) {|_self| ... } ⇒ Blueprint
constructor
A new instance of Blueprint.
- #inline_op_function_def(op) ⇒ Object
- #inline_op_return_type(op) ⇒ Object
- #inline_op_return_typename(op) ⇒ Object
- #inspect ⇒ Object
- #long_key ⇒ Object
-
#mutate_functions(type_symbol) ⇒ Object
To be called by Generator only after everything is setup.
-
#op(id, types_and_patterns = {}) ⇒ Object
Declare an operation that this blueprint should manage.
-
#op_symbols ⇒ Object
Get a list of op symbols used in this blueprint.
-
#params(type_symbol) ⇒ Object
Return a hash giving mappings from template typenames (keys, e.g., ‘TYPE’) to ctypes.
- #parsed_inline_op_function(op) ⇒ Object
- #read_source(source_filename) ⇒ Object
- #recognizes?(id, k) ⇒ Boolean
-
#responds_to_typename?(k) ⇒ Boolean
Does this blueprint contain instructions for dealing with some key (e.g., ‘TYPE’)?.
-
#sources(ary = [], extra_typenames_and_blueprint_ids = {}) ⇒ Object
Declare source files containing functions for types within this blueprint.
-
#type(id, ctype, options = {}) ⇒ Object
Declare a type within this blueprint.
-
#vars(type_symbol) ⇒ Object
Return a hash giving mappings from template variables (e.g., UINT_MAX, LONG_UINT_MAX) to actual variables.
Methods included from Indexable
Constructor Details
#initialize(generator_obj, id, template_param, field_params) {|_self| ... } ⇒ Blueprint
Returns a new instance of Blueprint.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/csquare/generator/blueprint.rb', line 7 def initialize generator_obj, id, template_param, field_params @id = id @key = template_param @fields = field_params @types = {} @externs = { "#{@key}_MAX" => @id, "#{@key}_MIN" => @id, "LONG_#{@key}_MAX" => @id, "LONG_#{@key}_MIN" => @id } @ops = {} @sources = [] @generator= generator_obj @inline_sources = {} @extra_templates_by_source = Hash.new { |h,k| h[k] = {} } yield self if block_given? # STDERR.puts "#{@key.inspect} EXTERNS: " + @externs.inspect end |
Instance Attribute Details
#externs(h = nil) ⇒ Object (readonly)
Register symbols available to functions in this blueprint, and their template parameters. Note that this is only used to register symbols from other blueprints. Takes a hash as only argument.
Example:
c.blueprint(:int, 'TYPE') do |t|
t.type :i16, 'int16_t', :long => :i32
t.type :i32, 'int32_t'
t.sources %w{gcf} # gcf is a templated function for :i16 and :i32
end
c.blueprint(:rational, 'TYPE', :n => 'INT', :d => 'INT') do |t|
t.type :r32, 'rational32', :long => :r64, 'INT' => :i16
t.type :r64, 'rational64', 'INT' => :i32
t.externs 'gcf' => 'INT' # lets us know that gcf is a templated function returning :i16 or :i32 depending
end
143 144 145 |
# File 'lib/csquare/generator/blueprint.rb', line 143 def externs @externs end |
#extra_templates_by_source ⇒ Object (readonly)
Returns the value of attribute extra_templates_by_source.
30 31 32 |
# File 'lib/csquare/generator/blueprint.rb', line 30 def extra_templates_by_source @extra_templates_by_source end |
#fields ⇒ Object (readonly)
Returns the value of attribute fields.
30 31 32 |
# File 'lib/csquare/generator/blueprint.rb', line 30 def fields @fields end |
#generator ⇒ Object (readonly)
Returns the value of attribute generator.
30 31 32 |
# File 'lib/csquare/generator/blueprint.rb', line 30 def generator @generator end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
30 31 32 |
# File 'lib/csquare/generator/blueprint.rb', line 30 def id @id end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
30 31 32 |
# File 'lib/csquare/generator/blueprint.rb', line 30 def key @key end |
#types ⇒ Object (readonly)
Returns the value of attribute types.
30 31 32 |
# File 'lib/csquare/generator/blueprint.rb', line 30 def types @types end |
Instance Method Details
#decorated_expression(type_symbol, op_id, args_and_types, should_return) ⇒ Object
Generate a C Abstract Syntax Tree based on a pattern given to generator/blueprint in configuration.
Returns the return type of the final expression and the expression AST.
276 277 278 279 |
# File 'lib/csquare/generator/blueprint.rb', line 276 def decorated_expression type_symbol, op_id, args_and_types, should_return return nil unless @ops.has_key?(op_id) @ops[op_id].decorated(args_and_types, should_return, type_symbol) end |
#expand_ops! ⇒ Object
Helper function called by Generator after all blueprints are declared. Goes back and replaces blueprint IDs with ctypes.
256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/csquare/generator/blueprint.rb', line 256 def @ops.clone.each_pair do |id, types_and_patterns| h = {} types_and_patterns.patterns.each_pair do |arg1,pattern| if arg1.is_a?(Symbol) && @generator.blueprints.has_key?(arg1) @generator[arg1].types.each_pair do |type_id, type| next if types_and_patterns.patterns.has_key?(type.ctype) # Don't override a user op h[type.ctype] = pattern end end end @ops[id].patterns.merge!(h) end end |
#extra_keys(source) ⇒ Object
341 342 343 |
# File 'lib/csquare/generator/blueprint.rb', line 341 def extra_keys source @extra_templates_by_source[source].keys end |
#has_op?(id) ⇒ Boolean
86 87 88 |
# File 'lib/csquare/generator/blueprint.rb', line 86 def has_op? id @ops.has_key?(id) end |
#has_source?(f_name) ⇒ Boolean
174 175 176 |
# File 'lib/csquare/generator/blueprint.rb', line 174 def has_source? f_name @sources.include?(f_name) end |
#indices ⇒ Object
32 33 34 |
# File 'lib/csquare/generator/blueprint.rb', line 32 def indices defined?(@indices) ? @indices : {} end |
#inline_op_function_def(op) ⇒ Object
300 301 302 |
# File 'lib/csquare/generator/blueprint.rb', line 300 def inline_op_function_def op "inline #{inline_op_return_typename(op)} #{inline_op_function_name(op)}(const #{@key} x, const #{@key} y) { return (x #{op.to_s} y); }" end |
#inline_op_return_type(op) ⇒ Object
288 289 290 |
# File 'lib/csquare/generator/blueprint.rb', line 288 def inline_op_return_type op CSquare::Generator::OP_RETURN_TYPES[op] == :key ? @key : CSquare::Generator::OP_RETURN_TYPES[op] end |
#inline_op_return_typename(op) ⇒ Object
293 294 295 296 297 |
# File 'lib/csquare/generator/blueprint.rb', line 293 def inline_op_return_typename op type = inline_op_return_type(op) return 'bool' if type == :boolean type end |
#inspect ⇒ Object
36 37 38 39 |
# File 'lib/csquare/generator/blueprint.rb', line 36 def inspect obj_id = "0x#{(self.object_id << 1).to_s(16)}" "#<#{self.class.to_s}:#{obj_id} #{@id.inspect}=>#{@key.inspect}=>#{@fields.inspect} type_ids=#{@types.keys.inspect} ops=#{@ops.keys.inspect} sources=#{@sources.inspect}>" end |
#long_key ⇒ Object
41 42 43 |
# File 'lib/csquare/generator/blueprint.rb', line 41 def long_key "LONG_#{@key}" end |
#mutate_functions(type_symbol) ⇒ Object
To be called by Generator only after everything is setup.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/csquare/generator/blueprint.rb', line 217 def mutate_functions type_symbol functions = [] local_template_params = self.params(type_symbol) # Handle templates added by the index method. @inline_sources.each_pair do |op, f| functions << f.clone.mutate!(self, type_symbol, local_template_params) end # Handle templates added by the sources method. @sources.each do |source| # First, mutate on the current blueprint function = read_and_parse_source(source).mutate!(self, type_symbol, local_template_params) if @extra_templates_by_source[source].size > 1 raise NotImplementedError, "only two templates supported at a time" elsif @extra_templates_by_source[source].size == 1 @extra_templates_by_source[source].each_pair do |typename,blueprint_id| other_blueprint = generator.blueprints[blueprint_id] other_blueprint.types.each_pair do |type_id, type_obj| functions << function.clone.mutate!(other_blueprint, type_id, {typename => @generator.types[type_id].ctype}) end end else functions << function end end functions end |
#op(id, types_and_patterns = {}) ⇒ Object
Declare an operation that this blueprint should manage. First argument is a symbol, e.g., :‘*’ (for C::Multiply). Second argument is a hash: keys are template parameters (e.g., ‘TYPE’), C basic types (e.g., ‘int’), values (e.g., 0, 1), or blueprint IDs (e.g., :integer). Values of this hash are patterns to substitute the operations for.
Expect boolean operations in C to return a blueprint ID of :boolean. This is declared implicitly, as are :integer and :float. All can be overridden.
Example:
t,sources %w{mul2 mul4}
t.op :'*', 'TYPE' => 'mul2($0, $1)', :integer => 'mul4($0.r, $0.i, $1, 0)', :float => 'mul4($0.r, $0.i, $1, 0)' # for complex multiplication
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/csquare/generator/blueprint.rb', line 192 def op id, types_and_patterns = {} raise(ArgumentError, "op id #{id} already declared") if @ops.has_key?(id) op_class = if CSquare::Generator::BOOL_CAST_TO_OP.has_value?(id) CSquare::Generator::BooleanOp elsif CSquare::Generator::BINARY_ASSIGN_CAST_TO_OP.has_value?(id) || CSquare::Generator::BINARY_CAST_TO_OP.has_value?(id) CSquare::Generator::BinaryOp elsif id == :'=' CSquare::Generator::AssignOp else # UNARY #TODO: This may need its own class CSquare::Generator::AssignOp end @ops[id] ||= op_class.send(:new, self, id) types_and_patterns.each_pair do |type_id, pattern| @ops[id][type_id] = pattern end self end |
#op_symbols ⇒ Object
Get a list of op symbols used in this blueprint
312 313 314 |
# File 'lib/csquare/generator/blueprint.rb', line 312 def op_symbols @ops.values.map { |o| o.id } end |
#params(type_symbol) ⇒ Object
Return a hash giving mappings from template typenames (keys, e.g., ‘TYPE’) to ctypes.
92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/csquare/generator/blueprint.rb', line 92 def params type_symbol k = @types[type_symbol].ctype_keys # hash of typenames to type ids begin k[@key] = @generator.types[type_symbol].ctype rescue NoMethodError STDERR.puts "NoMethodError: @key=#{@key}, type_symbol = #{type_symbol}" end k["LONG_#{@key}"] = (generator.types[type_symbol].long || generator.types[type_symbol]).ctype k end |
#parsed_inline_op_function(op) ⇒ Object
305 306 307 308 |
# File 'lib/csquare/generator/blueprint.rb', line 305 def parsed_inline_op_function op code = inline_op_function_def(op) CSquare::Function.new(code, self.keys) end |
#read_source(source_filename) ⇒ Object
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'lib/csquare/generator/blueprint.rb', line 316 def read_source source_filename begin g = self.generator Dir.chdir(g.path) do # First check type's own directory, then check for global if type doesn't have it. if File.exists?(File.join(self.id.to_s, source_filename)) Dir.chdir(self.id.to_s) do preprocess_source File.new(source_filename, "r") end elsif File.exists?(source_filename) preprocess_source File.new(source_filename, "r") else raise("source file not found: #{source_filename.inspect}") end end rescue Errno::ENOENT => e # This is really helpful for people who are using rake compile and don't know what # the template directory should be, since they don't know their current location. STDERR.puts "CSquare: Exception thrown: #{e.inspect}" STDERR.puts "CSquare: Current directory: #{Dir.pwd.inspect}" raise e end end |
#recognizes?(id, k) ⇒ Boolean
77 78 79 80 81 82 83 |
# File 'lib/csquare/generator/blueprint.rb', line 77 def recognizes? id, k if has_op?(id) return true if responds_to_typename?(k) return true if @ops[id].has_key?(k) end false end |
#responds_to_typename?(k) ⇒ Boolean
Does this blueprint contain instructions for dealing with some key (e.g., ‘TYPE’)?
72 73 74 75 |
# File 'lib/csquare/generator/blueprint.rb', line 72 def responds_to_typename? k return true if k == @key || k == "LONG_#{@key}" false end |
#sources(ary = [], extra_typenames_and_blueprint_ids = {}) ⇒ Object
Declare source files containing functions for types within this blueprint.
Example:
t.sources %w{gemm div2 div4 mul2 mul4}
These will frequently be referenced by the op method.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/csquare/generator/blueprint.rb', line 155 def sources ary = [], extra_typenames_and_blueprint_ids = {} ary.each do |str| # Do this first so that the extra typenames are registered @extra_templates_by_source[str] = extra_typenames_and_blueprint_ids # go ahead and load the source to get the return type f = read_and_parse_source(str) # Add this to our list of externs STDERR.puts("Warning: overriding extern '#{str}' (value='#{@externs[str]}') --> '#{f.return_type}'") if @externs.has_key?(str) @externs[str] = f.return_type @sources << str end @sources end |
#type(id, ctype, options = {}) ⇒ Object
Declare a type within this blueprint. It will be used to transform the blueprint and create a set of functions.
Must provide at least an id (a shorthand symbol, such as :i64) and a ctype String (e.g., “int64_t”). Optionally, may also provide a hash of options
- :long
-
Gives the id for another type in this blueprint which is the long version of this type
-
template params which correspond to the field parameters in the blueprint.
Example:
c.blueprint(:complex, 'TYPE', :r => 'FLOAT', :i => 'FLOAT') do |t|
t.type :c64, 'complex64', :long => :c128, 'FLOAT' => :f32 # f32 and f64 are declared in a separate blueprint
t.type :c128, 'complex128', 'FLOAT' => :f64
end
60 61 62 63 64 65 66 67 68 69 |
# File 'lib/csquare/generator/blueprint.rb', line 60 def type id, ctype, = {} raise(ArgumentError, "id #{id} already declared") if @types.has_key?(id) || @generator.blueprints.has_key?(id) @types[id] = CSquare::Generator::Type.new(self, id, ctype, ) @externs[@types[id].max] = self.id unless @types[id].max.nil? @externs[@types[id].min] = self.id unless @types[id].min.nil? self end |
#vars(type_symbol) ⇒ Object
Return a hash giving mappings from template variables (e.g., UINT_MAX, LONG_UINT_MAX) to actual variables.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/csquare/generator/blueprint.rb', line 106 def vars type_symbol @vars ||= {} @vars[type_symbol] = begin h = {} type = @types[type_symbol] h["#{@key}_MIN"] = type.min unless type.min.nil? h["#{@key}_MAX"] = type.max unless type.max.nil? long_type = type.long if long_type h["LONG_#{@key}_MIN"] = long_type.min unless long_type.min.nil? h["LONG_#{@key}_MAX"] = long_type.max unless long_type.max.nil? end h end end |