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