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