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 };
164 d.push(leaf(format!("from {:?}", decl.from.value)));
165 kids.push(node(head, d));
166 }
167 format!("extern {}", target.target.name)
168 }
169 ItemKind::Config(entry) => {
170 flag(entry.public, "pub", &mut kids);
171 kids.push(leaf(entry.name.name.clone()));
172 kids.push(ty(&entry.ty));
173 kids.push(expr(&entry.value));
174 "const".to_string()
175 }
176 ItemKind::Struct(decl) => {
177 flag(decl.public, "pub", &mut kids);
178 kids.push(leaf(decl.name.name.clone()));
179 generics(&decl.generics, &mut kids);
180 kids.extend(decl.fields.iter().map(field));
181 "struct".to_string()
182 }
183 ItemKind::Enum(decl) => {
184 flag(decl.public, "pub", &mut kids);
185 kids.push(leaf(decl.name.name.clone()));
186 generics(&decl.generics, &mut kids);
187 for v in &decl.variants {
188 let mut vk = Vec::new();
189 docs(&v.docs, &mut vk);
190 vk.push(leaf(v.name.name.clone()));
191 match &v.payload {
192 VariantPayload::None => {}
193 VariantPayload::Tuple(types) => {
194 vk.push(node("tuple", types.iter().map(ty).collect()))
195 }
196 VariantPayload::Struct(fields) => {
197 vk.push(node("fields", fields.iter().map(field).collect()))
198 }
199 }
200 kids.push(node("variant", vk));
201 }
202 "enum".to_string()
203 }
204 ItemKind::Alias(decl) => {
205 flag(decl.public, "pub", &mut kids);
206 kids.push(leaf(decl.name.name.clone()));
207 generics(&decl.generics, &mut kids);
208 kids.push(ty(&decl.ty));
209 "alias".to_string()
210 }
211 ItemKind::IntrinsicType(decl) => {
212 flag(decl.public, "pub", &mut kids);
213 kids.push(leaf(decl.name.name.clone()));
214 generics(&decl.generics, &mut kids);
215 "intrinsic type".to_string()
216 }
217 ItemKind::Interface(decl) => {
218 flag(decl.public, "pub", &mut kids);
219 kids.push(leaf(decl.name.name.clone()));
220 generics(&decl.generics, &mut kids);
221 for m in &decl.methods {
222 let mut mk = Vec::new();
223 docs(&m.docs, &mut mk);
224 sig(&m.sig, &mut mk);
225 kids.push(node("sig", mk));
226 }
227 "interface".to_string()
228 }
229 ItemKind::Impl(block) => {
230 kids.push(leaf(block.type_name.name.clone()));
231 generics(&block.generics, &mut kids);
232 if let Some(interface) = &block.interface {
233 kids.push(node("for", vec![ty(interface)]));
234 }
235 for m in &block.methods {
236 let mut mk = Vec::new();
237 docs(&m.docs, &mut mk);
238 fn_decl(&m.decl, &mut mk);
239 kids.push(node("fn", mk));
240 }
241 "impl".to_string()
242 }
243 ItemKind::Fn(decl) => {
244 fn_decl(decl, &mut kids);
245 "fn".to_string()
246 }
247 ItemKind::Test(test) => {
248 kids.push(leaf(format!("{:?}", test.name.value)));
249 kids.push(block(&test.body));
250 "test".to_string()
251 }
252 };
253 node(head, kids)
254}
255
256fn field(f: &Field) -> Tree {
257 let mut kids = Vec::new();
258 docs(&f.docs, &mut kids);
259 flag(f.public, "pub", &mut kids);
260 kids.push(leaf(f.name.name.clone()));
261 kids.push(ty(&f.ty));
262 node("field", kids)
263}
264
265fn fn_decl(decl: &FnDecl, kids: &mut Vec<Tree>) {
266 flag(decl.public, "pub", kids);
267 flag(decl.intrinsic, "intrinsic", kids);
268 sig(&decl.sig, kids);
269 if let Some(body) = &decl.body {
270 kids.push(block(body));
271 }
272}
273
274fn mode(m: Mode) -> &'static str {
275 match m {
276 Mode::Read => "",
277 Mode::Mut => "mut ",
278 Mode::Own => "own ",
279 }
280}
281
282fn sig(s: &FnSig, kids: &mut Vec<Tree>) {
283 kids.push(leaf(s.name.name.clone()));
284 generics(&s.generics, kids);
285 let params = s
286 .params
287 .iter()
288 .map(|p| match &p.kind {
289 ParamKind::SelfParam => leaf(format!("{}self", mode(p.mode))),
290 ParamKind::Named { name, ty: t } => {
291 node(format!("{}{}", mode(p.mode), name.name), vec![ty(t)])
292 }
293 })
294 .collect();
295 kids.push(group("params", "()", params));
296 if let Some(ret) = &s.ret {
297 kids.push(node("->", vec![ty(ret)]));
298 }
299}
300
301fn ty(t: &Ty) -> Tree {
302 match &t.kind {
303 TyKind::Path { path: p, args } => {
304 if args.is_empty() {
305 leaf(path(p))
306 } else {
307 node(path(p), args.iter().map(ty).collect())
308 }
309 }
310 TyKind::Fn { params, ret } => {
311 let mut kids: Vec<Tree> = params
312 .iter()
313 .map(|(m, t)| {
314 if *m == Mode::Read {
315 ty(t)
316 } else {
317 node(mode(*m).trim(), vec![ty(t)])
318 }
319 })
320 .collect();
321 if let Some(ret) = ret {
322 kids.push(node("->", vec![ty(ret)]));
323 }
324 node("fn", kids)
325 }
326 TyKind::SelfType => leaf("Self"),
327 TyKind::Error => leaf("<error>"),
328 }
329}
330
331fn block(b: &Block) -> Tree {
332 group("block", "{}", b.stmts.iter().map(stmt).collect())
333}
334
335fn stmt(s: &Stmt) -> Tree {
336 match &s.kind {
337 StmtKind::Let {
338 mutable,
339 name,
340 ty: t,
341 value,
342 } => {
343 let mut kids = vec![leaf(name.as_ref().map_or("_", |n| n.name.as_str()))];
344 if let Some(t) = t {
345 kids.push(ty(t));
346 }
347 kids.push(expr(value));
348 node(if *mutable { "var" } else { "let" }, kids)
349 }
350 StmtKind::Assign { target, op, value } => {
351 node(assign_symbol(*op), vec![expr(target), expr(value)])
352 }
353 StmtKind::While { cond, body } => node("while", vec![expr(cond), block(body)]),
354 StmtKind::For { var, iter, body } => {
355 let iter = match iter {
356 ForIter::Collection { mode: m, expr: e } => {
357 if *m == Mode::Read {
358 expr(e)
359 } else {
360 node(mode(*m).trim(), vec![expr(e)])
361 }
362 }
363 ForIter::Range {
364 start,
365 end,
366 inclusive,
367 } => node(
368 if *inclusive { "..=" } else { ".." },
369 vec![expr(start), expr(end)],
370 ),
371 };
372 node("for", vec![leaf(var.name.clone()), iter, block(body)])
373 }
374 StmtKind::Expr(e) => expr(e),
375 }
376}
377
378fn assign_symbol(op: AssignOp) -> &'static str {
379 match op {
380 AssignOp::Assign => "=",
381 AssignOp::Add => "+=",
382 AssignOp::Sub => "-=",
383 AssignOp::Mul => "*=",
384 AssignOp::Div => "/=",
385 AssignOp::Rem => "%=",
386 AssignOp::BitAnd => "&=",
387 AssignOp::BitOr => "|=",
388 AssignOp::BitXor => "^=",
389 AssignOp::Shl => "<<=",
390 AssignOp::Shr => ">>=",
391 }
392}
393
394fn expr(e: &Expr) -> Tree {
395 match &e.kind {
396 ExprKind::Int(v) => leaf(v.to_string()),
397 ExprKind::Float(v) => leaf(format!("{v:?}")),
398 ExprKind::Str(v) => leaf(format!("{v:?}")),
399 ExprKind::Bool(v) => leaf(v.to_string()),
400 ExprKind::Unit => leaf("()"),
401 ExprKind::Name(n) => leaf(n.name.clone()),
402 ExprKind::SelfValue => leaf("self"),
403 ExprKind::SelfType => leaf("Self"),
404 ExprKind::Paren(inner) => node("paren", vec![expr(inner)]),
405 ExprKind::List(items) => group("list", "[]", items.iter().map(expr).collect()),
406 ExprKind::Map(entries) => group(
407 "map",
408 "[:]",
409 entries
410 .iter()
411 .map(|(k, v)| node(":", vec![expr(k), expr(v)]))
412 .collect(),
413 ),
414 ExprKind::StructLit {
415 path: p,
416 type_args,
417 fields,
418 } => {
419 let mut kids = vec![leaf(path(p))];
420 if !type_args.is_empty() {
421 kids.push(node(".<>", type_args.iter().map(ty).collect()));
422 }
423 for f in fields {
424 kids.push(match &f.value {
425 Some(v) => node(format!("{}:", f.name.name), vec![expr(v)]),
426 None => leaf(f.name.name.clone()),
427 });
428 }
429 node("struct", kids)
430 }
431 ExprKind::Field { base, name } => node(".", vec![expr(base), leaf(name.name.clone())]),
432 ExprKind::TypeArgs { base, args } => {
433 let mut kids = vec![expr(base)];
434 kids.extend(args.iter().map(ty));
435 node(".<>", kids)
436 }
437 ExprKind::Call { callee, args } => {
438 let mut kids = vec![expr(callee)];
439 for a in args {
440 kids.push(if a.mode == Mode::Read {
441 expr(&a.value)
442 } else {
443 node(mode(a.mode).trim(), vec![expr(&a.value)])
444 });
445 }
446 node("call", kids)
447 }
448 ExprKind::Index { base, index } => node("index", vec![expr(base), expr(index)]),
449 ExprKind::Slice {
450 base,
451 start,
452 end,
453 inclusive,
454 } => {
455 let bound = |b: &Option<Box<Expr>>| b.as_ref().map_or(leaf("_"), |e| expr(e));
456 node(
457 if *inclusive { "slice..=" } else { "slice.." },
458 vec![expr(base), bound(start), bound(end)],
459 )
460 }
461 ExprKind::Try(inner) => node("?", vec![expr(inner)]),
462 ExprKind::Unary { op, operand } => {
463 let symbol = match op {
464 UnaryOp::Neg => "neg",
465 UnaryOp::Not => "!",
466 UnaryOp::BitNot => "~",
467 };
468 node(symbol, vec![expr(operand)])
469 }
470 ExprKind::Binary { op, lhs, rhs } => node(op.symbol(), vec![expr(lhs), expr(rhs)]),
471 ExprKind::Closure { params, ret, body } => {
472 let params = params
473 .iter()
474 .map(|p| match &p.ty {
475 Some(t) => node(p.name.name.clone(), vec![ty(t)]),
476 None => leaf(p.name.name.clone()),
477 })
478 .collect();
479 let mut kids = vec![group("params", "||", params)];
480 if let Some(ret) = ret {
481 kids.push(node("->", vec![ty(ret)]));
482 }
483 kids.push(expr(body));
484 node("closure", kids)
485 }
486 ExprKind::Block(b) => block(b),
487 ExprKind::If {
488 cond,
489 then,
490 otherwise,
491 } => {
492 let mut kids = vec![expr(cond), block(then)];
493 if let Some(other) = otherwise {
494 kids.push(node("else", vec![expr(other)]));
495 }
496 node("if", kids)
497 }
498 ExprKind::Match {
499 mode: m,
500 scrutinee,
501 arms,
502 } => {
503 let mut kids = vec![if *m == Mode::Read {
504 expr(scrutinee)
505 } else {
506 node(mode(*m).trim(), vec![expr(scrutinee)])
507 }];
508 for arm in arms {
509 let mut ak = vec![pat(&arm.pattern)];
510 if let Some(guard) = &arm.guard {
511 ak.push(node("if", vec![expr(guard)]));
512 }
513 ak.push(expr(&arm.body));
514 kids.push(node("=>", ak));
515 }
516 node("match", kids)
517 }
518 ExprKind::Return(value) => match value {
519 Some(v) => node("return", vec![expr(v)]),
520 None => leaf("return"),
521 },
522 ExprKind::Break => leaf("break"),
523 ExprKind::Continue => leaf("continue"),
524 ExprKind::Error => leaf("<error>"),
525 }
526}
527
528fn pat(p: &Pat) -> Tree {
529 match &p.kind {
530 PatKind::Wild => leaf("_"),
531 PatKind::Name(n) => leaf(n.name.clone()),
532 PatKind::Int { negative, value } => {
533 leaf(format!("{}{}", if *negative { "-" } else { "" }, value))
534 }
535 PatKind::Str(s) => leaf(format!("{s:?}")),
536 PatKind::Bool(b) => leaf(b.to_string()),
537 PatKind::Path(p) => leaf(path(p)),
538 PatKind::Tuple { path: p, items } => node(path(p), items.iter().map(pat).collect()),
539 PatKind::Struct {
540 path: p,
541 fields,
542 rest,
543 } => {
544 let mut kids: Vec<Tree> = fields
545 .iter()
546 .map(|f| match &f.pat {
547 Some(sub) => node(format!("{}:", f.name.name), vec![pat(sub)]),
548 None => leaf(f.name.name.clone()),
549 })
550 .collect();
551 if *rest {
552 kids.push(leaf(".."));
553 }
554 node(format!("{} {{}}", path(p)), kids)
555 }
556 PatKind::Or(alts) => node("|", alts.iter().map(pat).collect()),
557 PatKind::Error => leaf("<error>"),
558 }
559}