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 for m in &decl.methods {
226 let mut mk = Vec::new();
227 docs(&m.docs, &mut mk);
228 flag(m.decl.overrides.is_some(), "override", &mut mk);
229 sig(&m.decl.sig, &mut mk);
230 match &m.decl.body {
231 Some(body) => {
232 mk.push(block(body));
233 kids.push(node("default", mk));
234 }
235 None => kids.push(node("sig", mk)),
236 }
237 }
238 "interface".to_string()
239 }
240 ItemKind::Impl(block) => {
241 kids.push(leaf(block.type_name.name.clone()));
242 generics(&block.generics, &mut kids);
243 if let Some(interface) = &block.interface {
244 kids.push(node("for", vec![ty(interface)]));
245 }
246 for m in &block.methods {
247 let mut mk = Vec::new();
248 docs(&m.docs, &mut mk);
249 fn_decl(&m.decl, &mut mk);
250 kids.push(node("fn", mk));
251 }
252 "impl".to_string()
253 }
254 ItemKind::Fn(decl) => {
255 fn_decl(decl, &mut kids);
256 "fn".to_string()
257 }
258 ItemKind::Test(test) => {
259 kids.push(leaf(format!("{:?}", test.name.value)));
260 kids.push(block(&test.body));
261 "test".to_string()
262 }
263 };
264 node(head, kids)
265}
266
267fn field(f: &Field) -> Tree {
268 let mut kids = Vec::new();
269 docs(&f.docs, &mut kids);
270 flag(f.public, "pub", &mut kids);
271 kids.push(leaf(f.name.name.clone()));
272 kids.push(ty(&f.ty));
273 node("field", kids)
274}
275
276fn fn_decl(decl: &FnDecl, kids: &mut Vec<Tree>) {
277 flag(decl.public, "pub", kids);
278 flag(decl.intrinsic, "intrinsic", kids);
279 flag(decl.overrides.is_some(), "override", kids);
280 sig(&decl.sig, kids);
281 if let Some(body) = &decl.body {
282 kids.push(block(body));
283 }
284}
285
286fn mode(m: Mode) -> &'static str {
287 match m {
288 Mode::Read => "",
289 Mode::Mut => "mut ",
290 Mode::Own => "own ",
291 }
292}
293
294fn sig(s: &FnSig, kids: &mut Vec<Tree>) {
295 kids.push(leaf(s.name.name.clone()));
296 generics(&s.generics, kids);
297 let params = s
298 .params
299 .iter()
300 .map(|p| match &p.kind {
301 ParamKind::SelfParam => leaf(format!("{}self", mode(p.mode))),
302 ParamKind::Named { name, ty: t } => {
303 node(format!("{}{}", mode(p.mode), name.name), vec![ty(t)])
304 }
305 })
306 .collect();
307 kids.push(group("params", "()", params));
308 if let Some(ret) = &s.ret {
309 kids.push(node("->", vec![ty(ret)]));
310 }
311}
312
313fn ty(t: &Ty) -> Tree {
314 match &t.kind {
315 TyKind::Path { path: p, args } => {
316 if args.is_empty() {
317 leaf(path(p))
318 } else {
319 node(path(p), args.iter().map(ty).collect())
320 }
321 }
322 TyKind::Fn { params, ret } => {
323 let mut kids: Vec<Tree> = params
324 .iter()
325 .map(|(m, t)| {
326 if *m == Mode::Read {
327 ty(t)
328 } else {
329 node(mode(*m).trim(), vec![ty(t)])
330 }
331 })
332 .collect();
333 if let Some(ret) = ret {
334 kids.push(node("->", vec![ty(ret)]));
335 }
336 node("fn", kids)
337 }
338 TyKind::SelfType => leaf("Self"),
339 TyKind::Error => leaf("<error>"),
340 }
341}
342
343fn block(b: &Block) -> Tree {
344 group("block", "{}", b.stmts.iter().map(stmt).collect())
345}
346
347fn stmt(s: &Stmt) -> Tree {
348 match &s.kind {
349 StmtKind::Let {
350 mutable,
351 name,
352 ty: t,
353 value,
354 } => {
355 let mut kids = vec![leaf(name.as_ref().map_or("_", |n| n.name.as_str()))];
356 if let Some(t) = t {
357 kids.push(ty(t));
358 }
359 kids.push(expr(value));
360 node(if *mutable { "var" } else { "let" }, kids)
361 }
362 StmtKind::LetPattern {
363 mutable,
364 pattern,
365 value,
366 } => node(
367 if *mutable { "var" } else { "let" },
368 vec![pat(pattern), expr(value)],
369 ),
370 StmtKind::Assign { target, op, value } => {
371 node(assign_symbol(*op), vec![expr(target), expr(value)])
372 }
373 StmtKind::While { label, cond, body } => {
374 labelled(label, node("while", vec![expr(cond), block(body)]))
375 }
376 StmtKind::WhileLet {
377 label,
378 pattern,
379 mode: m,
380 value,
381 body,
382 } => labelled(
383 label,
384 node(
385 "while let",
386 vec![pat(pattern), moded(*m, expr(value)), block(body)],
387 ),
388 ),
389 StmtKind::For {
390 label,
391 var,
392 iter,
393 body,
394 } => {
395 let iter = match iter {
396 ForIter::Collection { mode: m, expr: e } => {
397 if *m == Mode::Read {
398 expr(e)
399 } else {
400 node(mode(*m).trim(), vec![expr(e)])
401 }
402 }
403 ForIter::Range {
404 start,
405 end,
406 inclusive,
407 } => node(
408 if *inclusive { "..=" } else { ".." },
409 vec![expr(start), expr(end)],
410 ),
411 };
412 labelled(
413 label,
414 node("for", vec![leaf(var.name.clone()), iter, block(body)]),
415 )
416 }
417 StmtKind::Expr(e) => expr(e),
418 }
419}
420
421fn labelled(label: &Option<Ident>, t: Tree) -> Tree {
423 match label {
424 Some(l) => node(format!("{}:", l.name), vec![t]),
425 None => t,
426 }
427}
428
429fn moded(m: Mode, t: Tree) -> Tree {
431 if m == Mode::Read {
432 t
433 } else {
434 node(mode(m).trim(), vec![t])
435 }
436}
437
438fn assign_symbol(op: AssignOp) -> &'static str {
439 match op {
440 AssignOp::Assign => "=",
441 AssignOp::Add => "+=",
442 AssignOp::Sub => "-=",
443 AssignOp::Mul => "*=",
444 AssignOp::Div => "/=",
445 AssignOp::Rem => "%=",
446 AssignOp::BitAnd => "&=",
447 AssignOp::BitOr => "|=",
448 AssignOp::BitXor => "^=",
449 AssignOp::Shl => "<<=",
450 AssignOp::Shr => ">>=",
451 }
452}
453
454fn expr(e: &Expr) -> Tree {
455 match &e.kind {
456 ExprKind::Int(v) => leaf(v.to_string()),
457 ExprKind::Float(v) => leaf(format!("{v:?}")),
458 ExprKind::Str(v) => leaf(format!("{v:?}")),
459 ExprKind::FStr(parts) => node(
460 "f",
461 parts
462 .iter()
463 .map(|part| match part {
464 FStrPart::Text(t) => leaf(format!("{t:?}")),
465 FStrPart::Expr(e, None) => expr(e),
466 FStrPart::Expr(e, Some(spec)) => {
467 node(format!("format {:?}", spec.text()), vec![expr(e)])
468 }
469 })
470 .collect(),
471 ),
472 ExprKind::Bool(v) => leaf(v.to_string()),
473 ExprKind::Unit => leaf("()"),
474 ExprKind::Name(n) => leaf(n.name.clone()),
475 ExprKind::SelfValue => leaf("self"),
476 ExprKind::SelfType => leaf("Self"),
477 ExprKind::Paren(inner) => node("paren", vec![expr(inner)]),
478 ExprKind::List(items) => group("list", "[]", items.iter().map(expr).collect()),
479 ExprKind::Map(entries) => group(
480 "map",
481 "[:]",
482 entries
483 .iter()
484 .map(|(k, v)| node(":", vec![expr(k), expr(v)]))
485 .collect(),
486 ),
487 ExprKind::StructLit {
488 path: p,
489 type_args,
490 fields,
491 base,
492 } => {
493 let mut kids = vec![leaf(path(p))];
494 if !type_args.is_empty() {
495 kids.push(node(".<>", type_args.iter().map(ty).collect()));
496 }
497 for f in fields {
498 kids.push(match &f.value {
499 Some(v) => node(format!("{}:", f.name.name), vec![expr(v)]),
500 None => leaf(f.name.name.clone()),
501 });
502 }
503 if let Some(base) = base {
504 kids.push(node("..", vec![expr(base)]));
505 }
506 node("struct", kids)
507 }
508 ExprKind::Field { base, name } => node(".", vec![expr(base), leaf(name.name.clone())]),
509 ExprKind::TypeArgs { base, args } => {
510 let mut kids = vec![expr(base)];
511 kids.extend(args.iter().map(ty));
512 node(".<>", kids)
513 }
514 ExprKind::Call { callee, args } => {
515 let mut kids = vec![expr(callee)];
516 for a in args {
517 kids.push(if a.mode == Mode::Read {
518 expr(&a.value)
519 } else {
520 node(mode(a.mode).trim(), vec![expr(&a.value)])
521 });
522 }
523 node("call", kids)
524 }
525 ExprKind::Index { base, index } => node("index", vec![expr(base), expr(index)]),
526 ExprKind::Slice {
527 base,
528 start,
529 end,
530 inclusive,
531 } => {
532 let bound = |b: &Option<Box<Expr>>| b.as_ref().map_or(leaf("_"), |e| expr(e));
533 node(
534 if *inclusive { "slice..=" } else { "slice.." },
535 vec![expr(base), bound(start), bound(end)],
536 )
537 }
538 ExprKind::Try(inner) => node("?", vec![expr(inner)]),
539 ExprKind::Unary { op, operand } => {
540 let symbol = match op {
541 UnaryOp::Neg => "neg",
542 UnaryOp::Not => "!",
543 UnaryOp::BitNot => "~",
544 };
545 node(symbol, vec![expr(operand)])
546 }
547 ExprKind::Binary { op, lhs, rhs } => node(op.symbol(), vec![expr(lhs), expr(rhs)]),
548 ExprKind::Closure { params, ret, body } => {
549 let params = params
550 .iter()
551 .map(|p| match &p.ty {
552 Some(t) => node(p.name.name.clone(), vec![ty(t)]),
553 None => leaf(p.name.name.clone()),
554 })
555 .collect();
556 let mut kids = vec![group("params", "||", params)];
557 if let Some(ret) = ret {
558 kids.push(node("->", vec![ty(ret)]));
559 }
560 kids.push(expr(body));
561 node("closure", kids)
562 }
563 ExprKind::Block(b) => block(b),
564 ExprKind::If {
565 cond,
566 then,
567 otherwise,
568 } => {
569 let mut kids = vec![expr(cond), block(then)];
570 if let Some(other) = otherwise {
571 kids.push(node("else", vec![expr(other)]));
572 }
573 node("if", kids)
574 }
575 ExprKind::IfLet {
576 pattern,
577 mode: m,
578 value,
579 then,
580 otherwise,
581 } => {
582 let mut kids = vec![pat(pattern), moded(*m, expr(value)), block(then)];
583 if let Some(other) = otherwise {
584 kids.push(node("else", vec![expr(other)]));
585 }
586 node("if let", kids)
587 }
588 ExprKind::Loop { label, body } => labelled(label, node("loop", vec![block(body)])),
589 ExprKind::Match {
590 mode: m,
591 scrutinee,
592 arms,
593 } => {
594 let mut kids = vec![if *m == Mode::Read {
595 expr(scrutinee)
596 } else {
597 node(mode(*m).trim(), vec![expr(scrutinee)])
598 }];
599 for arm in arms {
600 let mut ak = vec![pat(&arm.pattern)];
601 if let Some(guard) = &arm.guard {
602 ak.push(node("if", vec![expr(guard)]));
603 }
604 ak.push(expr(&arm.body));
605 kids.push(node("=>", ak));
606 }
607 node("match", kids)
608 }
609 ExprKind::Return(value) => match value {
610 Some(v) => node("return", vec![expr(v)]),
611 None => leaf("return"),
612 },
613 ExprKind::Break { label, value } => {
614 let mut kids = Vec::new();
615 if let Some(l) = label {
616 kids.push(leaf(format!("{}:", l.name)));
617 }
618 if let Some(v) = value {
619 kids.push(expr(v));
620 }
621 if kids.is_empty() {
622 leaf("break")
623 } else {
624 node("break", kids)
625 }
626 }
627 ExprKind::Continue { label } => match label {
628 Some(l) => node("continue", vec![leaf(format!("{}:", l.name))]),
629 None => leaf("continue"),
630 },
631 ExprKind::Error => leaf("<error>"),
632 }
633}
634
635fn pat(p: &Pat) -> Tree {
636 match &p.kind {
637 PatKind::Wild => leaf("_"),
638 PatKind::Name(n) => leaf(n.name.clone()),
639 PatKind::Int { negative, value } => {
640 leaf(format!("{}{}", if *negative { "-" } else { "" }, value))
641 }
642 PatKind::Str(s) => leaf(format!("{s:?}")),
643 PatKind::Bool(b) => leaf(b.to_string()),
644 PatKind::Path(p) => leaf(path(p)),
645 PatKind::Tuple { path: p, items } => node(path(p), items.iter().map(pat).collect()),
646 PatKind::Struct {
647 path: p,
648 fields,
649 rest,
650 } => {
651 let mut kids: Vec<Tree> = fields
652 .iter()
653 .map(|f| match &f.pat {
654 Some(sub) => node(format!("{}:", f.name.name), vec![pat(sub)]),
655 None => leaf(f.name.name.clone()),
656 })
657 .collect();
658 if *rest {
659 kids.push(leaf(".."));
660 }
661 node(format!("{} {{}}", path(p)), kids)
662 }
663 PatKind::Or(alts) => node("|", alts.iter().map(pat).collect()),
664 PatKind::Error => leaf("<error>"),
665 }
666}