Class: CSquare::Generator

Inherits:
Object
  • Object
show all
Includes:
Indexable
Defined in:
lib/csquare/generator.rb

Defined Under Namespace

Classes: AssignOp, BinaryOp, Blueprint, BooleanOp, Enum, Index, Op, Type

Constant Summary collapse

DEFAULT_EXTERNS =
{'fprintf' => 'int'}
OP_RETURN_TYPES =

To use for :inline index functions – need to know return type

{
    :'<' => :boolean,
    :'>' => :boolean,
    :'<=' => :boolean,
    :'>=' => :boolean,
    :'==' => :boolean,
    :'!=' => :boolean,
    :'+' => :key,
    :'-' => :key,
    :'*' => :key,
    :'/' => :key,
    :'%' => :key
}
OP_FUNCTION_NAMES =

To use for :inline index functions that should be automatically generated

{
    :'<' => 'lt',
    :'>' => 'gt',
    :'<=' => 'lte',
    :'>=' => 'gte',
    :'==' => 'eqeq',
    :'!=' => 'neq',
    :'+' => 'add',
    :'-' => 'sub',
    :'*' => 'mul',
    :'/' => 'div',
    :'%' => 'mod'
}
BOOL_CAST_TO_OP =
{
    C::Less => :'<',
    C::More => :'>',
    C::LessOrEqual => :'<=',
    C::MoreOrEqual => :'>=',
    C::Equal => :'==',
    C::NotEqual => :'!=',
    C::And => :'&&',
    C::Or => :'||'
}
UNARY_CAST_TO_OP =
{
    C::Negative => :'-@',
    C::Not => :'!@',
    C::Arrow => :'->',
    C::Dereference => :'*@'
}
ASSIGN_CAST_TO_OP =
{
    C::Assign => :'=',
}
BINARY_ASSIGN_CAST_TO_OP =
{
    C::AddAssign => :'+=',
    C::SubtractAssign => :'-=',
    C::MultiplyAssign => :'*=',
    C::DivideAssign => :'/=',
    C::ModAssign => :'%='
}
BINARY_CAST_TO_OP =
{
C::Add => :'+',
C::Subtract => :'-',
C::Multiply => :'*',
C::Divide => :'/',
C::Mod => :'%',}
BIT_CAST_TO_OP =
{
    C::BitAnd => :'&',
    C::BitOr => :'|',
    C::BitXor => :'^',
    C::ShiftLeft => :'<<',
    C::ShiftRight => :'>>'
}
CAST_TO_OP =
BOOL_CAST_TO_OP.
merge(UNARY_CAST_TO_OP).
merge(ASSIGN_CAST_TO_OP).
merge(BINARY_CAST_TO_OP).
merge(BIT_CAST_TO_OP).
merge(BINARY_ASSIGN_CAST_TO_OP)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Indexable

included

Constructor Details

#initialize(path, c_output_basename, options = {}) {|_self| ... } ⇒ Generator

Returns a new instance of Generator.

Yields:

  • (_self)

Yield Parameters:



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/csquare/generator.rb', line 90

def initialize path, c_output_basename, options = {}
  options = {
      :include_guards => true,
      :header => true,
      :include_header => true
  }.merge(options)

  @default_key  = 'TYPE'
  @path         = path
  @basename     = c_output_basename
  @externs      = DEFAULT_EXTERNS
  @blueprints   = {}
  @enumerators  = {}

  yield self

  # STDERR.puts "GENERATOR EXTERNS: " + @externs.inspect

  @blueprints.each_key do |id|
    @blueprints[id].expand_ops!
  end

  mutant_functions = []
  blueprints.each_value do |blueprint|
    blueprint.types.each_pair do |type_symbol,type|
      mutant_functions = mutant_functions.concat(blueprint.mutate_functions(type_symbol))
    end
  end

  declarations = write_c_file(options[:include_guards], options[:include_header], mutant_functions)
  write_h_file(options[:include_guards], declarations) if options[:header]
end

Instance Attribute Details

#basenameObject (readonly)

Returns the value of attribute basename.



123
124
125
# File 'lib/csquare/generator.rb', line 123

def basename
  @basename
end

#blueprintsObject (readonly)

Returns the value of attribute blueprints.



123
124
125
# File 'lib/csquare/generator.rb', line 123

def blueprints
  @blueprints
end

#enumeratorsObject (readonly)

Returns the value of attribute enumerators.



123
124
125
# File 'lib/csquare/generator.rb', line 123

def enumerators
  @enumerators
end

#pathObject (readonly)

Returns the value of attribute path.



123
124
125
# File 'lib/csquare/generator.rb', line 123

def path
  @path
end

Instance Method Details

#[](blueprint_id) ⇒ Object

Shorthand for blueprints



154
155
156
# File 'lib/csquare/generator.rb', line 154

def [] blueprint_id
  blueprints[blueprint_id]
end

#blueprint(id, template_param = 'TYPE', field_params = {}, &block) ⇒ Object

Create a blueprint for a set of types that all behave a certain way.

At minimum, you should provide the name of the blueprint (e.g., blueprint(:integer)). You may also provide a template parameter name, which defaults to TYPE, and field parameters.

Example (complex):

