cairo_lang_lowering/
fmt.rs

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
18/// Holds all the information needed for formatting lowered representations.
19/// Acts like a "db" for DebugWithDb.
20pub 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}