casty 0.3.1

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