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 match size {
181 FloatSize::Float => "float",
182 FloatSize::Double => "double",
183 FloatSize::LongDouble => "long double",
184 }
185}
186
187fn array_size(size: &ArraySize) -> String {
188 match size {
189 ArraySize::Unspecified => "?".to_owned(),
190 ArraySize::Star => "*".to_owned(),
191 ArraySize::Expr(e) => match &e.kind {
192 ExprKind::Int(lit) => lit.value.to_string(),
193 _ => "expr".to_owned(),
194 },
195 }
196}
197
198struct Dumper<'a> {
199 unit: &'a TranslationUnit,
201 out: String,
202 indent: usize,
203}
204
205impl<'a> Dumper<'a> {
206 fn new(unit: &'a TranslationUnit) -> Self {
207 Self {
208 unit,
209 out: String::new(),
210 indent: 0,
211 }
212 }
213
214 fn ty(&self, ty: &Type) -> String {
216 type_to_string(self.unit, ty)
217 }
218
219 fn line(&mut self, text: impl AsRef<str>) {
220 for _ in 0..self.indent {
221 self.out.push_str(" ");
222 }
223 self.out.push_str(text.as_ref());
224 self.out.push('\n');
225 }
226
227 fn under(&mut self, label: &str, f: impl FnOnce(&mut Self)) {
229 self.line(label);
230 self.indent += 1;
231 f(self);
232 self.indent -= 1;
233 }
234
235 fn external_decl(&mut self, item: &ExternalDecl) {
238 match item {
239 ExternalDecl::Function(f) => self.function_def(f),
240 ExternalDecl::Decl(d) => self.decl(d),
241 ExternalDecl::StaticAssert(sa) => self.static_assert(sa),
242 }
243 }
244
245 fn static_assert(&mut self, sa: &StaticAssert) {
246 let label = match &sa.message {
247 Some(message) => format!("static-assert {message}"),
248 None => "static-assert".to_owned(),
249 };
250 self.under(&label, |d| d.expr(&sa.cond));
251 }
252
253 fn function_def(&mut self, f: &FunctionDef) {
254 let mut header = format!("function '{}' : {}", f.name.name, self.ty(&f.ty));
255 if let Some(storage) = &f.specifiers.storage {
256 header.push_str(&format!(" [{}]", storage.node.as_str()));
257 }
258 if f.specifiers.inline {
259 header.push_str(" [inline]");
260 }
261 self.line(header);
262 self.indent += 1;
263 self.type_body(&f.specifiers.base);
264 for kr in &f.kr_decls {
265 self.under("kr-param-decl", |d| d.decl_inner(kr));
266 }
267 self.under("body", |d| {
268 for item in &f.body.items {
269 d.block_item(item);
270 }
271 });
272 self.indent -= 1;
273 }
274
275 fn decl(&mut self, decl: &Decl) {
276 self.line("declaration");
277 self.indent += 1;
278 self.decl_inner(decl);
279 self.indent -= 1;
280 }
281
282 fn decl_inner(&mut self, decl: &Decl) {
283 let mut header = format!("specifiers: {}", self.ty(&decl.specifiers.base));
284 if let Some(storage) = &decl.specifiers.storage {
285 header.push_str(&format!(" [{}]", storage.node.as_str()));
286 }
287 if decl.specifiers.inline {
288 header.push_str(" [inline]");
289 }
290 self.line(header);
291 self.type_body(&decl.specifiers.base);
292 for d in &decl.declarators {
293 let name = d.name.as_ref().map_or("<abstract>", |n| n.name.as_str());
294 self.line(format!("declarator '{}' : {}", name, self.ty(&d.ty)));
295 if let Some(init) = &d.init {
296 self.indent += 1;
297 self.under("init", |dd| dd.initializer(init));
298 self.indent -= 1;
299 }
300 }
301 }
302
303 fn type_body(&mut self, ty: &Type) {
306 match &ty.kind {
307 TypeKind::Record(id) => {
308 let r = self.unit.record(*id);
309 let Some(fields) = &r.fields else { return };
310 let label = format!(
311 "{} '{}' members",
312 r.kind.as_str(),
313 r.name.as_ref().map_or("<anonymous>", |n| n.name.as_str())
314 );
315 self.under(&label, |d| {
316 for f in fields {
317 let name = f.name.as_ref().map_or("<anonymous>", |n| n.name.as_str());
318 let mut line = format!("field '{}' : {}", name, d.ty(&f.ty));
319 if let Some(w) = &f.bit_width {
320 if let ExprKind::Int(lit) = &w.kind {
321 line.push_str(&format!(" : {}", lit.value));
322 } else {
323 line.push_str(" : <expr>");
324 }
325 }
326 d.line(line);
327 d.indent += 1;
328 d.type_body(&f.specifiers.base);
329 d.indent -= 1;
330 }
331 for assert in &r.asserts {
332 d.static_assert(assert);
333 }
334 });
335 }
336 TypeKind::Enum(id) => {
337 let e = self.unit.enum_spec(*id);
338 let Some(enumerators) = &e.enumerators else {
339 return;
340 };
341 let label = format!(
342 "enum '{}' enumerators",
343 e.name.as_ref().map_or("<anonymous>", |n| n.name.as_str())
344 );
345 self.under(&label, |d| {
346 for en in enumerators {
347 match &en.value {
348 Some(v) => {
349 d.under(&format!("enumerator '{}'", en.name.name), |dd| dd.expr(v))
350 }
351 None => d.line(format!("enumerator '{}'", en.name.name)),
352 }
353 }
354 });
355 }
356 _ => {}
357 }
358 }
359
360 fn initializer(&mut self, init: &Initializer) {
361 match &init.kind {
362 InitializerKind::Expr(e) => self.expr(e),
363 InitializerKind::List(items) => self.under("init-list", |d| {
364 for item in items {
365 let label = element_label(&item.designators);
366 d.under(&label, |dd| dd.initializer(&item.init));
367 }
368 }),
369 }
370 }
371
372 fn block_item(&mut self, item: &BlockItem) {
375 match item {
376 BlockItem::Decl(d) => self.decl(d),
377 BlockItem::Stmt(s) => self.stmt(s),
378 BlockItem::StaticAssert(sa) => self.static_assert(sa),
379 BlockItem::NestedFunction(f) => self.function_def(f),
380 }
381 }
382
383 fn stmt(&mut self, stmt: &Stmt) {
384 match &stmt.kind {
385 StmtKind::Labeled { label, body } => {
386 self.under(&format!("label '{}'", label.name), |d| d.stmt(body));
387 }
388 StmtKind::Case { value, upper, body } => self.under("case", |d| {
389 d.under("value", |dd| dd.expr(value));
390 if let Some(upper) = upper {
391 d.under("upto", |dd| dd.expr(upper));
392 }
393 d.stmt(body);
394 }),
395 StmtKind::Default { body } => self.under("default", |d| d.stmt(body)),
396 StmtKind::Compound(block) => self.under("block", |d| {
397 for item in &block.items {
398 d.block_item(item);
399 }
400 }),
401 StmtKind::Expr(None) => self.line("null-stmt"),
402 StmtKind::Expr(Some(e)) => self.under("expr-stmt", |d| d.expr(e)),
403 StmtKind::If {
404 cond,
405 then_branch,
406 else_branch,
407 } => self.under("if", |d| {
408 d.under("cond", |dd| dd.expr(cond));
409 d.under("then", |dd| dd.stmt(then_branch));
410 if let Some(e) = else_branch {
411 d.under("else", |dd| dd.stmt(e));
412 }
413 }),
414 StmtKind::Switch { cond, body } => self.under("switch", |d| {
415 d.under("cond", |dd| dd.expr(cond));
416 d.under("body", |dd| dd.stmt(body));
417 }),
418 StmtKind::While { cond, body } => self.under("while", |d| {
419 d.under("cond", |dd| dd.expr(cond));
420 d.under("body", |dd| dd.stmt(body));
421 }),
422 StmtKind::DoWhile { body, cond } => self.under("do-while", |d| {
423 d.under("body", |dd| dd.stmt(body));
424 d.under("cond", |dd| dd.expr(cond));
425 }),
426 StmtKind::For {
427 init,
428 cond,
429 step,
430 body,
431 } => self.under("for", |d| {
432 match init {
433 ForInit::None => d.line("init: <none>"),
434 ForInit::Expr(e) => d.under("init", |dd| dd.expr(e)),
435 ForInit::Decl(decl) => d.under("init", |dd| dd.decl(decl)),
436 ForInit::StaticAssert(sa) => d.under("init", |dd| dd.static_assert(sa)),
437 }
438 match cond {
439 Some(e) => d.under("cond", |dd| dd.expr(e)),
440 None => d.line("cond: <none>"),
441 }
442 match step {
443 Some(e) => d.under("step", |dd| dd.expr(e)),
444 None => d.line("step: <none>"),
445 }
446 d.under("body", |dd| dd.stmt(body));
447 }),
448 StmtKind::Goto(label) => self.line(format!("goto '{}'", label.name)),
449 StmtKind::GotoPtr(target) => self.under("goto-ptr", |d| d.expr(target)),
450 StmtKind::Continue => self.line("continue"),
451 StmtKind::Break => self.line("break"),
452 StmtKind::Return(None) => self.line("return"),
453 StmtKind::Return(Some(e)) => self.under("return", |d| d.expr(e)),
454 StmtKind::Error => self.line("<error-stmt>"),
455 }
456 }
457
458 fn expr(&mut self, expr: &Expr) {
461 match &expr.kind {
462 ExprKind::Ident(id) => self.line(format!("ident '{}'", id.name)),
463 ExprKind::Int(lit) => {
464 let mut s = format!("int {}", lit.value);
465 if lit.unsigned {
466 s.push_str(" unsigned");
467 }
468 match lit.long {
469 LongKind::None => {}
470 LongKind::Long => s.push_str(" long"),
471 LongKind::LongLong => s.push_str(" long-long"),
472 }
473 self.line(s);
474 }
475 ExprKind::Float(lit) => {
476 let mut s = format!("float {}", lit.value);
477 match lit.suffix {
478 FloatSuffix::None => {}
479 FloatSuffix::Float => s.push_str(" f"),
480 FloatSuffix::LongDouble => s.push_str(" l"),
481 }
482 self.line(s);
483 }
484 ExprKind::Char(lit) => {
485 self.line(format!(
486 "char {}{} = {}",
487 lit.kind.prefix(),
488 lit.text,
489 lit.value
490 ));
491 }
492 ExprKind::Str(lit) => {
493 self.line(format!(
494 "string {}{} ({} elements)",
495 lit.kind.prefix(),
496 lit.text,
497 lit.values.len()
498 ));
499 }
500 ExprKind::Unary { op, operand } => {
501 self.under(&format!("unary '{}'", op.as_str()), |d| d.expr(operand));
502 }
503 ExprKind::Binary { op, lhs, rhs } => {
504 self.under(&format!("binary '{}'", op.as_str()), |d| {
505 d.expr(lhs);
506 d.expr(rhs);
507 });
508 }
509 ExprKind::Assign { op, lhs, rhs } => {
510 let label = match op {
511 Some(op) => format!("assign '{}='", op.as_str()),
512 None => "assign '='".to_owned(),
513 };
514 self.under(&label, |d| {
515 d.expr(lhs);
516 d.expr(rhs);
517 });
518 }
519 ExprKind::Conditional {
520 cond,
521 then_expr,
522 else_expr,
523 } => self.under("conditional", |d| {
524 d.under("cond", |dd| dd.expr(cond));
525 if let Some(then_expr) = then_expr {
526 d.under("then", |dd| dd.expr(then_expr));
527 }
528 d.under("else", |dd| dd.expr(else_expr));
529 }),
530 ExprKind::Comma { lhs, rhs } => self.under("comma", |d| {
531 d.expr(lhs);
532 d.expr(rhs);
533 }),
534 ExprKind::Call { callee, args } => self.under("call", |d| {
535 d.under("callee", |dd| dd.expr(callee));
536 for arg in args {
537 d.under("arg", |dd| dd.expr(arg));
538 }
539 }),
540 ExprKind::Member { base, arrow, field } => {
541 let op = if *arrow { "->" } else { "." };
542 self.under(&format!("member '{}{}'", op, field.name), |d| d.expr(base));
543 }
544 ExprKind::Index { base, index } => self.under("index", |d| {
545 d.expr(base);
546 d.expr(index);
547 }),
548 ExprKind::PostIncDec { op, operand } => {
549 self.under(&format!("postfix '{}'", op.as_str()), |d| d.expr(operand));
550 }
551 ExprKind::PreIncDec { op, operand } => {
552 self.under(&format!("prefix '{}'", op.as_str()), |d| d.expr(operand));
553 }
554 ExprKind::Cast { ty, expr } => {
555 self.under(&format!("cast to {}", self.ty(&ty.ty)), |d| d.expr(expr));
556 }
557 ExprKind::LabelAddr(label) => self.line(format!("label-addr '{}'", label.name)),
558 ExprKind::SizeofExpr(inner) => self.under("sizeof-expr", |d| d.expr(inner)),
559 ExprKind::SizeofType(ty) => {
560 self.line(format!("sizeof-type {}", self.ty(&ty.ty)));
561 }
562 ExprKind::AlignofExpr(inner) => self.under("alignof-expr", |d| d.expr(inner)),
563 ExprKind::AlignofType(ty) => {
564 self.line(format!("alignof-type {}", self.ty(&ty.ty)));
565 }
566 ExprKind::Generic {
567 controlling,
568 assocs,
569 } => self.under("generic", |d| {
570 d.under("controlling", |dd| dd.expr(controlling));
571 for assoc in assocs {
572 let label = match &assoc.ty {
573 Some(ty) => format!("assoc {}", d.ty(&ty.ty)),
574 None => "assoc default".to_owned(),
575 };
576 d.under(&label, |dd| dd.expr(&assoc.value));
577 }
578 }),
579 ExprKind::Bool(value) => self.line(if *value { "true" } else { "false" }),
580 ExprKind::Nullptr => self.line("nullptr"),
581 ExprKind::VaArg { ap, ty } => {
582 self.under(&format!("va_arg {}", self.ty(&ty.ty)), |d| d.expr(ap));
583 }
584 ExprKind::OffsetOf { ty, member, path } => {
585 let rest = element_label(path);
586 let rest = rest.strip_prefix("element").unwrap_or(&rest);
587 self.line(format!(
588 "offsetof {} .{}{rest}",
589 self.ty(&ty.ty),
590 member.name
591 ));
592 }
593 ExprKind::CompoundLiteral { ty, init } => {
594 self.under(&format!("compound-literal {}", self.ty(&ty.ty)), |d| {
595 for item in init {
596 let label = element_label(&item.designators);
597 d.under(&label, |dd| dd.initializer(&item.init));
598 }
599 })
600 }
601 ExprKind::StmtExpr(block) => self.under("stmt-expr", |d| {
602 for item in &block.items {
603 d.block_item(item);
604 }
605 }),
606 ExprKind::TypesCompatible { lhs, rhs } => self.line(format!(
607 "types-compatible {} {}",
608 self.ty(&lhs.ty),
609 self.ty(&rhs.ty)
610 )),
611 ExprKind::ChooseExpr {
612 cond,
613 then_expr,
614 else_expr,
615 } => self.under("choose-expr", |d| {
616 d.under("cond", |dd| dd.expr(cond));
617 d.under("then", |dd| dd.expr(then_expr));
618 d.under("else", |dd| dd.expr(else_expr));
619 }),
620 ExprKind::ComplexPart { real, operand } => {
621 let name = if *real { "__real__" } else { "__imag__" };
622 self.under(name, |d| d.expr(operand));
623 }
624 ExprKind::Error => self.line("<error-expr>"),
625 }
626 }
627}
628
629fn element_label(designators: &[Designator]) -> String {
631 let mut label = String::from("element");
632 let index = |e: &Expr| match &e.kind {
633 ExprKind::Int(lit) => lit.value.to_string(),
634 _ => "expr".to_owned(),
635 };
636 for designator in designators {
637 match designator {
638 Designator::Field(f) => label.push_str(&format!(" .{}", f.name)),
639 Designator::Index(e) => label.push_str(&format!(" [{}]", index(e))),
640 Designator::Range(low, high) => {
641 label.push_str(&format!(" [{} ... {}]", index(low), index(high)));
642 }
643 }
644 }
645 label
646}