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