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}