Skip to main content

graphix_compiler/expr/
print.rs

1use super::Sig;
2use crate::{
3    expr::{
4        parser, ApplyExpr, BindExpr, BindSig, Doc, Expr, ExprKind, LambdaExpr,
5        ModuleKind, Sandbox, SelectExpr, SigItem, SigKind, StructExpr, StructWithExpr,
6        TypeDefExpr,
7    },
8    typ::Type,
9};
10use compact_str::format_compact;
11use netidx::{path::Path, utils::Either};
12use netidx_value::{parser::VAL_ESC, Value};
13use poolshark::local::LPooled;
14use std::fmt::{self, Formatter, Write};
15
16fn pretty_print_exprs_int<'a, A, F: Fn(&'a A) -> &'a Expr>(
17    buf: &mut PrettyBuf,
18    exprs: &'a [A],
19    open: &str,
20    close: &str,
21    sep: &str,
22    f: F,
23) -> fmt::Result {
24    writeln!(buf, "{}", open)?;
25    buf.with_indent::<fmt::Result, _>(2, |buf| {
26        for i in 0..exprs.len() {
27            f(&exprs[i]).kind.fmt_pretty(buf)?;
28            if i < exprs.len() - 1 {
29                buf.kill_newline();
30                writeln!(buf, "{}", sep)?
31            }
32        }
33        Ok(())
34    })?;
35    writeln!(buf, "{}", close)
36}
37
38fn pretty_print_exprs(
39    buf: &mut PrettyBuf,
40    exprs: &[Expr],
41    open: &str,
42    close: &str,
43    sep: &str,
44) -> fmt::Result {
45    pretty_print_exprs_int(buf, exprs, open, close, sep, |a| a)
46}
47
48#[derive(Debug)]
49pub struct PrettyBuf {
50    pub indent: usize,
51    pub limit: usize,
52    pub buf: LPooled<String>,
53}
54
55impl PrettyBuf {
56    pub fn new(limit: usize) -> Self {
57        Self { indent: 0, limit, buf: LPooled::take() }
58    }
59
60    pub fn len(&self) -> usize {
61        self.buf.len()
62    }
63
64    pub fn newline(&self) -> bool {
65        self.buf.chars().next_back().map(|c| c == '\n').unwrap_or(true)
66    }
67
68    pub fn push_indent(&mut self) {
69        if self.newline() {
70            self.buf.extend((0..self.indent).into_iter().map(|_| ' '));
71        }
72    }
73
74    pub fn with_indent<R, F: FnOnce(&mut Self) -> R>(&mut self, inc: usize, f: F) -> R {
75        self.indent += inc;
76        let r = f(self);
77        self.indent -= inc;
78        r
79    }
80
81    pub fn kill_newline(&mut self) {
82        if let Some('\n') = self.buf.chars().next_back() {
83            self.buf.pop();
84        }
85    }
86}
87
88impl fmt::Write for PrettyBuf {
89    fn write_char(&mut self, c: char) -> fmt::Result {
90        self.push_indent();
91        self.buf.write_char(c)
92    }
93
94    fn write_str(&mut self, s: &str) -> fmt::Result {
95        self.push_indent();
96        self.buf.write_str(s)
97    }
98
99    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
100        self.push_indent();
101        self.buf.write_fmt(args)
102    }
103}
104
105pub trait PrettyDisplay: fmt::Display {
106    /// Do the actual pretty print. This should not be called directly, it will
107    /// be called by fmt_pretty when we know it can't fit on a single line.
108    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result;
109
110    /// This is the user facing fmt method, it will first try to format the
111    /// expression on a single line, and if that is impossible it will call the
112    /// pretty printer.
113    fn fmt_pretty(&self, buf: &mut PrettyBuf) -> fmt::Result {
114        use fmt::Write;
115        let start = buf.len();
116        writeln!(buf, "{}", self)?;
117        // CR codex for eric: This compares total bytes written, not line width. If we're mid-line
118        // or have indentation, we can exceed the intended column limit while still passing this
119        // check. The old printer tracked line start/indent; consider restoring per-line width.
120        if buf.len() - start <= buf.limit {
121            return Ok(());
122        } else {
123            buf.buf.truncate(start);
124            self.fmt_pretty_inner(buf)
125        }
126    }
127
128    /// Pretty print to a pooled string
129    fn to_string_pretty(&self, limit: usize) -> LPooled<String> {
130        let mut buf = PrettyBuf::new(limit);
131        self.fmt_pretty(&mut buf).unwrap();
132        buf.buf
133    }
134}
135
136impl fmt::Display for Doc {
137    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
138        if let Some(doc) = self.0.as_ref() {
139            if doc == "" {
140                writeln!(f, "///")?;
141            } else {
142                for line in doc.lines() {
143                    writeln!(f, "///{line}")?;
144                }
145            }
146        }
147        Ok(())
148    }
149}
150
151impl PrettyDisplay for Doc {
152    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
153        if let Some(doc) = self.0.as_ref() {
154            if doc == "" {
155                writeln!(buf, "///")?;
156            } else {
157                for line in doc.lines() {
158                    writeln!(buf, "///{line}")?;
159                }
160            }
161        }
162        Ok(())
163    }
164}
165
166impl TypeDefExpr {
167    fn write_name_and_params(&self, f: &mut impl fmt::Write) -> fmt::Result {
168        write!(f, "type {}", self.name)?;
169        if !self.params.is_empty() {
170            write!(f, "<")?;
171            for (i, (tv, ct)) in self.params.iter().enumerate() {
172                write!(f, "{tv}")?;
173                if let Some(ct) = ct {
174                    write!(f, ": {ct}")?;
175                }
176                if i < self.params.len() - 1 {
177                    write!(f, ", ")?;
178                }
179            }
180            write!(f, ">")?;
181        }
182        Ok(())
183    }
184}
185
186impl fmt::Display for TypeDefExpr {
187    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188        self.write_name_and_params(f)?;
189        match &self.typ {
190            Type::Abstract { .. } => Ok(()),
191            typ => write!(f, " = {typ}"),
192        }
193    }
194}
195
196impl PrettyDisplay for TypeDefExpr {
197    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
198        self.write_name_and_params(buf)?;
199        match &self.typ {
200            Type::Abstract { .. } => Ok(()),
201            typ => {
202                writeln!(buf, " =")?;
203                buf.with_indent(2, |buf| typ.fmt_pretty(buf))
204            }
205        }
206    }
207}
208
209impl fmt::Display for Sandbox {
210    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
211        macro_rules! write_sandbox {
212            ($kind:literal, $l:expr) => {{
213                write!(f, "sandbox {} [ ", $kind)?;
214                for (i, p) in $l.iter().enumerate() {
215                    if i < $l.len() - 1 {
216                        write!(f, "{}, ", p)?
217                    } else {
218                        write!(f, "{}", p)?
219                    }
220                }
221                write!(f, " ]")
222            }};
223        }
224        match self {
225            Sandbox::Unrestricted => write!(f, "sandbox unrestricted"),
226            Sandbox::Blacklist(l) => write_sandbox!("blacklist", l),
227            Sandbox::Whitelist(l) => write_sandbox!("whitelist", l),
228        }
229    }
230}
231
232impl PrettyDisplay for Sandbox {
233    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
234        macro_rules! write_sandbox {
235            ($kind:literal, $l:expr) => {{
236                writeln!(buf, "sandbox {} [ ", $kind)?;
237                buf.with_indent::<fmt::Result, _>(2, |buf| {
238                    for (i, p) in $l.iter().enumerate() {
239                        if i < $l.len() - 1 {
240                            writeln!(buf, "{}, ", p)?
241                        } else {
242                            writeln!(buf, "{}", p)?
243                        }
244                    }
245                    Ok(())
246                })?;
247                write!(buf, " ]")
248            }};
249        }
250        match self {
251            Sandbox::Blacklist(l) => write_sandbox!("blacklist", l),
252            Sandbox::Whitelist(l) => write_sandbox!("whitelist", l),
253            Sandbox::Unrestricted => writeln!(buf, "sandbox unrestricted"),
254        }
255    }
256}
257
258impl fmt::Display for BindSig {
259    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
260        write!(f, "val {}: {}", self.name, self.typ)
261    }
262}
263
264impl PrettyDisplay for BindSig {
265    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
266        write!(buf, "val {}: ", self.name)?;
267        self.typ.fmt_pretty(buf)
268    }
269}
270
271impl fmt::Display for SigItem {
272    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
273        write!(f, "{}", self.doc)?;
274        match &self.kind {
275            SigKind::TypeDef(td) => write!(f, "{td}"),
276            SigKind::Bind(bind) => write!(f, "{bind}"),
277            SigKind::Module(name) => write!(f, "mod {name}"),
278            SigKind::Use(path) => write!(f, "use {path}"),
279        }
280    }
281}
282
283impl PrettyDisplay for SigItem {
284    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
285        write!(buf, "{}", self.doc)?;
286        match &self.kind {
287            SigKind::Bind(b) => b.fmt_pretty(buf),
288            SigKind::TypeDef(d) => d.fmt_pretty(buf),
289            SigKind::Module(name) => writeln!(buf, "mod {name}"),
290            SigKind::Use(path) => writeln!(buf, "use {path}"),
291        }
292    }
293}
294
295impl fmt::Display for Sig {
296    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297        if !self.toplevel {
298            write!(f, "sig {{ ")?;
299        }
300        for (i, si) in self.iter().enumerate() {
301            write!(f, "{si}")?;
302            if i < self.len() - 1 {
303                write!(f, "; ")?
304            }
305        }
306        if !self.toplevel {
307            write!(f, " }}")?
308        }
309        Ok(())
310    }
311}
312
313impl PrettyDisplay for Sig {
314    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
315        if !self.toplevel {
316            writeln!(buf, "sig {{")?;
317        }
318        buf.with_indent(2, |buf| {
319            for (i, si) in self.iter().enumerate() {
320                si.fmt_pretty(buf)?;
321                if i < self.len() - 1 {
322                    buf.kill_newline();
323                    writeln!(buf, ";")?
324                }
325            }
326            Ok(())
327        })?;
328        if !self.toplevel {
329            writeln!(buf, "}}")?
330        }
331        Ok(())
332    }
333}
334
335impl fmt::Display for BindExpr {
336    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
337        let BindExpr { rec, pattern, typ, value } = self;
338        let rec = if *rec { " rec" } else { "" };
339        match typ {
340            None => write!(f, "let{} {pattern} = {value}", rec),
341            Some(typ) => write!(f, "let{} {pattern}: {typ} = {value}", rec),
342        }
343    }
344}
345
346impl PrettyDisplay for BindExpr {
347    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
348        let BindExpr { rec, pattern, typ, value } = self;
349        let rec = if *rec { " rec" } else { "" };
350        match typ {
351            None => writeln!(buf, "let{} {pattern} = ", rec)?,
352            Some(typ) => writeln!(buf, "let{} {pattern}: {typ} = ", rec)?,
353        }
354        buf.with_indent(2, |buf| value.fmt_pretty(buf))
355    }
356}
357
358impl fmt::Display for StructWithExpr {
359    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
360        let Self { source, replace } = self;
361        match &source.kind {
362            ExprKind::Ref { .. } => write!(f, "{{ {source} with ")?,
363            _ => write!(f, "{{ ({source}) with ")?,
364        }
365        for (i, (name, e)) in replace.iter().enumerate() {
366            match &e.kind {
367                ExprKind::Ref { name: n }
368                    if Path::dirname(&**n).is_none()
369                        && Path::basename(&**n) == Some(&**name) =>
370                {
371                    write!(f, "{name}")?
372                }
373                _ => write!(f, "{name}: {e}")?,
374            }
375            if i < replace.len() - 1 {
376                write!(f, ", ")?
377            }
378        }
379        write!(f, " }}")
380    }
381}
382
383impl PrettyDisplay for StructWithExpr {
384    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
385        let Self { source, replace } = self;
386        match &source.kind {
387            ExprKind::Ref { .. } => writeln!(buf, "{{ {source} with")?,
388            _ => writeln!(buf, "{{ ({source}) with")?,
389        }
390        buf.with_indent::<fmt::Result, _>(2, |buf| {
391            for (i, (name, e)) in replace.iter().enumerate() {
392                match &e.kind {
393                    ExprKind::Ref { name: n }
394                        if Path::dirname(&**n).is_none()
395                            && Path::basename(&**n) == Some(&**name) =>
396                    {
397                        write!(buf, "{name}")?
398                    }
399                    e => {
400                        write!(buf, "{name}: ")?;
401                        buf.with_indent(2, |buf| e.fmt_pretty(buf))?
402                    }
403                }
404                if i < replace.len() - 1 {
405                    buf.kill_newline();
406                    writeln!(buf, ",")?
407                }
408            }
409            Ok(())
410        })?;
411        writeln!(buf, "}}")
412    }
413}
414
415impl fmt::Display for StructExpr {
416    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
417        let Self { args } = self;
418        write!(f, "{{ ")?;
419        for (i, (n, e)) in args.iter().enumerate() {
420            match &e.kind {
421                ExprKind::Ref { name }
422                    if Path::dirname(&**name).is_none()
423                        && Path::basename(&**name) == Some(&**n) =>
424                {
425                    write!(f, "{n}")?
426                }
427                _ => write!(f, "{n}: {e}")?,
428            }
429            if i < args.len() - 1 {
430                write!(f, ", ")?
431            }
432        }
433        write!(f, " }}")
434    }
435}
436
437impl PrettyDisplay for StructExpr {
438    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
439        let Self { args } = self;
440        writeln!(buf, "{{")?;
441        buf.with_indent::<fmt::Result, _>(2, |buf| {
442            for (i, (n, e)) in args.iter().enumerate() {
443                match &e.kind {
444                    ExprKind::Ref { name }
445                        if Path::dirname(&**name).is_none()
446                            && Path::basename(&**name) == Some(&**n) =>
447                    {
448                        write!(buf, "{n}")?
449                    }
450                    _ => {
451                        write!(buf, "{n}: ")?;
452                        buf.with_indent(2, |buf| e.fmt_pretty(buf))?;
453                    }
454                }
455                if i < args.len() - 1 {
456                    buf.kill_newline();
457                    writeln!(buf, ", ")?
458                }
459            }
460            Ok(())
461        })?;
462        writeln!(buf, "}}")
463    }
464}
465
466impl fmt::Display for ApplyExpr {
467    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
468        let Self { args, function } = self;
469        match &function.kind {
470            ExprKind::Ref { name: _ } => write!(f, "{function}")?,
471            function => write!(f, "({function})")?,
472        }
473        write!(f, "(")?;
474        for i in 0..args.len() {
475            match &args[i].0 {
476                None => write!(f, "{}", &args[i].1)?,
477                Some(name) => match &args[i].1.kind {
478                    ExprKind::Ref { name: n }
479                        if Path::dirname(&n.0).is_none()
480                            && Path::basename(&n.0) == Some(name.as_str()) =>
481                    {
482                        write!(f, "#{name}")?
483                    }
484                    _ => write!(f, "#{name}: {}", &args[i].1)?,
485                },
486            }
487            if i < args.len() - 1 {
488                write!(f, ", ")?
489            }
490        }
491        write!(f, ")")
492    }
493}
494
495impl PrettyDisplay for ApplyExpr {
496    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
497        let Self { args, function } = self;
498        match &function.kind {
499            ExprKind::Ref { .. } => function.fmt_pretty(buf)?,
500            e => {
501                write!(buf, "(")?;
502                e.fmt_pretty(buf)?;
503                buf.kill_newline();
504                write!(buf, ")")?;
505            }
506        }
507        buf.kill_newline();
508        writeln!(buf, "(")?;
509        buf.with_indent::<fmt::Result, _>(2, |buf| {
510            for i in 0..args.len() {
511                match &args[i].0 {
512                    None => args[i].1.fmt_pretty(buf)?,
513                    Some(name) => match &args[i].1.kind {
514                        ExprKind::Ref { name: n }
515                            if Path::dirname(&n.0).is_none()
516                                && Path::basename(&n.0) == Some(name.as_str()) =>
517                        {
518                            writeln!(buf, "#{name}")?
519                        }
520                        _ => {
521                            write!(buf, "#{name}: ")?;
522                            buf.with_indent(2, |buf| args[i].1.fmt_pretty(buf))?
523                        }
524                    },
525                }
526                if i < args.len() - 1 {
527                    buf.kill_newline();
528                    writeln!(buf, ",")?
529                }
530            }
531            Ok(())
532        })?;
533        writeln!(buf, ")")
534    }
535}
536
537impl fmt::Display for LambdaExpr {
538    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
539        let LambdaExpr { args, vargs, rtype, constraints, throws, body } = self;
540        for (i, (tvar, typ)) in constraints.iter().enumerate() {
541            write!(f, "{tvar}: {typ}")?;
542            if i < constraints.len() - 1 {
543                write!(f, ", ")?;
544            }
545        }
546        write!(f, "|")?;
547        for (i, a) in args.iter().enumerate() {
548            match &a.labeled {
549                None => {
550                    write!(f, "{}", a.pattern)?;
551                    if let Some(t) = &a.constraint {
552                        write!(f, ": {t}")?
553                    }
554                }
555                Some(def) => {
556                    write!(f, "#{}", a.pattern)?;
557                    if let Some(t) = &a.constraint {
558                        write!(f, ": {t}")?
559                    }
560                    if let Some(def) = def {
561                        write!(f, " = {def}")?;
562                    }
563                }
564            }
565            if vargs.is_some() || i < args.len() - 1 {
566                write!(f, ", ")?
567            }
568        }
569        if let Some(typ) = vargs {
570            match typ {
571                None => write!(f, "@args")?,
572                Some(typ) => write!(f, "@args: {typ}")?,
573            }
574        }
575        write!(f, "| ")?;
576        if let Some(t) = rtype {
577            match t {
578                Type::Fn(ft) => write!(f, "-> ({ft}) ")?,
579                Type::ByRef(t) => match &**t {
580                    Type::Fn(ft) => write!(f, "-> &({ft}) ")?,
581                    t => write!(f, "-> &{t} ")?,
582                },
583                t => write!(f, "-> {t} ")?,
584            }
585        }
586        if let Some(t) = throws {
587            write!(f, "throws {t} ")?
588        }
589        match body {
590            Either::Right(builtin) => write!(f, "'{builtin}"),
591            Either::Left(body) => write!(f, "{body}"),
592        }
593    }
594}
595
596impl PrettyDisplay for LambdaExpr {
597    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
598        let LambdaExpr { args, vargs, rtype, constraints, throws, body } = self;
599        for (i, (tvar, typ)) in constraints.iter().enumerate() {
600            write!(buf, "{tvar}: {typ}")?;
601            if i < constraints.len() - 1 {
602                write!(buf, ", ")?;
603            }
604        }
605        write!(buf, "|")?;
606        for (i, a) in args.iter().enumerate() {
607            match &a.labeled {
608                None => {
609                    write!(buf, "{}", a.pattern)?;
610                    if let Some(typ) = &a.constraint {
611                        write!(buf, ": {typ}")?;
612                    }
613                }
614                Some(def) => {
615                    write!(buf, "#{}", a.pattern)?;
616                    if let Some(t) = &a.constraint {
617                        write!(buf, ": {t}")?
618                    }
619                    if let Some(def) = def {
620                        write!(buf, " = {def}")?;
621                    }
622                }
623            }
624            if vargs.is_some() || i < args.len() - 1 {
625                write!(buf, ", ")?
626            }
627        }
628        if let Some(typ) = vargs {
629            write!(buf, "@args")?;
630            if let Some(t) = typ {
631                write!(buf, ": {t}")?
632            }
633        }
634        write!(buf, "| ")?;
635        if let Some(t) = rtype {
636            match t {
637                Type::Fn(ft) => write!(buf, "-> ({ft}) ")?,
638                Type::ByRef(t) => match &**t {
639                    Type::Fn(ft) => write!(buf, "-> &({ft}) ")?,
640                    t => write!(buf, "-> &{t} ")?,
641                },
642                t => write!(buf, "-> {t} ")?,
643            }
644        }
645        if let Some(t) = throws {
646            write!(buf, "throws {t} ")?
647        }
648        match body {
649            Either::Right(builtin) => {
650                writeln!(buf, "'{builtin}")
651            }
652            Either::Left(body) => match &body.kind {
653                ExprKind::Do { exprs } => pretty_print_exprs(buf, exprs, "{", "}", ";"),
654                _ => body.fmt_pretty(buf),
655            },
656        }
657    }
658}
659
660impl fmt::Display for SelectExpr {
661    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
662        let SelectExpr { arg, arms } = self;
663        write!(f, "select {arg} {{")?;
664        for (i, (pat, rhs)) in arms.iter().enumerate() {
665            if let Some(tp) = &pat.type_predicate {
666                write!(f, "{tp} as ")?;
667            }
668            write!(f, "{} ", pat.structure_predicate)?;
669            if let Some(guard) = &pat.guard {
670                write!(f, "if {guard} ")?;
671            }
672            write!(f, "=> {rhs}")?;
673            if i < arms.len() - 1 {
674                write!(f, ", ")?
675            }
676        }
677        write!(f, "}}")
678    }
679}
680
681impl PrettyDisplay for SelectExpr {
682    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
683        let SelectExpr { arg, arms } = self;
684        write!(buf, "select ")?;
685        arg.fmt_pretty(buf)?;
686        buf.kill_newline();
687        writeln!(buf, " {{")?;
688        buf.with_indent(2, |buf| {
689            for (i, (pat, expr)) in arms.iter().enumerate() {
690                if let Some(tp) = &pat.type_predicate {
691                    write!(buf, "{tp} as ")?;
692                }
693                write!(buf, "{} ", pat.structure_predicate)?;
694                if let Some(guard) = &pat.guard {
695                    write!(buf, "if ")?;
696                    buf.with_indent(2, |buf| guard.fmt_pretty(buf))?;
697                    buf.kill_newline();
698                    write!(buf, " ")?;
699                }
700                write!(buf, "=> ")?;
701                if let ExprKind::Do { exprs } = &expr.kind {
702                    let term = if i < arms.len() - 1 { "}," } else { "}" };
703                    buf.with_indent(2, |buf| {
704                        pretty_print_exprs(buf, exprs, "{", term, ";")
705                    })?;
706                } else if i < arms.len() - 1 {
707                    buf.with_indent(2, |buf| expr.fmt_pretty(buf))?;
708                    buf.kill_newline();
709                    writeln!(buf, ",")?
710                } else {
711                    buf.with_indent(2, |buf| expr.fmt_pretty(buf))?;
712                }
713            }
714            Ok(())
715        })?;
716        writeln!(buf, "}}")
717    }
718}
719
720impl PrettyDisplay for ExprKind {
721    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
722        macro_rules! binop {
723            ($sep:literal, $lhs:expr, $rhs:expr) => {{
724                writeln!(buf, "{} {}", $lhs, $sep)?;
725                $rhs.fmt_pretty(buf)
726            }};
727        }
728        match self {
729            ExprKind::Constant(_)
730            | ExprKind::NoOp
731            | ExprKind::Use { .. }
732            | ExprKind::Ref { .. }
733            | ExprKind::StructRef { .. }
734            | ExprKind::TupleRef { .. }
735            | ExprKind::TypeDef { .. }
736            | ExprKind::ArrayRef { .. }
737            | ExprKind::MapRef { .. }
738            | ExprKind::ArraySlice { .. }
739            | ExprKind::StringInterpolate { .. }
740            | ExprKind::Module {
741                name: _,
742                value: ModuleKind::Unresolved { .. } | ModuleKind::Resolved { .. },
743            } => {
744                writeln!(buf, "{self}")
745            }
746            ExprKind::ExplicitParens(e) => {
747                writeln!(buf, "(")?;
748                buf.with_indent(2, |buf| e.fmt_pretty(buf))?;
749                writeln!(buf, ")")
750            }
751            ExprKind::Do { exprs } => pretty_print_exprs(buf, exprs, "{", "}", ";"),
752            ExprKind::Array { args } => pretty_print_exprs(buf, args, "[", "]", ","),
753            ExprKind::Tuple { args } => pretty_print_exprs(buf, args, "(", ")", ","),
754            ExprKind::Bind(b) => b.fmt_pretty(buf),
755            ExprKind::StructWith(sw) => sw.fmt_pretty(buf),
756            ExprKind::Module {
757                name,
758                value: ModuleKind::Dynamic { sandbox, sig, source },
759            } => {
760                writeln!(buf, "mod {name} dynamic {{")?;
761                buf.with_indent(2, |buf| {
762                    sandbox.fmt_pretty(buf)?;
763                    buf.kill_newline();
764                    writeln!(buf, ";")?;
765                    sig.fmt_pretty(buf)?;
766                    buf.kill_newline();
767                    writeln!(buf, ";")?;
768                    write!(buf, "source ")?;
769                    buf.with_indent(2, |buf| source.fmt_pretty(buf))?;
770                    buf.kill_newline();
771                    writeln!(buf, ";")
772                })?;
773                writeln!(buf, "}}")
774            }
775            ExprKind::Connect { name, value, deref } => {
776                let deref = if *deref { "*" } else { "" };
777                writeln!(buf, "{deref}{name} <- ")?;
778                buf.with_indent(2, |buf| value.fmt_pretty(buf))
779            }
780            ExprKind::TypeCast { expr, typ } => {
781                writeln!(buf, "cast<{typ}>(")?;
782                buf.with_indent(2, |buf| expr.fmt_pretty(buf))?;
783                writeln!(buf, ")")
784            }
785            ExprKind::Map { args } => {
786                writeln!(buf, "{{")?;
787                buf.with_indent::<fmt::Result, _>(2, |buf| {
788                    for (i, (k, v)) in args.iter().enumerate() {
789                        writeln!(buf, "{k} => {v}")?;
790                        if i < args.len() - 1 {
791                            buf.kill_newline();
792                            writeln!(buf, ",")?
793                        }
794                    }
795                    Ok(())
796                })?;
797                writeln!(buf, "}}")
798            }
799            ExprKind::Any { args } => {
800                write!(buf, "any")?;
801                pretty_print_exprs(buf, args, "(", ")", ",")
802            }
803            ExprKind::Variant { tag: _, args } if args.len() == 0 => {
804                write!(buf, "{self}")
805            }
806            ExprKind::Variant { tag, args } => {
807                write!(buf, "`{tag}")?;
808                pretty_print_exprs(buf, args, "(", ")", ",")
809            }
810            ExprKind::Struct(st) => st.fmt_pretty(buf),
811            ExprKind::Qop(e) => {
812                e.fmt_pretty(buf)?;
813                buf.kill_newline();
814                writeln!(buf, "?")
815            }
816            ExprKind::OrNever(e) => {
817                e.fmt_pretty(buf)?;
818                buf.kill_newline();
819                writeln!(buf, "$")
820            }
821            ExprKind::TryCatch(tc) => {
822                writeln!(buf, "try")?;
823                pretty_print_exprs(buf, &tc.exprs, "", "", "; ")?;
824                match &tc.constraint {
825                    None => write!(buf, "catch({}) => ", tc.bind)?,
826                    Some(t) => write!(buf, "catch({}: {t}) => ", tc.bind)?,
827                }
828                match &tc.handler.kind {
829                    ExprKind::Do { exprs } => {
830                        pretty_print_exprs(buf, exprs, "{", "}", "; ")
831                    }
832                    _ => {
833                        writeln!(buf, "")?;
834                        buf.with_indent(2, |buf| tc.handler.fmt_pretty(buf))
835                    }
836                }
837            }
838            ExprKind::Apply(ae) => ae.fmt_pretty(buf),
839            ExprKind::Lambda(l) => l.fmt_pretty(buf),
840            ExprKind::Eq { lhs, rhs } => binop!("==", lhs, rhs),
841            ExprKind::Ne { lhs, rhs } => binop!("!=", lhs, rhs),
842            ExprKind::Lt { lhs, rhs } => binop!("<", lhs, rhs),
843            ExprKind::Gt { lhs, rhs } => binop!(">", lhs, rhs),
844            ExprKind::Lte { lhs, rhs } => binop!("<=", lhs, rhs),
845            ExprKind::Gte { lhs, rhs } => binop!(">=", lhs, rhs),
846            ExprKind::And { lhs, rhs } => binop!("&&", lhs, rhs),
847            ExprKind::Or { lhs, rhs } => binop!("||", lhs, rhs),
848            ExprKind::Add { lhs, rhs } => binop!("+", lhs, rhs),
849            ExprKind::Sub { lhs, rhs } => binop!("-", lhs, rhs),
850            ExprKind::Mul { lhs, rhs } => binop!("*", lhs, rhs),
851            ExprKind::Div { lhs, rhs } => binop!("/", lhs, rhs),
852            ExprKind::Mod { lhs, rhs } => binop!("%", lhs, rhs),
853            ExprKind::Sample { lhs, rhs } => binop!("~", lhs, rhs),
854            ExprKind::Not { expr } => match &expr.kind {
855                ExprKind::Do { exprs } => pretty_print_exprs(buf, exprs, "!{", "}", ";"),
856                _ => {
857                    write!(buf, "!")?;
858                    expr.fmt_pretty(buf)
859                }
860            },
861            ExprKind::ByRef(e) => {
862                write!(buf, "&")?;
863                e.fmt_pretty(buf)
864            }
865            ExprKind::Deref(e) => {
866                write!(buf, "*")?;
867                buf.with_indent(2, |buf| e.fmt_pretty(buf))
868            }
869            ExprKind::Select(se) => se.fmt_pretty(buf),
870        }
871    }
872}
873
874impl fmt::Display for ExprKind {
875    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
876        fn print_exprs(
877            f: &mut fmt::Formatter,
878            exprs: &[Expr],
879            open: &str,
880            close: &str,
881            sep: &str,
882        ) -> fmt::Result {
883            write!(f, "{open}")?;
884            for i in 0..exprs.len() {
885                write!(f, "{}", &exprs[i])?;
886                if i < exprs.len() - 1 {
887                    write!(f, "{sep}")?
888                }
889            }
890            write!(f, "{close}")
891        }
892        match self {
893            ExprKind::Constant(v @ Value::String(_)) => {
894                v.fmt_ext(f, &parser::GRAPHIX_ESC, true)
895            }
896            ExprKind::NoOp => Ok(()),
897            ExprKind::ExplicitParens(e) => write!(f, "({e})"),
898            ExprKind::Constant(v) => v.fmt_ext(f, &VAL_ESC, true),
899            ExprKind::Bind(b) => write!(f, "{b}"),
900            ExprKind::StructWith(sw) => write!(f, "{sw}"),
901            ExprKind::Connect { name, value, deref } => {
902                let deref = if *deref { "*" } else { "" };
903                write!(f, "{deref}{name} <- {value}")
904            }
905            ExprKind::Use { name } => {
906                write!(f, "use {name}")
907            }
908            ExprKind::Ref { name } => {
909                write!(f, "{name}")
910            }
911            ExprKind::StructRef { source, field } => match &source.kind {
912                ExprKind::Ref { .. } => {
913                    write!(f, "{source}.{field}")
914                }
915                source => write!(f, "({source}).{field}"),
916            },
917            ExprKind::TupleRef { source, field } => match &source.kind {
918                ExprKind::Ref { .. } => {
919                    write!(f, "{source}.{field}")
920                }
921                source => write!(f, "({source}).{field}"),
922            },
923            ExprKind::Module {
924                value:
925                    ModuleKind::Resolved { from_interface: true, .. }
926                    | ModuleKind::Unresolved { from_interface: true },
927                ..
928            } => Ok(()),
929            ExprKind::Module { name, value } => {
930                write!(f, "mod {name}")?;
931                match value {
932                    ModuleKind::Resolved { .. } | ModuleKind::Unresolved { .. } => Ok(()),
933                    ModuleKind::Dynamic { sandbox, sig, source } => {
934                        write!(f, " dynamic {{ {sandbox};")?;
935                        write!(f, " {sig};")?;
936                        write!(f, " source {source} }}")
937                    }
938                }
939            }
940            ExprKind::TypeCast { expr, typ } => write!(f, "cast<{typ}>({expr})"),
941            ExprKind::TypeDef(td) => write!(f, "{td}"),
942            ExprKind::Do { exprs } => print_exprs(f, &**exprs, "{", "}", "; "),
943            ExprKind::Lambda(l) => write!(f, "{l}"),
944            ExprKind::Array { args } => print_exprs(f, args, "[", "]", ", "),
945            ExprKind::Map { args } => {
946                write!(f, "{{")?;
947                for (i, (k, v)) in args.iter().enumerate() {
948                    write!(f, "{k} => {v}")?;
949                    if i < args.len() - 1 {
950                        write!(f, ", ")?
951                    }
952                }
953                write!(f, "}}")
954            }
955            ExprKind::MapRef { source, key } => match &source.kind {
956                ExprKind::Ref { name } => write!(f, "{name}{{{key}}}"),
957                _ => write!(f, "({source}){{{key}}}"),
958            },
959            ExprKind::Any { args } => {
960                write!(f, "any")?;
961                print_exprs(f, args, "(", ")", ", ")
962            }
963            ExprKind::Tuple { args } => print_exprs(f, args, "(", ")", ", "),
964            ExprKind::Variant { tag, args } if args.len() == 0 => {
965                write!(f, "`{tag}")
966            }
967            ExprKind::Variant { tag, args } => {
968                write!(f, "`{tag}")?;
969                print_exprs(f, args, "(", ")", ", ")
970            }
971            ExprKind::Struct(st) => write!(f, "{st}"),
972            ExprKind::Qop(e) => write!(f, "{}?", e),
973            ExprKind::OrNever(e) => write!(f, "{}$", e),
974            ExprKind::TryCatch(tc) => {
975                write!(f, "try ")?;
976                print_exprs(f, &tc.exprs, "", "", "; ")?;
977                match &tc.constraint {
978                    None => write!(f, " catch({}) => {}", tc.bind, tc.handler),
979                    Some(t) => write!(f, " catch({}: {t}) => {}", tc.bind, tc.handler),
980                }
981            }
982            ExprKind::StringInterpolate { args } => {
983                write!(f, "\"")?;
984                for s in args.iter() {
985                    match &s.kind {
986                        ExprKind::Constant(Value::String(s)) if s.len() > 0 => {
987                            let es = parser::GRAPHIX_ESC.escape(&*s);
988                            write!(f, "{es}",)?;
989                        }
990                        s => {
991                            write!(f, "[{s}]")?;
992                        }
993                    }
994                }
995                write!(f, "\"")
996            }
997            ExprKind::ArrayRef { source, i } => match &source.kind {
998                ExprKind::Ref { .. } => {
999                    write!(f, "{}[{}]", source, i)
1000                }
1001                _ => write!(f, "({})[{}]", &source, &i),
1002            },
1003            ExprKind::ArraySlice { source, start, end } => {
1004                let s = match start.as_ref() {
1005                    None => "",
1006                    Some(e) => &format_compact!("{e}"),
1007                };
1008                let e = match &end.as_ref() {
1009                    None => "",
1010                    Some(e) => &format_compact!("{e}"),
1011                };
1012                match &source.kind {
1013                    ExprKind::Ref { .. } => {
1014                        write!(f, "{}[{}..{}]", source, s, e)
1015                    }
1016                    _ => write!(f, "({})[{}..{}]", source, s, e),
1017                }
1018            }
1019            ExprKind::Apply(ap) => write!(f, "{ap}"),
1020            ExprKind::Select(se) => write!(f, "{se}"),
1021            ExprKind::Eq { lhs, rhs } => write!(f, "{lhs} == {rhs}"),
1022            ExprKind::Ne { lhs, rhs } => write!(f, "{lhs} != {rhs}"),
1023            ExprKind::Gt { lhs, rhs } => write!(f, "{lhs} > {rhs}"),
1024            ExprKind::Lt { lhs, rhs } => write!(f, "{lhs} < {rhs}"),
1025            ExprKind::Gte { lhs, rhs } => write!(f, "{lhs} >= {rhs}"),
1026            ExprKind::Lte { lhs, rhs } => write!(f, "{lhs} <= {rhs}"),
1027            ExprKind::And { lhs, rhs } => write!(f, "{lhs} && {rhs}"),
1028            ExprKind::Or { lhs, rhs } => write!(f, "{lhs} || {rhs}"),
1029            ExprKind::Add { lhs, rhs } => write!(f, "{lhs} + {rhs}"),
1030            ExprKind::Sub { lhs, rhs } => write!(f, "{lhs} - {rhs}"),
1031            ExprKind::Mul { lhs, rhs } => write!(f, "{lhs} * {rhs}"),
1032            ExprKind::Div { lhs, rhs } => write!(f, "{lhs} / {rhs}"),
1033            ExprKind::Mod { lhs, rhs } => write!(f, "{lhs} % {rhs}"),
1034            ExprKind::Sample { lhs, rhs } => write!(f, "{lhs} ~ {rhs}"),
1035            ExprKind::ByRef(e) => write!(f, "&{e}"),
1036            ExprKind::Deref(e) => write!(f, "*{e}"),
1037            ExprKind::Not { expr } => write!(f, "!{expr}"),
1038        }
1039    }
1040}