1use super::expr::{ExprId, Lit, Node};
4use super::level::{LevelId, LevelNode};
5use super::tc::Kernel;
6
7const BUDGET: usize = 400;
8
9pub fn show(k: &Kernel, e: ExprId) -> String {
10 let mut out = String::new();
11 let mut budget = BUDGET;
12 go(k, e, 0, &mut out, &mut budget, false);
13 out
14}
15
16pub fn show_level(k: &Kernel, l: LevelId) -> String {
17 match k.s.levels.node(l) {
18 LevelNode::Zero => "0".into(),
19 LevelNode::SProp => "SProp".into(),
20 LevelNode::Param(n) => k.s.names.display(n),
21 LevelNode::Succ(_) => {
22 let (mut base, mut n) = (l, 0);
23 while let LevelNode::Succ(a) = k.s.levels.node(base) {
24 base = a;
25 n += 1;
26 }
27 if base == LevelId::ZERO {
28 n.to_string()
29 } else {
30 format!("{}+{}", show_level(k, base), n)
31 }
32 }
33 LevelNode::Max(a, b) => format!("max ({}) ({})", show_level(k, a), show_level(k, b)),
34 LevelNode::IMax(a, b) => format!("imax ({}) ({})", show_level(k, a), show_level(k, b)),
35 }
36}
37
38fn go(k: &Kernel, e: ExprId, depth: u32, out: &mut String, budget: &mut usize, paren: bool) {
39 if *budget == 0 {
40 out.push('…');
41 return;
42 }
43 *budget -= 1;
44 let open = |out: &mut String| {
45 if paren {
46 out.push('(')
47 }
48 };
49 let close = |out: &mut String| {
50 if paren {
51 out.push(')')
52 }
53 };
54 match k.s.node(e) {
55 Node::BVar(i) => {
56 if i < depth {
57 out.push_str(&format!("x{}", depth - 1 - i));
58 } else {
59 out.push_str(&format!("#{i}"));
60 }
61 }
62 Node::FVar(i) => out.push_str(&format!("h{i}")),
63 Node::Sort(l) => {
64 if l == LevelId::ZERO {
65 out.push_str("Prop");
66 } else {
67 out.push_str(&format!("Sort ({})", show_level(k, l)));
68 }
69 }
70 Node::Const(n, _) => out.push_str(&k.s.names.display(n)),
71 Node::App(..) => {
72 open(out);
73 let (f, args) = k.s.app_args(e);
74 go(k, f, depth, out, budget, true);
75 for a in args {
76 out.push(' ');
77 go(k, a, depth, out, budget, true);
78 }
79 close(out);
80 }
81 Node::Lam(t, b) => {
82 open(out);
83 out.push_str(&format!("fun (x{depth} : "));
84 go(k, t, depth, out, budget, false);
85 out.push_str(") => ");
86 go(k, b, depth + 1, out, budget, false);
87 close(out);
88 }
89 Node::Pi(t, b) => {
90 open(out);
91 if k.s.loose_bvar_range(b) == 0 {
92 go(k, t, depth, out, budget, true);
93 out.push_str(" → ");
94 } else {
95 out.push_str(&format!("(x{depth} : "));
96 go(k, t, depth, out, budget, false);
97 out.push_str(") → ");
98 }
99 go(k, b, depth + 1, out, budget, false);
100 close(out);
101 }
102 Node::Let(t, v, b) => {
103 open(out);
104 out.push_str(&format!("let x{depth} : "));
105 go(k, t, depth, out, budget, false);
106 out.push_str(" := ");
107 go(k, v, depth, out, budget, false);
108 out.push_str("; ");
109 go(k, b, depth + 1, out, budget, false);
110 close(out);
111 }
112 Node::NatLit(n) => out.push_str(&k.s.nat(n).to_decimal()),
113 Node::StrLit(s) => out.push_str(&format!("{:?}", &*k.s.string(s))),
114 Node::Proj(_, i, x) => {
115 go(k, x, depth, out, budget, true);
116 out.push_str(&format!(".{}", i + 1));
117 }
118 Node::Lit(l) => out.push_str(&match k.s.lit_value(l) {
119 Lit::Int(i) => i.to_string(),
120 Lit::BigInt(b) => b.to_string(),
121 Lit::Float(bits) => format!("{:?}", f64::from_bits(*bits)),
122 Lit::Duration(d) => format!("{d}ns"),
123 Lit::Date(d) => format!("date({d})"),
124 Lit::Moment(m) => format!("moment({m})"),
125 }),
126 Node::Match(d, m, cs) => {
127 open(out);
128 out.push_str("match ");
129 go(k, d, depth, out, budget, true);
130 out.push_str(" return ");
131 go(k, m, depth, out, budget, true);
132 out.push_str(" with");
133 for c in k.s.seq_items(cs) {
134 out.push_str(" | ");
135 go(k, c, depth, out, budget, false);
136 }
137 out.push_str(" end");
138 close(out);
139 }
140 Node::Fix(b) => {
141 open(out);
142 out.push_str(&format!("fix x{depth} => "));
143 go(k, b, depth + 1, out, budget, false);
144 close(out);
145 }
146 Node::MutualFix(ds, i) => {
147 open(out);
148 let ds = k.s.seq_items(ds);
149 let n = ds.len() as u32;
150 out.push_str("fix");
151 for (j, b) in ds.iter().enumerate() {
152 out.push_str(&format!(
153 " {}x{} => ",
154 if j == 0 { "" } else { "with " },
155 depth + j as u32
156 ));
157 go(k, *b, depth + n, out, budget, false);
158 }
159 out.push_str(&format!(" return x{}", depth + i));
160 close(out);
161 }
162 Node::Seq(..) | Node::Nil => out.push_str("⟨sequence⟩"),
163 }
164}