1use std::fmt;
2
3use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
4use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
5use itertools::Itertools;
6
7use crate::ids::{
8 ConcreteLibfuncId, ConcreteTypeId, FunctionId, GenericLibfuncId, GenericTypeId, UserTypeId,
9 VarId,
10};
11use crate::labeled_statement::replace_statement_id;
12use crate::program::{
13 ConcreteLibfuncLongId, ConcreteTypeLongId, GenBranchInfo, GenBranchTarget, GenFunction,
14 GenInvocation, GenStatement, GenericArg, LibfuncDeclaration, Param, Program, StatementIdx,
15 TypeDeclaration,
16};
17
18impl fmt::Display for Program {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 for declaration in &self.type_declarations {
21 writeln!(f, "{declaration};")?;
22 }
23 writeln!(f)?;
24 for declaration in &self.libfunc_declarations {
25 writeln!(f, "{declaration};")?;
26 }
27 writeln!(f)?;
28 let funcs_labels = UnorderedHashMap::<usize, String>::from_iter(
30 self.funcs.iter().enumerate().map(|(i, f)| (f.entry_point.0, format!("F{i}"))),
31 );
32 let mut block_offsets = UnorderedHashSet::<usize>::default();
34 for s in &self.statements {
35 replace_statement_id(s.clone(), |idx| {
36 block_offsets.insert(idx.0);
37 });
38 }
39 let mut labels = funcs_labels.clone();
41 let mut function_label = "NONE".to_string();
43 let mut inner_idx = 0;
45 for i in 0..self.statements.len() {
46 if let Some(label) = funcs_labels.get(&i) {
47 function_label = label.clone();
48 inner_idx = 0;
49 } else if block_offsets.contains(&i) {
50 labels.insert(i, format!("{function_label}_B{inner_idx}"));
51 inner_idx += 1;
52 }
53 }
54
55 for (i, statement) in self.statements.iter().enumerate() {
56 if let Some(label) = labels.get(&i) {
57 writeln!(f, "{label}:")?;
58 }
59 let with_labels = replace_statement_id(statement.clone(), |idx| labels[&idx.0].clone());
60 writeln!(f, "{with_labels};")?;
61 }
62 writeln!(f)?;
63 for func in &self.funcs {
64 let with_label = GenFunction {
65 id: func.id.clone(),
66 signature: func.signature.clone(),
67 params: func.params.clone(),
68 entry_point: labels[&func.entry_point.0].clone(),
69 };
70 writeln!(f, "{with_label};",)?;
71 }
72 Ok(())
73 }
74}
75
76impl fmt::Display for TypeDeclaration {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 let TypeDeclaration { id, long_id, declared_type_info } = self;
79 write!(f, "type {id} = {long_id}")?;
80 if let Some(info) = declared_type_info {
81 write!(
82 f,
83 " [storable: {:?}, drop: {:?}, dup: {:?}, zero_sized: {:?}]",
84 info.storable, info.droppable, info.duplicatable, info.zero_sized
85 )?;
86 }
87 Ok(())
88 }
89}
90
91impl fmt::Display for ConcreteTypeLongId {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(f, "{}", self.generic_id)?;
94 write_template_args(f, &self.generic_args)
95 }
96}
97
98impl fmt::Display for LibfuncDeclaration {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(f, "libfunc {} = {}", self.id, self.long_id)
101 }
102}
103
104impl fmt::Display for ConcreteLibfuncLongId {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "{}", self.generic_id)?;
107 write_template_args(f, &self.generic_args)
108 }
109}
110
111impl<StatementId: fmt::Display> fmt::Display for GenFunction<StatementId> {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(
114 f,
115 "{}@{}({}) -> ({})",
116 self.id,
117 self.entry_point,
118 self.params.iter().format(", "),
119 self.signature.ret_types.iter().format(", ")
120 )
121 }
122}
123
124impl fmt::Display for Param {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "{}: {}", self.id, self.ty)
127 }
128}
129
130macro_rules! display_generic_identity {
131 ($type_name:tt) => {
132 impl fmt::Display for $type_name {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(f, "{}", self.0)
135 }
136 }
137 };
138}
139
140display_generic_identity!(GenericLibfuncId);
141display_generic_identity!(GenericTypeId);
142
143macro_rules! display_identity {
144 ($type_name:tt) => {
145 impl fmt::Display for $type_name {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match &self.debug_name {
148 Some(name) => write!(f, "{name}"),
149 None => write!(f, "[{}]", self.id),
150 }
151 }
152 }
153 };
154}
155
156display_identity!(ConcreteLibfuncId);
157display_identity!(FunctionId);
158display_identity!(UserTypeId);
159display_identity!(VarId);
160display_identity!(ConcreteTypeId);
161
162impl fmt::Display for GenericArg {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match self {
165 GenericArg::Type(id) => write!(f, "{id}"),
166 GenericArg::UserType(id) => write!(f, "ut@{id}"),
167 GenericArg::Value(v) => write!(f, "{v}"),
168 GenericArg::UserFunc(id) => write!(f, "user@{id}"),
169 GenericArg::Libfunc(id) => write!(f, "lib@{id}"),
170 }
171 }
172}
173
174impl<StatementId: fmt::Display> fmt::Display for GenStatement<StatementId> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 match self {
177 GenStatement::Invocation(invocation) => write!(f, "{invocation}"),
178 GenStatement::Return(ids) => {
179 write!(f, "return({})", ids.iter().format(", "))
180 }
181 }
182 }
183}
184
185impl<StatementId: fmt::Display> fmt::Display for GenInvocation<StatementId> {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 write!(f, "{}({}) ", self.libfunc_id, self.args.iter().format(", "))?;
188 if let [GenBranchInfo { target: GenBranchTarget::Fallthrough, results }] =
189 &self.branches[..]
190 {
191 write!(f, "-> ({})", results.iter().format(", "))
192 } else {
193 write!(f, "{{ ")?;
194 self.branches.iter().try_for_each(|branch_info| write!(f, "{branch_info} "))?;
195 write!(f, "}}")
196 }
197 }
198}
199
200impl<StatementId: fmt::Display> fmt::Display for GenBranchInfo<StatementId> {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 write!(f, "{}({})", self.target, self.results.iter().format(", "))
203 }
204}
205
206impl<StatementId: fmt::Display> fmt::Display for GenBranchTarget<StatementId> {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 match self {
209 GenBranchTarget::Fallthrough => write!(f, "fallthrough"),
210 GenBranchTarget::Statement(id) => write!(f, "{id}"),
211 }
212 }
213}
214
215impl fmt::Display for StatementIdx {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(f, "{}", self.0)
218 }
219}
220
221fn write_template_args(f: &mut fmt::Formatter<'_>, args: &[GenericArg]) -> fmt::Result {
222 if args.is_empty() { Ok(()) } else { write!(f, "<{}>", args.iter().format(", ")) }
223}