c.blueprint(:complex, 'TYPE', :r => 'FLOAT', :i => 'FLOAT') do |t|
  # ...
end

Raises:

  • (ArgumentError)


181
182
183
184
185
186
187
188
189
190
# File 'lib/csquare/generator.rb', line 181

def blueprint id, template_param = 'TYPE', field_params = {}, &block
  raise(ArgumentError, "id #{id} already declared") if @blueprints.has_key?(id)

  # Clear cache of blueprints by type_id
  @blueprint_for = nil

  @blueprints[id] = Blueprint.new(self, id, template_param, field_params, &block)

  self
end

#blueprint_for(type_id) ⇒ Object

Returns the blueprint corresponding to some type_id. Caches types for faster lookup.



209
210
211
212
# File 'lib/csquare/generator.rb', line 209

def blueprint_for type_id
  @blueprint_for ||= types
  @blueprint_for[type_id].blueprint
end

#c_filenameObject



145
146
147
# File 'lib/csquare/generator.rb', line 145

def c_filename
  "#{@basename}.c"
end

#c_include_guardObject



136
137
138
# File 'lib/csquare/generator.rb', line 136

def c_include_guard
  "#{@basename.upcase}_C"
end

#default_key(k = nil) ⇒ Object



130
131
132
133
# File 'lib/csquare/generator.rb', line 130

def default_key k=nil
  return @default_key if k.nil?
  @default_key = k
end

#enumerate(name, opts = {}) ⇒ Object



215
216
217
# File 'lib/csquare/generator.rb', line 215

def enumerate name, opts = {}
  @enumerators[name] = CSquare::Generator::Enum.new(name, opts)
end

#externs(h = nil) ⇒ Object

Register symbols available to all functions, and their types. Takes a hash as only argument.

Example:

c.externs 'NM_MAX' => :integer, 'CblasNoTrans' => 'char', 'fprintf' => 'int'


165
166
167
168
# File 'lib/csquare/generator.rb', line 165

def externs h=nil
  return @externs if h.nil?
  @externs.merge!(h)
end

#h_filenameObject



149
150
151
# File 'lib/csquare/generator.rb', line 149

def h_filename
  "#{@basename}.h"
end

#h_include_guardObject



140
141
142
# File 'lib/csquare/generator.rb', line 140

def h_include_guard
  "#{@basename.upcase}_H"
end

#indices_c_codeObject



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/csquare/generator.rb', line 228

def indices_c_code
  ary = []

  # Blueprint-scoped indices
  @blueprints.each_value do |blueprint|
    blueprint.indices.values.flatten.each do |index|
      blueprint.types.each_key do |type_id|
        ary << index.to_c(type_id)
      end
    end
  end

  # Add generator-scoped indices
  @indices.values.flatten.each do |index|
    ary << index.to_c
  end

  ary
end

#inspectObject



125
126
127
128
# File 'lib/csquare/generator.rb', line 125

def inspect
  obj_id = "0x#{(self.object_id << 1).to_s(16)}"
  "#<#{self.class.to_s}:#{obj_id} basename=#{@basename.inspect} blueprint_ids=#{@blueprints.keys.inspect} path=#{@path.inspect}>"
end

#keys_for(f_name) ⇒ Object

Return all possible typenames for a given source



285
286
287
288
289
290
291
292
# File 'lib/csquare/generator.rb', line 285

def keys_for f_name
  ary = self.template_keys(f_name)
  @blueprints.each_value do |blueprint|
    next unless blueprint.has_source?(f_name)
    ary << blueprint.template_keys(f_name)
  end
  ary.flatten.compact.uniq
end

#op_symbolsObject

Get a list of ops used (just the symbols)



220
221
222
223
224
225
226
# File 'lib/csquare/generator.rb', line 220

def op_symbols
  ary = []
  @blueprints.each_value do |blueprint|
    ary = ary.concat blueprint.op_symbols
  end
  ary.sort.uniq
end

#params(type_symbol) ⇒ Object

Return a hash giving mappings from template typenames (keys, e.g., ‘TYPE’) to ctypes.



270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/csquare/generator.rb', line 270

def params type_symbol
  types_ = types[type_symbol]
  k = types_.ctype_keys # hash of typenames to type ids

  begin
    k[@default_key] = types_.ctype
  rescue NoMethodError
    STDERR.puts "NoMethodError: @default_key=#{@default_key}, type_symbol = #{type_symbol}"
  end
  k["LONG_#{@default_key}"] = (types_.long || types_).ctype
  k
end

#read_source(source_filename) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/csquare/generator.rb', line 249

def read_source source_filename
  begin
    g = self.is_a?(CSquare::Generator) ? self : self.generator
    Dir.chdir(g.path) do
      if File.exists?(source_filename)
        preprocess_source File.new(source_filename, "r")
      else
        raise IOError, "file '#{source_filename}' not found in '#{g.path}' or '#{File.join(g.path, self.id.to_s)}'"
      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

#typesObject

Get all types stored in the various template types



194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/csquare/generator.rb', line 194

def types
  h = {}
  @blueprints.each_value do |blueprint|
    blueprint.types.each_pair do |id, type|
      if h.has_key?(id)
        raise(StandardError, "two types with same id: #{id}")
      else
        h[id] = type
      end
    end
  end
  h
end