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        write!(f, " = {}", self.typ)
190    }
191}
192
193impl PrettyDisplay for TypeDefExpr {
194    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
195        self.write_name_and_params(buf)?;
196        writeln!(buf, " =")?;
197        buf.with_indent(2, |buf| self.typ.fmt_pretty(buf))
198    }
199}
200
201impl fmt::Display for Sandbox {
202    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
203        macro_rules! write_sandbox {
204            ($kind:literal, $l:expr) => {{
205                write!(f, "sandbox {} [ ", $kind)?;
206                for (i, p) in $l.iter().enumerate() {
207                    if i < $l.len() - 1 {
208                        write!(f, "{}, ", p)?
209                    } else {
210                        write!(f, "{}", p)?
211                    }
212                }
213                write!(f, " ]")
214            }};
215        }
216        match self {
217            Sandbox::Unrestricted => write!(f, "sandbox unrestricted"),
218            Sandbox::Blacklist(l) => write_sandbox!("blacklist", l),
219            Sandbox::Whitelist(l) => write_sandbox!("whitelist", l),
220        }
221    }
222}
223
224impl PrettyDisplay for Sandbox {
225    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
226        macro_rules! write_sandbox {
227            ($kind:literal, $l:expr) => {{
228                writeln!(buf, "sandbox {} [ ", $kind)?;
229                buf.with_indent::<fmt::Result, _>(2, |buf| {
230                    for (i, p) in $l.iter().enumerate() {
231                        if i < $l.len() - 1 {
232                            writeln!(buf, "{}, ", p)?
233                        } else {
234                            writeln!(buf, "{}", p)?
235                        }
236                    }
237                    Ok(())
238                })?;
239                write!(buf, " ]")
240            }};
241        }
242        match self {
243            Sandbox::Blacklist(l) => write_sandbox!("blacklist", l),
244            Sandbox::Whitelist(l) => write_sandbox!("whitelist", l),
245            Sandbox::Unrestricted => writeln!(buf, "sandbox unrestricted"),
246        }
247    }
248}
249
250impl fmt::Display for BindSig {
251    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
252        write!(f, "val {}: {}", self.name, self.typ)
253    }
254}
255
256impl PrettyDisplay for BindSig {
257    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
258        write!(buf, "val {}: ", self.name)?;
259        self.typ.fmt_pretty(buf)
260    }
261}
262
263impl fmt::Display for SigItem {
264    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
265        write!(f, "{}", self.doc)?;
266        match &self.kind {
267            SigKind::TypeDef(td) => write!(f, "{td}"),
268            SigKind::Bind(bind) => write!(f, "{bind}"),
269            SigKind::Module(name) => write!(f, "mod {name}"),
270            SigKind::Use(path) => write!(f, "use {path}"),
271        }
272    }
273}
274
275impl PrettyDisplay for SigItem {
276    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
277        write!(buf, "{}", self.doc)?;
278        match &self.kind {
279            SigKind::Bind(b) => b.fmt_pretty(buf),
280            SigKind::TypeDef(d) => d.fmt_pretty(buf),
281            SigKind::Module(name) => writeln!(buf, "mod {name}"),
282            SigKind::Use(path) => writeln!(buf, "use {path}"),
283        }
284    }
285}
286
287impl fmt::Display for Sig {
288    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289        if !self.toplevel {
290            write!(f, "sig {{ ")?;
291        }
292        for (i, si) in self.iter().enumerate() {
293            write!(f, "{si}")?;
294            if i < self.len() - 1 {
295                write!(f, "; ")?
296            }
297        }
298        if !self.toplevel {
299            write!(f, " }}")?
300        }
301        Ok(())
302    }
303}
304
305impl PrettyDisplay for Sig {
306    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
307        if !self.toplevel {
308            writeln!(buf, "sig {{")?;
309        }
310        buf.with_indent(2, |buf| {
311            for (i, si) in self.iter().enumerate() {
312                si.fmt_pretty(buf)?;
313                if i < self.len() - 1 {
314                    buf.kill_newline();
315                    writeln!(buf, ";")?
316                }
317            }
318            Ok(())
319        })?;
320        if !self.toplevel {
321            writeln!(buf, "}}")?
322        }
323        Ok(())
324    }
325}
326
327impl fmt::Display for BindExpr {
328    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
329        let BindExpr { rec, pattern, typ, value } = self;
330        let rec = if *rec { " rec" } else { "" };
331        match typ {
332            None => write!(f, "let{} {pattern} = {value}", rec),
333            Some(typ) => write!(f, "let{} {pattern}: {typ} = {value}", rec),
334        }
335    }
336}
337
338impl PrettyDisplay for BindExpr {
339    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
340        let BindExpr { rec, pattern, typ, value } = self;
341        let rec = if *rec { " rec" } else { "" };
342        match typ {
343            None => writeln!(buf, "let{} {pattern} = ", rec)?,
344            Some(typ) => writeln!(buf, "let{} {pattern}: {typ} = ", rec)?,
345        }
346        buf.with_indent(2, |buf| value.fmt_pretty(buf))
347    }
348}
349
350impl fmt::Display for StructWithExpr {
351    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
352        let Self { source, replace } = self;
353        match &source.kind {
354            ExprKind::Ref { .. } => write!(f, "{{ {source} with ")?,
355            _ => write!(f, "{{ ({source}) with ")?,
356        }
357        for (i, (name, e)) in replace.iter().enumerate() {
358            match &e.kind {
359                ExprKind::Ref { name: n }
360                    if Path::dirname(&**n).is_none()
361                        && Path::basename(&**n) == Some(&**name) =>
362                {
363                    write!(f, "{name}")?
364                }
365                _ => write!(f, "{name}: {e}")?,
366            }
367            if i < replace.len() - 1 {
368                write!(f, ", ")?
369            }
370        }
371        write!(f, " }}")
372    }
373}
374
375impl PrettyDisplay for StructWithExpr {
376    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
377        let Self { source, replace } = self;
378        match &source.kind {
379            ExprKind::Ref { .. } => writeln!(buf, "{{ {source} with")?,
380            _ => writeln!(buf, "{{ ({source}) with")?,
381        }
382        buf.with_indent::<fmt::Result, _>(2, |buf| {
383            for (i, (name, e)) in replace.iter().enumerate() {
384                match &e.kind {
385                    ExprKind::Ref { name: n }
386                        if Path::dirname(&**n).is_none()
387                            && Path::basename(&**n) == Some(&**name) =>
388                    {
389                        write!(buf, "{name}")?
390                    }
391                    e => {
392                        write!(buf, "{name}: ")?;
393                        buf.with_indent(2, |buf| e.fmt_pretty(buf))?
394                    }
395                }
396                if i < replace.len() - 1 {
397                    buf.kill_newline();
398                    writeln!(buf, ",")?
399                }
400            }
401            Ok(())
402        })?;
403        writeln!(buf, "}}")
404    }
405}
406
407impl fmt::Display for StructExpr {
408    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
409        let Self { args } = self;
410        write!(f, "{{ ")?;
411        for (i, (n, e)) in args.iter().enumerate() {
412            match &e.kind {
413                ExprKind::Ref { name }
414                    if Path::dirname(&**name).is_none()
415                        && Path::basename(&**name) == Some(&**n) =>
416                {
417                    write!(f, "{n}")?
418                }
419                _ => write!(f, "{n}: {e}")?,
420            }
421            if i < args.len() - 1 {
422                write!(f, ", ")?
423            }
424        }
425        write!(f, " }}")
426    }
427}
428
429impl PrettyDisplay for StructExpr {
430    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
431        let Self { args } = self;
432        writeln!(buf, "{{")?;
433        buf.with_indent::<fmt::Result, _>(2, |buf| {
434            for (i, (n, e)) in args.iter().enumerate() {
435                match &e.kind {
436                    ExprKind::Ref { name }
437                        if Path::dirname(&**name).is_none()
438                            && Path::basename(&**name) == Some(&**n) =>
439                    {
440                        write!(buf, "{n}")?
441                    }
442                    _ => {
443                        write!(buf, "{n}: ")?;
444                        buf.with_indent(2, |buf| e.fmt_pretty(buf))?;
445                    }
446                }
447                if i < args.len() - 1 {
448                    buf.kill_newline();
449                    writeln!(buf, ", ")?
450                }
451            }
452            Ok(())
453        })?;
454        writeln!(buf, "}}")
455    }
456}
457
458impl fmt::Display for ApplyExpr {
459    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
460        let Self { args, function } = self;
461        match &function.kind {
462            ExprKind::Ref { name: _ } => write!(f, "{function}")?,
463            function => write!(f, "({function})")?,
464        }
465        write!(f, "(")?;
466        for i in 0..args.len() {
467            match &args[i].0 {
468                None => write!(f, "{}", &args[i].1)?,
469                Some(name) => match &args[i].1.kind {
470                    ExprKind::Ref { name: n }
471                        if Path::dirname(&n.0).is_none()
472                            && Path::basename(&n.0) == Some(name.as_str()) =>
473                    {
474                        write!(f, "#{name}")?
475                    }
476                    _ => write!(f, "#{name}: {}", &args[i].1)?,
477                },
478            }
479            if i < args.len() - 1 {
480                write!(f, ", ")?
481            }
482        }
483        write!(f, ")")
484    }
485}
486
487impl PrettyDisplay for ApplyExpr {
488    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
489        let Self { args, function } = self;
490        match &function.kind {
491            ExprKind::Ref { .. } => function.fmt_pretty(buf)?,
492            e => {
493                write!(buf, "(")?;
494                e.fmt_pretty(buf)?;
495                buf.kill_newline();
496                write!(buf, ")")?;
497            }
498        }
499        buf.kill_newline();
500        writeln!(buf, "(")?;
501        buf.with_indent::<fmt::Result, _>(2, |buf| {
502            for i in 0..args.len() {
503                match &args[i].0 {
504                    None => args[i].1.fmt_pretty(buf)?,
505                    Some(name) => match &args[i].1.kind {
506                        ExprKind::Ref { name: n }
507                            if Path::dirname(&n.0).is_none()
508                                && Path::basename(&n.0) == Some(name.as_str()) =>
509                        {
510                            writeln!(buf, "#{name}")?
511                        }
512                        _ => {
513                            write!(buf, "#{name}: ")?;
514                            buf.with_indent(2, |buf| args[i].1.fmt_pretty(buf))?
515                        }
516                    },
517                }
518                if i < args.len() - 1 {
519                    buf.kill_newline();
520                    writeln!(buf, ",")?
521                }
522            }
523            Ok(())
524        })?;
525        writeln!(buf, ")")
526    }
527}
528
529impl fmt::Display for LambdaExpr {
530    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
531        let LambdaExpr { args, vargs, rtype, constraints, throws, body } = self;
532        for (i, (tvar, typ)) in constraints.iter().enumerate() {
533            write!(f, "{tvar}: {typ}")?;
534            if i < constraints.len() - 1 {
535                write!(f, ", ")?;
536            }
537        }
538        write!(f, "|")?;
539        for (i, a) in args.iter().enumerate() {
540            match &a.labeled {
541                None => {
542                    write!(f, "{}", a.pattern)?;
543                    if let Some(t) = &a.constraint {
544                        write!(f, ": {t}")?
545                    }
546                }
547                Some(def) => {
548                    write!(f, "#{}", a.pattern)?;
549                    if let Some(t) = &a.constraint {
550                        write!(f, ": {t}")?
551                    }
552                    if let Some(def) = def {
553                        write!(f, " = {def}")?;
554                    }
555                }
556            }
557            if vargs.is_some() || i < args.len() - 1 {
558                write!(f, ", ")?
559            }
560        }
561        if let Some(typ) = vargs {
562            match typ {
563                None => write!(f, "@args")?,
564                Some(typ) => write!(f, "@args: {typ}")?,
565            }
566        }
567        write!(f, "| ")?;
568        if let Some(t) = rtype {
569            match t {
570                Type::Fn(ft) => write!(f, "-> ({ft}) ")?,
571                Type::ByRef(t) => match &**t {
572                    Type::Fn(ft) => write!(f, "-> &({ft}) ")?,
573                    t => write!(f, "-> &{t} ")?,
574                },
575                t => write!(f, "-> {t} ")?,
576            }
577        }
578        if let Some(t) = throws {
579            write!(f, "throws {t} ")?
580        }
581        match body {
582            Either::Right(builtin) => write!(f, "'{builtin}"),
583            Either::Left(body) => write!(f, "{body}"),
584        }
585    }
586}
587
588impl PrettyDisplay for LambdaExpr {
589    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
590        let LambdaExpr { args, vargs, rtype, constraints, throws, body } = self;
591        for (i, (tvar, typ)) in constraints.iter().enumerate() {
592            write!(buf, "{tvar}: {typ}")?;
593            if i < constraints.len() - 1 {
594                write!(buf, ", ")?;
595            }
596        }
597        write!(buf, "|")?;
598        for (i, a) in args.iter().enumerate() {
599            match &a.labeled {
600                None => {
601                    write!(buf, "{}", a.pattern)?;
602                    if let Some(typ) = &a.constraint {
603                        write!(buf, ": {typ}")?;
604                    }
605                }
606                Some(def) => {
607                    write!(buf, "#{}", a.pattern)?;
608                    if let Some(t) = &a.constraint {
609                        write!(buf, ": {t}")?
610                    }
611                    if let Some(def) = def {
612                        write!(buf, " = {def}")?;
613                    }
614                }
615            }
616            if vargs.is_some() || i < args.len() - 1 {
617                write!(buf, ", ")?
618            }
619        }
620        if let Some(typ) = vargs {
621            write!(buf, "@args")?;
622            if let Some(t) = typ {
623                write!(buf, ": {t}")?
624            }
625        }
626        write!(buf, "| ")?;
627        if let Some(t) = rtype {
628            match t {
629                Type::Fn(ft) => write!(buf, "-> ({ft}) ")?,
630                Type::ByRef(t) => match &**t {
631                    Type::Fn(ft) => write!(buf, "-> &({ft}) ")?,
632                    t => write!(buf, "-> &{t} ")?,
633                },
634                t => write!(buf, "-> {t} ")?,
635            }
636        }
637        if let Some(t) = throws {
638            write!(buf, "throws {t} ")?
639        }
640        match body {
641            Either::Right(builtin) => {
642                writeln!(buf, "'{builtin}")
643            }
644            Either::Left(body) => match &body.kind {
645                ExprKind::Do { exprs } => pretty_print_exprs(buf, exprs, "{", "}", ";"),
646                _ => body.fmt_pretty(buf),
647            },
648        }
649    }
650}
651
652impl fmt::Display for SelectExpr {
653    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
654        let SelectExpr { arg, arms } = self;
655        write!(f, "select {arg} {{")?;
656        for (i, (pat, rhs)) in arms.iter().enumerate() {
657            if let Some(tp) = &pat.type_predicate {
658                write!(f, "{tp} as ")?;
659            }
660            write!(f, "{} ", pat.structure_predicate)?;
661            if let Some(guard) = &pat.guard {
662                write!(f, "if {guard} ")?;
663            }
664            write!(f, "=> {rhs}")?;
665            if i < arms.len() - 1 {
666                write!(f, ", ")?
667            }
668        }
669        write!(f, "}}")
670    }
671}
672
673impl PrettyDisplay for SelectExpr {
674    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
675        let SelectExpr { arg, arms } = self;
676        write!(buf, "select ")?;
677        arg.fmt_pretty(buf)?;
678        buf.kill_newline();
679        writeln!(buf, " {{")?;
680        buf.with_indent(2, |buf| {
681            for (i, (pat, expr)) in arms.iter().enumerate() {
682                if let Some(tp) = &pat.type_predicate {
683                    write!(buf, "{tp} as ")?;
684                }
685                write!(buf, "{} ", pat.structure_predicate)?;
686                if let Some(guard) = &pat.guard {
687                    write!(buf, "if ")?;
688                    buf.with_indent(2, |buf| guard.fmt_pretty(buf))?;
689                    buf.kill_newline();
690                    write!(buf, " ")?;
691                }
692                write!(buf, "=> ")?;
693                if let ExprKind::Do { exprs } = &expr.kind {
694                    let term = if i < arms.len() - 1 { "}," } else { "}" };
695                    buf.with_indent(2, |buf| {
696                        pretty_print_exprs(buf, exprs, "{", term, ";")
697                    })?;
698                } else if i < arms.len() - 1 {
699                    buf.with_indent(2, |buf| expr.fmt_pretty(buf))?;
700                    buf.kill_newline();
701                    writeln!(buf, ",")?
702                } else {
703                    buf.with_indent(2, |buf| expr.fmt_pretty(buf))?;
704                }
705            }
706            Ok(())
707        })?;
708        writeln!(buf, "}}")
709    }
710}
711
712impl PrettyDisplay for ExprKind {
713    fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
714        macro_rules! binop {
715            ($sep:literal, $lhs:expr, $rhs:expr) => {{
716                writeln!(buf, "{} {}", $lhs, $sep)?;
717                $rhs.fmt_pretty(buf)
718            }};
719        }
720        match self {
721            ExprKind::Constant(_)
722            | ExprKind::NoOp
723            | ExprKind::Use { .. }
724            | ExprKind::Ref { .. }
725            | ExprKind::StructRef { .. }
726            | ExprKind::TupleRef { .. }
727            | ExprKind::TypeDef { .. }
728            | ExprKind::ArrayRef { .. }
729            | ExprKind::MapRef { .. }
730            | ExprKind::ArraySlice { .. }
731            | ExprKind::StringInterpolate { .. }
732            | ExprKind::Module {
733                name: _,
734                value: ModuleKind::Unresolved { .. } | ModuleKind::Resolved { .. },
735            } => {
736                writeln!(buf, "{self}")
737            }
738            ExprKind::ExplicitParens(e) => {
739                writeln!(buf, "(")?;
740                buf.with_indent(2, |buf| e.fmt_pretty(buf))?;
741                writeln!(buf, ")")
742            }
743            ExprKind::Do { exprs } => pretty_print_exprs(buf, exprs, "{", "}", ";"),
744            ExprKind::Array { args } => pretty_print_exprs(buf, args, "[", "]", ","),
745            ExprKind::Tuple { args } => pretty_print_exprs(buf, args, "(", ")", ","),
746            ExprKind::Bind(b) => b.fmt_pretty(buf),
747            ExprKind::StructWith(sw) => sw.fmt_pretty(buf),
748            ExprKind::Module {
749                name,
750                value: ModuleKind::Dynamic { sandbox, sig, source },
751            } => {
752                writeln!(buf, "mod {name} dynamic {{")?;
753                buf.with_indent(2, |buf| {
754                    sandbox.fmt_pretty(buf)?;
755                    buf.kill_newline();
756                    writeln!(buf, ";")?;
757                    sig.fmt_pretty(buf)?;
758                    buf.kill_newline();
759                    writeln!(buf, ";")?;
760                    write!(buf, "source ")?;
761                    buf.with_indent(2, |buf| source.fmt_pretty(buf))?;
762                    buf.kill_newline();
763                    writeln!(buf, ";")
764                })?;
765                writeln!(buf, "}}")
766            }
767            ExprKind::Connect { name, value, deref } => {
768                let deref = if *deref { "*" } else { "" };
769                writeln!(buf, "{deref}{name} <- ")?;
770                buf.with_indent(2, |buf| value.fmt_pretty(buf))
771            }
772            ExprKind::TypeCast { expr, typ } => {
773                writeln!(buf, "cast<{typ}>(")?;
774                buf.with_indent(2, |buf| expr.fmt_pretty(buf))?;
775                writeln!(buf, ")")
776            }
777            ExprKind::Map { args } => {
778                writeln!(buf, "{{")?;
779                buf.with_indent::<fmt::Result, _>(2, |buf| {
780                    for (i, (k, v)) in args.iter().enumerate() {
781                        writeln!(buf, "{k} => {v}")?;
782                        if i < args.len() - 1 {
783                            buf.kill_newline();
784                            writeln!(buf, ",")?
785                        }
786                    }
787                    Ok(())
788                })?;
789                writeln!(buf, "}}")
790            }
791            ExprKind::Any { args } => {
792                write!(buf, "any")?;
793                pretty_print_exprs(buf, args, "(", ")", ",")
794            }
795            ExprKind::Variant { tag: _, args } if args.len() == 0 => {
796                write!(buf, "{self}")
797            }
798            ExprKind::Variant { tag, args } => {
799                write!(buf, "`{tag}")?;
800                pretty_print_exprs(buf, args, "(", ")", ",")
801            }
802            ExprKind::Struct(st) => st.fmt_pretty(buf),
803            ExprKind::Qop(e) => {
804                e.fmt_pretty(buf)?;
805                buf.kill_newline();
806                writeln!(buf, "?")
807            }
808            ExprKind::OrNever(e) => {
809                e.fmt_pretty(buf)?;
810                buf.kill_newline();
811                writeln!(buf, "$")
812            }
813            ExprKind::TryCatch(tc) => {
814                writeln!(buf, "try")?;
815                pretty_print_exprs(buf, &tc.exprs, "", "", "; ")?;
816                match &tc.constraint {
817                    None => write!(buf, "catch({}) => ", tc.bind)?,
818                    Some(t) => write!(buf, "catch({}: {t}) => ", tc.bind)?,
819                }
820                match &tc.handler.kind {
821                    ExprKind::Do { exprs } => {
822                        pretty_print_exprs(buf, exprs, "{", "}", "; ")
823                    }
824                    _ => {
825                        writeln!(buf, "")?;
826                        buf.with_indent(2, |buf| tc.handler.fmt_pretty(buf))
827                    }
828                }
829            }
830            ExprKind::Apply(ae) => ae.fmt_pretty(buf),
831            ExprKind::Lambda(l) => l.fmt_pretty(buf),
832            ExprKind::Eq { lhs, rhs } => binop!("==", lhs, rhs),
833            ExprKind::Ne { lhs, rhs } => binop!("!=", lhs, rhs),
834            ExprKind::Lt { lhs, rhs } => binop!("<", lhs, rhs),
835            ExprKind::Gt { lhs, rhs } => binop!(">", lhs, rhs),
836            ExprKind::Lte { lhs, rhs } => binop!("<=", lhs, rhs),
837            ExprKind::Gte { lhs, rhs } => binop!(">=", lhs, rhs),
838            ExprKind::And { lhs, rhs } => binop!("&&", lhs, rhs),
839            ExprKind::Or { lhs, rhs } => binop!("||", lhs, rhs),
840            ExprKind::Add { lhs, rhs } => binop!("+", lhs, rhs),
841            ExprKind::Sub { lhs, rhs } => binop!("-", lhs, rhs),
842            ExprKind::Mul { lhs, rhs } => binop!("*", lhs, rhs),
843            ExprKind::Div { lhs, rhs } => binop!("/", lhs, rhs),
844            ExprKind::Mod { lhs, rhs } => binop!("%", lhs, rhs),
845            ExprKind::Sample { lhs, rhs } => binop!("~", lhs, rhs),
846            ExprKind::Not { expr } => match &expr.kind {
847                ExprKind::Do { exprs } => pretty_print_exprs(buf, exprs, "!{", "}", ";"),
848                _ => {
849                    write!(buf, "!")?;
850                    expr.fmt_pretty(buf)
851                }
852            },
853            ExprKind::ByRef(e) => {
854                write!(buf, "&")?;
855                e.fmt_pretty(buf)
856            }
857            ExprKind::Deref(e) => {
858                write!(buf, "*")?;
859                buf.with_indent(2, |buf| e.fmt_pretty(buf))
860            }
861            ExprKind::Select(se) => se.fmt_pretty(buf),
862        }
863    }
864}
865
866impl fmt::Display for ExprKind {
867    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
868        fn print_exprs(
869            f: &mut fmt::Formatter,
870            exprs: &[Expr],
871            open: &str,
872            close: &str,
873            sep: &str,
874        ) -> fmt::Result {
875            write!(f, "{open}")?;
876            for i in 0..exprs.len() {
877                write!(f, "{}", &exprs[i])?;
878                if i < exprs.len() - 1 {
879                    write!(f, "{sep}")?
880                }
881            }
882            write!(f, "{close}")
883        }
884        match self {
885            ExprKind::Constant(v @ Value::String(_)) => {
886                v.fmt_ext(f, &parser::GRAPHIX_ESC, true)
887            }
888            ExprKind::NoOp => Ok(()),
889            ExprKind::ExplicitParens(e) => write!(f, "({e})"),
890            ExprKind::Constant(v) => v.fmt_ext(f, &VAL_ESC, true),
891            ExprKind::Bind(b) => write!(f, "{b}"),
892            ExprKind::StructWith(sw) => write!(f, "{sw}"),
893            ExprKind::Connect { name, value, deref } => {
894                let deref = if *deref { "*" } else { "" };
895                write!(f, "{deref}{name} <- {value}")
896            }
897            ExprKind::Use { name } => {
898                write!(f, "use {name}")
899            }
900            ExprKind::Ref { name } => {
901                write!(f, "{name}")
902            }
903            ExprKind::StructRef { source, field } => match &source.kind {
904                ExprKind::Ref { .. } => {
905                    write!(f, "{source}.{field}")
906                }
907                source => write!(f, "({source}).{field}"),
908            },
909            ExprKind::TupleRef { source, field } => match &source.kind {
910                ExprKind::Ref { .. } => {
911                    write!(f, "{source}.{field}")
912                }
913                source => write!(f, "({source}).{field}"),
914            },
915            ExprKind::Module {
916                value:
917                    ModuleKind::Resolved { from_interface: true, .. }
918                    | ModuleKind::Unresolved { from_interface: true },
919                ..
920            } => Ok(()),
921            ExprKind::Module { name, value } => {
922                write!(f, "mod {name}")?;
923                match value {
924                    ModuleKind::Resolved { .. } | ModuleKind::Unresolved { .. } => Ok(()),
925                    ModuleKind::Dynamic { sandbox, sig, source } => {
926                        write!(f, " dynamic {{ {sandbox};")?;
927                        write!(f, " {sig};")?;
928                        write!(f, " source {source} }}")
929                    }
930                }
931            }
932            ExprKind::TypeCast { expr, typ } => write!(f, "cast<{typ}>({expr})"),
933            ExprKind::TypeDef(td) => write!(f, "{td}"),
934            ExprKind::Do { exprs } => print_exprs(f, &**exprs, "{", "}", "; "),
935            ExprKind::Lambda(l) => write!(f, "{l}"),
936            ExprKind::Array { args } => print_exprs(f, args, "[", "]", ", "),
937            ExprKind::Map { args } => {
938                write!(f, "{{")?;
939                for (i, (k, v)) in args.iter().enumerate() {
940                    write!(f, "{k} => {v}")?;
941                    if i < args.len() - 1 {
942                        write!(f, ", ")?
943                    }
944                }
945                write!(f, "}}")
946            }
947            ExprKind::MapRef { source, key } => match &source.kind {
948                ExprKind::Ref { name } => write!(f, "{name}{{{key}}}"),
949                _ => write!(f, "({source}){{{key}}}"),
950            },
951            ExprKind::Any { args } => {
952                write!(f, "any")?;
953                print_exprs(f, args, "(", ")", ", ")
954            }
955            ExprKind::Tuple { args } => print_exprs(f, args, "(", ")", ", "),
956            ExprKind::Variant { tag, args } if args.len() == 0 => {
957                write!(f, "`{tag}")
958            }
959            ExprKind::Variant { tag, args } => {
960                write!(f, "`{tag}")?;
961                print_exprs(f, args, "(", ")", ", ")
962            }
963            ExprKind::Struct(st) => write!(f, "{st}"),
964            ExprKind::Qop(e) => write!(f, "{}?", e),
965            ExprKind::OrNever(e) => write!(f, "{}$", e),
966            ExprKind::TryCatch(tc) => {
967                write!(f, "try ")?;
968                print_exprs(f, &tc.exprs, "", "", "; ")?;
969                match &tc.constraint {
970                    None => write!(f, " catch({}) => {}", tc.bind, tc.handler),
971                    Some(t) => write!(f, " catch({}: {t}) => {}", tc.bind, tc.handler),
972                }
973            }
974            ExprKind::StringInterpolate { args } => {
975                write!(f, "\"")?;
976                for s in args.iter() {
977                    match &s.kind {
978                        ExprKind::Constant(Value::String(s)) if s.len() > 0 => {
979                            let es = parser::GRAPHIX_ESC.escape(&*s);
980                            write!(f, "{es}",)?;
981                        }
982                        s => {
983                            write!(f, "[{s}]")?;
984                        }
985                    }
986                }
987                write!(f, "\"")
988            }
989            ExprKind::ArrayRef { source, i } => match &source.kind {
990                ExprKind::Ref { .. } => {
991                    write!(f, "{}[{}]", source, i)
992                }
993                _ => write!(f, "({})[{}]", &source, &i),
994            },
995            ExprKind::ArraySlice { source, start, end } => {
996                let s = match start.as_ref() {
997                    None => "",
998                    Some(e) => &format_compact!("{e}"),
999                };
1000                let e = match &end.as_ref() {
1001                    None => "",
1002                    Some(e) => &format_compact!("{e}"),
1003                };
1004                match &source.kind {
1005                    ExprKind::Ref { .. } => {
1006                        write!(f, "{}[{}..{}]", source, s, e)
1007                    }
1008                    _ => write!(f, "({})[{}..{}]", source, s, e),
1009                }
1010            }
1011            ExprKind::Apply(ap) => write!(f, "{ap}"),
1012            ExprKind::Select(se) => write!(f, "{se}"),
1013            ExprKind::Eq { lhs, rhs } => write!(f, "{lhs} == {rhs}"),
1014            ExprKind::Ne { lhs, rhs } => write!(f, "{lhs} != {rhs}"),
1015            ExprKind::Gt { lhs, rhs } => write!(f, "{lhs} > {rhs}"),
1016            ExprKind::Lt { lhs, rhs } => write!(f, "{lhs} < {rhs}"),
1017            ExprKind::Gte { lhs, rhs } => write!(f, "{lhs} >= {rhs}"),
1018            ExprKind::Lte { lhs, rhs } => write!(f, "{lhs} <= {rhs}"),
1019            ExprKind::And { lhs, rhs } => write!(f, "{lhs} && {rhs}"),
1020            ExprKind::Or { lhs, rhs } => write!(f, "{lhs} || {rhs}"),
1021            ExprKind::Add { lhs, rhs } => write!(f, "{lhs} + {rhs}"),
1022            ExprKind::Sub { lhs, rhs } => write!(f, "{lhs} - {rhs}"),
1023            ExprKind::Mul { lhs, rhs } => write!(f, "{lhs} * {rhs}"),
1024            ExprKind::Div { lhs, rhs } => write!(f, "{lhs} / {rhs}"),
1025            ExprKind::Mod { lhs, rhs } => write!(f, "{lhs} % {rhs}"),
1026            ExprKind::Sample { lhs, rhs } => write!(f, "{lhs} ~ {rhs}"),
1027            ExprKind::ByRef(e) => write!(f, "&{e}"),
1028            ExprKind::Deref(e) => write!(f, "*{e}"),
1029            ExprKind::Not { expr } => write!(f, "!{expr}"),
1030        }
1031    }
1032}