spade_hir/
pretty_debug.rs

1use itertools::Itertools;
2use nesty::{code, Code};
3use spade_common::{
4    location_info::Loc,
5    name::{Identifier, NameID},
6};
7
8use crate::{
9    expression::{CapturedLambdaParam, NamedArgument},
10    ArgumentList, AttributeList, Binding, ConstGeneric, ConstGenericWithId, ExprKind, Expression,
11    Pattern, PatternArgument, Register, Statement, TraitSpec, TypeExpression, TypeParam, TypeSpec,
12    Unit, UnitHead, WhereClause,
13};
14
15pub trait PrettyDebug {
16    fn pretty_debug(&self) -> String;
17}
18
19impl PrettyDebug for Identifier {
20    fn pretty_debug(&self) -> String {
21        format!("{self}")
22    }
23}
24
25impl PrettyDebug for NameID {
26    fn pretty_debug(&self) -> String {
27        format!("{self:?}")
28    }
29}
30
31impl PrettyDebug for Unit {
32    fn pretty_debug(&self) -> String {
33        let Self {
34            name,
35            head:
36                UnitHead {
37                    name: _,
38                    inputs: _,
39                    output_type,
40                    unit_type_params,
41                    scope_type_params,
42                    unit_kind,
43                    where_clauses,
44                    documentation,
45                },
46            attributes,
47            inputs,
48            body,
49        } = self;
50
51        let type_params = format!(
52            "<{} | {}>",
53            scope_type_params
54                .iter()
55                .map(PrettyDebug::pretty_debug)
56                .join(","),
57            unit_type_params
58                .iter()
59                .map(PrettyDebug::pretty_debug)
60                .join(", ")
61        );
62
63        let inputs = inputs
64            .iter()
65            .map(|(n, t)| format!("{}: {}", n.pretty_debug(), t.pretty_debug()))
66            .join(", ");
67
68        code! [
69            [0] documentation;
70            [0] format!(
71                    "{} {unit_kind:?} {}{}({}) -> {}",
72                    attributes.pretty_debug(),
73                    name.name_id().pretty_debug(),
74                    type_params,
75                    inputs,
76                    output_type.pretty_debug()
77                );
78            [1] format!("where: {}", where_clauses.iter().map(PrettyDebug::pretty_debug).join(", "));
79            [0] "{";
80            [1]     body.pretty_debug();
81            [0] "}";
82        ]
83        .to_string()
84    }
85}
86
87impl PrettyDebug for WhereClause {
88    fn pretty_debug(&self) -> String {
89        match self {
90            WhereClause::Int { target, constraint } => format!(
91                "{}: {{{}}}",
92                target.pretty_debug(),
93                constraint.pretty_debug()
94            ),
95            WhereClause::Type { target, traits } => format!(
96                "{}: {}",
97                target.pretty_debug(),
98                traits.iter().map(|t| t.pretty_debug()).join(" + }")
99            ),
100        }
101    }
102}
103
104impl PrettyDebug for AttributeList {
105    fn pretty_debug(&self) -> String {
106        if self.0.len() != 0 {
107            format!("[attribute list omitted]")
108        } else {
109            String::new()
110        }
111    }
112}
113
114impl PrettyDebug for TypeExpression {
115    fn pretty_debug(&self) -> String {
116        match self {
117            TypeExpression::Integer(i) => format!("{i}"),
118            TypeExpression::TypeSpec(type_spec) => type_spec.pretty_debug(),
119            TypeExpression::ConstGeneric(inner) => inner.pretty_debug(),
120        }
121    }
122}
123
124impl PrettyDebug for TypeSpec {
125    fn pretty_debug(&self) -> String {
126        match self {
127            TypeSpec::Declared(name, args) => {
128                format!(
129                    "{}<{}>",
130                    name.pretty_debug(),
131                    args.iter().map(|arg| arg.pretty_debug()).join(", ")
132                )
133            }
134            TypeSpec::Generic(name) => name.pretty_debug(),
135            TypeSpec::Tuple(inner) => format!(
136                "({})",
137                inner.iter().map(|arg| arg.pretty_debug()).join(", ")
138            ),
139            TypeSpec::Array { inner, size } => {
140                format!("[{}; {}]", inner.pretty_debug(), size.pretty_debug())
141            }
142            TypeSpec::Inverted(inner) => format!("inv {}", inner.pretty_debug()),
143            TypeSpec::Wire(inner) => format!("&{}", inner.pretty_debug()),
144            TypeSpec::TraitSelf(_) => format!("TraitSelf"),
145            TypeSpec::Wildcard(_) => format!("_"),
146        }
147    }
148}
149
150impl PrettyDebug for ConstGeneric {
151    fn pretty_debug(&self) -> String {
152        match self {
153            ConstGeneric::Name(n) => n.pretty_debug(),
154            ConstGeneric::Const(big_int) => format!("{big_int}"),
155            ConstGeneric::Add(lhs, rhs) => {
156                format!("({} + {})", lhs.pretty_debug(), rhs.pretty_debug())
157            }
158            ConstGeneric::Sub(lhs, rhs) => {
159                format!("({} - {})", lhs.pretty_debug(), rhs.pretty_debug())
160            }
161            ConstGeneric::Mul(lhs, rhs) => {
162                format!("({} * {})", lhs.pretty_debug(), rhs.pretty_debug())
163            }
164            ConstGeneric::Div(lhs, rhs) => {
165                format!("({} / {})", lhs.pretty_debug(), rhs.pretty_debug())
166            }
167            ConstGeneric::Mod(lhs, rhs) => {
168                format!("({} % {})", lhs.pretty_debug(), rhs.pretty_debug())
169            }
170            ConstGeneric::UintBitsToFit(inner) => {
171                format!("{}", inner.pretty_debug())
172            }
173            ConstGeneric::Eq(lhs, rhs) => {
174                format!("({} == {})", lhs.pretty_debug(), rhs.pretty_debug())
175            }
176            ConstGeneric::NotEq(lhs, rhs) => {
177                format!("({} != {})", lhs.pretty_debug(), rhs.pretty_debug())
178            }
179        }
180    }
181}
182
183impl PrettyDebug for ConstGenericWithId {
184    fn pretty_debug(&self) -> String {
185        self.inner.pretty_debug()
186    }
187}
188
189impl PrettyDebug for Expression {
190    fn pretty_debug(&self) -> String {
191        self.kind.pretty_debug()
192    }
193}
194
195impl PrettyDebug for ExprKind {
196    fn pretty_debug(&self) -> String {
197        match &self {
198            crate::ExprKind::Error => "{error}".to_string(),
199            crate::ExprKind::Identifier(name_id) => name_id.pretty_debug(),
200            crate::ExprKind::IntLiteral(value, _) => format!("{value}"),
201            crate::ExprKind::BoolLiteral(value) => format!("{value}"),
202            crate::ExprKind::BitLiteral(value) => format!("{value:?}"),
203            crate::ExprKind::TypeLevelInteger(name_id) => name_id.pretty_debug(),
204            crate::ExprKind::CreatePorts => "port".to_string(),
205            crate::ExprKind::TupleLiteral(inner) => {
206                format!("({})", inner.iter().map(|i| i.pretty_debug()).join(", "))
207            }
208            crate::ExprKind::ArrayLiteral(inner) => {
209                format!("[{}]", inner.iter().map(|i| i.pretty_debug()).join(", "))
210            }
211            crate::ExprKind::ArrayShorthandLiteral(inner, size) => {
212                format!("[{}; {}]", inner.pretty_debug(), size.pretty_debug())
213            }
214            crate::ExprKind::Index(base, idx) => {
215                format!("{}[{}]", base.pretty_debug(), idx.pretty_debug())
216            }
217            crate::ExprKind::RangeIndex { target, start, end } => {
218                format!(
219                    "{}[{}..{}]",
220                    target.pretty_debug(),
221                    start.pretty_debug(),
222                    end.pretty_debug()
223                )
224            }
225            crate::ExprKind::TupleIndex(base, idx) => {
226                format!("{}#{}", base.pretty_debug(), idx)
227            }
228            crate::ExprKind::FieldAccess(base, field) => {
229                format!("{}.{}", base.pretty_debug(), field)
230            }
231            crate::ExprKind::MethodCall {
232                target,
233                name,
234                args,
235                call_kind: _,
236                turbofish,
237            } => {
238                code! {
239                    [0] format!("{}", target.pretty_debug());
240                    [1]    format!(".{name}<{}>", turbofish.pretty_debug());
241                    [1]    format!("{}", args.pretty_debug())
242                }.to_string()
243            }
244            crate::ExprKind::Call {
245                kind: _,
246                callee,
247                args,
248                turbofish,
249            } => {
250                code! {
251                    [0] format!("{}::<{}>{}", callee.pretty_debug(), turbofish.pretty_debug(), args.pretty_debug());
252                }.to_string()
253            }
254            crate::ExprKind::BinaryOperator(lhs, op, rhs) => {
255                format!("({} {} {})", lhs.pretty_debug(), op, rhs.pretty_debug())
256            },
257            crate::ExprKind::UnaryOperator(op, rhs) => format!("{op}{}", rhs.pretty_debug()),
258            crate::ExprKind::Match(expr, branches) => {
259                code!{
260                    [0] format!("match {} {{", expr.pretty_debug());
261                    [1]     branches.iter().map(|(pat, expr)| {
262                        format!("{} => {},", pat.pretty_debug(), expr.pretty_debug())
263                    }).join("\n");
264                    [0] "}"
265                }.to_string()
266            },
267            crate::ExprKind::Block(block) => {
268                code!{
269                    [0] "{";
270                    [1]    block.statements.iter().map(|stmt| stmt.pretty_debug()).join("\n");
271                    [1]    block.result.pretty_debug();
272                    [0] "}"
273                }.to_string()
274            },
275            crate::ExprKind::If(cond, on_true, on_false) => code! {
276                [0] format!("if {} {{", cond.pretty_debug());
277                [1]    on_true.pretty_debug();
278                [0] "} else {";
279                [1]    on_false.pretty_debug();
280                [0] "}";
281            }.to_string(),
282            crate::ExprKind::TypeLevelIf(cond, on_true, on_false) => code!{
283                [0] format!("gen if {} {{", cond.pretty_debug());
284                [1]    on_true.pretty_debug();
285                [0] "} else {";
286                [1]    on_false.pretty_debug();
287                [0] "}";
288            }.to_string(),
289            crate::ExprKind::PipelineRef {
290                stage: _,
291                name: _,
292                declares_name: _,
293                depth_typeexpr_id: _,
294            } => format!("[pipeline ref omitted]"),
295            crate::ExprKind::LambdaDef {
296                lambda_type,
297                lambda_type_params,
298                captured_generic_params,
299                lambda_unit,
300                arguments,
301                body,
302            } => {
303                code!{
304                    [0] format!("fn ({}) {{", arguments.iter().map(PrettyDebug::pretty_debug).join(", "));
305                    [1]     body.pretty_debug();
306                    [0] "}";
307                    [2] format!("Lambda creates {}", lambda_unit.pretty_debug());
308                    [2] format!(
309                        "with type {}<{}>",
310                        lambda_type.pretty_debug(),
311                        lambda_type_params.iter().map(PrettyDebug::pretty_debug).join(", ")
312                    );
313                    [2] format!(
314                        "and captures type params [{}]",
315                        captured_generic_params.iter().map(PrettyDebug::pretty_debug).join(", ")
316                    );
317                }.to_string()
318            },
319            crate::ExprKind::StageValid => format!("stage.valid"),
320            crate::ExprKind::StageReady => format!("stage.ready"),
321            crate::ExprKind::StaticUnreachable(_) => {
322                format!("<STATIC_UNREACHABLE>")
323            },
324            crate::ExprKind::Null => format!("<NULL>"),
325        }
326    }
327}
328
329impl PrettyDebug for TypeParam {
330    fn pretty_debug(&self) -> String {
331        let Self {
332            ident: _,
333            name_id,
334            trait_bounds,
335            meta,
336        } = self;
337
338        format!(
339            "{:?} {}: ({})",
340            meta,
341            name_id.pretty_debug(),
342            trait_bounds.iter().map(PrettyDebug::pretty_debug).join(",")
343        )
344    }
345}
346
347impl PrettyDebug for TraitSpec {
348    fn pretty_debug(&self) -> String {
349        let Self { name, type_params } = self;
350
351        format!(
352            "{}{}",
353            name.name_loc().pretty_debug(),
354            type_params
355                .as_ref()
356                .map(|tp| { format!("<{}>", tp.iter().map(PrettyDebug::pretty_debug).join(", ")) })
357                .unwrap_or(String::new())
358        )
359    }
360}
361
362impl PrettyDebug for CapturedLambdaParam {
363    fn pretty_debug(&self) -> String {
364        let Self {
365            name_in_lambda,
366            name_in_body,
367        } = self;
368        format!("(in def: {name_in_lambda}, in body: {name_in_body})")
369    }
370}
371
372impl PrettyDebug for Pattern {
373    fn pretty_debug(&self) -> String {
374        match &self.kind {
375            crate::PatternKind::Integer(val) => format!("{val}"),
376            crate::PatternKind::Bool(val) => format!("{val}"),
377            crate::PatternKind::Name {
378                name,
379                pre_declared: _,
380            } => name.pretty_debug(),
381            crate::PatternKind::Tuple(inner) => {
382                format!("({})", inner.iter().map(|i| i.pretty_debug()).join(", "))
383            }
384            crate::PatternKind::Array(inner) => {
385                format!("[{}]", inner.iter().map(|i| i.pretty_debug()).join(", "))
386            }
387            crate::PatternKind::Type(base, args) => format!(
388                "{}{{{}}}",
389                base.pretty_debug(),
390                args.iter().map(|arg| arg.pretty_debug()).join(", ")
391            ),
392        }
393    }
394}
395
396impl PrettyDebug for Statement {
397    fn pretty_debug(&self) -> String {
398        match self {
399            Statement::Error => "{error}".to_string(),
400            Statement::Binding(Binding {
401                pattern,
402                ty,
403                value,
404                wal_trace: _,
405            }) => {
406                format!(
407                    "let {}: {} = {};",
408                    pattern.pretty_debug(),
409                    ty.pretty_debug(),
410                    value.pretty_debug()
411                )
412            }
413            Statement::Expression(expr) => format!("{};", expr.pretty_debug()),
414            Statement::Register(Register {
415                pattern,
416                clock,
417                reset,
418                initial,
419                value,
420                value_type,
421                attributes,
422            }) => {
423                format!(
424                    "{} reg({}) {}: {}{}{} = {};",
425                    attributes.pretty_debug(),
426                    clock.pretty_debug(),
427                    pattern.pretty_debug(),
428                    value_type.pretty_debug(),
429                    reset
430                        .as_ref()
431                        .map(|(trig, val)| format!(
432                            "reset ({}: {})",
433                            trig.pretty_debug(),
434                            val.pretty_debug()
435                        ))
436                        .unwrap_or(String::new()),
437                    initial
438                        .as_ref()
439                        .map(|val| format!("initial ({})", val.pretty_debug()))
440                        .unwrap_or(String::new()),
441                    value.pretty_debug()
442                )
443            }
444            Statement::Declaration(names) => {
445                format!(
446                    "decl {};",
447                    names.iter().map(PrettyDebug::pretty_debug).join(", ")
448                )
449            }
450            Statement::PipelineRegMarker(_) => format!("[pipeline reg marker]"),
451            Statement::Label(name) => format!("'{};", name.pretty_debug()),
452            Statement::Assert(loc) => format!("assert {};", loc.pretty_debug()),
453            Statement::Set { target, value } => {
454                format!("set {} = {}", target.pretty_debug(), value.pretty_debug())
455            }
456            Statement::WalSuffixed { .. } => format!("[val suffixed]"),
457        }
458    }
459}
460
461impl PrettyDebug for PatternArgument {
462    fn pretty_debug(&self) -> String {
463        format!("{}: {}", self.target, self.value.pretty_debug())
464    }
465}
466
467impl<Inner> PrettyDebug for NamedArgument<Inner>
468where
469    Inner: PrettyDebug,
470{
471    fn pretty_debug(&self) -> String {
472        match self {
473            NamedArgument::Full(name, val) => {
474                format!("{}: {}", name.pretty_debug(), val.pretty_debug())
475            }
476            NamedArgument::Short(_, value) => value.pretty_debug(),
477        }
478    }
479}
480
481impl<Inner> PrettyDebug for ArgumentList<Inner>
482where
483    Inner: PrettyDebug,
484{
485    fn pretty_debug(&self) -> String {
486        match self {
487            ArgumentList::Named(args) => code! {
488                [0] "$(";
489                [1] args.iter().map(|arg| arg.pretty_debug()).join("\n");
490                [0] ")";
491            }
492            .to_string(),
493            ArgumentList::Positional(args) => code! {
494                [0] "(";
495                [1]     args.iter().map(|arg| arg.pretty_debug()).join("\n");
496                [0] ")"
497            }
498            .to_string(),
499        }
500    }
501}
502
503impl<T> PrettyDebug for &T
504where
505    T: PrettyDebug,
506{
507    fn pretty_debug(&self) -> String {
508        (*self).pretty_debug()
509    }
510}
511
512impl<T> PrettyDebug for Loc<T>
513where
514    T: PrettyDebug,
515{
516    fn pretty_debug(&self) -> String {
517        self.inner.pretty_debug()
518    }
519}
520
521impl<T> PrettyDebug for Option<T>
522where
523    T: PrettyDebug,
524{
525    fn pretty_debug(&self) -> String {
526        match self {
527            Some(inner) => inner.pretty_debug(),
528            None => String::new(),
529        }
530    }
531}