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
data/lib/csquare/base.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class CSquare::Base
|
2
|
+
EXTRA_TYPE_NAMES = %w{bool}
|
3
|
+
|
4
|
+
def initialize code, type_names
|
5
|
+
@parser = C::Parser.new
|
6
|
+
type_names = (type_names + EXTRA_TYPE_NAMES).uniq
|
7
|
+
type_names.each { |t| @parser.type_names << t }
|
8
|
+
|
9
|
+
tree = begin
|
10
|
+
@parser.parse(code)
|
11
|
+
rescue C::ParseError => e
|
12
|
+
if e.message.include?("parse error on ID (")
|
13
|
+
STDERR.puts "CSquare::Base: A parse error was encountered: #{e.message}"
|
14
|
+
STDERR.puts "This typically means you're using a special typename which CSquare does not know how to recognize."
|
15
|
+
STDERR.puts "It is recommended that you avoid doing so; however, if you must, try modifying CSquare::Base::EXTRA_TYPE_NAMES."
|
16
|
+
else
|
17
|
+
STDERR.puts "CSquare::Base: An unrecognized parse error was encountered."
|
18
|
+
STDERR.puts code.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
STDERR.puts "The currently defined types are: #{type_names.inspect}"
|
22
|
+
|
23
|
+
raise(e)
|
24
|
+
end
|
25
|
+
|
26
|
+
raise(ArgumentError, "multiple entities not supported") if tree.entities.size > 1
|
27
|
+
|
28
|
+
@entity = tree.entities[0]
|
29
|
+
end
|
30
|
+
|
31
|
+
def code
|
32
|
+
entity.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :entity, :parser
|
36
|
+
end
|
data/lib/csquare/cerb.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Loosely based on ERB by Masatoshi Seki.
|
2
|
+
#
|
3
|
+
# For handling Ruby code embedded in CSquare (C) sources.
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# int main() {
|
7
|
+
# #RUBY if blueprint.id == :rational
|
8
|
+
# return 0;
|
9
|
+
# #RUBY else
|
10
|
+
# return 1;
|
11
|
+
# #RUBY end
|
12
|
+
# }
|
13
|
+
#
|
14
|
+
# TODO: Rewrite this so it uses a grammar that can recognize comments.
|
15
|
+
#
|
16
|
+
# NOTE: DO NOT USE PRY IN HERE. Annoying to kill.
|
17
|
+
|
18
|
+
|
19
|
+
class CERB
|
20
|
+
SPLIT_REGEXP = /^\s*#\s*RUBY\s+/
|
21
|
+
|
22
|
+
def initialize file, blueprint
|
23
|
+
@blueprint = blueprint
|
24
|
+
|
25
|
+
out = Buffer.new
|
26
|
+
eval_str = nil
|
27
|
+
@src = []
|
28
|
+
|
29
|
+
while line = file.gets
|
30
|
+
line.chomp!
|
31
|
+
|
32
|
+
c_code, eval_str = line.split(SPLIT_REGEXP, 2)
|
33
|
+
|
34
|
+
#binding.pry if line == "#RUBY if blueprint.id != :complex"
|
35
|
+
|
36
|
+
if eval_str.nil?
|
37
|
+
out.push c_code
|
38
|
+
else
|
39
|
+
unless out.empty?
|
40
|
+
@src << "puts #{out.result.dump}"
|
41
|
+
out.reset!
|
42
|
+
end
|
43
|
+
|
44
|
+
@src << "puts ''" # empty line in place of #RUBY statements (ensures line numbers match source files in debugging)
|
45
|
+
@src << eval_str
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@src << "puts #{out.result.dump}" if eval_str.nil? && !out.empty?
|
50
|
+
@src << "puts ''" # prevent EOF errors
|
51
|
+
|
52
|
+
#binding.pry
|
53
|
+
|
54
|
+
eval @src.join("\n")
|
55
|
+
end
|
56
|
+
attr_reader :blueprint, :src
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
class Buffer
|
61
|
+
def initialize
|
62
|
+
@code = []
|
63
|
+
end
|
64
|
+
|
65
|
+
def push code
|
66
|
+
@code << code
|
67
|
+
end
|
68
|
+
|
69
|
+
def result
|
70
|
+
@code.join("\n")
|
71
|
+
end
|
72
|
+
|
73
|
+
def reset!
|
74
|
+
@code = []
|
75
|
+
end
|
76
|
+
|
77
|
+
def empty?
|
78
|
+
@code.size == 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# Represents a C function template.
|
2
|
+
class CSquare::Function < CSquare::Base
|
3
|
+
def initialize code, type_names
|
4
|
+
super code, type_names
|
5
|
+
@decorated_name = false
|
6
|
+
raise(SyntaxError, "expected function definition") unless entity.FunctionDef?
|
7
|
+
end
|
8
|
+
|
9
|
+
# Make a deep copy of this function.
|
10
|
+
def clone
|
11
|
+
CSquare::Function.new(self.code, @parser.type_names.to_a)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Return the function declaration for the header file
|
15
|
+
def declaration
|
16
|
+
t = @entity.type
|
17
|
+
"#{t.type.to_s} #{name}(#{t.params.to_s});"
|
18
|
+
end
|
19
|
+
|
20
|
+
def rename! new_name
|
21
|
+
@entity.name = new_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def decorate_name! type_symbol
|
25
|
+
@entity.name = decorated_name(type_symbol)
|
26
|
+
@decorated_name = true
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def decorated_name type_symbol
|
31
|
+
@decorated_name ? @entity.name : "#{@entity.name}_#{type_symbol}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
@entity.name
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return a hash of function parameters => types. Passing the argument :string will return type strings instead of CAST types.
|
39
|
+
def params(as=nil)
|
40
|
+
@entity.params(as)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return a hash of function local variables => types. You may pass :string as the sole argument if you want
|
44
|
+
def locals(as=nil)
|
45
|
+
@entity.def.locals(as)
|
46
|
+
end
|
47
|
+
|
48
|
+
def definition
|
49
|
+
@entity.def
|
50
|
+
end
|
51
|
+
|
52
|
+
def return_type
|
53
|
+
@entity.type.type
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Get those parameters which we need to watch, based on the template typenames given (as an argument).
|
58
|
+
def template_params typenames
|
59
|
+
watch_params = {}
|
60
|
+
|
61
|
+
params.each_pair do |varname, fparam|
|
62
|
+
if typenames.include?(fparam.underlying_typename)
|
63
|
+
watch_params[varname] = fparam.underlying_typename
|
64
|
+
end
|
65
|
+
end
|
66
|
+
watch_params
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Get those local variables which we need to watch when applying templates, based on the template typenames given (only argument).
|
71
|
+
def template_locals typenames
|
72
|
+
watch_locals = {}
|
73
|
+
|
74
|
+
locals.each_pair do |varname, fdec|
|
75
|
+
if typenames.include?(fdec.underlying_typename)
|
76
|
+
watch_locals[varname] = fdec.underlying_typename
|
77
|
+
end
|
78
|
+
end
|
79
|
+
watch_locals
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Given some hash of typenames to replacement types, change all parameters and declarations.
|
84
|
+
#
|
85
|
+
# Hash should consist of string values only.
|
86
|
+
def replace_types! h
|
87
|
+
# STDERR.puts "parser typenames: #{@parser.type_names.inspect}"
|
88
|
+
|
89
|
+
h.each_value do |new_typename|
|
90
|
+
@parser.type_names << new_typename
|
91
|
+
C.default_parser.type_names << new_typename
|
92
|
+
end
|
93
|
+
|
94
|
+
# Replace the types in the function prototype
|
95
|
+
@entity.entries[0].replace_types! h
|
96
|
+
|
97
|
+
# Recurse down into function blocks
|
98
|
+
@entity.entries[1].replace_types! h
|
99
|
+
|
100
|
+
# Replace typecasts
|
101
|
+
@entity.recursively_replace_casts! h
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Given all function calls, figure out what they should instead be and change the tree as we go.
|
106
|
+
def decorate_calls! blueprint, type_symbol
|
107
|
+
@entity.recursively_decorate_calls! blueprint, type_symbol
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# Return a list of local variables, function names, parameters, etc; hashed to type (string).
|
112
|
+
def locals_and_types blueprint
|
113
|
+
vars_and_types = blueprint.generator.externs.merge(blueprint.externs).
|
114
|
+
merge(params).
|
115
|
+
merge(locals)
|
116
|
+
|
117
|
+
# Go through and remove const indicators, as these will only get in the way
|
118
|
+
vars_and_types.each_pair do |var, type|
|
119
|
+
if type.is_a?(C::DirectType)
|
120
|
+
vars_and_types[var].const = false
|
121
|
+
vars_and_types[var] = vars_and_types[var].to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
vars_and_types
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# Is some local identifier in use?
|
130
|
+
def has_local? var, blueprint=nil
|
131
|
+
@entity.has_local? var, blueprint
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Return the type associated with some variable. Optionally can look for globals if blueprint is given.
|
136
|
+
def type_of var, blueprint=nil
|
137
|
+
@entity.type_of var, blueprint
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
def mutate! blueprint, new_type_symbol, params = nil
|
142
|
+
|
143
|
+
# Create a frozen duplicate of this function, that hasn't had its typenames changed.
|
144
|
+
f = self.clone
|
145
|
+
|
146
|
+
self.decorate_name! new_type_symbol
|
147
|
+
|
148
|
+
self.entity.recombine! f, blueprint, new_type_symbol
|
149
|
+
|
150
|
+
self.replace_types!(params || blueprint.params(new_type_symbol))
|
151
|
+
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
class << self
|
157
|
+
def find_broken_ast tree
|
158
|
+
begin
|
159
|
+
tree.to_s
|
160
|
+
return nil
|
161
|
+
rescue TypeError
|
162
|
+
tree.each do |e|
|
163
|
+
x = CSquare::Function.find_broken_ast(e)
|
164
|
+
unless x.nil?
|
165
|
+
require "pry"
|
166
|
+
binding.pry
|
167
|
+
end
|
168
|
+
end
|
169
|
+
return tree
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
end
|
@@ -0,0 +1,374 @@
|
|
1
|
+
class CSquare::Generator
|
2
|
+
include CSquare::Indexable
|
3
|
+
|
4
|
+
DEFAULT_EXTERNS = {'fprintf' => 'int'}
|
5
|
+
|
6
|
+
acts_as_indexable
|
7
|
+
|
8
|
+
# To use for :inline index functions -- need to know return type
|
9
|
+
OP_RETURN_TYPES = {
|
10
|
+
:'<' => :boolean,
|
11
|
+
:'>' => :boolean,
|
12
|
+
:'<=' => :boolean,
|
13
|
+
:'>=' => :boolean,
|
14
|
+
:'==' => :boolean,
|
15
|
+
:'!=' => :boolean,
|
16
|
+
:'+' => :key,
|
17
|
+
:'-' => :key,
|
18
|
+
:'*' => :key,
|
19
|
+
:'/' => :key,
|
20
|
+
:'%' => :key
|
21
|
+
}
|
22
|
+
|
23
|
+
# To use for :inline index functions that should be automatically generated
|
24
|
+
OP_FUNCTION_NAMES = {
|
25
|
+
:'<' => 'lt',
|
26
|
+
:'>' => 'gt',
|
27
|
+
:'<=' => 'lte',
|
28
|
+
:'>=' => 'gte',
|
29
|
+
:'==' => 'eqeq',
|
30
|
+
:'!=' => 'neq',
|
31
|
+
:'+' => 'add',
|
32
|
+
:'-' => 'sub',
|
33
|
+
:'*' => 'mul',
|
34
|
+
:'/' => 'div',
|
35
|
+
:'%' => 'mod'
|
36
|
+
}
|
37
|
+
|
38
|
+
BOOL_CAST_TO_OP = {
|
39
|
+
C::Less => :'<',
|
40
|
+
C::More => :'>',
|
41
|
+
C::LessOrEqual => :'<=',
|
42
|
+
C::MoreOrEqual => :'>=',
|
43
|
+
C::Equal => :'==',
|
44
|
+
C::NotEqual => :'!=',
|
45
|
+
C::And => :'&&',
|
46
|
+
C::Or => :'||'
|
47
|
+
}
|
48
|
+
|
49
|
+
UNARY_CAST_TO_OP = {
|
50
|
+
C::Negative => :'-@',
|
51
|
+
C::Not => :'!@',
|
52
|
+
C::Arrow => :'->',
|
53
|
+
C::Dereference => :'*@'
|
54
|
+
}
|
55
|
+
|
56
|
+
ASSIGN_CAST_TO_OP = {
|
57
|
+
C::Assign => :'=',
|
58
|
+
}
|
59
|
+
|
60
|
+
BINARY_ASSIGN_CAST_TO_OP = {
|
61
|
+
C::AddAssign => :'+=',
|
62
|
+
C::SubtractAssign => :'-=',
|
63
|
+
C::MultiplyAssign => :'*=',
|
64
|
+
C::DivideAssign => :'/=',
|
65
|
+
C::ModAssign => :'%='
|
66
|
+
}
|
67
|
+
|
68
|
+
BINARY_CAST_TO_OP = {
|
69
|
+
C::Add => :'+',
|
70
|
+
C::Subtract => :'-',
|
71
|
+
C::Multiply => :'*',
|
72
|
+
C::Divide => :'/',
|
73
|
+
C::Mod => :'%',}
|
74
|
+
|
75
|
+
BIT_CAST_TO_OP = {
|
76
|
+
C::BitAnd => :'&',
|
77
|
+
C::BitOr => :'|',
|
78
|
+
C::BitXor => :'^',
|
79
|
+
C::ShiftLeft => :'<<',
|
80
|
+
C::ShiftRight => :'>>'
|
81
|
+
}
|
82
|
+
|
83
|
+
CAST_TO_OP = BOOL_CAST_TO_OP.
|
84
|
+
merge(UNARY_CAST_TO_OP).
|
85
|
+
merge(ASSIGN_CAST_TO_OP).
|
86
|
+
merge(BINARY_CAST_TO_OP).
|
87
|
+
merge(BIT_CAST_TO_OP).
|
88
|
+
merge(BINARY_ASSIGN_CAST_TO_OP)
|
89
|
+
|
90
|
+
def initialize path, c_output_basename, options = {}
|
91
|
+
options = {
|
92
|
+
:include_guards => true,
|
93
|
+
:header => true,
|
94
|
+
:include_header => true
|
95
|
+
}.merge(options)
|
96
|
+
|
97
|
+
@default_key = 'TYPE'
|
98
|
+
@path = path
|
99
|
+
@basename = c_output_basename
|
100
|
+
@externs = DEFAULT_EXTERNS
|
101
|
+
@blueprints = {}
|
102
|
+
@enumerators = {}
|
103
|
+
|
104
|
+
yield self
|
105
|
+
|
106
|
+
# STDERR.puts "GENERATOR EXTERNS: " + @externs.inspect
|
107
|
+
|
108
|
+
@blueprints.each_key do |id|
|
109
|
+
@blueprints[id].expand_ops!
|
110
|
+
end
|
111
|
+
|
112
|
+
mutant_functions = []
|
113
|
+
blueprints.each_value do |blueprint|
|
114
|
+
blueprint.types.each_pair do |type_symbol,type|
|
115
|
+
mutant_functions = mutant_functions.concat(blueprint.mutate_functions(type_symbol))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
declarations = write_c_file(options[:include_guards], options[:include_header], mutant_functions)
|
120
|
+
write_h_file(options[:include_guards], declarations) if options[:header]
|
121
|
+
end
|
122
|
+
|
123
|
+
attr_reader :blueprints, :path, :basename, :enumerators
|
124
|
+
|
125
|
+
def inspect
|
126
|
+
obj_id = "0x#{(self.object_id << 1).to_s(16)}"
|
127
|
+
"#<#{self.class.to_s}:#{obj_id} basename=#{@basename.inspect} blueprint_ids=#{@blueprints.keys.inspect} path=#{@path.inspect}>"
|
128
|
+
end
|
129
|
+
|
130
|
+
def default_key k=nil
|
131
|
+
return @default_key if k.nil?
|
132
|
+
@default_key = k
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def c_include_guard
|
137
|
+
"#{@basename.upcase}_C"
|
138
|
+
end
|
139
|
+
|
140
|
+
def h_include_guard
|
141
|
+
"#{@basename.upcase}_H"
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def c_filename
|
146
|
+
"#{@basename}.c"
|
147
|
+
end
|
148
|
+
|
149
|
+
def h_filename
|
150
|
+
"#{@basename}.h"
|
151
|
+
end
|
152
|
+
|
153
|
+
# Shorthand for blueprints[id]
|
154
|
+
def [] blueprint_id
|
155
|
+
blueprints[blueprint_id]
|
156
|
+
end
|
157
|
+
|
158
|
+
# Register symbols available to all functions, and their types. Takes a hash as only argument.
|
159
|
+
#
|
160
|
+
# Example:
|
161
|
+
#
|
162
|
+
# c.externs 'NM_MAX' => :integer, 'CblasNoTrans' => 'char', 'fprintf' => 'int'
|
163
|
+
#
|
164
|
+
#
|
165
|
+
def externs h=nil
|
166
|
+
return @externs if h.nil?
|
167
|
+
@externs.merge!(h)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Create a blueprint for a set of types that all behave a certain way.
|
171
|
+
#
|
172
|
+
# At minimum, you should provide the name of the blueprint (e.g., <tt>blueprint(:integer)</tt>). You may also provide
|
173
|
+
# a template parameter name, which defaults to TYPE, and field parameters.
|
174
|
+
#
|
175
|
+
# Example (complex):
|
176
|
+
#
|
177
|
+
# c.blueprint(:complex, 'TYPE', :r => 'FLOAT', :i => 'FLOAT') do |t|
|
178
|
+
# # ...
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
def blueprint id, template_param = 'TYPE', field_params = {}, &block
|
182
|
+
raise(ArgumentError, "id #{id} already declared") if @blueprints.has_key?(id)
|
183
|
+
|
184
|
+
# Clear cache of blueprints by type_id
|
185
|
+
@blueprint_for = nil
|
186
|
+
|
187
|
+
@blueprints[id] = Blueprint.new(self, id, template_param, field_params, &block)
|
188
|
+
|
189
|
+
self
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
# Get all types stored in the various template types
|
194
|
+
def types
|
195
|
+
h = {}
|
196
|
+
@blueprints.each_value do |blueprint|
|
197
|
+
blueprint.types.each_pair do |id, type|
|
198
|
+
if h.has_key?(id)
|
199
|
+
raise(StandardError, "two types with same id: #{id}")
|
200
|
+
else
|
201
|
+
h[id] = type
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
h
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns the blueprint corresponding to some type_id. Caches types for faster lookup.
|
209
|
+
def blueprint_for type_id
|
210
|
+
@blueprint_for ||= types
|
211
|
+
@blueprint_for[type_id].blueprint
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
def enumerate name, opts = {}
|
216
|
+
@enumerators[name] = CSquare::Generator::Enum.new(name, opts)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Get a list of ops used (just the symbols)
|
220
|
+
def op_symbols
|
221
|
+
ary = []
|
222
|
+
@blueprints.each_value do |blueprint|
|
223
|
+
ary = ary.concat blueprint.op_symbols
|
224
|
+
end
|
225
|
+
ary.sort.uniq
|
226
|
+
end
|
227
|
+
|
228
|
+
def indices_c_code
|
229
|
+
ary = []
|
230
|
+
|
231
|
+
# Blueprint-scoped indices
|
232
|
+
@blueprints.each_value do |blueprint|
|
233
|
+
blueprint.indices.values.flatten.each do |index|
|
234
|
+
blueprint.types.each_key do |type_id|
|
235
|
+
ary << index.to_c(type_id)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Add generator-scoped indices
|
241
|
+
@indices.values.flatten.each do |index|
|
242
|
+
ary << index.to_c
|
243
|
+
end
|
244
|
+
|
245
|
+
ary
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
def read_source source_filename
|
250
|
+
begin
|
251
|
+
g = self.is_a?(CSquare::Generator) ? self : self.generator
|
252
|
+
Dir.chdir(g.path) do
|
253
|
+
if File.exists?(source_filename)
|
254
|
+
preprocess_source File.new(source_filename, "r")
|
255
|
+
else
|
256
|
+
raise IOError, "file '#{source_filename}' not found in '#{g.path}' or '#{File.join(g.path, self.id.to_s)}'"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
rescue Errno::ENOENT => e
|
260
|
+
# This is really helpful for people who are using rake compile and don't know what
|
261
|
+
# the template directory should be, since they don't know their current location.
|
262
|
+
STDERR.puts "CSquare: Exception thrown: #{e.inspect}"
|
263
|
+
STDERR.puts "CSquare: Current directory: #{Dir.pwd.inspect}"
|
264
|
+
raise e
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
# Return a hash giving mappings from template typenames (keys, e.g., 'TYPE') to ctypes.
|
270
|
+
def params type_symbol
|
271
|
+
types_ = types[type_symbol]
|
272
|
+
k = types_.ctype_keys # hash of typenames to type ids
|
273
|
+
|
274
|
+
begin
|
275
|
+
k[@default_key] = types_.ctype
|
276
|
+
rescue NoMethodError
|
277
|
+
STDERR.puts "NoMethodError: @default_key=#{@default_key}, type_symbol = #{type_symbol}"
|
278
|
+
end
|
279
|
+
k["LONG_#{@default_key}"] = (types_.long || types_).ctype
|
280
|
+
k
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
# Return all possible typenames for a given source
|
285
|
+
def keys_for f_name
|
286
|
+
ary = self.template_keys(f_name)
|
287
|
+
@blueprints.each_value do |blueprint|
|
288
|
+
next unless blueprint.has_source?(f_name)
|
289
|
+
ary << blueprint.template_keys(f_name)
|
290
|
+
end
|
291
|
+
ary.flatten.compact.uniq
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
protected
|
296
|
+
def write_c_file with_guards = true, include_header = true, functions = []
|
297
|
+
declarations = []
|
298
|
+
|
299
|
+
out = File.new(c_filename, "w")
|
300
|
+
|
301
|
+
out.puts("#ifndef #{c_include_guard}\n# define #{c_include_guard}\n\n") if with_guards
|
302
|
+
|
303
|
+
h = include_header == true ? h_filename : include_header
|
304
|
+
|
305
|
+
out.puts("#include \"#{h}\"\n\n") if include_header
|
306
|
+
|
307
|
+
out.puts indices_c_code.join("\n\n")
|
308
|
+
|
309
|
+
functions.each do |f|
|
310
|
+
begin
|
311
|
+
out.puts f.entity.to_s + "\n"
|
312
|
+
rescue TypeError => e
|
313
|
+
STDERR.puts e.inspect
|
314
|
+
CSquare::Function.find_broken_ast(f.entity)
|
315
|
+
end
|
316
|
+
declarations << f.declaration
|
317
|
+
end
|
318
|
+
|
319
|
+
out.puts("#endif // #{c_include_guard}") if with_guards
|
320
|
+
|
321
|
+
out.close
|
322
|
+
|
323
|
+
declarations
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
def write_h_file with_guards = true, declarations = []
|
328
|
+
out = File.new(h_filename, "w")
|
329
|
+
|
330
|
+
out.puts("#ifndef #{h_include_guard}\n# define #{h_include_guard}\n\n") if with_guards
|
331
|
+
|
332
|
+
enumerators.each_value do |enum|
|
333
|
+
out.puts enum.to_c
|
334
|
+
end
|
335
|
+
|
336
|
+
declarations.each do |d|
|
337
|
+
out.puts d
|
338
|
+
end
|
339
|
+
|
340
|
+
out.puts("#endif // #{h_include_guard}") if with_guards
|
341
|
+
|
342
|
+
out.close
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
def keys
|
347
|
+
k = [@default_key, "LONG_#{@default_key}"]
|
348
|
+
types.each_pair do |type_symbol, type|
|
349
|
+
k = k.concat(type.keys.keys)
|
350
|
+
end
|
351
|
+
k
|
352
|
+
end
|
353
|
+
|
354
|
+
def extra_template_keys_for source
|
355
|
+
keys = []
|
356
|
+
blueprints.each_value do |blueprint|
|
357
|
+
new_keys = blueprint.extra_keys(source) if blueprint.extra_templates_by_source.has_key?(source)
|
358
|
+
keys = keys.concat(new_keys) unless new_keys.nil?
|
359
|
+
end
|
360
|
+
keys.compact.uniq
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
require_relative 'generator/blueprint'
|
365
|
+
require_relative 'generator/index'
|
366
|
+
require_relative 'generator/type'
|
367
|
+
require_relative 'generator/op'
|
368
|
+
require_relative 'generator/binary_op'
|
369
|
+
require_relative 'generator/boolean_op'
|
370
|
+
require_relative 'generator/assign_op'
|
371
|
+
require_relative 'generator/enum'
|
372
|
+
require_relative 'generator/enum/namer'
|
373
|
+
require_relative 'generator/enum/op_namer'
|
374
|
+
require_relative 'generator/enum/sparse_op_namer'
|