1use crate::expr::{
2 parser, Bind, Expr, ExprKind, Lambda, ModuleKind, Sandbox, SigItem, TypeDef,
3};
4use compact_str::{format_compact, CompactString};
5use netidx::{path::Path, utils::Either};
6use netidx_value::{parser::VAL_ESC, Value};
7use std::fmt::{self, Formatter, Write};
8
9use super::Sig;
10
11impl fmt::Display for TypeDef {
12 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13 let Self { name, params, typ } = self;
14 write!(f, "type {name}")?;
15 if !params.is_empty() {
16 write!(f, "<")?;
17 for (i, (tv, ct)) in params.iter().enumerate() {
18 write!(f, "{tv}")?;
19 if let Some(ct) = ct {
20 write!(f, ": {ct}")?;
21 }
22 if i < params.len() - 1 {
23 write!(f, ", ")?;
24 }
25 }
26 write!(f, ">")?;
27 }
28 write!(f, " = {typ}")
29 }
30}
31
32impl fmt::Display for Sandbox {
33 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
34 macro_rules! write_sandbox {
35 ($kind:literal, $l:expr) => {{
36 write!(f, "sandbox {} [ ", $kind)?;
37 for (i, p) in $l.iter().enumerate() {
38 if i < $l.len() - 1 {
39 write!(f, "{}, ", p)?
40 } else {
41 write!(f, "{}", p)?
42 }
43 }
44 write!(f, " ]")
45 }};
46 }
47 match self {
48 Sandbox::Unrestricted => write!(f, "sandbox unrestricted"),
49 Sandbox::Blacklist(l) => write_sandbox!("blacklist", l),
50 Sandbox::Whitelist(l) => write_sandbox!("whitelist", l),
51 }
52 }
53}
54
55impl fmt::Display for SigItem {
56 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57 match self {
58 SigItem::TypeDef(td) => write!(f, "{td}"),
59 SigItem::Bind(name, typ) => write!(f, "val {name}: {typ}"),
60 SigItem::Module(name, sig) => write!(f, "mod {name}: {sig}"),
61 }
62 }
63}
64
65impl fmt::Display for Sig {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "sig {{ ")?;
68 for (i, si) in self.iter().enumerate() {
69 write!(f, "{si}")?;
70 if i < self.len() - 1 {
71 write!(f, "; ")?
72 }
73 }
74 write!(f, " }}")
75 }
76}
77
78fn push_indent(indent: usize, buf: &mut String) {
79 buf.extend((0..indent).into_iter().map(|_| ' '));
80}
81
82fn pretty_print_sandbox(indent: usize, buf: &mut String, s: &Sandbox) -> fmt::Result {
83 macro_rules! write_sandbox {
84 ($kind:literal, $l:expr) => {{
85 writeln!(buf, "sandbox {} [", $kind)?;
86 for (i, p) in $l.iter().enumerate() {
87 push_indent(indent + 4, buf);
88 if i < $l.len() - 1 {
89 writeln!(buf, "{},", p)?
90 } else {
91 writeln!(buf, "{}", p)?
92 }
93 }
94 writeln!(buf, "];")
95 }};
96 }
97 push_indent(indent, buf);
98 match s {
99 Sandbox::Unrestricted => writeln!(buf, "sandbox unrestricted;"),
100 Sandbox::Blacklist(l) => write_sandbox!("blacklist", l),
101 Sandbox::Whitelist(l) => write_sandbox!("whitelist", l),
102 }
103}
104
105fn pretty_print_sig_items(
106 indent: usize,
107 buf: &mut String,
108 it: &[SigItem],
109) -> fmt::Result {
110 for (i, si) in it.iter().enumerate() {
111 push_indent(indent, buf);
112 match si {
113 SigItem::TypeDef(td) => write!(buf, "{td}")?,
114 SigItem::Bind(name, typ) => write!(buf, "val {name}: {typ}")?,
115 SigItem::Module(name, sig) => {
116 writeln!(buf, "mod {name}: sig {{")?;
117 pretty_print_sig_items(indent + 2, buf, sig)?;
118 push_indent(indent, buf);
119 write!(buf, "}}")?
120 }
121 }
122 if i < it.len() - 1 {
123 writeln!(buf, ";")?
124 } else {
125 writeln!(buf, "")?
126 }
127 }
128 Ok(())
129}
130
131impl ExprKind {
132 pub fn to_string_pretty(&self, col_limit: usize) -> String {
133 let mut buf = String::new();
134 self.pretty_print(0, col_limit, true, &mut buf).unwrap();
135 buf
136 }
137
138 fn pretty_print(
139 &self,
140 indent: usize,
141 limit: usize,
142 newline: bool,
143 buf: &mut String,
144 ) -> fmt::Result {
145 macro_rules! kill_newline {
146 ($buf:expr) => {
147 if let Some('\n') = $buf.chars().next_back() {
148 $buf.pop();
149 }
150 };
151 }
152 macro_rules! try_single_line {
153 ($trunc:ident) => {{
154 let len = buf.len();
155 let (start, indent) = if newline {
156 push_indent(indent, buf);
157 (len, indent)
158 } else {
159 (buf.rfind('\n').unwrap_or(0), 0)
160 };
161 writeln!(buf, "{}", self)?;
162 if buf.len() - start <= limit {
163 return Ok(());
164 } else {
165 if $trunc {
166 buf.truncate(len + indent)
167 }
168 len + indent
169 }
170 }};
171 }
172 macro_rules! binop {
173 ($sep:literal, $lhs:expr, $rhs:expr) => {{
174 try_single_line!(true);
175 write!(buf, "(")?;
176 writeln!(buf, "{} {}", $lhs, $sep)?;
177 $rhs.kind.pretty_print(indent, limit, true, buf)?;
178 write!(buf, ")")
179 }};
180 }
181 let mut tbuf = CompactString::new("");
182 macro_rules! typ {
183 ($typ:expr) => {{
184 match $typ {
185 None => "",
186 Some(typ) => {
187 tbuf.clear();
188 write!(tbuf, ": {typ}")?;
189 tbuf.as_str()
190 }
191 }
192 }};
193 }
194 fn pretty_print_exprs_int<'a, A, F: Fn(&'a A) -> &'a Expr>(
195 indent: usize,
196 limit: usize,
197 buf: &mut String,
198 exprs: &'a [A],
199 open: &str,
200 close: &str,
201 sep: &str,
202 f: F,
203 ) -> fmt::Result {
204 writeln!(buf, "{}", open)?;
205 for i in 0..exprs.len() {
206 f(&exprs[i]).kind.pretty_print(indent + 2, limit, true, buf)?;
207 if i < exprs.len() - 1 {
208 kill_newline!(buf);
209 writeln!(buf, "{}", sep)?
210 }
211 }
212 push_indent(indent, buf);
213 writeln!(buf, "{}", close)
214 }
215 fn pretty_print_exprs(
216 indent: usize,
217 limit: usize,
218 buf: &mut String,
219 exprs: &[Expr],
220 open: &str,
221 close: &str,
222 sep: &str,
223 ) -> fmt::Result {
224 pretty_print_exprs_int(indent, limit, buf, exprs, open, close, sep, |a| a)
225 }
226 let exp = |export| if export { "pub " } else { "" };
227 match self {
228 ExprKind::Constant(_)
229 | ExprKind::Use { .. }
230 | ExprKind::Ref { .. }
231 | ExprKind::StructRef { .. }
232 | ExprKind::TupleRef { .. }
233 | ExprKind::TypeDef { .. }
234 | ExprKind::ArrayRef { .. }
235 | ExprKind::ArraySlice { .. }
236 | ExprKind::StringInterpolate { .. }
237 | ExprKind::Module {
238 name: _,
239 export: _,
240 value: ModuleKind::Unresolved | ModuleKind::Resolved(_),
241 } => {
242 if newline {
243 push_indent(indent, buf);
244 }
245 writeln!(buf, "{self}")
246 }
247 ExprKind::Bind(b) => {
248 let Bind { doc, pattern, typ, export, value } = &**b;
249 try_single_line!(true);
250 if let Some(doc) = doc {
251 if doc == "" {
252 writeln!(buf, "///")?;
253 } else {
254 for line in doc.lines() {
255 writeln!(buf, "///{line}")?;
256 }
257 }
258 }
259 writeln!(buf, "{}let {pattern}{} = ", exp(*export), typ!(typ))?;
260 value.kind.pretty_print(indent + 2, limit, false, buf)
261 }
262 ExprKind::StructWith { source, replace } => {
263 try_single_line!(true);
264 match &source.kind {
265 ExprKind::Ref { .. } => writeln!(buf, "{{ {source} with")?,
266 _ => writeln!(buf, "{{ ({source}) with")?,
267 }
268 let indent = indent + 2;
269 for (i, (name, e)) in replace.iter().enumerate() {
270 push_indent(indent, buf);
271 match &e.kind {
272 ExprKind::Ref { name: n }
273 if Path::dirname(&**n).is_none()
274 && Path::basename(&**n) == Some(&**name) =>
275 {
276 write!(buf, "{name}")?
277 }
278 e => {
279 write!(buf, "{name}: ")?;
280 e.pretty_print(indent + 2, limit, false, buf)?;
281 }
282 }
283 if i < replace.len() - 1 {
284 kill_newline!(buf);
285 writeln!(buf, ",")?
286 }
287 }
288 writeln!(buf, "}}")
289 }
290 ExprKind::Module { name, export, value: ModuleKind::Inline(exprs) } => {
291 try_single_line!(true);
292 write!(buf, "{}mod {name} ", exp(*export))?;
293 pretty_print_exprs(indent, limit, buf, exprs, "{", "}", ";")
294 }
295 ExprKind::Module {
296 name,
297 export,
298 value: ModuleKind::Dynamic { sandbox, sig, source },
299 } => {
300 try_single_line!(true);
301 writeln!(buf, "{}mod {name} dynamic {{", exp(*export))?;
302 pretty_print_sandbox(indent + 2, buf, sandbox)?;
303 push_indent(indent + 2, buf);
304 writeln!(buf, "sig {{")?;
305 pretty_print_sig_items(indent + 2, buf, sig)?;
306 push_indent(indent + 2, buf);
307 writeln!(buf, "}};")?;
308 push_indent(indent + 2, buf);
309 write!(buf, "source ")?;
310 source.kind.pretty_print(indent + 2, limit, false, buf)?;
311 writeln!(buf, "}}")
312 }
313 ExprKind::Do { exprs } => {
314 try_single_line!(true);
315 pretty_print_exprs(indent, limit, buf, exprs, "{", "}", ";")
316 }
317 ExprKind::Connect { name, value, deref } => {
318 try_single_line!(true);
319 let deref = if *deref { "*" } else { "" };
320 writeln!(buf, "{deref}{name} <- ")?;
321 value.kind.pretty_print(indent + 2, limit, false, buf)
322 }
323 ExprKind::TypeCast { expr, typ } => {
324 try_single_line!(true);
325 writeln!(buf, "cast<{typ}>(")?;
326 expr.kind.pretty_print(indent + 2, limit, true, buf)?;
327 writeln!(buf, ")")
328 }
329 ExprKind::Array { args } => {
330 try_single_line!(true);
331 pretty_print_exprs(indent, limit, buf, args, "[", "]", ",")
332 }
333 ExprKind::Any { args } => {
334 try_single_line!(true);
335 write!(buf, "any")?;
336 pretty_print_exprs(indent, limit, buf, args, "(", ")", ",")
337 }
338 ExprKind::Tuple { args } => {
339 try_single_line!(true);
340 pretty_print_exprs(indent, limit, buf, args, "(", ")", ",")
341 }
342 ExprKind::Variant { tag: _, args } if args.len() == 0 => {
343 if newline {
344 push_indent(indent, buf)
345 }
346 write!(buf, "{self}")
347 }
348 ExprKind::Variant { tag, args } => {
349 try_single_line!(true);
350 write!(buf, "`{tag}")?;
351 pretty_print_exprs(indent, limit, buf, args, "(", ")", ",")
352 }
353 ExprKind::Struct { args } => {
354 try_single_line!(true);
355 writeln!(buf, "{{")?;
356 for (i, (n, e)) in args.iter().enumerate() {
357 push_indent(indent + 2, buf);
358 match &e.kind {
359 ExprKind::Ref { name }
360 if Path::dirname(&**name).is_none()
361 && Path::basename(&**name) == Some(&**n) =>
362 {
363 write!(buf, "{n}")?
364 }
365 _ => {
366 write!(buf, "{n}: ")?;
367 e.kind.pretty_print(indent + 2, limit, false, buf)?;
368 }
369 }
370 if i < args.len() - 1 {
371 kill_newline!(buf);
372 writeln!(buf, ", ")?
373 }
374 }
375 push_indent(indent, buf);
376 writeln!(buf, "}}")
377 }
378 ExprKind::Qop(e) => {
379 try_single_line!(true);
380 e.kind.pretty_print(indent, limit, true, buf)?;
381 kill_newline!(buf);
382 writeln!(buf, "?")
383 }
384 ExprKind::Apply { function, args } => {
385 try_single_line!(true);
386 match &function.kind {
387 ExprKind::Ref { .. } => {
388 function.kind.pretty_print(indent, limit, true, buf)?
389 }
390 e => {
391 write!(buf, "(")?;
392 e.pretty_print(indent, limit, true, buf)?;
393 kill_newline!(buf);
394 write!(buf, ")")?;
395 }
396 }
397 kill_newline!(buf);
398 writeln!(buf, "(")?;
399 for i in 0..args.len() {
400 match &args[i].0 {
401 None => {
402 args[i].1.kind.pretty_print(indent + 2, limit, true, buf)?
403 }
404 Some(name) => match &args[i].1.kind {
405 ExprKind::Ref { name: n }
406 if Path::dirname(&n.0).is_none()
407 && Path::basename(&n.0) == Some(name.as_str()) =>
408 {
409 writeln!(buf, "#{name}")?
410 }
411 _ => {
412 write!(buf, "#{name}: ")?;
413 args[i].1.kind.pretty_print(
414 indent + 2,
415 limit,
416 false,
417 buf,
418 )?
419 }
420 },
421 }
422 if i < args.len() - 1 {
423 kill_newline!(buf);
424 writeln!(buf, ",")?
425 }
426 }
427 writeln!(buf, ")")
428 }
429 ExprKind::Lambda(l) => {
430 let Lambda { args, vargs, rtype, constraints, body } = &**l;
431 try_single_line!(true);
432 for (i, (tvar, typ)) in constraints.iter().enumerate() {
433 write!(buf, "{tvar}: {typ}")?;
434 if i < constraints.len() - 1 {
435 write!(buf, ", ")?;
436 }
437 }
438 write!(buf, "|")?;
439 for (i, a) in args.iter().enumerate() {
440 match &a.labeled {
441 None => {
442 write!(buf, "{}", a.pattern)?;
443 buf.push_str(typ!(&a.constraint));
444 }
445 Some(def) => {
446 write!(buf, "#{}", a.pattern)?;
447 buf.push_str(typ!(&a.constraint));
448 if let Some(def) = def {
449 write!(buf, " = {def}")?;
450 }
451 }
452 }
453 if vargs.is_some() || i < args.len() - 1 {
454 write!(buf, ", ")?
455 }
456 }
457 if let Some(typ) = vargs {
458 write!(buf, "@args{}", typ!(typ))?;
459 }
460 write!(buf, "| ")?;
461 if let Some(t) = rtype {
462 write!(buf, "-> {t} ")?
463 }
464 match body {
465 Either::Right(builtin) => {
466 writeln!(buf, "'{builtin}")
467 }
468 Either::Left(body) => match &body.kind {
469 ExprKind::Do { exprs } => {
470 pretty_print_exprs(indent, limit, buf, exprs, "{", "}", ";")
471 }
472 _ => body.kind.pretty_print(indent, limit, false, buf),
473 },
474 }
475 }
476 ExprKind::Eq { lhs, rhs } => binop!("==", lhs, rhs),
477 ExprKind::Ne { lhs, rhs } => binop!("!=", lhs, rhs),
478 ExprKind::Lt { lhs, rhs } => binop!("<", lhs, rhs),
479 ExprKind::Gt { lhs, rhs } => binop!(">", lhs, rhs),
480 ExprKind::Lte { lhs, rhs } => binop!("<=", lhs, rhs),
481 ExprKind::Gte { lhs, rhs } => binop!(">=", lhs, rhs),
482 ExprKind::And { lhs, rhs } => binop!("&&", lhs, rhs),
483 ExprKind::Or { lhs, rhs } => binop!("||", lhs, rhs),
484 ExprKind::Add { lhs, rhs } => binop!("+", lhs, rhs),
485 ExprKind::Sub { lhs, rhs } => binop!("-", lhs, rhs),
486 ExprKind::Mul { lhs, rhs } => binop!("*", lhs, rhs),
487 ExprKind::Div { lhs, rhs } => binop!("/", lhs, rhs),
488 ExprKind::Mod { lhs, rhs } => binop!("%", lhs, rhs),
489 ExprKind::Sample { lhs, rhs } => binop!("~", lhs, rhs),
490 ExprKind::Not { expr } => {
491 try_single_line!(true);
492 match &expr.kind {
493 ExprKind::Do { exprs } => {
494 pretty_print_exprs(indent, limit, buf, exprs, "!{", "}", ";")
495 }
496 _ => {
497 writeln!(buf, "!(")?;
498 expr.kind.pretty_print(indent + 2, limit, true, buf)?;
499 push_indent(indent, buf);
500 writeln!(buf, ")")
501 }
502 }
503 }
504 ExprKind::ByRef(e) => {
505 try_single_line!(true);
506 write!(buf, "&")?;
507 e.kind.pretty_print(indent + 2, limit, false, buf)
508 }
509 ExprKind::Deref(e) => match &e.kind {
510 ExprKind::Connect { .. } | ExprKind::Qop(_) => {
511 try_single_line!(true);
512 writeln!(buf, "*(")?;
513 e.kind.pretty_print(indent + 2, limit, newline, buf)?;
514 writeln!(buf, ")")
515 }
516 _ => {
517 try_single_line!(true);
518 write!(buf, "*")?;
519 e.kind.pretty_print(indent + 2, limit, false, buf)
520 }
521 },
522 ExprKind::Select { arg, arms } => {
523 try_single_line!(true);
524 write!(buf, "select ")?;
525 arg.kind.pretty_print(indent, limit, false, buf)?;
526 kill_newline!(buf);
527 writeln!(buf, " {{")?;
528 for (i, (pat, expr)) in arms.iter().enumerate() {
529 if let Some(tp) = &pat.type_predicate {
530 write!(buf, "{tp} as ")?;
531 }
532 write!(buf, "{} ", pat.structure_predicate)?;
533 if let Some(guard) = &pat.guard {
534 write!(buf, "if ")?;
535 guard.kind.pretty_print(indent + 2, limit, false, buf)?;
536 kill_newline!(buf);
537 write!(buf, " ")?;
538 }
539 write!(buf, "=> ")?;
540 if let ExprKind::Do { exprs } = &expr.kind {
541 let term = if i < arms.len() - 1 { "}," } else { "}" };
542 pretty_print_exprs(
543 indent + 2,
544 limit,
545 buf,
546 exprs,
547 "{",
548 term,
549 ";",
550 )?;
551 } else if i < arms.len() - 1 {
552 expr.kind.pretty_print(indent + 2, limit, false, buf)?;
553 kill_newline!(buf);
554 writeln!(buf, ",")?
555 } else {
556 expr.kind.pretty_print(indent, limit, false, buf)?;
557 }
558 }
559 push_indent(indent, buf);
560 writeln!(buf, "}}")
561 }
562 }
563 }
564}
565
566impl fmt::Display for ExprKind {
567 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568 fn write_binop(
569 f: &mut fmt::Formatter,
570 op: &str,
571 lhs: &Expr,
572 rhs: &Expr,
573 ) -> fmt::Result {
574 write!(f, "(")?;
575 write!(f, "{lhs} {op} {rhs}")?;
576 write!(f, ")")
577 }
578 fn print_exprs(
579 f: &mut fmt::Formatter,
580 exprs: &[Expr],
581 open: &str,
582 close: &str,
583 sep: &str,
584 ) -> fmt::Result {
585 write!(f, "{open}")?;
586 for i in 0..exprs.len() {
587 write!(f, "{}", &exprs[i])?;
588 if i < exprs.len() - 1 {
589 write!(f, "{sep}")?
590 }
591 }
592 write!(f, "{close}")
593 }
594 let mut tbuf = CompactString::new("");
595 macro_rules! typ {
596 ($typ:expr) => {{
597 match $typ {
598 None => "",
599 Some(typ) => {
600 tbuf.clear();
601 write!(tbuf, ": {typ}")?;
602 tbuf.as_str()
603 }
604 }
605 }};
606 }
607 let exp = |export| if export { "pub " } else { "" };
608 match self {
609 ExprKind::Constant(v @ Value::String(_)) => {
610 v.fmt_ext(f, &parser::GRAPHIX_ESC, true)
611 }
612 ExprKind::Constant(v) => v.fmt_ext(f, &VAL_ESC, true),
613 ExprKind::Bind(b) => {
614 let Bind { doc, pattern, typ, export, value } = &**b;
615 if let Some(doc) = doc {
616 if doc == "" {
617 writeln!(f, "///")?
618 } else {
619 for line in doc.lines() {
620 writeln!(f, "///{line}")?
621 }
622 }
623 }
624 write!(f, "{}let {pattern}{} = {value}", exp(*export), typ!(typ))
625 }
626 ExprKind::StructWith { source, replace } => {
627 match &source.kind {
628 ExprKind::Ref { .. } => write!(f, "{{ {source} with ")?,
629 _ => write!(f, "{{ ({source}) with ")?,
630 }
631 for (i, (name, e)) in replace.iter().enumerate() {
632 match &e.kind {
633 ExprKind::Ref { name: n }
634 if Path::dirname(&**n).is_none()
635 && Path::basename(&**n) == Some(&**name) =>
636 {
637 write!(f, "{name}")?
638 }
639 _ => write!(f, "{name}: {e}")?,
640 }
641 if i < replace.len() - 1 {
642 write!(f, ", ")?
643 }
644 }
645 write!(f, " }}")
646 }
647 ExprKind::Connect { name, value, deref } => {
648 let deref = if *deref { "*" } else { "" };
649 write!(f, "{deref}{name} <- {value}")
650 }
651 ExprKind::Use { name } => {
652 write!(f, "use {name}")
653 }
654 ExprKind::Ref { name } => {
655 write!(f, "{name}")
656 }
657 ExprKind::StructRef { source, field } => match &source.kind {
658 ExprKind::Ref { .. } => {
659 write!(f, "{source}.{field}")
660 }
661 source => write!(f, "({source}).{field}"),
662 },
663 ExprKind::TupleRef { source, field } => match &source.kind {
664 ExprKind::Ref { .. } => {
665 write!(f, "{source}.{field}")
666 }
667 source => write!(f, "({source}).{field}"),
668 },
669 ExprKind::Module { name, export, value } => {
670 write!(f, "{}mod {name}", exp(*export))?;
671 match value {
672 ModuleKind::Resolved(_) | ModuleKind::Unresolved => Ok(()),
673 ModuleKind::Inline(exprs) => print_exprs(f, &**exprs, "{", "}", "; "),
674 ModuleKind::Dynamic { sandbox, sig, source } => {
675 write!(f, " dynamic {{ {sandbox};")?;
676 write!(f, " {sig};")?;
677 write!(f, " source {source} }}")
678 }
679 }
680 }
681 ExprKind::TypeCast { expr, typ } => write!(f, "cast<{typ}>({expr})"),
682 ExprKind::TypeDef(td) => write!(f, "{td}"),
683 ExprKind::Do { exprs } => print_exprs(f, &**exprs, "{", "}", "; "),
684 ExprKind::Lambda(l) => {
685 let Lambda { args, vargs, rtype, constraints, body } = &**l;
686 for (i, (tvar, typ)) in constraints.iter().enumerate() {
687 write!(f, "{tvar}: {typ}")?;
688 if i < constraints.len() - 1 {
689 write!(f, ", ")?;
690 }
691 }
692 write!(f, "|")?;
693 for (i, a) in args.iter().enumerate() {
694 match &a.labeled {
695 None => {
696 write!(f, "{}", a.pattern)?;
697 write!(f, "{}", typ!(&a.constraint))?;
698 }
699 Some(def) => {
700 write!(f, "#{}", a.pattern)?;
701 write!(f, "{}", typ!(&a.constraint))?;
702 if let Some(def) = def {
703 write!(f, " = {def}")?;
704 }
705 }
706 }
707 if vargs.is_some() || i < args.len() - 1 {
708 write!(f, ", ")?
709 }
710 }
711 if let Some(typ) = vargs {
712 write!(f, "@args{}", typ!(typ))?;
713 }
714 write!(f, "| ")?;
715 if let Some(t) = rtype {
716 write!(f, "-> {t} ")?
717 }
718 match body {
719 Either::Right(builtin) => write!(f, "'{builtin}"),
720 Either::Left(body) => write!(f, "{body}"),
721 }
722 }
723 ExprKind::Array { args } => print_exprs(f, args, "[", "]", ", "),
724 ExprKind::Any { args } => {
725 write!(f, "any")?;
726 print_exprs(f, args, "(", ")", ", ")
727 }
728 ExprKind::Tuple { args } => print_exprs(f, args, "(", ")", ", "),
729 ExprKind::Variant { tag, args } if args.len() == 0 => {
730 write!(f, "`{tag}")
731 }
732 ExprKind::Variant { tag, args } => {
733 write!(f, "`{tag}")?;
734 print_exprs(f, args, "(", ")", ", ")
735 }
736 ExprKind::Struct { args } => {
737 write!(f, "{{ ")?;
738 for (i, (n, e)) in args.iter().enumerate() {
739 match &e.kind {
740 ExprKind::Ref { name }
741 if Path::dirname(&**name).is_none()
742 && Path::basename(&**name) == Some(&**n) =>
743 {
744 write!(f, "{n}")?
745 }
746 _ => write!(f, "{n}: {e}")?,
747 }
748 if i < args.len() - 1 {
749 write!(f, ", ")?
750 }
751 }
752 write!(f, " }}")
753 }
754 ExprKind::Qop(e) => write!(f, "{}?", e),
755 ExprKind::StringInterpolate { args } => {
756 write!(f, "\"")?;
757 for s in args.iter() {
758 match &s.kind {
759 ExprKind::Constant(Value::String(s)) if s.len() > 0 => {
760 let es = parser::GRAPHIX_ESC.escape(&*s);
761 write!(f, "{es}",)?;
762 }
763 s => {
764 write!(f, "[{s}]")?;
765 }
766 }
767 }
768 write!(f, "\"")
769 }
770 ExprKind::ArrayRef { source, i } => match &source.kind {
771 ExprKind::Ref { .. } => {
772 write!(f, "{}[{}]", source, i)
773 }
774 _ => write!(f, "({})[{}]", &source, &i),
775 },
776 ExprKind::ArraySlice { source, start, end } => {
777 let s = match start.as_ref() {
778 None => "",
779 Some(e) => &format_compact!("{e}"),
780 };
781 let e = match &end.as_ref() {
782 None => "",
783 Some(e) => &format_compact!("{e}"),
784 };
785 match &source.kind {
786 ExprKind::Ref { .. } => {
787 write!(f, "{}[{}..{}]", source, s, e)
788 }
789 _ => write!(f, "({})[{}..{}]", source, s, e),
790 }
791 }
792 ExprKind::Apply { args, function } => {
793 match &function.kind {
794 ExprKind::Ref { name: _ } => write!(f, "{function}")?,
795 function => write!(f, "({function})")?,
796 }
797 write!(f, "(")?;
798 for i in 0..args.len() {
799 match &args[i].0 {
800 None => write!(f, "{}", &args[i].1)?,
801 Some(name) => match &args[i].1.kind {
802 ExprKind::Ref { name: n }
803 if Path::dirname(&n.0).is_none()
804 && Path::basename(&n.0) == Some(name.as_str()) =>
805 {
806 write!(f, "#{name}")?
807 }
808 _ => write!(f, "#{name}: {}", &args[i].1)?,
809 },
810 }
811 if i < args.len() - 1 {
812 write!(f, ", ")?
813 }
814 }
815 write!(f, ")")
816 }
817 ExprKind::Select { arg, arms } => {
818 write!(f, "select {arg} {{")?;
819 for (i, (pat, rhs)) in arms.iter().enumerate() {
820 if let Some(tp) = &pat.type_predicate {
821 write!(f, "{tp} as ")?;
822 }
823 write!(f, "{} ", pat.structure_predicate)?;
824 if let Some(guard) = &pat.guard {
825 write!(f, "if {guard} ")?;
826 }
827 write!(f, "=> {rhs}")?;
828 if i < arms.len() - 1 {
829 write!(f, ", ")?
830 }
831 }
832 write!(f, "}}")
833 }
834 ExprKind::Eq { lhs, rhs } => write_binop(f, "==", lhs, rhs),
835 ExprKind::Ne { lhs, rhs } => write_binop(f, "!=", lhs, rhs),
836 ExprKind::Gt { lhs, rhs } => write_binop(f, ">", lhs, rhs),
837 ExprKind::Lt { lhs, rhs } => write_binop(f, "<", lhs, rhs),
838 ExprKind::Gte { lhs, rhs } => write_binop(f, ">=", lhs, rhs),
839 ExprKind::Lte { lhs, rhs } => write_binop(f, "<=", lhs, rhs),
840 ExprKind::And { lhs, rhs } => write_binop(f, "&&", lhs, rhs),
841 ExprKind::Or { lhs, rhs } => write_binop(f, "||", lhs, rhs),
842 ExprKind::Add { lhs, rhs } => write_binop(f, "+", lhs, rhs),
843 ExprKind::Sub { lhs, rhs } => write_binop(f, "-", lhs, rhs),
844 ExprKind::Mul { lhs, rhs } => write_binop(f, "*", lhs, rhs),
845 ExprKind::Div { lhs, rhs } => write_binop(f, "/", lhs, rhs),
846 ExprKind::Mod { lhs, rhs } => write_binop(f, "%", lhs, rhs),
847 ExprKind::Sample { lhs, rhs } => write_binop(f, "~", lhs, rhs),
848 ExprKind::ByRef(e) => write!(f, "&{e}"),
849 ExprKind::Deref(e) => match &e.kind {
850 ExprKind::Qop(e) => write!(f, "*({e}?)"),
851 ExprKind::Connect { .. } => write!(f, "*({e})"),
852 _ => write!(f, "*{e}"),
853 },
854 ExprKind::Not { expr } => {
855 write!(f, "(!{expr})")
856 }
857 }
858 }
859}