1use std::collections::HashMap;
8
9use itertools::Itertools;
10use spade_common::id_tracker::ExprID;
11
12use crate::{diff::VarMap, Entity};
13use crate::{Binding, MirInput, Register, Statement, ValueName};
14
15pub fn translate_expr(
16 name: ExprID,
17 lhs_trans: &impl Fn(ExprID) -> Option<ExprID>,
18 rhs_trans: &impl Fn(ExprID) -> Option<ExprID>,
19) -> String {
20 let lhs = lhs_trans(name)
21 .map(|n| format!("{}", n.0))
22 .unwrap_or_else(|| "?".to_string());
23 let rhs = rhs_trans(name)
24 .map(|n| format!("{}", n.0))
25 .unwrap_or_else(|| "?".to_string());
26
27 format!("e({}|{})", lhs, rhs)
28}
29
30pub fn translate_name(
31 (id, name): (u64, &str),
32 lhs_trans: &impl Fn(u64) -> Option<u64>,
33 rhs_trans: &impl Fn(u64) -> Option<u64>,
34) -> String {
35 let lhs = lhs_trans(id)
36 .map(|i| format!("{}", i))
37 .unwrap_or_else(|| "?".to_string());
38 let rhs = rhs_trans(id)
39 .map(|i| format!("{}", i))
40 .unwrap_or_else(|| "?".to_string());
41
42 format!("n({}|{}, {})", lhs, rhs, name)
43}
44
45pub struct NameTranslator<F, G>
46where
47 F: Fn(ExprID) -> Option<ExprID>,
48 G: Fn(u64) -> Option<u64>,
49{
50 expr: F,
51 name: G,
52}
53
54pub fn identity_name_translator(
55) -> NameTranslator<impl Fn(ExprID) -> Option<ExprID>, impl Fn(u64) -> Option<u64>> {
56 NameTranslator {
57 expr: Some,
58 name: Some,
59 }
60}
61
62pub fn map_name_translator(
63 expr: HashMap<ExprID, ExprID>,
64 name: HashMap<u64, u64>,
65) -> NameTranslator<impl Fn(ExprID) -> Option<ExprID>, impl Fn(u64) -> Option<u64>> {
66 NameTranslator {
67 expr: move |x| expr.get(&x).cloned(),
68 name: move |x| name.get(&x).cloned(),
69 }
70}
71
72pub fn translate_val_name<LF, LG, RF, RG>(
73 name: &ValueName,
74 lhs_trans: &NameTranslator<LF, LG>,
75 rhs_trans: &NameTranslator<RF, RG>,
76) -> String
77where
78 LF: Fn(ExprID) -> Option<ExprID>,
79 LG: Fn(u64) -> Option<u64>,
80 RF: Fn(ExprID) -> Option<ExprID>,
81 RG: Fn(u64) -> Option<u64>,
82{
83 match name {
84 ValueName::Named(id, n, _) => translate_name((*id, n), &lhs_trans.name, &rhs_trans.name),
85 ValueName::Expr(id) => translate_expr(*id, &lhs_trans.expr, &rhs_trans.expr),
86 }
87}
88
89pub fn translate_statement<LF, LG, RF, RG>(
90 statement: &Statement,
91 lhs_trans: &NameTranslator<LF, LG>,
92 rhs_trans: &NameTranslator<RF, RG>,
93) -> String
94where
95 LF: Fn(ExprID) -> Option<ExprID>,
96 LG: Fn(u64) -> Option<u64>,
97 RF: Fn(ExprID) -> Option<ExprID>,
98 RG: Fn(u64) -> Option<u64>,
99{
100 match statement {
101 Statement::Binding(Binding {
102 name,
103 operator,
104 operands,
105 ty,
106 loc: _,
107 }) => {
108 let name = translate_val_name(name, lhs_trans, rhs_trans);
109 let operands = operands
110 .iter()
111 .map(|op| translate_val_name(op, lhs_trans, rhs_trans))
112 .collect::<Vec<_>>()
113 .join(",");
114
115 format!("{}: {} <- {}({})", name, ty, operator, operands)
116 }
117 Statement::Register(Register {
118 name,
119 ty,
120 clock,
121 reset,
122 initial,
123 value,
124 loc: _,
125 traced,
126 }) => {
127 let name = translate_val_name(name, lhs_trans, rhs_trans);
128 let clock = translate_val_name(clock, lhs_trans, rhs_trans);
129 let reset = reset
130 .as_ref()
131 .map(|(trig, val)| {
132 let trig = translate_val_name(trig, lhs_trans, rhs_trans);
133 let val = translate_val_name(val, lhs_trans, rhs_trans);
134 format!(" reset ({}, {})", trig, val)
135 })
136 .unwrap_or_else(|| "".to_string());
137 let initial = initial
138 .as_ref()
139 .map(|i| {
140 format!(
141 " initial ({})",
142 i.iter().map(|v| format!("{v}").to_string()).join("; ")
143 )
144 })
145 .unwrap_or_else(|| "".to_string());
146 let value = translate_val_name(value, lhs_trans, rhs_trans);
147 let traced = if let Some(traced) = traced {
148 format!(
149 "traced({})",
150 translate_val_name(traced, lhs_trans, rhs_trans)
151 )
152 } else {
153 "".to_string()
154 };
155
156 format!("{traced}reg {name}: {ty} clock {clock}{reset}{initial} {value}",)
157 }
158 Statement::Constant(name, ty, value) => {
159 let name = translate_expr(*name, &lhs_trans.expr, &rhs_trans.expr);
160
161 format!("const {}: {} = {}", name, ty, value)
162 }
163 Statement::Assert(value) => {
164 let value = translate_val_name(value, lhs_trans, rhs_trans);
165 format!("assert {value}")
166 }
167 Statement::Set { target, value } => {
168 let value = translate_val_name(value, lhs_trans, rhs_trans);
169 let target = translate_val_name(target, lhs_trans, rhs_trans);
170 format!("set {target} = {value}")
171 }
172 Statement::WalTrace {
173 name,
174 val,
175 suffix,
176 ty,
177 } => {
178 let name = translate_val_name(name, lhs_trans, rhs_trans);
179 let val = translate_val_name(val, lhs_trans, rhs_trans);
180 format!("wal_trace ({name}, {val}, '{suffix}', {ty})")
181 }
182 }
183}
184
185pub fn translate_entity<LF, LG, RF, RG>(
186 entity: &Entity,
187 lhs_trans: &NameTranslator<LF, LG>,
188 rhs_trans: &NameTranslator<RF, RG>,
189) -> String
190where
191 LF: Fn(ExprID) -> Option<ExprID>,
192 LG: Fn(u64) -> Option<u64>,
193 RF: Fn(ExprID) -> Option<ExprID>,
194 RG: Fn(u64) -> Option<u64>,
195{
196 let Entity {
197 name,
198 inputs,
199 output,
200 output_type,
201 statements,
202 } = entity;
203
204 let inputs = inputs
205 .iter()
206 .map(
207 |MirInput {
208 name,
209 val_name,
210 ty,
211 no_mangle,
212 }| {
213 let val_name = translate_val_name(val_name, lhs_trans, rhs_trans);
214
215 format!(
216 "({}{name}, {val_name}: {ty})",
217 no_mangle.map(|_| "#[no_mangle]").unwrap_or("")
218 )
219 },
220 )
221 .collect::<Vec<_>>()
222 .join(",");
223
224 let output = translate_val_name(output, lhs_trans, rhs_trans);
225
226 let statements = statements
227 .iter()
228 .map(|s| translate_statement(s, lhs_trans, rhs_trans))
229 .map(|s| format!(" {}", s))
230 .collect::<Vec<_>>()
231 .join("\n");
232
233 indoc::formatdoc!(
234 r#"entity {}({}) -> {} {{
235 {}
236 }} => {}"#,
237 name,
238 inputs,
239 output_type,
240 statements,
241 output
242 )
243}
244
245pub fn translated_strings(lhs: &Entity, rhs: &Entity, map: &VarMap) -> (String, String) {
247 let lhs_string = translate_entity(
248 lhs,
249 &identity_name_translator(),
250 &map_name_translator(map.expr_map.clone(), map.name_map.clone()),
251 );
252
253 let rhs_string = translate_entity(
254 rhs,
255 &map_name_translator(map.expr_map_rev.clone(), map.name_map_rev.clone()),
256 &identity_name_translator(),
257 );
258
259 (lhs_string, rhs_string)
260}