chelsy 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/.yardopts +1 -0
- data/README.md +38 -6
- data/chelsy.gemspec +12 -11
- data/lib/chelsy/ast.rb +922 -91
- data/lib/chelsy/syntax.rb +23 -10
- data/lib/chelsy/translator.rb +562 -43
- data/lib/chelsy/version.rb +1 -1
- data/sample/hello_chelsy.rb +1 -2
- data/sample/temperature.c +17 -0
- data/sample/temperature.rb +39 -0
- metadata +21 -4
data/lib/chelsy/translator.rb
CHANGED
@@ -5,9 +5,9 @@ module Chelsy
|
|
5
5
|
|
6
6
|
DEFAULT_INDENT_STRING = ' '.freeze
|
7
7
|
|
8
|
-
def initialize()
|
9
|
-
@indent_string =
|
10
|
-
@indent_level =
|
8
|
+
def initialize(indent_string: DEFAULT_INDENT_STRING, indent_level: 0)
|
9
|
+
@indent_string = indent_string
|
10
|
+
@indent_level = indent_level
|
11
11
|
end
|
12
12
|
|
13
13
|
def translate(node)
|
@@ -41,8 +41,28 @@ module Chelsy
|
|
41
41
|
case node
|
42
42
|
when String
|
43
43
|
node.to_s
|
44
|
+
when Comment::Multi
|
45
|
+
translate_comment_multi(node)
|
46
|
+
when Comment::Single
|
47
|
+
translate_comment_single(node)
|
44
48
|
when Directive::Include
|
45
49
|
translate_include(node)
|
50
|
+
when Directive::Define
|
51
|
+
translate_define(node)
|
52
|
+
when Directive::Undef
|
53
|
+
translate_undef(node)
|
54
|
+
when Directive::If
|
55
|
+
translate_if_directive(node)
|
56
|
+
when Directive::ElseIf
|
57
|
+
translate_elif_directive(node)
|
58
|
+
when Directive::Else
|
59
|
+
translate_else_directive(node)
|
60
|
+
when Directive::EndIf
|
61
|
+
translate_endif_directive(node)
|
62
|
+
when Directive::Line
|
63
|
+
translate_line_directive(node)
|
64
|
+
when Directive::Pragma
|
65
|
+
translate_pragma_directive(node)
|
46
66
|
else
|
47
67
|
raise ArgumentError, "Unrecognized AST fragment: #{node.inspect}"
|
48
68
|
end
|
@@ -63,25 +83,56 @@ module Chelsy
|
|
63
83
|
translate_integral(node)
|
64
84
|
when Constant::String
|
65
85
|
translate_string(node)
|
66
|
-
when
|
67
|
-
|
86
|
+
when Operator::Unary
|
87
|
+
translate_unary_operator(node)
|
88
|
+
when Operator::Binary
|
89
|
+
translate_binary_operator(node)
|
90
|
+
when Operator::Conditional
|
91
|
+
translate_ternary_conditional(node)
|
68
92
|
|
69
93
|
# Statements
|
70
94
|
when EmptyStmt
|
71
95
|
translate_empty_stmt(node)
|
72
96
|
when ExprStmt
|
73
97
|
translate_expr_stmt(node)
|
98
|
+
when If
|
99
|
+
translate_if(node)
|
100
|
+
when Switch
|
101
|
+
translate_switch(node)
|
102
|
+
when While
|
103
|
+
translate_while(node)
|
104
|
+
when DoWhile
|
105
|
+
translate_do_while(node)
|
106
|
+
when For
|
107
|
+
translate_for(node)
|
108
|
+
when Break
|
109
|
+
translate_break(node)
|
110
|
+
when Continue
|
111
|
+
translate_continue(node)
|
112
|
+
when Case
|
113
|
+
translate_case(node)
|
114
|
+
when Labeled
|
115
|
+
translate_labeled(node)
|
116
|
+
when Goto
|
117
|
+
translate_goto(node)
|
74
118
|
when Return
|
75
119
|
translate_return(node)
|
76
120
|
when Block
|
77
121
|
translate_block(node)
|
78
122
|
|
79
123
|
# Definition
|
124
|
+
when Declaration, Typedef
|
125
|
+
translate_declaration(node)
|
126
|
+
when BitField
|
127
|
+
translate_bit_field(node)
|
80
128
|
when Function
|
81
129
|
translate_function(node)
|
82
130
|
when Param
|
83
|
-
|
84
|
-
|
131
|
+
translate_param(node)
|
132
|
+
when Initializer
|
133
|
+
translate_initializer(node)
|
134
|
+
when InitializerList
|
135
|
+
translate_initializer_list(node)
|
85
136
|
else
|
86
137
|
raise ArgumentError, "Unrecognized AST element: #{node.inspect}"
|
87
138
|
end
|
@@ -99,7 +150,13 @@ module Chelsy
|
|
99
150
|
end
|
100
151
|
|
101
152
|
def translate_document(node)
|
102
|
-
node.map {|nd| translate(nd) }
|
153
|
+
node.map {|nd| translate(nd) }
|
154
|
+
.join("\n\n")
|
155
|
+
.tap do |src|
|
156
|
+
# Document's fragments and body should be separated by empty line for
|
157
|
+
# source code readability.
|
158
|
+
src.insert(0, "\n") unless src.empty? || node.fragments.empty?
|
159
|
+
end
|
103
160
|
end
|
104
161
|
|
105
162
|
def translate_ident(node)
|
@@ -114,28 +171,100 @@ module Chelsy
|
|
114
171
|
|
115
172
|
def translate_typed_name(ty, name=nil)
|
116
173
|
case ty
|
174
|
+
when Type::Pointer
|
175
|
+
translate_pointer_type(ty, name)
|
176
|
+
when Type::Array
|
177
|
+
translate_array_type(ty, name)
|
178
|
+
when Type::Function
|
179
|
+
translate_function_type(ty, name)
|
180
|
+
when Type::Struct
|
181
|
+
translate_struct_type(ty, name)
|
182
|
+
when Type::Union
|
183
|
+
translate_union_type(ty, name)
|
184
|
+
when Type::Enum
|
185
|
+
translate_enum_type(ty, name)
|
117
186
|
when Type::Derived
|
118
|
-
# TODO
|
119
187
|
raise NotImplementedError
|
120
188
|
else
|
121
|
-
translate_primitive_type(ty)
|
122
|
-
|
123
|
-
|
189
|
+
translate_primitive_type(ty, name)
|
190
|
+
end
|
191
|
+
.tap do |src|
|
192
|
+
src.strip!
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def translate_pointer_type(ty, name=nil)
|
197
|
+
# qualifiers
|
198
|
+
src = ''.tap do |qualifier|
|
199
|
+
qualifier << '*'
|
200
|
+
qualifier << 'const ' if ty.const?
|
201
|
+
qualifier << 'volatile ' if ty.volatile?
|
202
|
+
qualifier << 'restrict ' if ty.restrict?
|
203
|
+
end
|
204
|
+
|
205
|
+
# name
|
206
|
+
src << name.to_s
|
207
|
+
|
208
|
+
# parenthesize if needed
|
209
|
+
case ty.pointee
|
210
|
+
when Type::Function, Type::Array
|
211
|
+
translate_typed_name(ty.pointee, "(#{src})")
|
212
|
+
else
|
213
|
+
translate_typed_name(ty.pointee, src)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def translate_array_type(ty, name=nil)
|
218
|
+
src = name.to_s.tap do |subscript|
|
219
|
+
subscript << '['
|
220
|
+
subscript << 'const ' if ty.const?
|
221
|
+
subscript << 'volatile ' if ty.volatile?
|
222
|
+
subscript << 'static ' if ty.static?
|
223
|
+
subscript << translate(ty.size) if ty.size
|
224
|
+
subscript << ']'
|
225
|
+
end
|
226
|
+
|
227
|
+
translate_typed_name(coerce_func_ptr(ty.element_type), src)
|
228
|
+
end
|
229
|
+
|
230
|
+
def translate_function_type(ty, name=nil)
|
231
|
+
src = name.to_s.tap do |params|
|
232
|
+
params << '('
|
233
|
+
params << ty.params.map {|p| translate(coerce_func_ptr(p)) }.join(', ')
|
234
|
+
params << ')'
|
124
235
|
end
|
236
|
+
|
237
|
+
translate_typed_name(coerce_func_ptr(ty.return_type), src)
|
238
|
+
end
|
239
|
+
|
240
|
+
def translate_struct_type(ty, name=nil)
|
241
|
+
translate_taggable_type_members(ty, name)
|
125
242
|
end
|
126
243
|
|
127
|
-
def
|
244
|
+
def translate_union_type(ty, name=nil)
|
245
|
+
translate_taggable_type_members(ty, name)
|
246
|
+
end
|
247
|
+
|
248
|
+
def translate_enum_type(ty, name=nil)
|
249
|
+
translate_taggable_type_members(ty, name)
|
250
|
+
end
|
251
|
+
|
252
|
+
def translate_primitive_type(ty, name=nil)
|
253
|
+
src = case ty
|
254
|
+
when :void; 'void'
|
255
|
+
when Type::Integral
|
256
|
+
translate_integral_type(ty)
|
257
|
+
else
|
258
|
+
translate_numeric_type(ty)
|
259
|
+
end
|
128
260
|
case ty
|
129
|
-
when
|
130
|
-
when Type::Char; 'char'
|
131
|
-
when Type::Short; 'short'
|
132
|
-
when Type::Integral
|
133
|
-
translate_integral_type(ty)
|
134
|
-
end.tap do |src|
|
135
|
-
# qualifiers
|
261
|
+
when Type::Base;
|
136
262
|
src.insert(0, 'const ') if ty.const?
|
137
263
|
src.insert(0, 'volatile ') if ty.volatile?
|
138
|
-
|
264
|
+
end
|
265
|
+
|
266
|
+
src.tap do |src|
|
267
|
+
src << " #{name}" if name
|
139
268
|
end
|
140
269
|
end
|
141
270
|
|
@@ -151,6 +280,21 @@ module Chelsy
|
|
151
280
|
end
|
152
281
|
end
|
153
282
|
|
283
|
+
def translate_numeric_type(ty)
|
284
|
+
case ty
|
285
|
+
when Type::Bool; '_Bool'
|
286
|
+
when Type::Float; 'float'
|
287
|
+
when Type::Double; 'double'
|
288
|
+
when Type::LongDouble; 'long double'
|
289
|
+
when Type::Complex; '_Complex'
|
290
|
+
when Type::FloatComplex; 'float _Complex'
|
291
|
+
when Type::DoubleComplex; 'double _Complex'
|
292
|
+
when Type::LongDoubleComplex; 'long double _Complex'
|
293
|
+
else
|
294
|
+
raise NotImplementedError
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
154
298
|
# = Expressions
|
155
299
|
|
156
300
|
def translate_integral(node)
|
@@ -165,37 +309,266 @@ module Chelsy
|
|
165
309
|
end
|
166
310
|
end
|
167
311
|
|
312
|
+
def translate_unary_operator(node)
|
313
|
+
case node
|
314
|
+
when Operator::Subscription
|
315
|
+
translate_subscription(node)
|
316
|
+
when Operator::Call
|
317
|
+
translate_function_call(node)
|
318
|
+
when Operator::Access
|
319
|
+
translate_member_access(node)
|
320
|
+
when Operator::Cast
|
321
|
+
translate_type_cast(node)
|
322
|
+
when Operator::SizeOf
|
323
|
+
translate_size_of(node)
|
324
|
+
when Operator::Postfix
|
325
|
+
translate_postfix_operator(node)
|
326
|
+
when Operator::Prefix
|
327
|
+
translate_prefix_operator(node)
|
328
|
+
when Operator::Defined
|
329
|
+
translate_defined_operator(node)
|
330
|
+
else
|
331
|
+
raise NotImplementedError, "Unrecognized unary operator: #{node.inspect}"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def translate_subscription(node)
|
336
|
+
subscriptee = expr(node.subscriptee, node)
|
337
|
+
index = translate(node.index)
|
338
|
+
|
339
|
+
"#{subscriptee}[#{index}]"
|
340
|
+
end
|
341
|
+
|
168
342
|
def translate_function_call(node)
|
169
|
-
callee = expr(node.callee)
|
170
|
-
args = node.args.map {|a|
|
343
|
+
callee = expr(node.callee, node)
|
344
|
+
args = node.args.map {|a| translate(a) }.join(', ')
|
171
345
|
|
172
346
|
"#{callee}(#{args})"
|
173
347
|
end
|
174
348
|
|
349
|
+
def translate_member_access(node)
|
350
|
+
object = expr(node.object, node)
|
351
|
+
name = translate(node.name)
|
352
|
+
|
353
|
+
"#{object}#{node.class.operator}#{name}"
|
354
|
+
end
|
355
|
+
|
356
|
+
def translate_prefix_operator(node)
|
357
|
+
operand = expr(node.operand, node)
|
358
|
+
"#{node.class.operator}#{operand}"
|
359
|
+
end
|
360
|
+
|
361
|
+
def translate_postfix_operator(node)
|
362
|
+
operand = expr(node.operand, node)
|
363
|
+
"#{operand}#{node.class.operator}"
|
364
|
+
end
|
365
|
+
|
366
|
+
def translate_type_cast(node)
|
367
|
+
operand = expr(node.operand, node)
|
368
|
+
"(#{translate node.type})#{operand}"
|
369
|
+
end
|
370
|
+
|
371
|
+
def translate_size_of(node)
|
372
|
+
operand = translate(node.operand)
|
373
|
+
"sizeof(#{operand})"
|
374
|
+
end
|
375
|
+
|
376
|
+
def translate_defined_operator(node)
|
377
|
+
operand = translate(node.operand)
|
378
|
+
"defined #{operand}"
|
379
|
+
end
|
380
|
+
|
381
|
+
def translate_binary_operator(node)
|
382
|
+
lhs = expr(node.lhs, node)
|
383
|
+
rhs = expr(node.rhs, node)
|
384
|
+
|
385
|
+
case node
|
386
|
+
when Operator::Comma
|
387
|
+
"#{lhs}#{node.class.operator} #{rhs}"
|
388
|
+
else
|
389
|
+
"#{lhs} #{node.class.operator} #{rhs}"
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
def translate_ternary_conditional(node)
|
394
|
+
condition_expr = expr(node.condition, node)
|
395
|
+
|
396
|
+
# Expression between `?` and `:` must be parenthesized.
|
397
|
+
then_expr = case node.then
|
398
|
+
when Operator::Binary, Operator::Conditional
|
399
|
+
"(#{translate(node.then)})"
|
400
|
+
else
|
401
|
+
expr(node.then, node)
|
402
|
+
end
|
403
|
+
else_expr = expr(node.else, node)
|
404
|
+
|
405
|
+
"#{condition_expr} ? #{then_expr} : #{else_expr}"
|
406
|
+
end
|
407
|
+
|
175
408
|
# = Statements
|
176
409
|
|
177
410
|
def translate_empty_stmt(node)
|
178
|
-
|
411
|
+
''
|
179
412
|
end
|
180
413
|
|
181
414
|
def translate_expr_stmt(node)
|
182
|
-
|
415
|
+
translate(node.expr)
|
416
|
+
end
|
417
|
+
|
418
|
+
def translate_if(node)
|
419
|
+
"if (#{translate node.condition}) #{translate node.then}".tap do |src|
|
420
|
+
src << " else #{translate node.else}" if node.else
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def translate_switch(node)
|
425
|
+
"switch (#{translate node.expr}) #{translate node.stmt}"
|
426
|
+
end
|
427
|
+
|
428
|
+
def translate_while(node)
|
429
|
+
"while (#{translate node.condition}) #{translate node.body}"
|
430
|
+
end
|
431
|
+
|
432
|
+
def translate_do_while(node)
|
433
|
+
"do #{translate node.body} while (#{translate node.condition})"
|
434
|
+
end
|
435
|
+
|
436
|
+
def translate_for(node)
|
437
|
+
init = node.init ? translate(node.init) : ''
|
438
|
+
cond = node.condition ? ' ' + translate(node.condition) : ''
|
439
|
+
loop_expr = node.loop ? ' ' + translate(node.loop) : ''
|
440
|
+
|
441
|
+
"for (#{init};#{cond};#{loop_expr}) #{translate node.body}"
|
442
|
+
end
|
443
|
+
|
444
|
+
def translate_break(node); 'break' end
|
445
|
+
def translate_continue(node); 'continue' end
|
446
|
+
|
447
|
+
def translate_goto(node)
|
448
|
+
"goto #{node.label}"
|
449
|
+
end
|
450
|
+
|
451
|
+
# We need labeled statement to indent differently.
|
452
|
+
def translate_case(node)
|
453
|
+
[
|
454
|
+
"case #{translate(node.expr)}",
|
455
|
+
translate(node.stmt),
|
456
|
+
]
|
457
|
+
end
|
458
|
+
|
459
|
+
def translate_labeled(node)
|
460
|
+
[
|
461
|
+
node.label.to_s,
|
462
|
+
translate(node.stmt),
|
463
|
+
]
|
183
464
|
end
|
184
465
|
|
185
466
|
def translate_return(node)
|
186
467
|
if node.expr
|
187
|
-
|
468
|
+
'return ' << translate(node.expr)
|
188
469
|
else
|
189
|
-
|
470
|
+
'return'
|
190
471
|
end
|
191
472
|
end
|
192
473
|
|
193
474
|
def translate_block(node)
|
194
|
-
|
195
|
-
|
196
|
-
|
475
|
+
translate_stmts_with_indent(node)
|
476
|
+
end
|
477
|
+
|
478
|
+
# = Declaration
|
479
|
+
def translate_declaration(node)
|
480
|
+
[
|
481
|
+
node.storage.to_s,
|
482
|
+
translate_typed_name(node.type, node.name),
|
483
|
+
]
|
484
|
+
.tap {|src|
|
485
|
+
unless node.init.nil?
|
486
|
+
src << '='
|
487
|
+
src << translate(node.init)
|
488
|
+
end
|
489
|
+
}
|
490
|
+
.join(' ')
|
491
|
+
.strip
|
492
|
+
end
|
493
|
+
|
494
|
+
def translate_designator(node)
|
495
|
+
case node
|
496
|
+
when IndexDesignator
|
497
|
+
"[#{node.index}]"
|
498
|
+
when MemberDesignator
|
499
|
+
".#{node.name}"
|
500
|
+
else
|
501
|
+
raise NotImplementedError, 'designator must be Index or Member'
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def translate_initializer(node)
|
506
|
+
if node.designator
|
507
|
+
[
|
508
|
+
translate_designator(node.designator),
|
509
|
+
'=',
|
510
|
+
translate(node.value),
|
511
|
+
]
|
512
|
+
.join(' ')
|
513
|
+
else
|
514
|
+
translate(node.value)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
def translate_initializer_list(node)
|
519
|
+
node
|
520
|
+
.map {|m| translate(m)}
|
521
|
+
.join(', ')
|
522
|
+
.insert( 0, '{ ')
|
523
|
+
.insert(-1, ' }')
|
524
|
+
end
|
197
525
|
|
198
|
-
|
526
|
+
def translate_bit_field(node)
|
527
|
+
if node.declaration
|
528
|
+
"#{translate node.declaration} : #{translate node.bits}"
|
529
|
+
else
|
530
|
+
": #{translate node.bits}"
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
# = Function
|
535
|
+
def translate_function(node)
|
536
|
+
params = node.params.map {|p| translate(p) }.join(', ')
|
537
|
+
|
538
|
+
[
|
539
|
+
node.storage.to_s,
|
540
|
+
translate(node.return_type),
|
541
|
+
"#{translate node.name}(#{params})",
|
542
|
+
translate(node.body),
|
543
|
+
]
|
544
|
+
.join(' ')
|
545
|
+
.strip
|
546
|
+
end
|
547
|
+
|
548
|
+
def translate_param(node)
|
549
|
+
ty = coerce_func_ptr(node.type)
|
550
|
+
translate_typed_name(ty, node.name)
|
551
|
+
end
|
552
|
+
|
553
|
+
# = Comment
|
554
|
+
def translate_comment_multi(node)
|
555
|
+
case node.lines.size
|
556
|
+
when 0
|
557
|
+
""
|
558
|
+
when 1
|
559
|
+
"/* #{node.lines[0]} */"
|
560
|
+
else
|
561
|
+
src =
|
562
|
+
node
|
563
|
+
.lines
|
564
|
+
.map {|line| "#{indent} * #{line}"}
|
565
|
+
.join("\n")
|
566
|
+
"/*\n#{src}\n#{indent} */"
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
def translate_comment_single(node)
|
571
|
+
"// #{node.body}"
|
199
572
|
end
|
200
573
|
|
201
574
|
# = Directives
|
@@ -207,27 +580,172 @@ module Chelsy
|
|
207
580
|
end
|
208
581
|
end
|
209
582
|
|
210
|
-
|
583
|
+
def translate_define(node)
|
584
|
+
"#define #{node.name}".tap do |src|
|
585
|
+
if node.params
|
586
|
+
src << '('
|
587
|
+
src << node.params.map(&:to_s).join(", ")
|
588
|
+
src << ')'
|
589
|
+
end
|
211
590
|
|
212
|
-
|
213
|
-
|
214
|
-
|
591
|
+
unless node.replacement.empty?
|
592
|
+
src << ' '
|
593
|
+
src << node.replacement.to_s
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
def translate_undef(node)
|
599
|
+
"#undef #{node.name}"
|
215
600
|
end
|
216
601
|
|
217
|
-
def
|
218
|
-
|
602
|
+
def translate_if_directive(node)
|
603
|
+
"#if #{translate node.condition}"
|
604
|
+
end
|
605
|
+
|
606
|
+
def translate_elif_directive(node)
|
607
|
+
"#elif #{translate node.condition}"
|
608
|
+
end
|
609
|
+
|
610
|
+
def translate_else_directive(node); "#else" end
|
611
|
+
|
612
|
+
def translate_endif_directive(node); "#endif" end
|
613
|
+
|
614
|
+
def translate_line_directive(node)
|
615
|
+
"#line #{node.lineno}".tap do |src|
|
616
|
+
src << " \"#{node.filename}\"" if node.filename
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
def translate_pragma_directive(node)
|
621
|
+
"#pragma #{node.pragma}"
|
219
622
|
end
|
220
623
|
|
221
624
|
private
|
222
625
|
|
223
|
-
def indent
|
224
|
-
|
626
|
+
def indent(indent_level=nil)
|
627
|
+
indent_level = @indent_level if indent_level.nil?
|
628
|
+
@indent_string * indent_level
|
225
629
|
end
|
226
630
|
|
227
|
-
#
|
228
|
-
def expr(node)
|
229
|
-
|
230
|
-
|
631
|
+
# Parenthesize if `node` has lower precedence than `parent` node.
|
632
|
+
def expr(node, parent)
|
633
|
+
expr = translate(node)
|
634
|
+
|
635
|
+
if node.is_a?(Operator::Base) && node.class.precedence < parent.class.precedence
|
636
|
+
"(#{expr})"
|
637
|
+
else
|
638
|
+
expr
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def translate_taggable_type_members(ty, name=nil)
|
643
|
+
[].tap do |buffer|
|
644
|
+
buffer << 'const ' if ty.const?
|
645
|
+
buffer << 'volatile ' if ty.volatile?
|
646
|
+
buffer << case ty
|
647
|
+
when Type::Struct; 'struct'
|
648
|
+
when Type::Union; 'union'
|
649
|
+
when Type::Enum; 'enum'
|
650
|
+
end
|
651
|
+
buffer << ty.tag if ty.tag
|
652
|
+
buffer << name if name
|
653
|
+
end
|
654
|
+
.join(' ')
|
655
|
+
.tap do |src|
|
656
|
+
if ty.members
|
657
|
+
src << ' ' << translate_taggable_members(ty.members)
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
def translate_taggable_members(members)
|
663
|
+
case members
|
664
|
+
when StructOrUnionMemberList
|
665
|
+
translate_stmts_with_indent(members)
|
666
|
+
when EnumMemberList
|
667
|
+
translate_enum_members(members)
|
668
|
+
else
|
669
|
+
raise "Unrecognized members: #{members.inspect}"
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
def translate_enum_members(members)
|
674
|
+
@indent_level += 1
|
675
|
+
|
676
|
+
lines = members.map do |item|
|
677
|
+
case item
|
678
|
+
when EnumMember
|
679
|
+
if item.init
|
680
|
+
"#{translate item.name} = #{translate item.init}"
|
681
|
+
else
|
682
|
+
"#{translate item.name}"
|
683
|
+
end
|
684
|
+
when Symbol
|
685
|
+
"#{translate item}"
|
686
|
+
else
|
687
|
+
raise "Unrecognized enum member: #{item.inspect}"
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
body = lines.map {|line| indent << line }.join(",\n")
|
692
|
+
@indent_level -= 1
|
693
|
+
|
694
|
+
"{\n#{body}\n#{indent}}"
|
695
|
+
end
|
696
|
+
|
697
|
+
def should_terminate_with_semicolon(node)
|
698
|
+
case node
|
699
|
+
when If
|
700
|
+
if node.else
|
701
|
+
should_terminate_with_semicolon(node.else)
|
702
|
+
else
|
703
|
+
should_terminate_with_semicolon(node.then)
|
704
|
+
end
|
705
|
+
when While, For
|
706
|
+
should_terminate_with_semicolon(node.body)
|
707
|
+
when Block
|
708
|
+
false
|
709
|
+
else
|
710
|
+
true
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
def translate_stmts_with_indent(node)
|
715
|
+
@indent_level += 1
|
716
|
+
|
717
|
+
lines = node.map do |item|
|
718
|
+
src = translate(item)
|
719
|
+
|
720
|
+
if Array === src && src.size == 2
|
721
|
+
(label, stmt) = *src
|
722
|
+
|
723
|
+
src = "#{indent(@indent_level-1)}#{label}:\n"
|
724
|
+
src << "#{indent}#{stmt}"
|
725
|
+
else
|
726
|
+
src.insert 0, indent
|
727
|
+
end
|
728
|
+
|
729
|
+
# terminate ';' if needed
|
730
|
+
src << ';' if should_terminate_with_semicolon(item)
|
731
|
+
src
|
732
|
+
end
|
733
|
+
|
734
|
+
@indent_level -= 1
|
735
|
+
|
736
|
+
body = lines.join("\n")
|
737
|
+
|
738
|
+
"{\n#{body}\n#{indent}}"
|
739
|
+
end
|
740
|
+
|
741
|
+
# In some situation, function type shall be pointer to function type
|
742
|
+
def coerce_func_ptr(node)
|
743
|
+
case node
|
744
|
+
when Type::Function
|
745
|
+
Type::Pointer.new(node)
|
746
|
+
else
|
747
|
+
node
|
748
|
+
end
|
231
749
|
end
|
232
750
|
|
233
751
|
def integer_prefix(node)
|
@@ -259,6 +777,7 @@ module Chelsy
|
|
259
777
|
suffix
|
260
778
|
end
|
261
779
|
end
|
780
|
+
|
262
781
|
end
|
263
782
|
|
264
783
|
end
|