1use crate::*;
7
8pub fn dump(file: &File) -> String {
10 let mut out = String::new();
11 render(&file_tree(file), 0, &mut out);
12 out
13}
14
15const WIDTH: usize = 100;
16
17struct Tree {
18 head: String,
19 kids: Vec<Tree>,
20}
21
22fn leaf(head: impl Into<String>) -> Tree {
23 Tree {
24 head: head.into(),
25 kids: Vec::new(),
26 }
27}
28
29fn node(head: impl Into<String>, kids: Vec<Tree>) -> Tree {
30 Tree {
31 head: head.into(),
32 kids,
33 }
34}
35
36fn group(head: &str, empty: &str, kids: Vec<Tree>) -> Tree {
38 if kids.is_empty() {
39 leaf(empty)
40 } else {
41 node(head, kids)
42 }
43}
44
45fn flat(tree: &Tree, out: &mut String) {
46 if tree.kids.is_empty() {
47 out.push_str(&tree.head);
48 return;
49 }
50 out.push('(');
51 out.push_str(&tree.head);
52 for kid in &tree.kids {
53 out.push(' ');
54 flat(kid, out);
55 }
56 out.push(')');
57}
58
59fn render(tree: &Tree, indent: usize, out: &mut String) {
60 let mut line = String::new();
61 flat(tree, &mut line);
62 out.push_str(&" ".repeat(indent));
63 if tree.kids.is_empty() || indent + line.len() <= WIDTH {
64 out.push_str(&line);
65 out.push('\n');
66 return;
67 }
68 out.push_str(&tree.head);
69 out.push('\n');
70 for kid in &tree.kids {
71 render(kid, indent + 2, out);
72 }
73}
74
75fn path(p: &Path) -> String {
76 p.segments
77 .iter()
78 .map(|s| s.name.as_str())
79 .collect::<Vec<_>>()
80 .join(".")
81}
82
83fn docs(list: &[Doc], kids: &mut Vec<Tree>) {
84 for doc in list {
85 let kind = if doc.inner { "doc!" } else { "doc" };
86 kids.push(leaf(format!("{kind} {:?}", doc.text)));
87 }
88}
89
90fn flag(on: bool, name: &str, kids: &mut Vec<Tree>) {
91 if on {
92 kids.push(leaf(name));
93 }
94}
95
96fn file_tree(file: &File) -> Tree {
97 let mut kids = Vec::new();
98 docs(&file.docs, &mut kids);
99 match &file.module {
100 Some(p) => kids.push(leaf(format!("module {}", path(p)))),
101 None => kids.push(leaf("module <missing>")),
102 }
103 for section in &file.sections {
104 let items = section.items.iter().map(item).collect();
105 kids.push(node(format!("section {}", section.kind.name()), items));
106 }
107 node("file", kids)
108}
109
110fn generics(list: &[GenericParam], kids: &mut Vec<Tree>) {
111 if list.is_empty() {
112 return;
113 }
114 let params = list
115 .iter()
116 .map(|g| {
117 if g.bounds.is_empty() {
118 leaf(g.name.name.clone())
119 } else {
120 node(g.name.name.clone(), g.bounds.iter().map(ty).collect())
121 }
122 })
123 .collect();
124 kids.push(node("generics", params));
125}
126
127fn item(item: &Item) -> Tree {
128 let mut kids = Vec::new();
129 docs(&item.docs, &mut kids);
130 let head = match &item.kind {
131 ItemKind::Import(import) => {
132 flag(import.public, "pub", &mut kids);
133 kids.push(leaf(path(&import.path)));
134 if let Some(alias) = &import.alias {
135 kids.push(leaf(format!("as {}", alias.name)));
136 }
137 if let Some(names) = &import.names {
138 let group = names
139 .iter()
140 .map(|n| match &n.alias {
141 Some(alias) => leaf(format!("{} as {}", n.name.name, alias.name)),
142 None => leaf(n.name.name.clone()),
143 })
144 .collect();
145 kids.push(node("names", group));
146 }
147 "import".to_string()
148 }
149 ItemKind::ExternTarget(target) => {
150 for decl in &target.decls {
151 let mut d = Vec::new();
152 docs(&decl.docs, &mut d);
153 flag(decl.public, "pub", &mut d);
154 let head = match &decl.kind {
155 ExternDeclKind::Fn(s) => {
156 sig(s, &mut d);
157 "fn"
158 }
159 ExternDeclKind::Type(name) => {
160 d.push(leaf(name.name.clone()));
161 "type"
162 }
163 ExternDeclKind::Struct(name) => {
164 d.push(leaf(name.name.clone()));
165 "struct"
166 }
167 };
168 d.push(leaf(format!("from {:?}", decl.from.value)));
169 kids.push(node(head, d));
170 }
171 format!("extern {}", target.target.name)
172 }
173 ItemKind::Config(entry) => {
174 flag(entry.public, "pub", &mut kids);
175 kids.push(leaf(entry.name.name.clone()));
176 kids.push(ty(&entry.ty));
177 kids.push(expr(&entry.value));
178 "const".to_string()
179 }
180 ItemKind::Struct(decl) => {
181 flag(decl.public, "pub", &mut kids);
182 kids.push(leaf(decl.name.name.clone()));
183 generics(&decl.generics, &mut kids);
184 kids.extend(decl.fields.iter().map(field));
185 "struct".to_string()
186 }
187 ItemKind::Enum(decl) => {
188 flag(decl.public, "pub", &mut kids);
189 kids.push(leaf(decl.name.name.clone()));
190 generics(&decl.generics, &mut kids);
191 for v in &decl.variants {
192 let mut vk = Vec::new();
193 docs(&v.docs, &mut vk);
194 vk.push(leaf(v.name.name.clone()));
195 match &v.payload {
196 VariantPayload::None => {}
197 VariantPayload::Tuple(types) => {
198 vk.push(node("tuple", types.iter().map(ty).collect()))
199 }
200 VariantPayload::Struct(fields) => {
201 vk.push(node("fields", fields.iter().map(field).collect()))
202 }
203 }
204 kids.push(node("variant", vk));
205 }
206 "enum".to_string()
207 }
208 ItemKind::Alias(decl) => {
209 flag(decl.public, "pub", &mut kids);
210 kids.push(leaf(decl.name.name.clone()));
211 generics(&decl.generics, &mut kids);
212 kids.push(ty(&decl.ty));
213 "alias".to_string()
214 }
215 ItemKind::IntrinsicType(decl) => {
216 flag(decl.public, "pub", &mut kids);
217 kids.push(leaf(decl.name.name.clone()));
218 generics(&decl.generics, &mut kids);
219 "intrinsic type".to_string()
220 }
221 ItemKind::Interface(decl) => {
222 flag(decl.public, "pub", &mut kids);
223 kids.push(leaf(decl.name.name.clone()));
224 generics(&decl.generics, &mut kids);
225 if !decl.supers.is_empty() {
226 kids.push(node(":", decl.supers.iter().map(ty).collect()));
227 }
228 for m in &decl.methods {
229 let mut mk = Vec::new();
230 docs(&m.docs, &mut mk);
231 flag(m.decl.overrides.is_some(), "override", &mut mk);
232 sig(&m.decl.sig, &mut mk);
233 match &m.decl.body {
234 Some(body) => {
235 mk.push(block(body));
236 kids.push(node("default", mk));
237 }
238 None => kids.push(node("sig", mk)),
239 }
240 }
241 "interface".to_string()
242 }
243 ItemKind::Impl(block) => {
244 kids.push(leaf(block.type_name.name.clone()));
245 generics(&block.generics, &mut kids);
246 if let Some(interface) = &block.interface {
247 kids.push(node("for", vec![ty(interface)]));
248 }
249 for m in &block.methods {
250 let mut mk = Vec::new();
251 docs(&m.docs, &mut mk);
252 fn_decl(&m.decl, &mut mk);
253 kids.push(node("fn", mk));
254 }
255 "impl".to_string()
256 }
257 ItemKind::Fn(decl) => {
258 fn_decl(decl, &mut kids);
259 "fn".to_string()
260 }
261 ItemKind::Test(test) => {
262 kids.push(leaf(format!("{:?}", test.name.value)));
263 kids.push(block(&test.body));
264 "test".to_string()
265 }
266 };
267 node(head, kids)
268}
269
270fn field(f: &Field) -> Tree {
271 let mut kids = Vec::new();
272 docs(&f.docs, &mut kids);
273 flag(f.public, "pub", &mut kids);
274 kids.push(leaf(f.name.name.clone()));
275 kids.push(ty(&f.ty));
276 node("field", kids)
277}
278
279fn fn_decl(decl: &FnDecl, kids: &mut Vec<Tree>) {
280 flag(decl.public, "pub", kids);
281 flag(decl.intrinsic, "intrinsic", kids);
282 flag(decl.overrides.is_some(), "override", kids);
283 sig(&decl.sig, kids);
284 if let Some(body) = &decl.body {
285 kids.push(block(body));
286 }
287}
288
289fn mode(m: Mode) -> &'static str {
290 match m {
291 Mode::Read => "",
292 Mode::Mut => "mut ",
293 Mode::Own => "own ",
294 }
295}
296
297fn sig(s: &FnSig, kids: &mut Vec<Tree>) {
298 kids.push(leaf(s.name.name.clone()));
299 generics(&s.generics, kids);
300 let params = s
301 .params
302 .iter()
303 .map(|p| match &p.kind {
304 ParamKind::SelfParam => leaf(format!("{}self", mode(p.mode))),
305 ParamKind::Named { name, ty: t } => {
306 node(format!("{}{}", mode(p.mode), name.name), vec![ty(t)])
307 }
308 })
309 .collect();
310 kids.push(group("params", "()", params));
311 if let Some(ret) = &s.ret {
312 kids.push(node("->", vec![ty(ret)]));
313 }
314}
315
316fn ty(t: &Ty) -> Tree {
317 match &t.kind {
318 TyKind::Path { path: p, args } => {
319 if args.is_empty() {
320 leaf(path(p))
321 } else {
322 node(path(p), args.iter().map(ty).collect())
323 }
324 }
325 TyKind::Fn { params, ret } => {
326 let mut kids: Vec<Tree> = params
327 .iter()
328 .map(|(m, t)| {
329 if *m == Mode::Read {
330 ty(t)
331 } else {
332 node(mode(*m).trim(), vec![ty(t)])
333 }
334 })
335 .collect();
336 if let Some(ret) = ret {
337 kids.push(node("->", vec![ty(ret)]));
338 }
339 node("fn", kids)
340 }
341 TyKind::SelfType => leaf("Self"),
342 TyKind::Error => leaf("<error>"),
343 }
344}
345
346fn block(b: &Block) -> Tree {
347 group("block", "{}", b.stmts.iter().map(stmt).collect())
348}
349
350fn stmt(s: &Stmt) -> Tree {
351 match &s.kind {
352 StmtKind::Let {
353 mutable,
354 name,
355 ty: t,
356 value,
357 } => {
358 let mut kids = vec![leaf(name.as_ref().map_or("_", |n| n.name.as_str()))];
359 if let Some(t) = t {
360 kids.push(ty(t));
361 }
362 kids.push(expr(value));
363 node(if *mutable { "var" } else { "let" }, kids)
364 }
365 StmtKind::LetPattern {
366 mutable,
367 pattern,
368 value,
369 } => node(
370 if *mutable { "var" } else { "let" },
371 vec![pat(pattern), expr(value)],
372 ),
373 StmtKind::Assign { target, op, value } => {
374 node(assign_symbol(*op), vec![expr(target), expr(value)])
375 }
376 StmtKind::While { label, cond, body } => {
377 labelled(label, node("while", vec![expr(cond), block(body)]))
378 }
379 StmtKind::WhileLet { label, items, body } => {
380 let mut kids = cond_items(items);
381 kids.push(block(body));
382 labelled(label, node("while let", kids))
383 }
384 StmtKind::For {
385 label,
386 var,
387 iter,
388 body,
389 } => {
390 let iter = match iter {
391 ForIter::Collection { mode: m, expr: e } => {
392 if *m == Mode::Read {
393 expr(e)
394 } else {
395 node(mode(*m).trim(), vec![expr(e)])
396 }
397 }
398 ForIter::Range {
399 start,
400 end,
401 inclusive,
402 } => node(
403 if *inclusive { "..=" } else { ".." },
404 vec![expr(start), expr(end)],
405 ),
406 };
407 labelled(
408 label,
409 node("for", vec![leaf(var.name.clone()), iter, block(body)]),
410 )
411 }
412 StmtKind::Expr(e) => expr(e),
413 }
414}
415
416fn labelled(label: &Option<Ident>, t: Tree) -> Tree {
418 match label {
419 Some(l) => node(format!("{}:", l.name), vec![t]),
420 None => t,
421 }
422}
423
424fn cond_items(items: &[CondItem]) -> Vec<Tree> {
427 if let [
428 CondItem::Let {
429 pattern,
430 mode,
431 value,
432 },
433 ] = items
434 {
435 return vec![pat(pattern), moded(*mode, expr(value))];
436 }
437 items
438 .iter()
439 .map(|item| match item {
440 CondItem::Let {
441 pattern,
442 mode,
443 value,
444 } => node("let", vec![pat(pattern), moded(*mode, expr(value))]),
445 CondItem::Bool(e) => expr(e),
446 })
447 .collect()
448}
449
450fn moded(m: Mode, t: Tree) -> Tree {
452 if m == Mode::Read {
453 t
454 } else {
455 node(mode(m).trim(), vec![t])
456 }
457}
458
459fn assign_symbol(op: AssignOp) -> &'static str {
460 match op {
461 AssignOp::Assign => "=",
462 AssignOp::Add => "+=",
463 AssignOp::Sub => "-=",
464 AssignOp::Mul => "*=",
465 AssignOp::Div => "/=",
466 AssignOp::Rem => "%=",
467 AssignOp::BitAnd => "&=",
468 AssignOp::BitOr => "|=",
469 AssignOp::BitXor => "^=",
470 AssignOp::Shl => "<<=",
471 AssignOp::Shr => ">>=",
472 }
473}
474
475fn expr(e: &Expr) -> Tree {
476 match &e.kind {
477 ExprKind::Int(v) => leaf(v.to_string()),
478 ExprKind::Float(v) => leaf(format!("{v:?}")),
479 ExprKind::Str(v) => leaf(format!("{v:?}")),
480 ExprKind::FStr(parts) => node(
481 "f",
482 parts
483 .iter()
484 .map(|part| match part {
485 FStrPart::Text(t) => leaf(format!("{t:?}")),
486 FStrPart::Expr(e, None) => expr(e),
487 FStrPart::Expr(e, Some(spec)) => {
488 node(format!("format {:?}", spec.text()), vec![expr(e)])
489 }
490 })
491 .collect(),
492 ),
493 ExprKind::Bool(v) => leaf(v.to_string()),
494 ExprKind::Unit => leaf("()"),
495 ExprKind::Name(n) => leaf(n.name.clone()),
496 ExprKind::SelfValue => leaf("self"),
497 ExprKind::SelfType => leaf("Self"),
498 ExprKind::Paren(inner) => node("paren", vec![expr(inner)]),
499 ExprKind::List(items) => group("list", "[]", items.iter().map(expr).collect()),
500 ExprKind::Map(entries) => group(
501 "map",
502 "[:]",
503 entries
504 .iter()
505 .map(|(k, v)| node(":", vec![expr(k), expr(v)]))
506 .collect(),
507 ),
508 ExprKind::StructLit {
509 path: p,
510 type_args,
511 fields,
512 base,
513 } => {
514 let mut kids = vec![leaf(path(p))];
515 if !type_args.is_empty() {
516 kids.push(node(".<>", type_args.iter().map(ty).collect()));
517 }
518 for f in fields {
519 kids.push(match &f.value {
520 Some(v) => node(format!("{}:", f.name.name), vec![expr(v)]),
521 None => leaf(f.name.name.clone()),
522 });
523 }
524 if let Some(base) = base {
525 kids.push(node("..", vec![expr(base)]));
526 }
527 node("struct", kids)
528 }
529 ExprKind::Field { base, name } => node(".", vec![expr(base), leaf(name.name.clone())]),
530 ExprKind::TypeArgs { base, args } => {
531 let mut kids = vec![expr(base)];
532 kids.extend(args.iter().map(ty));
533 node(".<>", kids)
534 }
535 ExprKind::Call { callee, args } => {
536 let mut kids = vec![expr(callee)];
537 for a in args {
538 kids.push(if a.mode == Mode::Read {
539 expr(&a.value)
540 } else {
541 node(mode(a.mode).trim(), vec![expr(&a.value)])
542 });
543 }
544 node("call", kids)
545 }
546 ExprKind::Index { base, index } => node("index", vec![expr(base), expr(index)]),
547 ExprKind::Slice {
548 base,
549 start,
550 end,
551 inclusive,
552 } => {
553 let bound = |b: &Option<Box<Expr>>| b.as_ref().map_or(leaf("_"), |e| expr(e));
554 node(
555 if *inclusive { "slice..=" } else { "slice.." },
556 vec![expr(base), bound(start), bound(end)],
557 )
558 }
559 ExprKind::Try(inner) => node("?", vec![expr(inner)]),
560 ExprKind::Unary { op, operand } => {
561 let symbol = match op {
562 UnaryOp::Neg => "neg",
563 UnaryOp::Not => "!",
564 UnaryOp::BitNot => "~",
565 };
566 node(symbol, vec![expr(operand)])
567 }
568 ExprKind::Binary { op, lhs, rhs } => node(op.symbol(), vec![expr(lhs), expr(rhs)]),
569 ExprKind::Closure { params, ret, body } => {
570 let params = params
571 .iter()
572 .map(|p| match &p.ty {
573 Some(t) => node(p.name.name.clone(), vec![ty(t)]),
574 None => leaf(p.name.name.clone()),
575 })
576 .collect();
577 let mut kids = vec![group("params", "||", params)];
578 if let Some(ret) = ret {
579 kids.push(node("->", vec![ty(ret)]));
580 }
581 kids.push(expr(body));
582 node("closure", kids)
583 }
584 ExprKind::Block(b) => block(b),
585 ExprKind::If {
586 cond,
587 then,
588 otherwise,
589 } => {
590 let mut kids = vec![expr(cond), block(then)];
591 if let Some(other) = otherwise {
592 kids.push(node("else", vec![expr(other)]));
593 }
594 node("if", kids)
595 }
596 ExprKind::IfLet {
597 items,
598 then,
599 otherwise,
600 } => {
601 let mut kids = cond_items(items);
602 kids.push(block(then));
603 if let Some(other) = otherwise {
604 kids.push(node("else", vec![expr(other)]));
605 }
606 node("if let", kids)
607 }
608 ExprKind::Loop { label, body } => labelled(label, node("loop", vec![block(body)])),
609 ExprKind::Match {
610 mode: m,
611 scrutinee,
612 arms,
613 } => {
614 let mut kids = vec![if *m == Mode::Read {
615 expr(scrutinee)
616 } else {
617 node(mode(*m).trim(), vec![expr(scrutinee)])
618 }];
619 for arm in arms {
620 let mut ak = vec![pat(&arm.pattern)];
621 if let Some(guard) = &arm.guard {
622 ak.push(node("if", vec![expr(guard)]));
623 }
624 ak.push(expr(&arm.body));
625 kids.push(node("=>", ak));
626 }
627 node("match", kids)
628 }
629 ExprKind::Return(value) => match value {
630 Some(v) => node("return", vec![expr(v)]),
631 None => leaf("return"),
632 },
633 ExprKind::Break { label, value } => {
634 let mut kids = Vec::new();
635 if let Some(l) = label {
636 kids.push(leaf(format!("{}:", l.name)));
637 }
638 if let Some(v) = value {
639 kids.push(expr(v));
640 }
641 if kids.is_empty() {
642 leaf("break")
643 } else {
644 node("break", kids)
645 }
646 }
647 ExprKind::Continue { label } => match label {
648 Some(l) => node("continue", vec![leaf(format!("{}:", l.name))]),
649 None => leaf("continue"),
650 },
651 ExprKind::Error => leaf("<error>"),
652 }
653}
654
655fn pat(p: &Pat) -> Tree {
656 match &p.kind {
657 PatKind::Wild => leaf("_"),
658 PatKind::Name(n) => leaf(n.name.clone()),
659 PatKind::Int { negative, value } => {
660 leaf(format!("{}{}", if *negative { "-" } else { "" }, value))
661 }
662 PatKind::Str(s) => leaf(format!("{s:?}")),
663 PatKind::Bool(b) => leaf(b.to_string()),
664 PatKind::Path(p) => leaf(path(p)),
665 PatKind::Tuple { path: p, items } => node(path(p), items.iter().map(pat).collect()),
666 PatKind::Struct {
667 path: p,
668 fields,
669 rest,
670 } => {
671 let mut kids: Vec<Tree> = fields
672 .iter()
673 .map(|f| match &f.pat {
674 Some(sub) => node(format!("{}:", f.name.name), vec![pat(sub)]),
675 None => leaf(f.name.name.clone()),
676 })
677 .collect();
678 if *rest {
679 kids.push(leaf(".."));
680 }
681 node(format!("{} {{}}", path(p)), kids)
682 }
683 PatKind::Or(alts) => node("|", alts.iter().map(pat).collect()),
684 PatKind::Error => leaf("<error>"),
685 }
686}