cairo_lang_sierra/
fmt.rs

1use std::fmt;
2
3use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
4use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
5use cairo_lang_utils::write_comma_separated;
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        // The labels of function starts.
29        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        // The offsets of branch targets.
33        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        // All labels including inner function labels.
40        let mut labels = funcs_labels.clone();
41        // Starting as `NONE` for support of invalid Sierra code.
42        let mut function_label = "NONE".to_string();
43        // Assuming function code is contiguous - this is the index for same function labels.
44        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!(f, "{}@{}(", self.id, self.entry_point)?;
114        write_comma_separated(f, &self.params)?;
115        write!(f, ") -> (")?;
116        write_comma_separated(f, &self.signature.ret_types)?;
117        write!(f, ")")
118    }
119}
120
121impl fmt::Display for Param {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        write!(f, "{}: {}", self.id, self.ty)
124    }
125}
126
127macro_rules! display_generic_identity {
128    ($type_name:tt) => {
129        impl fmt::Display for $type_name {
130            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131                write!(f, "{}", self.0)
132            }
133        }
134    };
135}
136
137display_generic_identity!(GenericLibfuncId);
138display_generic_identity!(GenericTypeId);
139
140macro_rules! display_identity {
141    ($type_name:tt) => {
142        impl fmt::Display for $type_name {
143            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144                match &self.debug_name {
145                    Some(name) => write!(f, "{name}"),
146                    None => write!(f, "[{}]", self.id),
147                }
148            }
149        }
150    };
151}
152
153display_identity!(ConcreteLibfuncId);
154display_identity!(FunctionId);
155display_identity!(UserTypeId);
156display_identity!(VarId);
157display_identity!(ConcreteTypeId);
158
159impl fmt::Display for GenericArg {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        match self {
162            GenericArg::Type(id) => write!(f, "{id}"),
163            GenericArg::UserType(id) => write!(f, "ut@{id}"),
164            GenericArg::Value(v) => write!(f, "{v}"),
165            GenericArg::UserFunc(id) => write!(f, "user@{id}"),
166            GenericArg::Libfunc(id) => write!(f, "lib@{id}"),
167        }
168    }
169}
170
171impl<StatementId: fmt::Display> fmt::Display for GenStatement<StatementId> {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        match self {
174            GenStatement::Invocation(invocation) => write!(f, "{invocation}"),
175            GenStatement::Return(ids) => {
176                write!(f, "return(")?;
177                write_comma_separated(f, ids)?;
178                write!(f, ")")
179            }
180        }
181    }
182}
183
184impl<StatementId: fmt::Display> fmt::Display for GenInvocation<StatementId> {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        write!(f, "{}(", self.libfunc_id)?;
187        write_comma_separated(f, &self.args)?;
188        if let [GenBranchInfo { target: GenBranchTarget::Fallthrough, results }] =
189            &self.branches[..]
190        {
191            write!(f, ") -> (")?;
192            write_comma_separated(f, results)?;
193            write!(f, ")")
194        } else {
195            write!(f, ") {{ ")?;
196            self.branches.iter().try_for_each(|branch_info| write!(f, "{branch_info} "))?;
197            write!(f, "}}")
198        }
199    }
200}
201
202impl<StatementId: fmt::Display> fmt::Display for GenBranchInfo<StatementId> {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        write!(f, "{}(", self.target)?;
205        write_comma_separated(f, &self.results)?;
206        write!(f, ")")
207    }
208}
209
210impl<StatementId: fmt::Display> fmt::Display for GenBranchTarget<StatementId> {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        match self {
213            GenBranchTarget::Fallthrough => write!(f, "fallthrough"),
214            GenBranchTarget::Statement(id) => write!(f, "{id}"),
215        }
216    }
217}
218
219impl fmt::Display for StatementIdx {
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        write!(f, "{}", self.0)
222    }
223}
224
225fn write_template_args(f: &mut fmt::Formatter<'_>, args: &[GenericArg]) -> fmt::Result {
226    if args.is_empty() {
227        Ok(())
228    } else {
229        write!(f, "<")?;
230        write_comma_separated(f, args)?;
231        write!(f, ">")
232    }
233}