1use crate::ast::*;
8use crate::lex::{FloatSuffix, LongKind};
9
10pub fn dump_translation_unit(unit: &TranslationUnit) -> String {
12 let mut d = Dumper::new(unit);
13 d.line("translation-unit");
14 d.indent += 1;
15 for item in &unit.items {
16 d.external_decl(item);
17 }
18 d.out
19}
20
21pub fn dump_expr(unit: &TranslationUnit, expr: &Expr) -> String {
26 let mut d = Dumper::new(unit);
27 d.expr(expr);
28 d.out
29}
30
31pub fn type_to_string(unit: &TranslationUnit, ty: &Type) -> String {
33 let mut s = String::new();
34 if ty.qualifiers.is_const {
35 s.push_str("const ");
36 }
37 if ty.qualifiers.is_volatile {
38 s.push_str("volatile ");
39 }
40 if ty.qualifiers.is_restrict {
41 s.push_str("restrict ");
42 }
43 if ty.qualifiers.is_atomic {
44 s.push_str("_Atomic ");
45 }
46 match &ty.kind {
47 TypeKind::Void => s.push_str("void"),
48 TypeKind::Bool => s.push_str("_Bool"),
49 TypeKind::Char(None) => s.push_str("char"),
50 TypeKind::Char(Some(Sign::Signed)) => s.push_str("signed char"),
51 TypeKind::Char(Some(Sign::Unsigned)) => s.push_str("unsigned char"),
52 TypeKind::Int { sign, size } => {
53 if *sign == Sign::Unsigned {
54 s.push_str("unsigned ");
55 }
56 s.push_str(match size {
57 IntSize::Short => "short",
58 IntSize::Int => "int",
59 IntSize::Long => "long",
60 IntSize::LongLong => "long long",
61 IntSize::Int128 => "__int128",
62 });
63 }
64 TypeKind::Float(size) => s.push_str(float_size(*size)),
65 TypeKind::Complex(size) => {
66 s.push_str(float_size(*size));
67 s.push_str(" _Complex");
68 }
69 TypeKind::Imaginary(size) => {
70 s.push_str(float_size(*size));
71 s.push_str(" _Imaginary");
72 }
73 TypeKind::Pointer(inner) => {
74 s.push_str("ptr<");
75 s.push_str(&type_to_string(unit, inner));
76 s.push('>');
77 }
78 TypeKind::Array {
79 elem,
80 size,
81 qualifiers,
82 is_static,
83 } => {
84 s.push_str("array<");
85 s.push_str(&type_to_string(unit, elem));
86 s.push_str(", ");
87 s.push_str(&array_size(size));
88 if *is_static {
89 s.push_str(", static");
90 }
91 if qualifiers.any() {
92 s.push_str(", ");
93 if qualifiers.is_const {
94 s.push_str("const ");
95 }
96 if qualifiers.is_volatile {
97 s.push_str("volatile ");
98 }
99 if qualifiers.is_restrict {
100 s.push_str("restrict ");
101 }
102 s.pop();
103 }
104 s.push('>');
105 }
106 TypeKind::Function(ft) => {
107 s.push_str("fn(");
108 if !ft.has_prototype {
109 if ft.kr_names.is_empty() {
110 s.push_str("<unspecified>");
111 } else {
112 s.push_str("<K&R> ");
113 let names: Vec<&str> = ft.kr_names.iter().map(|n| n.name.as_str()).collect();
114 s.push_str(&names.join(", "));
115 }
116 } else if ft.params.is_empty() && !ft.variadic {
117 s.push_str("void");
118 } else {
119 let params: Vec<String> = ft
120 .params
121 .iter()
122 .map(|p| match &p.name {
123 Some(n) => format!("{}: {}", n.name, type_to_string(unit, &p.ty)),
124 None => type_to_string(unit, &p.ty),
125 })
126 .collect();
127 s.push_str(¶ms.join(", "));
128 if ft.variadic {
129 if !params.is_empty() {
130 s.push_str(", ");
131 }
132 s.push_str("...");
133 }
134 }
135 s.push_str(") -> ");
136 s.push_str(&type_to_string(unit, &ft.ret));
137 }
138 TypeKind::Record(id) => {
139 let r = unit.record(*id);
140 s.push_str(r.kind.as_str());
141 s.push(' ');
142 match &r.name {
143 Some(n) => s.push_str(&n.name),
144 None => s.push_str("<anonymous>"),
145 }
146 if r.fields.is_some() {
147 s.push_str(" {…}");
148 }
149 }
150 TypeKind::Enum(id) => {
151 let e = unit.enum_spec(*id);
152 s.push_str("enum ");
153 match &e.name {
154 Some(n) => s.push_str(&n.name),
155 None => s.push_str("<anonymous>"),
156 }
157 if e.enumerators.is_some() {
158 s.push_str(" {…}");
159 }
160 }
161 TypeKind::Typedef(id) => {
162 s.push_str("typedef-name ");
163 s.push_str(&id.name);
164 }
165 TypeKind::Typeof { id, unqual } => {
166 s.push_str(if *unqual { "typeof_unqual<" } else { "typeof<" });
167 match unit.typeof_operand(*id) {
168 TypeofOperand::Expr(_) => s.push_str("expr"),
169 TypeofOperand::Type(name) => s.push_str(&type_to_string(unit, &name.ty)),
170 }
171 s.push('>');
172 }
173 TypeKind::Auto => s.push_str("auto"),
174 TypeKind::Error => s.push_str("<error>"),
175 }
176 s
177}
178
179fn float_size(size: FloatSize) -> &'static str {
180 size.as_str()
181}
182
183fn array_size(size: &ArraySize) -> String {
184 match size {
185 ArraySize::Unspecified => "?".to_owned(),
186 ArraySize::Star => "*".to_owned(),
187 ArraySize::Expr(e) => match &e.kind {
188 ExprKind::Int(lit) => lit.value.to_string(),
189 _ => "expr".to_owned(),
190 },
191 }
192}
193
194struct Dumper<'a> {
195 unit: &'a TranslationUnit,
197 out: String,
198 indent: usize,
199}
200
201impl<'a> Dumper<'a> {
202 fn new(unit: &'a TranslationUnit) -> Self {
203 Self {
204 unit,
205 out: String::new(),
206 indent: 0,
207 }
208 }
209
210 fn ty(&self, ty: &Type) -> String {
212 type_to_string(self.unit, ty)
213 }
214
215 fn line(&mut self, text: impl AsRef<str>) {
216 for _ in 0..self.indent {
217 self.out.push_str(" ");
218 }
219 self.out.push_str(text.as_ref());
220 self.out.push('\n');
221 }
222
223 fn under(&mut self, label: &str, f: impl FnOnce(&mut Self)) {
225 self.line(label);
226 self.indent += 1;
227 f(self);
228 self.indent -= 1;
229 }
230
231 fn external_decl(&mut self, item: &ExternalDecl) {
234 match item {
235 ExternalDecl::Function(f) => self.function_def(f),
236 ExternalDecl::Decl(d) => self.decl(d),
237 ExternalDecl::StaticAssert(sa) => self.static_assert(sa),
238 }
239 }
240
241 fn static_assert(&mut self, sa: &StaticAssert) {
242 let label = match &sa.message {
243 Some(message) => format!("static-assert {message}"),
244 None => "static-assert".to_owned(),
245 };
246 self.under(&label, |d| d.expr(&sa.cond));
247 }
248
249 fn function_def(&mut self, f: &FunctionDef) {
250 let mut header = format!("function '{}' : {}", f.name.name, self.ty(&f.ty));
251 if let Some(storage) = &f.specifiers.storage {
252 header.push_str(&format!(" [{}]", storage.node.as_str()));
253 }
254 if f.specifiers.inline {
255 header.push_str(" [inline]");
256 }
257 self.line(header);
258 self.indent += 1;
259 self.type_body(&f.specifiers.base);
260 for kr in &f.kr_decls {
261 self.under("kr-param-decl", |d| d.decl_inner(kr));
262 }
263 self.under("body", |d| {
264 for item in &f.body.items {
265 d.block_item(item);
266 }
267 });
268 self.indent -= 1;
269 }
270
271 fn decl(&mut self, decl: &Decl) {
272 self.line("declaration");
273 self.indent += 1;
274 self.decl_inner(decl);
275 self.indent -= 1;
276 }
277
278 fn decl_inner(&mut self, decl: &Decl) {
279 let mut header = format!("specifiers: {}", self.ty(&decl.specifiers.base));
280 if let Some(storage) = &decl.specifiers.storage {
281 header.push_str(&format!(" [{}]", storage.node.as_str()));
282 }
283 if decl.specifiers.inline {
284 header.push_str(" [inline]");
285 }
286 self.line(header);
287 self.type_body(&decl.specifiers.base);
288 for d in &decl.declarators {
289 let name = d.name.as_ref().map_or("<abstract>", |n| n.name.as_str());
290 self.line(format!("declarator '{}' : {}", name, self.ty(&d.ty)));
291 if let Some(init) = &d.init {
292 self.indent += 1;
293 self.under("init", |dd| dd.initializer(init));
294 self.indent -= 1;
295 }
296 }
297 }
298
299 fn type_body(&mut self, ty: &Type) {
302 match &ty.kind {
303 TypeKind::Record(id) => {
304 let r = self.unit.record(*id);
305 let Some(fields) = &r.fields else { return };
306 let label = format!(
307 "{} '{}' members",
308 r.kind.as_str(),
309 r.name.as_ref().map_or("<anonymous>", |n| n.name.as_str())
310 );
311 self.under(&label, |d| {
312 for f in fields {
313 let name = f.name.as_ref().map_or("<anonymous>", |n| n.name.as_str());
314 let mut line = format!("field '{}' : {}", name, d.ty(&f.ty));
315 if let Some(w) = &f.bit_width {
316 if let ExprKind::Int(lit) = &w.kind {
317 line.push_str(&format!(" : {}", lit.value));
318 } else {
319 line.push_str(" : <expr>");
320 }
321 }
322 d.line(line);
323 d.indent += 1;
324 d.type_body(&f.specifiers.base);
325 d.indent -= 1;
326 }
327 for assert in &r.asserts {
328 d.static_assert(assert);
329 }
330 });
331 }
332 TypeKind::Enum(id) => {
333 let e = self.unit.enum_spec(*id);
334 let Some(enumerators) = &e.enumerators else {
335 return;
336 };
337 let label = format!(
338 "enum '{}' enumerators",
339 e.name.as_ref().map_or("<anonymous>", |n| n.name.as_str())
340 );
341 self.under(&label, |d| {
342 for en in enumerators {
343 match &en.value {
344 Some(v) => {
345 d.under(&format!("enumerator '{}'", en.name.name), |dd| dd.expr(v))
346 }
347 None => d.line(format!("enumerator '{}'", en.name.name)),
348 }
349 }
350 });
351 }
352 _ => {}
353 }
354 }
355
356 fn initializer(&mut self, init: &Initializer) {
357 match &init.kind {
358 InitializerKind::Expr(e) => self.expr(e),
359 InitializerKind::List(items) => self.under("init-list", |d| {
360 for item in items {
361 let label = element_label(&item.designators);
362 d.under(&label, |dd| dd.initializer(&item.init));
363 }
364 }),
365 }
366 }
367
368 fn block_item(&mut self, item: &BlockItem) {
371 match item {
372 BlockItem::Decl(d) => self.decl(d),
373 BlockItem::Stmt(s) => self.stmt(s),
374 BlockItem::StaticAssert(sa) => self.static_assert(sa),
375 BlockItem::NestedFunction(f) => self.function_def(f),
376 }
377 }
378
379 fn stmt(&mut self, stmt: &Stmt) {
380 match &stmt.kind {
381 StmtKind::Labeled { label, body } => {
382 self.under(&format!("label '{}'", label.name), |d| d.stmt(body));
383 }
384 StmtKind::Case { value, upper, body } => self.under("case", |d| {
385 d.under("value", |dd| dd.expr(value));
386 if let Some(upper) = upper {
387 d.under("upto", |dd| dd.expr(upper));
388 }
389 d.stmt(body);
390 }),
391 StmtKind::Default { body } => self.under("default", |d| d.stmt(body)),
392 StmtKind::Compound(block) => self.under("block", |d| {
393 for item in &block.items {
394 d.block_item(item);
395 }
396 }),
397 StmtKind::Expr(None) => self.line("null-stmt"),
398 StmtKind::Expr(Some(e)) => self.under("expr-stmt", |d| d.expr(e)),
399 StmtKind::If {
400 cond,
401 then_branch,
402 else_branch,
403 } => self.under("if", |d| {
404 d.under("cond", |dd| dd.expr(cond));
405 d.under("then", |dd| dd.stmt(then_branch));
406 if let Some(e) = else_branch {
407 d.under("else", |dd| dd.stmt(e));
408 }
409 }),
410 StmtKind::Switch { cond, body } => self.under("switch", |d| {
411 d.under("cond", |dd| dd.expr(cond));
412 d.under("body", |dd| dd.stmt(body));
413 }),
414 StmtKind::While { cond, body } => self.under("while", |d| {
415 d.under("cond", |dd| dd.expr(cond));
416 d.under("body", |dd| dd.stmt(body));
417 }),
418 StmtKind::DoWhile { body, cond } => self.under("do-while", |d| {
419 d.under("body", |dd| dd.stmt(body));
420 d.under("cond", |dd| dd.expr(cond));
421 }),
422 StmtKind::For {
423 init,
424 cond,
425 step,
426 body,
427 } => self.under("for", |d| {
428 match init {
429 ForInit::None => d.line("init: <none>"),
430 ForInit::Expr(e) => d.under("init", |dd| dd.expr(e)),
431 ForInit::Decl(decl) => d.under("init", |dd| dd.decl(decl)),
432 ForInit::StaticAssert(sa) => d.under("init", |dd| dd.static_assert(sa)),
433 }
434 match cond {
435 Some(e) => d.under("cond", |dd| dd.expr(e)),
436 None => d.line("cond: <none>"),
437 }
438 match step {
439 Some(e) => d.under("step", |dd| dd.expr(e)),
440 None => d.line("step: <none>"),
441 }
442 d.under("body", |dd| dd.stmt(body));
443 }),
444 StmtKind::Goto(label) => self.line(format!("goto '{}'", label.name)),
445 StmtKind::GotoPtr(target) => self.under("goto-ptr", |d| d.expr(target)),
446 StmtKind::Continue => self.line("continue"),
447 StmtKind::Break => self.line("break"),
448 StmtKind::Return(None) => self.line("return"),
449 StmtKind::Return(Some(e)) => self.under("return", |d| d.expr(e)),
450 StmtKind::Asm(asm) => self.asm(asm),
451 StmtKind::Error => self.line("<error-stmt>"),
452 }
453 }
454
455 fn asm(&mut self, asm: &AsmStmt) {
456 let mut head = String::from(if asm.extended { "asm" } else { "asm basic" });
457 for (flag, name) in [
458 (asm.volatile, "volatile"),
459 (asm.inline, "inline"),
460 (asm.goto, "goto"),
461 ] {
462 if flag {
463 head.push(' ');
464 head.push_str(name);
465 }
466 }
467 self.under(&head, |d| {
468 d.line(format!("template {:?}", asm.template.node));
469 for (what, operands) in [("output", &asm.outputs), ("input", &asm.inputs)] {
470 for operand in operands {
471 let mut line = format!("{what} {:?}", operand.constraint.node);
472 if let Some(name) = &operand.name {
473 line.push_str(&format!(" [{}]", name.name));
474 }
475 d.under(&line, |dd| dd.expr(&operand.expr));
476 }
477 }
478 for clobber in &asm.clobbers {
479 d.line(format!("clobber {:?}", clobber.node));
480 }
481 for label in &asm.labels {
482 d.line(format!("label '{}'", label.name));
483 }
484 });
485 }
486
487 fn expr(&mut self, expr: &Expr) {
490 match &expr.kind {
491 ExprKind::Ident(id) => self.line(format!("ident '{}'", id.name)),
492 ExprKind::Int(lit) => {
493 let mut s = format!("int {}", lit.value);
494 if lit.unsigned {
495 s.push_str(" unsigned");
496 }
497 match lit.long {
498 LongKind::None => {}
499 LongKind::Long => s.push_str(" long"),
500 LongKind::LongLong => s.push_str(" long-long"),
501 }
502 self.line(s);
503 }
504 ExprKind::Float(lit) => {
505 let mut s = format!("float {}", lit.value);
506 match lit.suffix {
507 FloatSuffix::None => {}
508 FloatSuffix::Float => s.push_str(" f"),
509 FloatSuffix::LongDouble => s.push_str(" l"),
510 }
511 self.line(s);
512 }
513 ExprKind::Char(lit) => {
514 self.line(format!(
515 "char {}{} = {}",
516 lit.kind.prefix(),
517 lit.text,
518 lit.value
519 ));
520 }
521 ExprKind::Str(lit) => {
522 self.line(format!(
523 "string {}{} ({} elements)",
524 lit.kind.prefix(),
525 lit.text,
526 lit.values.len()
527 ));
528 }
529 ExprKind::Unary { op, operand } => {
530 self.under(&format!("unary '{}'", op.as_str()), |d| d.expr(operand));
531 }
532 ExprKind::Binary { op, lhs, rhs } => {
533 self.under(&format!("binary '{}'", op.as_str()), |d| {
534 d.expr(lhs);
535 d.expr(rhs);
536 });
537 }
538 ExprKind::Assign { op, lhs, rhs } => {
539 let label = match op {
540 Some(op) => format!("assign '{}='", op.as_str()),
541 None => "assign '='".to_owned(),
542 };
543 self.under(&label, |d| {
544 d.expr(lhs);
545 d.expr(rhs);
546 });
547 }
548 ExprKind::Conditional {
549 cond,
550 then_expr,
551 else_expr,
552 } => self.under("conditional", |d| {
553 d.under("cond", |dd| dd.expr(cond));
554 if let Some(then_expr) = then_expr {
555 d.under("then", |dd| dd.expr(then_expr));
556 }
557 d.under("else", |dd| dd.expr(else_expr));
558 }),
559 ExprKind::Comma { lhs, rhs } => self.under("comma", |d| {
560 d.expr(lhs);
561 d.expr(rhs);
562 }),
563 ExprKind::Call { callee, args } => self.under("call", |d| {
564 d.under("callee", |dd| dd.expr(callee));
565 for arg in args {
566 d.under("arg", |dd| dd.expr(arg));
567 }
568 }),
569 ExprKind::Member { base, arrow, field } => {
570 let op = if *arrow { "->" } else { "." };
571 self.under(&format!("member '{}{}'", op, field.name), |d| d.expr(base));
572 }
573 ExprKind::Index { base, index } => self.under("index", |d| {
574 d.expr(base);
575 d.expr(index);
576 }),
577 ExprKind::PostIncDec { op, operand } => {
578 self.under(&format!("postfix '{}'", op.as_str()), |d| d.expr(operand));
579 }
580 ExprKind::PreIncDec { op, operand } => {
581 self.under(&format!("prefix '{}'", op.as_str()), |d| d.expr(operand));
582 }
583 ExprKind::Cast { ty, expr } => {
584 self.under(&format!("cast to {}", self.ty(&ty.ty)), |d| d.expr(expr));
585 }
586 ExprKind::LabelAddr(label) => self.line(format!("label-addr '{}'", label.name)),
587 ExprKind::SizeofExpr(inner) => self.under("sizeof-expr", |d| d.expr(inner)),
588 ExprKind::SizeofType(ty) => {
589 self.line(format!("sizeof-type {}", self.ty(&ty.ty)));
590 }
591 ExprKind::AlignofExpr(inner) => self.under("alignof-expr", |d| d.expr(inner)),
592 ExprKind::AlignofType(ty) => {
593 self.line(format!("alignof-type {}", self.ty(&ty.ty)));
594 }
595 ExprKind::Generic {
596 controlling,
597 assocs,
598 } => self.under("generic", |d| {
599 d.under("controlling", |dd| dd.expr(controlling));
600 for assoc in assocs {
601 let label = match &assoc.ty {
602 Some(ty) => format!("assoc {}", d.ty(&ty.ty)),
603 None => "assoc default".to_owned(),
604 };
605 d.under(&label, |dd| dd.expr(&assoc.value));
606 }
607 }),
608 ExprKind::Bool(value) => self.line(if *value { "true" } else { "false" }),
609 ExprKind::Nullptr => self.line("nullptr"),
610 ExprKind::VaArg { ap, ty } => {
611 self.under(&format!("va_arg {}", self.ty(&ty.ty)), |d| d.expr(ap));
612 }
613 ExprKind::OffsetOf { ty, member, path } => {
614 let rest = element_label(path);
615 let rest = rest.strip_prefix("element").unwrap_or(&rest);
616 self.line(format!(
617 "offsetof {} .{}{rest}",
618 self.ty(&ty.ty),
619 member.name
620 ));
621 }
622 ExprKind::CompoundLiteral { ty, init } => {
623 self.under(&format!("compound-literal {}", self.ty(&ty.ty)), |d| {
624 for item in init {
625 let label = element_label(&item.designators);
626 d.under(&label, |dd| dd.initializer(&item.init));
627 }
628 })
629 }
630 ExprKind::StmtExpr(block) => self.under("stmt-expr", |d| {
631 for item in &block.items {
632 d.block_item(item);
633 }
634 }),
635 ExprKind::TypesCompatible { lhs, rhs } => self.line(format!(
636 "types-compatible {} {}",
637 self.ty(&lhs.ty),
638 self.ty(&rhs.ty)
639 )),
640 ExprKind::ChooseExpr {
641 cond,
642 then_expr,
643 else_expr,
644 } => self.under("choose-expr", |d| {
645 d.under("cond", |dd| dd.expr(cond));
646 d.under("then", |dd| dd.expr(then_expr));
647 d.under("else", |dd| dd.expr(else_expr));
648 }),
649 ExprKind::ComplexPart { real, operand } => {
650 let name = if *real { "__real__" } else { "__imag__" };
651 self.under(name, |d| d.expr(operand));
652 }
653 ExprKind::Error => self.line("<error-expr>"),
654 }
655 }
656}
657
658fn element_label(designators: &[Designator]) -> String {
660 let mut label = String::from("element");
661 let index = |e: &Expr| match &e.kind {
662 ExprKind::Int(lit) => lit.value.to_string(),
663 _ => "expr".to_owned(),
664 };
665 for designator in designators {
666 match designator {
667 Designator::Field(f) => label.push_str(&format!(" .{}", f.name)),
668 Designator::Index(e) => label.push_str(&format!(" [{}]", index(e))),
669 Designator::Range(low, high) => {
670 label.push_str(&format!(" [{} ... {}]", index(low), index(high)));
671 }
672 }
673 }
674 label
675}