bend/fun/
display.rs

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
5/* Some aux structures for things that are not so simple to display */
6
7pub 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
41/* The actual display implementations */
42
43static 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
336/* Pretty printing  */
337
338impl 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}