1use cairo_lang_debug::DebugWithDb;
2use cairo_lang_defs::ids::NamedLanguageElementId;
3use cairo_lang_utils::LookupIntern;
4use id_arena::Arena;
5use itertools::Itertools;
6
7use crate::db::LoweringGroup;
8use crate::objects::{
9 BlockId, MatchExternInfo, Statement, StatementCall, StatementConst, StatementStructDestructure,
10 VariableId,
11};
12use crate::{
13 FlatBlock, FlatBlockEnd, FlatLowered, MatchArm, MatchEnumInfo, MatchEnumValue, MatchInfo,
14 StatementDesnap, StatementEnumConstruct, StatementSnapshot, StatementStructConstruct,
15 VarRemapping, VarUsage, Variable,
16};
17
18pub struct LoweredFormatter<'db> {
21 pub db: &'db dyn LoweringGroup,
22 pub variables: &'db Arena<Variable>,
23 pub include_usage_location: bool,
24}
25impl<'db> LoweredFormatter<'db> {
26 pub fn new(db: &'db dyn LoweringGroup, variables: &'db Arena<Variable>) -> Self {
27 Self { db, variables, include_usage_location: false }
28 }
29}
30
31impl DebugWithDb<LoweredFormatter<'_>> for VarRemapping {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
33 let mut remapping = self.iter().peekable();
34 write!(f, "{{")?;
35 while let Some((dst, src)) = remapping.next() {
36 src.var_id.fmt(f, ctx)?;
37 write!(f, " -> ")?;
38 dst.fmt(f, ctx)?;
39 if remapping.peek().is_some() {
40 write!(f, ", ")?;
41 }
42 }
43 write!(f, "}}")?;
44 Ok(())
45 }
46}
47impl DebugWithDb<LoweredFormatter<'_>> for FlatLowered {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
49 write!(f, "Parameters:")?;
50 let mut inputs = self.parameters.iter().peekable();
51 while let Some(var) = inputs.next() {
52 write!(f, " ")?;
53 format_var_with_ty(*var, f, ctx)?;
54 if inputs.peek().is_some() {
55 write!(f, ",")?;
56 }
57 }
58 writeln!(f)?;
59 let mut blocks = self.blocks.iter();
60 if let Some((root_block_id, root_block)) = blocks.next() {
61 root_block_id.fmt(f, ctx)?;
62 writeln!(f, " (root):")?;
63 root_block.fmt(f, ctx)?;
64 writeln!(f)?;
65 }
66 for (block_id, block) in blocks {
67 block_id.fmt(f, ctx)?;
68 writeln!(f, ":")?;
69 block.fmt(f, ctx)?;
70 writeln!(f)?;
71 }
72 Ok(())
73 }
74}
75
76impl DebugWithDb<LoweredFormatter<'_>> for FlatBlock {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
78 writeln!(f, "Statements:")?;
79 for stmt in &self.statements {
80 write!(f, " ")?;
81 stmt.fmt(f, ctx)?;
82 writeln!(f)?;
83 }
84
85 writeln!(f, "End:")?;
86 self.end.fmt(f, ctx)?;
87 writeln!(f)
88 }
89}
90
91impl DebugWithDb<LoweredFormatter<'_>> for FlatBlockEnd {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
93 let outputs = match &self {
94 FlatBlockEnd::Return(returns, _location) => {
95 write!(f, " Return(")?;
96 returns.iter().map(|var_usage| var_usage.var_id).collect()
97 }
98 FlatBlockEnd::Panic(data) => {
99 write!(f, " Panic(")?;
100 vec![data.var_id]
101 }
102 FlatBlockEnd::Goto(block_id, remapping) => {
103 return write!(f, " Goto({:?}, {:?})", block_id.debug(ctx), remapping.debug(ctx));
104 }
105 FlatBlockEnd::NotSet => unreachable!(),
106 FlatBlockEnd::Match { info } => {
107 return write!(f, " Match({:?})", info.debug(ctx));
108 }
109 };
110 let mut outputs = outputs.iter().peekable();
111 while let Some(var) = outputs.next() {
112 var.fmt(f, ctx)?;
113 if outputs.peek().is_some() {
114 write!(f, ", ")?;
115 }
116 }
117 write!(f, ")")
118 }
119}
120
121fn format_var_with_ty(
122 var_id: VariableId,
123 f: &mut std::fmt::Formatter<'_>,
124 ctx: &LoweredFormatter<'_>,
125) -> std::fmt::Result {
126 var_id.fmt(f, ctx)?;
127 let var = &ctx.variables[var_id];
128 write!(f, ": {}", var.ty.format(ctx.db.upcast()))
129}
130
131impl DebugWithDb<LoweredFormatter<'_>> for BlockId {
132 fn fmt(
133 &self,
134 f: &mut std::fmt::Formatter<'_>,
135 _lowered: &LoweredFormatter<'_>,
136 ) -> std::fmt::Result {
137 write!(f, "blk{:?}", self.0)
138 }
139}
140
141impl DebugWithDb<LoweredFormatter<'_>> for VarUsage {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
143 write!(f, "v{:?}", self.var_id.index(),)?;
144 if ctx.include_usage_location {
145 write!(
146 f,
147 "{{`{}`}}",
148 self.location
149 .lookup_intern(ctx.db)
150 .stable_location
151 .syntax_node(ctx.db.upcast())
152 .get_text_without_trivia(ctx.db.upcast())
153 .lines()
154 .map(|s| s.trim())
155 .join(" ")
156 )?;
157 }
158 Ok(())
159 }
160}
161
162impl DebugWithDb<LoweredFormatter<'_>> for VariableId {
163 fn fmt(
164 &self,
165 f: &mut std::fmt::Formatter<'_>,
166 _lowered: &LoweredFormatter<'_>,
167 ) -> std::fmt::Result {
168 write!(f, "v{:?}", self.index())
169 }
170}
171
172impl DebugWithDb<LoweredFormatter<'_>> for Statement {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
174 write!(f, "(")?;
175 let mut outputs = self.outputs().iter().peekable();
176 while let Some(var) = outputs.next() {
177 format_var_with_ty(*var, f, ctx)?;
178 if outputs.peek().is_some() {
179 write!(f, ", ")?;
180 }
181 }
182 write!(f, ") <- ")?;
183 match self {
184 Statement::Const(stmt) => stmt.fmt(f, ctx),
185 Statement::Call(stmt) => stmt.fmt(f, ctx),
186 Statement::StructConstruct(stmt) => stmt.fmt(f, ctx),
187 Statement::StructDestructure(stmt) => stmt.fmt(f, ctx),
188 Statement::EnumConstruct(stmt) => stmt.fmt(f, ctx),
189 Statement::Snapshot(stmt) => stmt.fmt(f, ctx),
190 Statement::Desnap(stmt) => stmt.fmt(f, ctx),
191 }
192 }
193}
194
195impl DebugWithDb<LoweredFormatter<'_>> for MatchInfo {
196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
197 match self {
198 MatchInfo::Extern(s) => s.fmt(f, ctx),
199 MatchInfo::Enum(s) => s.fmt(f, ctx),
200 MatchInfo::Value(s) => s.fmt(f, ctx),
201 }
202 }
203}
204
205impl DebugWithDb<LoweredFormatter<'_>> for StatementConst {
206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
207 self.value.fmt(f, ctx.db)
208 }
209}
210
211impl DebugWithDb<LoweredFormatter<'_>> for StatementCall {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
213 write!(f, "{:?}(", self.function.lookup_intern(ctx.db).debug(ctx.db))?;
214 for (i, var) in self.inputs.iter().enumerate() {
215 let is_last = i == self.inputs.len() - 1;
216 if is_last && self.with_coupon {
217 write!(f, "__coupon__: ")?;
218 }
219 var.fmt(f, ctx)?;
220 if !is_last {
221 write!(f, ", ")?;
222 }
223 }
224 write!(f, ")")
225 }
226}
227
228impl DebugWithDb<LoweredFormatter<'_>> for MatchExternInfo {
229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
230 write!(f, "match {:?}(", self.function.lookup_intern(ctx.db).debug(ctx.db))?;
231 let mut inputs = self.inputs.iter().peekable();
232 while let Some(var) = inputs.next() {
233 var.fmt(f, ctx)?;
234 if inputs.peek().is_some() {
235 write!(f, ", ")?;
236 }
237 }
238 writeln!(f, ") {{")?;
239 for arm in &self.arms {
240 arm.fmt(f, ctx)?;
241 writeln!(f)?;
242 }
243 write!(f, " }}")
244 }
245}
246
247impl DebugWithDb<LoweredFormatter<'_>> for MatchArm {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
249 write!(f, " {:?}", self.arm_selector.debug(ctx.db))?;
250
251 if !self.var_ids.is_empty() {
252 write!(f, "(")?;
253 let mut var_ids = self.var_ids.iter().peekable();
254 while let Some(var_id) = var_ids.next() {
255 var_id.fmt(f, ctx)?;
256 if var_ids.peek().is_some() {
257 write!(f, ", ")?;
258 }
259 }
260 write!(f, ")")?;
261 }
262
263 write!(f, " => {:?},", self.block_id.debug(ctx))
264 }
265}
266
267impl DebugWithDb<LoweredFormatter<'_>> for MatchEnumInfo {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
269 write!(f, "match_enum(")?;
270 self.input.fmt(f, ctx)?;
271 writeln!(f, ") {{")?;
272 for arm in &self.arms {
273 arm.fmt(f, ctx)?;
274 writeln!(f)?;
275 }
276 write!(f, " }}")
277 }
278}
279
280impl DebugWithDb<LoweredFormatter<'_>> for MatchEnumValue {
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
282 write!(f, "match_enum.(")?;
283 self.input.fmt(f, ctx)?;
284 writeln!(f, ") {{")?;
285 for arm in &self.arms {
286 arm.fmt(f, ctx)?;
287 writeln!(f)?;
288 }
289 write!(f, " }}")
290 }
291}
292
293impl DebugWithDb<LoweredFormatter<'_>> for StatementEnumConstruct {
294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
295 let enum_name =
296 self.variant.concrete_enum_id.enum_id(ctx.db.upcast()).name(ctx.db.upcast());
297 let variant_name = self.variant.id.name(ctx.db.upcast());
298 write!(f, "{enum_name}::{variant_name}(",)?;
299 self.input.fmt(f, ctx)?;
300 write!(f, ")")
301 }
302}
303
304impl DebugWithDb<LoweredFormatter<'_>> for StatementStructConstruct {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
306 write!(f, "struct_construct(")?;
307 let mut inputs = self.inputs.iter().peekable();
308 while let Some(var) = inputs.next() {
309 var.fmt(f, ctx)?;
310 if inputs.peek().is_some() {
311 write!(f, ", ")?;
312 }
313 }
314 write!(f, ")")
315 }
316}
317
318impl DebugWithDb<LoweredFormatter<'_>> for StatementStructDestructure {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
320 write!(f, "struct_destructure(")?;
321 self.input.fmt(f, ctx)?;
322 write!(f, ")")
323 }
324}
325
326impl DebugWithDb<LoweredFormatter<'_>> for StatementSnapshot {
327 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
328 write!(f, "snapshot(")?;
329 self.input.fmt(f, ctx)?;
330 write!(f, ")")
331 }
332}
333
334impl DebugWithDb<LoweredFormatter<'_>> for StatementDesnap {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &LoweredFormatter<'_>) -> std::fmt::Result {
336 write!(f, "desnap(")?;
337 self.input.fmt(f, ctx)?;
338 write!(f, ")")
339 }
340}