casty 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,254 @@
1
+ ######################################################################
2
+ #
3
+ # C.default_parser and the parse_* methods.
4
+ #
5
+ # Yeah, this could be so much faster.
6
+ #
7
+ ######################################################################
8
+
9
+ module C
10
+ @@default_parser = Parser.new
11
+ def self.default_parser
12
+ @@default_parser
13
+ end
14
+ def self.default_parser=(val)
15
+ @@default_parser = val
16
+ end
17
+
18
+ class Node
19
+ #
20
+ # Return true if `str' is parsed to something `==' to this Node.
21
+ # str is first converted to a String using #to_s, then given to
22
+ # self.class.parse (along with the optional `parser').
23
+ #
24
+ def match?(str, parser=nil)
25
+ node = self.class.parse(str.to_s, parser) rescue (return false)
26
+ self == node
27
+ end
28
+ #
29
+ # Same as #match?.
30
+ #
31
+ def =~(*args)
32
+ match?(*args)
33
+ end
34
+ private
35
+ end
36
+ class NodeList
37
+ #
38
+ # As defined in Node.
39
+ #
40
+ def match?(arr, parser=nil)
41
+ arr = arr.to_a
42
+ return false if arr.length != self.length
43
+ each_with_index do |node, i|
44
+ node.match?(arr[i], parser) or return false
45
+ end
46
+ return true
47
+ end
48
+ end
49
+
50
+ def self.parse(s, parser=nil)
51
+ TranslationUnit.parse(s, parser)
52
+ end
53
+
54
+ class TranslationUnit
55
+ def self.parse(s, parser=nil)
56
+ parser ||= C.default_parser
57
+ parser.parse(s)
58
+ end
59
+ end
60
+
61
+ class Declaration
62
+ def self.parse(s, parser=nil)
63
+ parser ||= C.default_parser
64
+ ents = parser.parse(s).entities
65
+ if ents.length == 1 && # int i; int j;
66
+ ents[0].is_a?(Declaration) # void f() {}
67
+ return ents[0].detach
68
+ else
69
+ raise ParseError, "invalid Declaration"
70
+ end
71
+ end
72
+ end
73
+
74
+ class Parameter
75
+ def self.parse(s, parser=nil)
76
+ parser ||= C.default_parser
77
+ ents = parser.parse("void f(#{s}) {}").entities
78
+ if ents.length == 1 && # ) {} void (
79
+ ents[0].is_a?(FunctionDef) && # ); void(
80
+ ents[0].type.params && #
81
+ ents[0].type.params.length <= 1 # x,y
82
+ param = ents[0].type.params[0]
83
+ if param.nil?
84
+ return Parameter.new(Void.new)
85
+ else
86
+ return param.detach
87
+ end
88
+ else
89
+ raise ParseError, "invalid Parameter"
90
+ end
91
+ end
92
+ end
93
+
94
+ class Declarator
95
+ def self.parse(s, parser=nil)
96
+ parser ||= C.default_parser
97
+ # if there's a ':', declare in a struct so we can populate num_bits
98
+ if s =~ /:/
99
+ ents = parser.parse("struct {int #{s};};").entities
100
+ if ents.length == 1 && # i:1;}; struct {int i
101
+ ents[0].type.members.length == 1 && # i:1; int j
102
+ ents[0].type.members[0].declarators.length == 1 # i:1,j
103
+ return ents[0].type.members[0].declarators[0].detach
104
+ end
105
+ else
106
+ ents = parser.parse("int #{s};").entities
107
+ if ents.length == 1 && # f; int f;
108
+ ents[0].declarators.length == 1 # i,j
109
+ return ents[0].declarators[0].detach
110
+ end
111
+ end
112
+ raise ParseError, "invalid Declarator"
113
+ end
114
+ end
115
+
116
+ class FunctionDef
117
+ def self.parse(s, parser=nil)
118
+ parser ||= C.default_parser
119
+ ents = parser.parse(s).entities
120
+ if ents.length == 1 && # void f(); void g();
121
+ ents[0].is_a?(FunctionDef) # int i;
122
+ return ents[0].detach
123
+ else
124
+ raise ParseError, "invalid FunctionDef"
125
+ end
126
+ end
127
+ end
128
+
129
+ class Enumerator
130
+ def self.parse(s, parser=nil)
131
+ parser ||= C.default_parser
132
+ ents = parser.parse("enum {#{s}};").entities
133
+ if ents.length == 1 && # } enum {
134
+ ents[0].is_a?(Declaration) && # } f() {
135
+ ents[0].type.members.length == 1 # X, Y
136
+ return ents[0].type.members[0].detach
137
+ else
138
+ raise ParseError, "invalid Enumerator"
139
+ end
140
+ end
141
+ end
142
+
143
+ class MemberInit
144
+ def self.parse(s, parser=nil)
145
+ parser ||= C.default_parser
146
+ ents = parser.parse("int f() {struct s x = {#{s}};}").entities
147
+ if ents.length == 1 && # } int f() {
148
+ ents[0].def.stmts.length == 1 && # }} f() {{
149
+ ents[0].def.stmts[0].declarators.length == 1 && # 1}, y
150
+ ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 # 1, 2
151
+ return ents[0].def.stmts[0].declarators[0].init.member_inits[0].detach
152
+ else
153
+ raise ParseError, "invalid MemberInit"
154
+ end
155
+ end
156
+ end
157
+
158
+ class Member
159
+ def self.parse(s, parser=nil)
160
+ parser ||= C.default_parser
161
+ ents = parser.parse("int f() {struct s x = {.#{s} = 1};}").entities
162
+ if ents.length == 1 && # a = 1};} int f() {struct s x = {a
163
+ ents[0].def.stmts.length == 1 && # a = 1}; struct s y = {.a
164
+ #ents[0].def.stmts[0].length == 1 && # a = 1}, x = {.a
165
+ ents[0].def.stmts[0].declarators.length == 1 && # a = 1}, x = {.a
166
+ ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 && # x = 1, y
167
+ ents[0].def.stmts[0].declarators[0].init.member_inits[0].member && # 1
168
+ ents[0].def.stmts[0].declarators[0].init.member_inits[0].member.length == 1 # a .b
169
+ return ents[0].def.stmts[0].declarators[0].init.member_inits[0].member[0].detach
170
+ else
171
+ raise ParseError, "invalid Member"
172
+ end
173
+ end
174
+ end
175
+
176
+ class Statement
177
+ def self.parse(s, parser=nil)
178
+ parser ||= C.default_parser
179
+ ents = parser.parse("void f() {#{s}}").entities
180
+ if ents.length == 1 && # } void f() {
181
+ ents[0].def.stmts.length == 1 && # ;;
182
+ ents[0].def.stmts[0].is_a?(self) # int i;
183
+ return ents[0].def.stmts[0].detach
184
+ else
185
+ raise ParseError, "invalid #{self}"
186
+ end
187
+ end
188
+ end
189
+
190
+ class Label
191
+ def self.parse(s, parser=nil)
192
+ parser ||= C.default_parser
193
+ ents = parser.parse("void f() {switch (0) #{s};}").entities
194
+ if ents.length == 1 && # } void f() {
195
+ ents[0].def.stmts.length == 1 && # ;
196
+ ents[0].def.stmts[0].stmt && #
197
+ ents[0].def.stmts[0].stmt.labels.length == 1 && # x
198
+ ents[0].def.stmts[0].stmt.labels[0].is_a?(self)
199
+ return ents[0].def.stmts[0].stmt.labels[0].detach
200
+ else
201
+ raise ParseError, "invalid #{self}"
202
+ end
203
+ end
204
+ end
205
+
206
+ class Expression
207
+ def self.parse(s, parser=nil)
208
+ parser ||= C.default_parser
209
+ if s =~ /\A(\s*(\/\*.*?\*\/)?)*\{/
210
+ # starts with a brace -- must be a CompoundLiteral. in this
211
+ # case, use a Declarator since only those can handle typeless
212
+ # CompoundLiterals.
213
+ ents = parser.parse("int i = #{s};").entities
214
+ if ents.length == 1 && # 1; int i = 1
215
+ ents[0].declarators.length == 1 && # 1, j = 2
216
+ ents[0].declarators[0].init.is_a?(self)
217
+ return ents[0].declarators[0].init.detach
218
+ else
219
+ raise ParseError, "invalid #{self}"
220
+ end
221
+ else
222
+ ents = parser.parse("void f() {#{s};}").entities
223
+ if ents.length == 1 && # } void f() {
224
+ ents[0].def.stmts.length == 1 && # ;
225
+ ents[0].def.stmts[0].is_a?(ExpressionStatement) && # int i
226
+ ents[0].def.stmts[0].expr.is_a?(self)
227
+ return ents[0].def.stmts[0].expr.detach
228
+ else
229
+ raise ParseError, "invalid #{self}"
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ class Type
236
+ def self.parse(s, parser=nil)
237
+ parser ||= C.default_parser
238
+ ents = parser.parse("void f() {(#{s})x;}").entities
239
+ if ents.length == 1 && # 1);} void f() {(int
240
+ ents[0].def.stmts.length == 1 && # 1); (int
241
+ ents[0].def.stmts[0].expr.type.is_a?(self)
242
+ return ents[0].def.stmts[0].expr.type.detach
243
+ else
244
+ raise ParseError, "invalid #{self}"
245
+ end
246
+ end
247
+ end
248
+
249
+ # Make sure we didn't miss any
250
+ CORE_C_NODE_CLASSES.each do |c|
251
+ c.respond_to? :parse or
252
+ raise "#{c}.parse not defined"
253
+ end
254
+ end
@@ -0,0 +1,92 @@
1
+ require 'rbconfig'
2
+
3
+ ######################################################################
4
+ #
5
+ # A C preprocessor that wraps the command in Config::CONFIG['CPP'].
6
+ #
7
+ # Assumes a POSIX-style cpp command line interface, in particular, -I
8
+ # and -D options.
9
+ #
10
+ ######################################################################
11
+
12
+ module C
13
+ class Preprocessor
14
+ class Error < StandardError
15
+ end
16
+
17
+ class << self
18
+ attr_accessor :command
19
+ end
20
+ self.command = (defined?(RbConfig) ? RbConfig : Config)::CONFIG['CPP']
21
+
22
+ attr_accessor :pwd, :include_path, :macros, :undef_macros
23
+
24
+ def initialize
25
+ @include_path = []
26
+ @macros = {}
27
+ @undef_macros = Set.new
28
+ end
29
+ def preprocess(text)
30
+ filename = nil
31
+ temp_file = nil
32
+ Tempfile.open(['cast-preprocessor-input.', '.c'], File.expand_path(pwd || '.')) do |file|
33
+ temp_file = file
34
+ filename = file.path
35
+ file.puts text
36
+ end
37
+ return preprocess_file(filename);
38
+ ensure
39
+ if temp_file
40
+ temp_file.close
41
+ temp_file.unlink
42
+ end
43
+ end
44
+ def preprocess_file(file_name, options={})
45
+ file_name = File.expand_path(file_name)
46
+ dir = File.dirname(file_name)
47
+ stderr_buf = Tempfile.new('cast-preprocessor-stderr.txt')
48
+ FileUtils.cd(dir) do
49
+ output = `#{full_command(file_name)} 2>#{shellquote(stderr_buf.path)}`
50
+ if $? == 0 || options[:force] && !output.empty?
51
+ return output
52
+ else
53
+ raise Error, stderr_buf.read
54
+ end
55
+ end
56
+ ensure
57
+ stderr_buf.close
58
+ stderr_buf.unlink
59
+ end
60
+
61
+ private # -------------------------------------------------------
62
+
63
+ def shellquote(arg)
64
+ if arg !~ /[\"\'\\$&<>\(\)|\s]/
65
+ return arg
66
+ elsif arg !~ /\'/
67
+ return "'#{arg}'"
68
+ else
69
+ arg.gsub!(/([\"\\$&<>|])/, '\\\\\\1')
70
+ return "\"#{arg}\""
71
+ end
72
+ end
73
+ def full_command(filename)
74
+ include_args = include_path.map do |path|
75
+ "#{shellquote('-I'+path)}"
76
+ end.join(' ')
77
+ macro_args = (undef_macros.map{|m| shellquote "-U#{m}"} +
78
+ macros.map do |key, val|
79
+ case key
80
+ when :@imacros
81
+ "-imacros" + shellquote(File.expand_path(val))
82
+ when :@include
83
+ "-include" + shellquote(File.expand_path(val))
84
+ else
85
+ shellquote("-D#{key}#{"=#{val}" if val}")
86
+ end
87
+ end).join(' ')
88
+ filename = shellquote(filename)
89
+ "#{Preprocessor.command} #{include_args} #{macro_args} #{filename}"
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,33 @@
1
+ ######################################################################
2
+ #
3
+ # Alternative to the standard ruby tempfile library, which lets you
4
+ # specify a filename suffix.
5
+ #
6
+ ######################################################################
7
+
8
+ require 'delegate'
9
+ require 'tmpdir'
10
+ require 'tempfile'
11
+
12
+ #
13
+ # Setting the extension of a temp file has only been possible since
14
+ # Ruby 1.8.7.
15
+ #
16
+ module C
17
+ if RUBY_VERSION >= '1.8.7'
18
+ Tempfile = ::Tempfile
19
+ else
20
+ class Tempfile < ::Tempfile
21
+ def initialize(basename, tmpdir=Dir::tmpdir)
22
+ if basename.is_a?(::Array)
23
+ basename, @suffix = *basename
24
+ end
25
+ super(basename, tmpdir)
26
+ end
27
+
28
+ def make_tmpname(basename, n)
29
+ sprintf('%s%d.%d%s', basename, $$, n, @suffix)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,555 @@
1
+ ######################################################################
2
+ #
3
+ # The Node#to_s methods.
4
+ #
5
+ # Yeah, this could be so so *SO* much faster.
6
+ #
7
+ ######################################################################
8
+
9
+ module C
10
+ # undef the #to_s methods so we can check that we didn't forget to
11
+ # define any
12
+ Node.send(:undef_method, :to_s)
13
+
14
+ INDENT = ' '
15
+ class Node
16
+ private
17
+ def indent(s, levels=1)
18
+ s.gsub(/^/, INDENT*levels)
19
+ end
20
+ def hang(stmt, cont=false)
21
+ if stmt.is_a?(Block) && stmt.labels.empty?
22
+ return " #{stmt.to_s(:hanging)}" << (cont ? ' ' : '')
23
+ else
24
+ return "\n#{stmt.to_s}" << (cont ? "\n" : '')
25
+ end
26
+ end
27
+ end
28
+
29
+ class TranslationUnit
30
+ def to_s
31
+ entities.map{|n| n.to_s}.join("\n\n")
32
+ end
33
+ end
34
+ class Declaration
35
+ def to_s
36
+ str = ''
37
+ inline? and str << "inline "
38
+ storage and str << "#{storage} "
39
+ if declarators.empty?
40
+ return str << "#{type};"
41
+ else
42
+ return str << "#{type} " << declarators.join(', ') << ';'
43
+ end
44
+ end
45
+ end
46
+ class Declarator
47
+ def to_s
48
+ (indirect_type ? indirect_type.to_s(name) : name.dup) <<
49
+ (init ? " = #{init}" : '') <<
50
+ (num_bits ? " : #{num_bits}" : '')
51
+ end
52
+ end
53
+ class FunctionDef
54
+ def to_s
55
+ str = ''
56
+ static? and str << 'static '
57
+ inline? and str << 'inline '
58
+ if no_prototype?
59
+ str << "#{type.to_s(name, true)}\n"
60
+ type.params.each do |p|
61
+ str << indent("#{p.to_s};\n")
62
+ end
63
+ str << "#{self.def.to_s(:hanging)}"
64
+ else
65
+ str << "#{type.to_s(name)}#{hang(self.def)}"
66
+ end
67
+ end
68
+ end
69
+
70
+ # ------------------------------------------------------------------
71
+ # Statements
72
+ # ------------------------------------------------------------------
73
+
74
+ class Statement
75
+ def label(str)
76
+ labels.map{|s| "#{s}\n"}.join + indent(str)
77
+ end
78
+ end
79
+ class Block
80
+ def to_s(hanging=false)
81
+ str = stmts.map do |s|
82
+ if s.is_a? Statement
83
+ s.to_s
84
+ else
85
+ indent(s.to_s)
86
+ end
87
+ end.join("\n")
88
+ str << "\n" unless str == ''
89
+ str = "{\n" << str << "}"
90
+ if hanging
91
+ if labels.empty?
92
+ return str
93
+ else
94
+ return "\n" << label(str)
95
+ end
96
+ else
97
+ return label(str)
98
+ end
99
+ end
100
+ end
101
+ class If
102
+ def to_s
103
+ str = "if (#{cond})"
104
+ if self.else.nil?
105
+ str << hang(self.then)
106
+ else
107
+ str << hang(self.then, :cont) << 'else' << hang(self.else)
108
+ end
109
+ return label(str)
110
+ end
111
+ end
112
+ class Switch
113
+ def to_s
114
+ label("switch (#{cond})" << hang(stmt))
115
+ end
116
+ end
117
+ class While
118
+ def to_s
119
+ if do?
120
+ label('do' << hang(stmt, :cont) << "while (#{cond});")
121
+ else
122
+ label("while (#{cond})" << hang(stmt))
123
+ end
124
+ end
125
+ end
126
+ class For
127
+ def to_s
128
+ initstr =
129
+ case init
130
+ when nil
131
+ ';'
132
+ when Declaration
133
+ "#{init}"
134
+ else
135
+ "#{init};"
136
+ end
137
+ condstr = cond ? " #{cond};" : ';'
138
+ iterstr = iter ? " #{iter}" : ''
139
+ label("for (#{initstr}#{condstr}#{iterstr})" << hang(stmt))
140
+ end
141
+ end
142
+ class Goto
143
+ def to_s
144
+ label("goto #{target};")
145
+ end
146
+ end
147
+ class Continue
148
+ def to_s
149
+ label("continue;")
150
+ end
151
+ end
152
+ class Break
153
+ def to_s
154
+ label("break;")
155
+ end
156
+ end
157
+ class Return
158
+ def to_s
159
+ label("return#{expr ? ' '+expr.to_s : ''};")
160
+ end
161
+ end
162
+ class ExpressionStatement
163
+ def to_s
164
+ label("#{expr};")
165
+ end
166
+ end
167
+
168
+ class PlainLabel
169
+ def to_s
170
+ "#{name}:"
171
+ end
172
+ end
173
+ class Default
174
+ def to_s
175
+ 'default:'
176
+ end
177
+ end
178
+ class Case
179
+ def to_s
180
+ "case #{expr}:"
181
+ end
182
+ end
183
+
184
+ # ------------------------------------------------------------------
185
+ # Expressions
186
+ # ------------------------------------------------------------------
187
+
188
+ precedence_table = {}
189
+ [[Comma],
190
+ [Assign, MultiplyAssign, DivideAssign, ModAssign, AddAssign,
191
+ SubtractAssign, ShiftLeftAssign, ShiftRightAssign, BitAndAssign,
192
+ BitXorAssign, BitOrAssign],
193
+ [Conditional],
194
+ [Or],
195
+ [And],
196
+ [BitOr],
197
+ [BitXor],
198
+ [BitAnd],
199
+ [Equal, NotEqual],
200
+ [Less, More, LessOrEqual, MoreOrEqual],
201
+ [ShiftLeft, ShiftRight],
202
+ [Add, Subtract],
203
+ [Multiply, Divide, Mod],
204
+ [PreInc, PreDec, Sizeof, Cast, Address, Dereference, Positive, Negative,
205
+ BitNot, Not],
206
+ [Index, Call, Arrow, Dot, PostInc, PostDec],
207
+ [Literal, Variable]
208
+ ].each_with_index do |klasses, prec|
209
+ klasses.each do |klass|
210
+ klass.send(:define_method, :to_s_precedence){|| prec}
211
+ end
212
+ end
213
+ # check all Expression classes have a precedence
214
+ C::Expression.subclasses_recursive do |c|
215
+ next if !C::Node.subclasses_recursive.include? c
216
+ c.instance_methods.include? 'to_s_precedence' or
217
+ raise "#{c}#to_s_precedence not defined"
218
+ end
219
+
220
+ # PrefixExpressions
221
+ [ [Cast , proc{"(#{self.type})"}, false],
222
+ [Address , proc{"&" }, true ],
223
+ [Dereference, proc{"*" }, false],
224
+ [Positive , proc{"+" }, true ],
225
+ [Negative , proc{"-" }, true ],
226
+ [PreInc , proc{"++" }, false],
227
+ [PreDec , proc{"--" }, false],
228
+ [BitNot , proc{"~" }, false],
229
+ [Not , proc{"!" }, false]
230
+ ].each do |c, proc, space_needed|
231
+ c.send(:define_method, :to_s) do | |
232
+ if expr.to_s_precedence < self.to_s_precedence
233
+ return "#{instance_eval(&proc)}(#{expr})"
234
+ elsif space_needed && expr.class == self.class
235
+ return "#{instance_eval(&proc)} #{expr}"
236
+ else
237
+ return "#{instance_eval(&proc)}#{expr}"
238
+ end
239
+ end
240
+ end
241
+ # PostfixExpressions
242
+ [ [Arrow , proc{"->#{member}"}],
243
+ [Dot , proc{".#{member}" }],
244
+ [Index , proc{"[#{index}]" }],
245
+ [PostInc , proc{"++" }],
246
+ [PostDec , proc{"--" }]
247
+ ].each do |c, proc|
248
+ c.send(:define_method, :to_s) do | |
249
+ if expr.to_s_precedence < self.to_s_precedence
250
+ return "(#{expr})#{instance_eval(&proc)}"
251
+ else
252
+ return "#{expr}#{instance_eval(&proc)}"
253
+ end
254
+ end
255
+ end
256
+ # BinaryExpressions
257
+ [ [Add , '+' ],
258
+ [Subtract , '-' ],
259
+ [Multiply , '*' ],
260
+ [Divide , '/' ],
261
+ [Mod , '%' ],
262
+ [Equal , '=='],
263
+ [NotEqual , '!='],
264
+ [Less , '<' ],
265
+ [More , '>' ],
266
+ [LessOrEqual, '<='],
267
+ [MoreOrEqual, '>='],
268
+ [BitAnd , '&' ],
269
+ [BitOr , '|' ],
270
+ [BitXor , '^' ],
271
+ [ShiftLeft , '<<'],
272
+ [ShiftRight , '>>'],
273
+ [And , '&&'],
274
+ [Or , '||'],
275
+ ].each do |c, op|
276
+ c.send(:define_method, :to_s) do | |
277
+ if expr1.to_s_precedence < self.to_s_precedence
278
+ str1 = "(#{expr1})"
279
+ else
280
+ str1 = "#{expr1}"
281
+ end
282
+ # all binary expressions are left associative
283
+ if expr2.to_s_precedence <= self.to_s_precedence
284
+ str2 = "(#{expr2})"
285
+ else
286
+ str2 = "#{expr2}"
287
+ end
288
+ "#{str1} #{op} #{str2}"
289
+ end
290
+ end
291
+ # AssignmentExpressions
292
+ [ [Assign , '' ],
293
+ [MultiplyAssign , '*' ],
294
+ [DivideAssign , '/' ],
295
+ [ModAssign , '%' ],
296
+ [AddAssign , '+' ],
297
+ [SubtractAssign , '-' ],
298
+ [ShiftLeftAssign , '<<'],
299
+ [ShiftRightAssign, '>>'],
300
+ [BitAndAssign , '&' ],
301
+ [BitXorAssign , '^' ],
302
+ [BitOrAssign , '|' ]
303
+ ].each do |c, op|
304
+ c.send(:define_method, :to_s) do | |
305
+ if rval.to_s_precedence < self.to_s_precedence
306
+ rvalstr = "(#{rval})"
307
+ else
308
+ rvalstr = "#{rval}"
309
+ end
310
+ if lval.to_s_precedence < self.to_s_precedence
311
+ lvalstr = "(#{lval})"
312
+ else
313
+ lvalstr = "#{lval}"
314
+ end
315
+ "#{lvalstr} #{op}= #{rvalstr}"
316
+ end
317
+ end
318
+ # Other Expressions
319
+ class Sizeof
320
+ def to_s
321
+ "sizeof(#{expr})"
322
+ end
323
+ end
324
+ # DirectTypes
325
+ int_longnesses = ['short ', '', 'long ', 'long long ']
326
+ float_longnesses = ['float', 'double', 'long double']
327
+ [ [Struct, proc do
328
+ str = 'struct'
329
+ name and str << " #{name}"
330
+ members and str << " {\n" << indent(members.join("\n")) << "\n}"
331
+ str
332
+ end],
333
+ [Union, proc do
334
+ str = 'union'
335
+ name and str << " #{name}"
336
+ members and str << " {\n" << indent(members.join("\n")) << "\n}"
337
+ str
338
+ end],
339
+ [Enum, proc do
340
+ str = 'enum'
341
+ name and str << " #{name}"
342
+ members and str << " {\n" << indent(members.join(",\n")) << "\n}"
343
+ str
344
+ end],
345
+ [CustomType, proc{name.dup }],
346
+ [Void , proc{'void' }],
347
+ [Int , proc do
348
+ longness_str = int_longnesses[longness+1].dup
349
+ "#{unsigned? ? 'unsigned ' : ''}#{longness_str}int"
350
+ end],
351
+ [Float , proc{float_longnesses[longness].dup}],
352
+ [Char , proc{"#{unsigned? ? 'unsigned ' : signed? ? 'signed ' : ''}char"}],
353
+ [Bool , proc{"_Bool" }],
354
+ [Complex , proc{"_Complex #{float_longnesses[longness]}"}],
355
+ [Imaginary , proc{"_Imaginary #{float_longnesses[longness]}"}]
356
+ ].each do |c, x|
357
+ c.send(:define_method, :to_s) do |*args|
358
+ case args.length
359
+ when 0
360
+ namestr = nil
361
+ when 1
362
+ namestr = args[0]
363
+ namestr = nil if namestr == ''
364
+ else
365
+ raise ArgumentError, "wrong number of args (#{args.length} for 1)"
366
+ end
367
+ str = ''
368
+ const? and str << 'const '
369
+ restrict? and str << 'restrict '
370
+ volatile? and str << 'volatile '
371
+ str << instance_eval(&x) << (namestr ? " #{namestr}" : '')
372
+ end
373
+ end
374
+
375
+ class Enumerator
376
+ def to_s
377
+ if val
378
+ "#{name} = #{val}"
379
+ else
380
+ "#{name}"
381
+ end
382
+ end
383
+ end
384
+
385
+ class Comma
386
+ def to_s
387
+ exprs.join(', ')
388
+ end
389
+ end
390
+
391
+ class Conditional
392
+ def to_s
393
+ strs = [:cond, :then, :else].map do |child|
394
+ val = send(child)
395
+ if val.to_s_precedence <= self.to_s_precedence
396
+ "(#{val})"
397
+ else
398
+ "#{val}"
399
+ end
400
+ end
401
+ "#{strs[0]} ? #{strs[1]} : #{strs[2]}"
402
+ end
403
+ end
404
+
405
+ class Call
406
+ def to_s
407
+ argstrs = args.map do |arg|
408
+ if arg.is_a? Comma
409
+ "(#{arg})"
410
+ else
411
+ "#{arg}"
412
+ end
413
+ end
414
+ if expr.to_s_precedence < self.to_s_precedence
415
+ exprstr = "(#{expr})"
416
+ else
417
+ exprstr = "#{expr}"
418
+ end
419
+ "#{exprstr}(#{argstrs.join(', ')})"
420
+ end
421
+ end
422
+
423
+ ## IndirectTypes
424
+ class Pointer
425
+ def to_s(name=nil)
426
+ str = '*'
427
+ const? and str << 'const '
428
+ restrict? and str << 'restrict '
429
+ volatile? and str << 'volatile '
430
+ str =
431
+ case type
432
+ when Function, Array
433
+ "(#{str}#{name})"
434
+ else
435
+ "#{str}#{name}"
436
+ end
437
+ if type
438
+ type.to_s(str)
439
+ else
440
+ str
441
+ end
442
+ end
443
+ end
444
+ class Array
445
+ def to_s(name=nil)
446
+ str = "#{name}[#{length}]"
447
+ if type
448
+ type.to_s(str)
449
+ else
450
+ str
451
+ end
452
+ end
453
+ end
454
+ class Function
455
+ def to_s(name=nil, no_types=false)
456
+ str =
457
+ if params.nil?
458
+ paramstr = ''
459
+ elsif params.empty?
460
+ paramstr = 'void'
461
+ else
462
+ if no_types
463
+ paramstr = params.map{|p| p.name}.join(', ')
464
+ else
465
+ paramstr = params.join(', ')
466
+ end
467
+ end
468
+ var_args? and paramstr << ', ...'
469
+ str = "#{name}(#{paramstr})"
470
+ if type
471
+ type.to_s(str)
472
+ else
473
+ str
474
+ end
475
+ end
476
+ end
477
+ class Parameter
478
+ def to_s
479
+ str = register? ? 'register ' : ''
480
+ if type
481
+ str << type.to_s(name)
482
+ else
483
+ str << name.to_s
484
+ end
485
+ end
486
+ end
487
+
488
+ ## Literals
489
+ class StringLiteral
490
+ def to_s
491
+ "\"#{val}\""
492
+ end
493
+ end
494
+ class CharLiteral
495
+ def to_s
496
+ "'#{val}'"
497
+ end
498
+ end
499
+ class CompoundLiteral
500
+ def to_s
501
+ str = ''
502
+ type and
503
+ str << "(#{type}) "
504
+ str << "{\n" << indent(member_inits.join(",\n")) << "\n}"
505
+ end
506
+ end
507
+ class MemberInit
508
+ def to_s
509
+ str = ''
510
+ if member
511
+ memberstr = member.map do |m|
512
+ if m.is_a? Expression
513
+ "[#{m}]"
514
+ else
515
+ ".#{m}"
516
+ end
517
+ end
518
+ str << memberstr.join(' ') << ' = '
519
+ end
520
+ return str << init.to_s
521
+ end
522
+ end
523
+ class Member
524
+ def to_s
525
+ name.dup
526
+ end
527
+ end
528
+ class IntLiteral
529
+ def to_s
530
+ val.to_s
531
+ end
532
+ end
533
+ class FloatLiteral
534
+ def to_s
535
+ val.to_s
536
+ end
537
+ end
538
+ class Variable
539
+ def to_s
540
+ name.dup
541
+ end
542
+ end
543
+ class BlockExpression
544
+ def to_s
545
+ # note that the grammar does not allow the block to have a label
546
+ "(#{block.to_s(:hanging)})"
547
+ end
548
+ end
549
+
550
+ # check we didn't miss any
551
+ CORE_C_NODE_CLASSES.each do |c|
552
+ c.method_defined? :to_s or
553
+ raise "#{c}#to_s not defined"
554
+ end
555
+ end