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