Skip to main content

cl_ast/ast/
display.rs

1use super::*;
2use crate::fmt::FmtAdapter;
3use std::{fmt::Display, format_args as fmt};
4
5impl<T: Display + AstNode, A: AstTypes> Display for At<T, A> {
6    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7        write!(f, "{}", self.0)
8    }
9}
10
11impl<T: AstNode, A: AstTypes> std::fmt::Debug for At<T, A> {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        if f.alternate() {
14            f.write_str("/* ")?;
15            <A::Annotation as std::fmt::Display>::fmt(&self.1, f)?;
16            f.write_str(" */\n")?;
17        }
18        <T as std::fmt::Debug>::fmt(&self.0, f)
19    }
20}
21
22impl<A: AstTypes> std::fmt::Debug for Expr<A> {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        use std::fmt::Debug;
25        match self {
26            Self::Omitted => write!(f, "Omitted"),
27            Self::Id(arg0) => write!(f, "Id({arg0:?})"),
28            Self::MetId(arg0) => write!(f, "MetId({arg0:?})"),
29            Self::Lit(arg0) => write!(f, "Lit({arg0:?})"),
30            Self::Use(arg0) => f.debug_tuple("Use").field(arg0).finish(),
31            Self::Bind(arg0) => Debug::fmt(arg0, f),
32            Self::Make(arg0) => Debug::fmt(arg0, f),
33            Self::Match(arg0) => Debug::fmt(arg0, f),
34            Self::Op(arg0, arg1) => {
35                let mut tup = f.debug_tuple(&format!("{arg0:?}"));
36                for arg in arg1 {
37                    tup.field(arg);
38                }
39                tup.finish()
40            }
41        }
42    }
43}
44
45impl<A: AstTypes> std::fmt::Debug for Pat<A> {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            Self::Ignore => write!(f, "Ignore"),
49            Self::Never => write!(f, "Never"),
50            Self::MetId(arg0) => write!(f, "MetId({arg0:?})"),
51            Self::Name(arg0) => write!(f, "Name({arg0:?})"),
52            Self::Value(arg0) => f.debug_tuple("Value").field(arg0).finish(),
53            Self::Op(arg0, arg1) => {
54                let mut tup = f.debug_tuple(&format!("{arg0:?}"));
55                for arg in arg1 {
56                    tup.field(arg);
57                }
58                tup.finish()
59            }
60        }
61    }
62}
63
64impl<A: AstTypes> std::fmt::Debug for Bind<A> {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        let Self(op, generics, pat, exprs) = self;
67        f.debug_tuple(&format!("Bind::{op:?}"))
68            .field(generics)
69            .field(pat)
70            .field(exprs)
71            .finish()
72    }
73}
74
75impl<A: AstTypes> Display for Expr<A> {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Self::Omitted => "...".fmt(f),
79            Self::Id(id) => id.fmt(f),
80            Self::MetId(id) => write!(f, "`{id}"),
81            Self::Lit(literal) => literal.fmt(f),
82            Self::Use(v) => write!(f, "use {v}"),
83            Self::Bind(v) => v.fmt(f),
84            Self::Make(v) => v.fmt(f),
85            Self::Match(v) => v.fmt(f),
86
87            Self::Op(op @ Op::Continue, exprs) => f.delimit(op, "").list(exprs, "!?,"),
88            Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
89                [cond, pass, At(Expr::Omitted, _)] => {
90                    write!(f, "{op}{cond} {pass}")
91                }
92                [cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
93                other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
94            },
95            Self::Op(Op::Array, exprs) => f.delimit("[", "]").list(exprs, ", "),
96            Self::Op(Op::ArRep, exprs) => f.delimit("[", "]").list(exprs, "; "),
97            Self::Op(Op::Block, exprs) => f
98                .delimit_indented("{", "}")
99                .list_wrap("\n", exprs, "\n", "\n"),
100            Self::Op(Op::Group, exprs) if let [At(Expr::Op(Op::Do, _), _)] = &exprs[..] => {
101                f.delimit_indented("(", ")").list(exprs, ";\n")
102            }
103            Self::Op(Op::Quote, exprs) => f.delimit("`", "`").list(exprs, ", "),
104            Self::Op(Op::Group, exprs) => f.delimit("(", ")").list(exprs, ", "),
105            Self::Op(op @ (Op::MetaInner | Op::MetaOuter), exprs) => match &exprs[..] {
106                [meta, expr @ ..] => f.delimit(fmt!("{op}[{meta}]\n"), "").list(expr, ","),
107                [] => write!(f, "{op}[]"),
108            },
109
110            Self::Op(op @ Op::Call, exprs) => match exprs.as_slice() {
111                [callee, At(Expr::Op(Op::Tuple, args), _)] => {
112                    f.delimit(fmt!("{callee}("), ")").list(args, ", ")
113                }
114                [callee, args @ ..] => f.delimit(fmt!("{callee}(?"), "?)").list(args, ", "),
115                [] => write!(f, "{op}"),
116            },
117            Self::Op(op @ Op::Index, exprs) => match exprs.as_slice() {
118                [callee, args @ ..] => f.delimit(fmt!("{callee}["), "]").list(args, ", "),
119                [] => write!(f, "{op}"),
120            },
121
122            Self::Op(Op::Tuple, exprs) if exprs.is_empty() => "()".fmt(f),
123            Self::Op(op @ (Op::Do | Op::Tuple | Op::Dot), exprs) => f.list(exprs, op),
124            Self::Op(op @ Op::Macro, exprs) => f.delimit(op, "").list(exprs, " => "),
125            Self::Op(op @ Op::Try, exprs) => f.delimit("(", fmt!("){op}")).list(exprs, ", "),
126            Self::Op(op, exprs) => match exprs.as_slice() {
127                [one] => write!(f, "{op}{one}"),
128                many => f.list(many, op),
129            },
130        }
131    }
132}
133
134impl Display for Op {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        f.write_str(match self {
137            Op::Do => ";\n",
138            Op::As => " as ",
139            Op::Macro => "macro ",
140            Op::Quote => "`",
141            Op::Block => "{}",
142            Op::Array => "[]",
143            Op::ArRep => "; ",
144            Op::Group => "()",
145            Op::Tuple => ", ",
146            Op::MetaInner => "#!",
147            Op::MetaOuter => "#",
148            Op::Try => "?",
149            Op::Index => "",
150            Op::Call => "",
151            Op::Pub => "pub ",
152            Op::Const => "const ",
153            Op::Static => "static ",
154            Op::Loop => "loop ",
155            Op::If => "if ",
156            Op::While => "while ",
157            Op::Defer => "defer ",
158            Op::Break => "break ",
159            Op::Return => "return ",
160            Op::Continue => "continue",
161            Op::Dot => ".",
162            Op::RangeEx => "..",
163            Op::RangeIn => "..=",
164            Op::Neg => "-",
165            Op::Not => "!",
166            Op::Identity => "!!",
167            Op::Refer => "&",
168            Op::Deref => "*",
169            Op::Mul => " * ",
170            Op::Div => " / ",
171            Op::Rem => " % ",
172            Op::Add => " + ",
173            Op::Sub => " - ",
174            Op::Shl => " << ",
175            Op::Shr => " >> ",
176            Op::And => " & ",
177            Op::Xor => " ^ ",
178            Op::Or => " | ",
179            Op::Lt => " < ",
180            Op::Leq => " <= ",
181            Op::Eq => " == ",
182            Op::Neq => " != ",
183            Op::Geq => " >= ",
184            Op::Gt => " > ",
185            Op::LogAnd => " && ",
186            Op::LogXor => " ^^ ",
187            Op::LogOr => " || ",
188            Op::Set => " = ",
189            Op::MulSet => " *= ",
190            Op::DivSet => " /= ",
191            Op::RemSet => " %= ",
192            Op::AddSet => " += ",
193            Op::SubSet => " -= ",
194            Op::ShlSet => " <<= ",
195            Op::ShrSet => " >>= ",
196            Op::AndSet => " &= ",
197            Op::XorSet => " ^= ",
198            Op::OrSet => " |= ",
199        })
200    }
201}
202
203impl<A: AstTypes> Display for Use<A> {
204    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205        match self {
206            Self::Glob => "*".fmt(f),
207            Self::Name(name) => name.fmt(f),
208            Self::Alias(name, alias) => write!(f, "{name} as {alias}"),
209            Self::Path(segment, rest) => write!(f, "{segment}::{rest}"),
210            Self::Tree(items) => match items.len() {
211                0 => "{}".fmt(f),
212                1..=3 => f.delimit("{ ", " }").list(items, ", "),
213                _ => f
214                    .delimit_indented("{", "}")
215                    .list_wrap("\n", items, ",\n", ",\n"),
216            },
217        }
218    }
219}
220
221impl<A: AstTypes> Display for Bind<A> {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        let Self(op, gens, pat, exprs) = self;
224        op.fmt(f)?;
225        if !gens.is_empty() {
226            f.delimit("<", "> ").list(gens, ", ")?;
227        }
228
229        match (op, exprs.as_slice()) {
230            (_, [At(Expr::Omitted, _)]) => write!(f, "{pat}"),
231            (BindOp::Fn | BindOp::Mod | BindOp::Impl, [At(Expr::Op(Op::Block, _), _)]) => {
232                f.delimit(fmt!("{pat} "), "").list(exprs, ",!? ")
233            }
234            (BindOp::Fn, _) => f.delimit(fmt!("{pat} = "), "").list(exprs, ""),
235            (BindOp::Mod | BindOp::Impl, _) => f.delimit(fmt!("{pat} "), "").list(exprs, "!?;"),
236            (BindOp::Struct | BindOp::Enum, _) => match pat.value() {
237                // TODO: Make these 'special' AST rules more robust
238                Pat::Op(PatOp::TypePrefixed, bind) => match bind.as_slice() {
239                    [name, At(Pat::Op(PatOp::Record, parts), ..)] => f
240                        .delimit_indented(fmt!("{name} {{"), "}")
241                        .list_wrap("\n", parts, ",\n", ",\n"),
242                    [name, At(Pat::Op(PatOp::Tuple, parts), ..)] => {
243                        f.delimit(fmt!("{name}("), ")").list(parts, ", ")
244                    }
245                    _ => pat.fmt(f),
246                },
247                _ => pat.fmt(f),
248            },
249            (BindOp::For, [iter, pass, At(Expr::Omitted, _)]) => {
250                write!(f, "{pat} in {iter} {pass}")
251            }
252            (BindOp::For, [iter, pass, fail]) => write!(f, "{pat} in {iter} {pass} else {fail}"),
253            (BindOp::For, other) => f.delimit(fmt!("{pat} in [["), "]]!?").list(other, ", "),
254            (_, []) => write!(f, "{pat}"),
255            (_, [value]) => write!(f, "{pat} = {value}"),
256            (_, [value, fail]) => write!(f, "{pat} = {value} else {fail}"),
257
258            (_, other) => f.delimit(fmt!("{pat} ("), ")").list(other, ", "),
259        }
260    }
261}
262
263impl Display for BindOp {
264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265        f.write_str(match self {
266            Self::Let => "let ",
267            Self::Type => "type ",
268            Self::Struct => "struct ",
269            Self::Enum => "enum ",
270            Self::Fn => "fn ",
271            Self::Mod => "mod ",
272            Self::Impl => "impl ",
273            Self::For => "for ",
274        })
275    }
276}
277
278impl<A: AstTypes> Display for Make<A> {
279    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280        let Self(expr, make_arms) = self;
281        f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ")
282    }
283}
284
285impl<A: AstTypes> Display for MakeArm<A> {
286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287        match self {
288            Self(name, Some(body)) => write!(f, "{name}: {body}"),
289            Self(name, None) => write!(f, "{name}"),
290        }
291    }
292}
293
294impl<A: AstTypes> Display for Match<A> {
295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        let Self(scrutinee, arms) = self;
297        f.delimit_indented(fmt!("match {scrutinee} {{"), "}")
298            .list_wrap("\n", arms, ";\n", ";\n")
299    }
300}
301
302impl<A: AstTypes> Display for MatchArm<A> {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        let Self(pat, expr) = self;
305        write!(f, "{pat} => {expr}")
306    }
307}
308
309impl<A: AstTypes> Display for Pat<A> {
310    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311        match self {
312            Self::Ignore => "_".fmt(f),
313            Self::Never => "!".fmt(f),
314            Self::Value(literal) => literal.fmt(f),
315            Self::MetId(name) => write!(f, "`{name}"),
316            Self::Name(name) => name.fmt(f),
317            Self::Op(PatOp::Record, pats) => f
318                .delimit_indented("{", "}")
319                .list_wrap("\n", pats, ",\n", ",\n"),
320            Self::Op(PatOp::Tuple, pats) => f.delimit("(", ")").list(pats, ", "),
321            Self::Op(PatOp::Slice, pats) => f.delimit("[", "]").list(pats, ", "),
322            Self::Op(op @ PatOp::ArRep, pats) => f.delimit("[", "]").list(pats, op),
323            Self::Op(op @ (PatOp::Typed | PatOp::Fn), pats) => match &pats[..] {
324                [fun] => write!(f, "fn {fun}"), // TODO: reconsider this
325                pats => f.list(pats, op),
326            },
327            Self::Op(op @ PatOp::Alt, pats) => f.list(pats, op),
328            Self::Op(op @ PatOp::Generic, pats) => match &pats[..] {
329                [] => op.fmt(f),
330                [first, rest @ ..] => f.delimit(fmt!("{first}<"), ">").list(rest, ", "),
331            },
332            Self::Op(op @ PatOp::TypePrefixed, pats) => match &pats[..] {
333                [] => op.fmt(f),
334                [first, rest @ ..] => f.delimit(fmt!("{first}"), "").list(rest, ",? "),
335            },
336
337            Self::Op(op @ (PatOp::MetaInner | PatOp::MetaOuter), pats) => match &pats[..] {
338                [meta, pat @ ..] => f.delimit(fmt!("{op}[{meta}]\n"), "").list(pat, ","),
339                [] => write!(f, "{op}[]"),
340            },
341            Self::Op(op, pats) => match &pats[..] {
342                [] => op.fmt(f),
343                [rest] => write!(f, "{op}{rest}"),
344                _ => f.delimit("(", ")").list(pats, op),
345            },
346        }
347    }
348}
349
350impl Display for PatOp {
351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352        f.write_str(match self {
353            Self::MetaInner => "#!",
354            Self::MetaOuter => "#",
355            Self::Pub => "pub ",
356            Self::Mut => "mut ",
357            Self::Ref => "&",
358            Self::Ptr => "*",
359            Self::Rest => "..",
360            Self::RangeEx => "..",
361            Self::RangeIn => "..=",
362            Self::Record => ", ",
363            Self::Tuple => ", ",
364            Self::Slice => ", ",
365            Self::ArRep => "; ",
366            Self::Typed => ": ",
367            Self::Generic => "T<>",
368            Self::TypePrefixed => "T()",
369            Self::Fn => " -> ",
370            Self::Guard => " if ",
371            Self::Alt => " | ",
372        })
373    }
374}