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}