1use super::{Book, Definition, FanKind, Name, Num, Op, Pattern, Rule, Tag, Term, Type};
2use crate::maybe_grow;
3use std::{fmt, ops::Deref, sync::atomic::AtomicU64};
4
5pub struct DisplayFn<F: Fn(&mut fmt::Formatter) -> fmt::Result>(pub F);
8
9impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> fmt::Display for DisplayFn<F> {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 self.0(f)
12 }
13}
14
15pub struct DisplayJoin<F, S>(pub F, pub S);
16
17impl<F, I, S> fmt::Display for DisplayJoin<F, S>
18where
19 F: (Fn() -> I),
20 I: IntoIterator,
21 I::Item: fmt::Display,
22 S: fmt::Display,
23{
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 for (i, x) in self.0().into_iter().enumerate() {
26 if i != 0 {
27 self.1.fmt(f)?;
28 }
29 x.fmt(f)?;
30 }
31 Ok(())
32 }
33}
34
35macro_rules! display {
36 ($($x:tt)*) => {
37 DisplayFn(move |f| write!(f, $($x)*))
38 };
39}
40
41static NAMEGEN: AtomicU64 = AtomicU64::new(0);
44
45fn gen_fan_pat_name() -> Name {
46 let n = NAMEGEN.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
47 Name::new(format!("pat%{}", super::num_to_name(n)))
48}
49
50fn namegen_reset() {
51 NAMEGEN.store(0, std::sync::atomic::Ordering::SeqCst);
52}
53
54impl fmt::Display for Term {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 maybe_grow(|| match self {
57 Term::Lam { tag, pat, bod } => match &**pat {
58 Pattern::Fan(_, _, _) => {
59 let name = gen_fan_pat_name();
60 write!(f, "{}λ{name} let {} = {name}; {}", tag.display_padded(), pat, bod)
61 }
62 _ => write!(f, "{}λ{} {}", tag.display_padded(), pat, bod),
63 },
64 Term::Var { nam } => write!(f, "{nam}"),
65 Term::Link { nam } => write!(f, "${nam}"),
66 Term::Let { pat, val, nxt } => write!(f, "let {} = {}; {}", pat, val, nxt),
67 Term::With { typ, bod } => write!(f, "with {typ} {{ {bod} }}"),
68 Term::Ask { pat, val, nxt } => write!(f, "ask {pat} = {val}; {nxt}"),
69 Term::Use { nam, val, nxt } => {
70 let Some(nam) = nam else { unreachable!() };
71 write!(f, "use {} = {}; {}", nam, val, nxt)
72 }
73 Term::Ref { nam: def_name } => write!(f, "{def_name}"),
74 Term::App { tag, fun, arg } => {
75 write!(f, "{}({} {})", tag.display_padded(), fun.display_app(tag), arg)
76 }
77 Term::Mat { arg, bnd, with_bnd, with_arg, arms } => {
78 write!(f, "match ")?;
79 if let Some(bnd) = bnd {
80 write!(f, "{} = ", bnd)?;
81 }
82 write!(f, "{} ", arg)?;
83 if !with_bnd.is_empty() {
84 write!(f, "with ")?;
85 for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
86 write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
87 }
88 }
89 write!(f, "{{ ")?;
90 for arm in arms {
91 write!(f, "{}", var_as_str(&arm.0))?;
92 for var in &arm.1 {
93 write!(f, " {}", var_as_str(var))?;
94 }
95 write!(f, ": {}; ", arm.2)?;
96 }
97 write!(f, "}}")
98 }
99 Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => {
100 write!(f, "switch ")?;
101 if let Some(bnd) = bnd {
102 write!(f, "{bnd} = ")?;
103 }
104 write!(f, "{arg} ")?;
105 if !with_bnd.is_empty() {
106 write!(f, "with ")?;
107 for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
108 write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
109 }
110 }
111 write!(f, "{{ ")?;
112 for (i, arm) in arms.iter().enumerate() {
113 if i == arms.len() - 1 {
114 write!(f, "_")?;
115 if let Some(pred) = pred {
116 write!(f, " {pred}")?;
117 }
118 } else {
119 write!(f, "{i}")?;
120 }
121 write!(f, ": {arm}; ")?;
122 }
123 write!(f, "}}")
124 }
125 Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
126 write!(f, "fold ")?;
127 if let Some(bnd) = bnd {
128 write!(f, "{} = ", bnd)?;
129 }
130 write!(f, "{} ", arg)?;
131 if !with_bnd.is_empty() {
132 write!(f, "with ")?;
133 for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
134 write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
135 }
136 }
137 write!(f, "{{ ")?;
138 for arm in arms {
139 write!(f, "{}", var_as_str(&arm.0))?;
140 for var in &arm.1 {
141 write!(f, " {}", var_as_str(var))?;
142 }
143 write!(f, ": {}; ", arm.2)?;
144 }
145 write!(f, "}}")
146 }
147 Term::Bend { bnd: bind, arg: init, cond, step, base } => {
148 write!(f, "bend ")?;
149 for (bind, init) in bind.iter().zip(init) {
150 if let Some(bind) = bind {
151 write!(f, "{} = ", bind)?;
152 }
153 write!(f, "{}, ", init)?;
154 }
155 write!(f, "{{ when {cond}: {step}; else: {base} }}")
156 }
157 Term::Fan { fan: FanKind::Tup, tag, els } => write!(f, "{}({})", tag, DisplayJoin(|| els.iter(), ", ")),
158 Term::Fan { fan: FanKind::Dup, tag, els } => write!(f, "{}{{{}}}", tag, DisplayJoin(|| els, " ")),
159 Term::Era => write!(f, "*"),
160 Term::Num { val: Num::U24(val) } => write!(f, "{val}"),
161 Term::Num { val: Num::I24(val) } => write!(f, "{}{}", if *val < 0 { "-" } else { "+" }, val.abs()),
162 Term::Num { val: Num::F24(val) } => write!(f, "{val:.3}"),
163 Term::Nat { val } => write!(f, "#{val}"),
164 Term::Str { val } => write!(f, "{val:?}"),
165 Term::Oper { opr, fst, snd } => {
166 write!(f, "({} {} {})", opr, fst, snd)
167 }
168 Term::List { els } => write!(f, "[{}]", DisplayJoin(|| els.iter(), ", "),),
169 Term::Open { typ, var, bod } => write!(f, "open {typ} {var}; {bod}"),
170 Term::Def { def, nxt } => {
171 write!(f, "def ")?;
172 for rule in def.rules.iter() {
173 write!(f, "{}", rule.display(&def.name))?;
174 }
175 write!(f, "{nxt}")
176 }
177 Term::Err => write!(f, "<Invalid>"),
178 })
179 }
180}
181
182impl fmt::Display for Tag {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 match self {
185 Tag::Named(name) => write!(f, "#{name}"),
186 Tag::Numeric(num) => write!(f, "#{num}"),
187 Tag::Auto => Ok(()),
188 Tag::Static => Ok(()),
189 }
190 }
191}
192
193impl fmt::Display for Pattern {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 match self {
196 Pattern::Var(None) => write!(f, "*"),
197 Pattern::Var(Some(nam)) => write!(f, "{nam}"),
198 Pattern::Chn(nam) => write!(f, "${nam}"),
199 Pattern::Ctr(nam, pats) => {
200 write!(f, "({}{})", nam, DisplayJoin(|| pats.iter().map(|p| display!(" {p}")), ""))
201 }
202 Pattern::Num(num) => write!(f, "{num}"),
203 Pattern::Fan(FanKind::Tup, tag, pats) => write!(f, "{}({})", tag, DisplayJoin(|| pats, ", ")),
204 Pattern::Fan(FanKind::Dup, tag, pats) => write!(f, "{}{{{}}}", tag, DisplayJoin(|| pats, " ")),
205 Pattern::Lst(pats) => write!(f, "[{}]", DisplayJoin(|| pats, ", ")),
206 Pattern::Str(str) => write!(f, "\"{str}\""),
207 }
208 }
209}
210
211impl Rule {
212 pub fn display<'a>(&'a self, def_name: &'a Name) -> impl fmt::Display + 'a {
213 display!(
214 "({}{}) = {}",
215 def_name,
216 DisplayJoin(|| self.pats.iter().map(|x| display!(" {x}")), ""),
217 self.body
218 )
219 }
220}
221
222impl fmt::Display for Definition {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 namegen_reset();
225 writeln!(f, "{}{}: {}", if !self.check { "unchecked " } else { "" }, self.name, self.typ)?;
226 write!(f, "{}", DisplayJoin(|| self.rules.iter().map(|x| x.display(&self.name)), "\n"))
227 }
228}
229
230impl fmt::Display for Book {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 write!(f, "{}", DisplayJoin(|| self.defs.values(), "\n\n"))?;
233 for def in self.hvm_defs.values() {
234 writeln!(f, "hvm {}:\n{}\n", def.name, def.body.show())?;
235 }
236 Ok(())
237 }
238}
239
240impl fmt::Display for Name {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 self.0.fmt(f)
243 }
244}
245
246impl Term {
247 fn display_app<'a>(&'a self, tag: &'a Tag) -> impl fmt::Display + 'a {
248 maybe_grow(|| {
249 DisplayFn(move |f| match self {
250 Term::App { tag: tag2, fun, arg } if tag2 == tag => {
251 write!(f, "{} {}", fun.display_app(tag), arg)
252 }
253 _ => write!(f, "{}", self),
254 })
255 })
256 }
257}
258
259impl fmt::Display for Op {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 match self {
262 Op::ADD => write!(f, "+"),
263 Op::SUB => write!(f, "-"),
264 Op::MUL => write!(f, "*"),
265 Op::DIV => write!(f, "/"),
266 Op::REM => write!(f, "%"),
267 Op::EQ => write!(f, "=="),
268 Op::NEQ => write!(f, "!="),
269 Op::LT => write!(f, "<"),
270 Op::GT => write!(f, ">"),
271 Op::AND => write!(f, "&"),
272 Op::OR => write!(f, "|"),
273 Op::XOR => write!(f, "^"),
274 Op::POW => write!(f, "**"),
275 Op::SHR => write!(f, ">>"),
276 Op::SHL => write!(f, "<<"),
277 Op::LE => write!(f, "<="),
278 Op::GE => write!(f, ">="),
279 }
280 }
281}
282
283impl Tag {
284 pub fn display_padded(&self) -> impl fmt::Display + '_ {
285 DisplayFn(move |f| match self {
286 Tag::Named(name) => write!(f, "#{name} "),
287 Tag::Numeric(num) => write!(f, "#{num} "),
288 Tag::Auto => Ok(()),
289 Tag::Static => Ok(()),
290 })
291 }
292}
293
294impl fmt::Display for Type {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 maybe_grow(|| match self {
297 Type::Hole => write!(f, "_"),
298 Type::Var(nam) => write!(f, "{nam}"),
299 Type::Arr(lft, rgt) => write!(f, "({} -> {})", lft, rgt.display_arrow()),
300 Type::Ctr(nam, args) => {
301 if args.is_empty() {
302 write!(f, "{nam}")
303 } else {
304 write!(f, "({nam} {})", DisplayJoin(|| args.iter(), " "))
305 }
306 }
307 Type::Number(t) => write!(f, "(Number {t})"),
308 Type::Integer(t) => write!(f, "(Integer {t})"),
309 Type::U24 => write!(f, "u24"),
310 Type::I24 => write!(f, "i24"),
311 Type::F24 => write!(f, "f24"),
312 Type::Any => write!(f, "Any"),
313 Type::None => write!(f, "None"),
314 Type::Tup(els) => write!(f, "({})", DisplayJoin(|| els.iter(), ", ")),
315 })
316 }
317}
318
319impl Type {
320 pub fn display_arrow(&self) -> impl fmt::Display + '_ {
321 maybe_grow(|| {
322 DisplayFn(move |f| match self {
323 Type::Arr(lft, rgt) => {
324 write!(f, "{} -> {}", lft, rgt.display_arrow())
325 }
326 _ => write!(f, "{}", self),
327 })
328 })
329 }
330}
331
332fn var_as_str(nam: &Option<Name>) -> &str {
333 nam.as_ref().map_or("*", Name::deref)
334}
335
336impl Book {
339 pub fn display_pretty(&self) -> impl fmt::Display + '_ {
340 display!(
341 "{}\n{}",
342 DisplayJoin(|| self.defs.values().map(|def| def.display_pretty()), "\n\n"),
343 DisplayJoin(
344 || self.hvm_defs.values().map(|def| display!("hvm {}:\n{}", def.name, def.body.show())),
345 "\n"
346 )
347 )
348 }
349}
350
351impl Definition {
352 pub fn display_pretty(&self) -> impl fmt::Display + '_ {
353 namegen_reset();
354 display!("{}", DisplayJoin(|| self.rules.iter().map(|x| x.display_pretty(&self.name)), "\n"))
355 }
356}
357
358impl Rule {
359 pub fn display_pretty<'a>(&'a self, def_name: &'a Name) -> impl fmt::Display + 'a {
360 display!(
361 "({}{}) =\n {}",
362 def_name,
363 DisplayJoin(|| self.pats.iter().map(|x| display!(" {x}")), ""),
364 self.body.display_pretty(2)
365 )
366 }
367
368 pub fn display_def_aux<'a>(&'a self, def_name: &'a Name, tab: usize) -> impl fmt::Display + 'a {
369 display!(
370 "({}{}) =\n {:tab$}{}",
371 def_name,
372 DisplayJoin(|| self.pats.iter().map(|x| display!(" {x}")), ""),
373 "",
374 self.body.display_pretty(tab + 2)
375 )
376 }
377}
378
379impl Term {
380 pub fn display_pretty(&self, tab: usize) -> impl fmt::Display + '_ {
381 maybe_grow(|| {
382 DisplayFn(move |f| match self {
383 Term::Lam { tag, pat, bod } => match &**pat {
384 Pattern::Fan(_, _, _) => {
385 let name = gen_fan_pat_name();
386 write!(
387 f,
388 "{}λ{name} let {} = {name};\n{:tab$}{}",
389 tag.display_padded(),
390 pat,
391 "",
392 bod.display_pretty(tab),
393 )
394 }
395 _ => write!(f, "{}λ{} {}", tag.display_padded(), pat, bod.display_pretty(tab)),
396 },
397 Term::Var { nam } => write!(f, "{nam}"),
398 Term::Link { nam } => write!(f, "${nam}"),
399 Term::Let { pat, val, nxt } => {
400 write!(f, "let {} = {};\n{:tab$}{}", pat, val.display_pretty(tab), "", nxt.display_pretty(tab))
401 }
402 Term::With { typ, bod } => {
403 writeln!(f, "with {typ} {{")?;
404 writeln!(f, "{:tab$}{}", "", bod.display_pretty(tab + 2), tab = tab + 2)?;
405 write!(f, "{:tab$}}}", "")
406 }
407 Term::Ask { pat, val, nxt } => {
408 write!(f, "ask {} = {};\n{:tab$}{}", pat, val.display_pretty(tab), "", nxt.display_pretty(tab))
409 }
410 Term::Use { nam, val, nxt } => {
411 write!(
412 f,
413 "use {} = {};\n{:tab$}{}",
414 var_as_str(nam),
415 val.display_pretty(tab),
416 "",
417 nxt.display_pretty(tab)
418 )
419 }
420 Term::App { tag, fun, arg } => {
421 write!(
422 f,
423 "{}({} {})",
424 tag.display_padded(),
425 fun.display_app_pretty(tag, tab),
426 arg.display_pretty(tab)
427 )
428 }
429 Term::Fan { fan: FanKind::Tup, tag, els } => {
430 write!(f, "{}({})", tag, DisplayJoin(|| els.iter().map(|e| e.display_pretty(tab)), ", "))
431 }
432 Term::Fan { fan: FanKind::Dup, tag, els } => {
433 write!(
434 f,
435 "{}{{{}}}",
436 tag.display_padded(),
437 DisplayJoin(|| els.iter().map(|e| e.display_pretty(tab)), " ")
438 )
439 }
440 Term::List { els } => {
441 write!(f, "[{}]", DisplayJoin(|| els.iter().map(|e| e.display_pretty(tab)), " "))
442 }
443 Term::Oper { opr, fst, snd } => {
444 write!(f, "({} {} {})", opr, fst.display_pretty(tab), snd.display_pretty(tab))
445 }
446 Term::Mat { bnd, arg, with_bnd, with_arg, arms } => {
447 write!(f, "match ")?;
448 if let Some(bnd) = bnd {
449 write!(f, "{} = ", bnd)?;
450 }
451 write!(f, "{} ", arg.display_pretty(tab))?;
452 if !with_bnd.is_empty() {
453 write!(f, "with ")?;
454 for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
455 write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
456 }
457 }
458 write!(f, "{{ ")?;
459 for arm in arms {
460 write!(f, "\n{:tab$}{}", "", var_as_str(&arm.0), tab = tab + 2)?;
461 for var in &arm.1 {
462 write!(f, " {}", var_as_str(var))?;
463 }
464 write!(f, ": {}; ", arm.2.display_pretty(tab + 4))?;
465 }
466 write!(f, "\n{:tab$}}}", "")
467 }
468 Term::Swt { bnd, arg, with_bnd, with_arg, pred, arms } => {
469 write!(f, "switch ")?;
470 if let Some(bnd) = bnd {
471 write!(f, "{bnd} = ")?;
472 }
473 write!(f, "{} ", arg.display_pretty(tab))?;
474 if !with_bnd.is_empty() {
475 write!(f, "with ")?;
476 for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
477 write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
478 }
479 }
480 writeln!(f, "{{")?;
481 for (i, arm) in arms.iter().enumerate() {
482 if i == arms.len() - 1 {
483 write!(f, "{:tab$}_", "", tab = tab + 2)?;
484 if let Some(pred) = pred {
485 write!(f, " {pred}")?;
486 }
487 } else {
488 write!(f, "{:tab$}{i}", "", tab = tab + 2)?;
489 }
490 writeln!(f, ": {};", arm.display_pretty(tab + 4))?;
491 }
492 write!(f, "{:tab$}}}", "")
493 }
494 Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
495 write!(f, "fold ")?;
496 if let Some(bnd) = bnd {
497 write!(f, "{} = ", bnd)?;
498 }
499 write!(f, "{} ", arg.display_pretty(tab))?;
500 if !with_bnd.is_empty() {
501 write!(f, "with ")?;
502 for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
503 write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
504 }
505 }
506 write!(f, "{{ ")?;
507 for arm in arms {
508 write!(f, "\n{:tab$}{}", "", var_as_str(&arm.0), tab = tab + 2)?;
509 for var in &arm.1 {
510 write!(f, " {}", var_as_str(var))?;
511 }
512 write!(f, ": {}; ", arm.2.display_pretty(tab + 4))?;
513 }
514 write!(f, "\n{:tab$}}}", "")
515 }
516 Term::Bend { bnd: bind, arg: init, cond, step, base } => {
517 write!(f, "bend ")?;
518 for (bind, init) in bind.iter().zip(init) {
519 if let Some(bind) = bind {
520 write!(f, "{} = ", bind)?;
521 }
522 write!(f, "{}, ", init)?;
523 }
524 writeln!(f, "{{")?;
525 writeln!(f, "{:tab$}when {}:", "", cond.display_pretty(tab + 2), tab = tab + 2)?;
526 writeln!(f, "{:tab$}{}", "", step.display_pretty(tab + 4), tab = tab + 4)?;
527 writeln!(f, "{:tab$}else:", "", tab = tab + 2)?;
528 writeln!(f, "{:tab$}{}", "", base.display_pretty(tab + 4), tab = tab + 4)?;
529 write!(f, "{:tab$}}}", "")
530 }
531 Term::Open { typ, var, bod } => {
532 write!(f, "open {typ} {var};\n{:tab$}{}", "", bod.display_pretty(tab))
533 }
534 Term::Nat { val } => write!(f, "#{val}"),
535 Term::Num { val: Num::U24(val) } => write!(f, "{val}"),
536 Term::Num { val: Num::I24(val) } => write!(f, "{}{}", if *val < 0 { "-" } else { "+" }, val.abs()),
537 Term::Num { val: Num::F24(val) } => write!(f, "{val:.3}"),
538 Term::Str { val } => write!(f, "{val:?}"),
539 Term::Ref { nam } => write!(f, "{nam}"),
540 Term::Def { def, nxt } => {
541 write!(f, "def ")?;
542 for (i, rule) in def.rules.iter().enumerate() {
543 if i == 0 {
544 writeln!(f, "{}", rule.display_def_aux(&def.name, tab + 4))?;
545 } else {
546 writeln!(f, "{:tab$}{}", "", rule.display_def_aux(&def.name, tab + 4), tab = tab + 4)?;
547 }
548 }
549 write!(f, "{:tab$}{}", "", nxt.display_pretty(tab))
550 }
551 Term::Era => write!(f, "*"),
552 Term::Err => write!(f, "<Error>"),
553 })
554 })
555 }
556
557 fn display_app_pretty<'a>(&'a self, tag: &'a Tag, tab: usize) -> impl fmt::Display + 'a {
558 maybe_grow(|| {
559 DisplayFn(move |f| match self {
560 Term::App { tag: tag2, fun, arg } if tag2 == tag => {
561 write!(f, "{} {}", fun.display_app_pretty(tag, tab), arg.display_pretty(tab))
562 }
563 _ => write!(f, "{}", self.display_pretty(tab)),
564 })
565 })
566 }
567}