cairo_lang_sierra/
debug_info.rs1use std::collections::HashMap;
2use std::hash::Hash;
3
4use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
5use itertools::Itertools;
6use serde::{Deserialize, Serialize};
7use smol_str::SmolStr;
8
9use crate::ids::{ConcreteLibfuncId, ConcreteTypeId, FunctionId};
10use crate::program::{GenericArg, Program, Statement};
11
12#[cfg(test)]
13#[path = "debug_info_test.rs"]
14mod test;
15
16#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
18pub struct DebugInfo {
19 #[serde(
20 serialize_with = "serialize_map::<ConcreteTypeId, _>",
21 deserialize_with = "deserialize_map::<ConcreteTypeId, _>"
22 )]
23 pub type_names: HashMap<ConcreteTypeId, SmolStr>,
24 #[serde(
25 serialize_with = "serialize_map::<ConcreteLibfuncId, _>",
26 deserialize_with = "deserialize_map::<ConcreteLibfuncId, _>"
27 )]
28 pub libfunc_names: HashMap<ConcreteLibfuncId, SmolStr>,
29 #[serde(
30 serialize_with = "serialize_map::<FunctionId, _>",
31 deserialize_with = "deserialize_map::<FunctionId, _>"
32 )]
33 pub user_func_names: HashMap<FunctionId, SmolStr>,
34 #[serde(default, skip_serializing_if = "Annotations::is_empty")]
38 pub annotations: Annotations,
39 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
41 pub executables: HashMap<SmolStr, Vec<FunctionId>>,
42}
43
44pub type Annotations = OrderedHashMap<String, serde_json::Value>;
66
67impl DebugInfo {
68 pub fn extract(program: &Program) -> Self {
70 Self {
71 type_names: program
72 .type_declarations
73 .iter()
74 .filter_map(|decl| {
75 decl.id.debug_name.clone().map(|name| (ConcreteTypeId::new(decl.id.id), name))
76 })
77 .collect(),
78 libfunc_names: program
79 .libfunc_declarations
80 .iter()
81 .filter_map(|decl| {
82 decl.id
83 .debug_name
84 .clone()
85 .map(|name| (ConcreteLibfuncId::new(decl.id.id), name))
86 })
87 .collect(),
88 user_func_names: program
89 .funcs
90 .iter()
91 .filter_map(|func| {
92 func.id.debug_name.clone().map(|name| (FunctionId::new(func.id.id), name))
93 })
94 .collect(),
95 annotations: Default::default(),
96 executables: Default::default(),
97 }
98 }
99
100 pub fn populate(&self, program: &mut Program) {
102 for decl in &mut program.type_declarations {
103 self.try_replace_type_id(&mut decl.id);
104 self.try_replace_generic_arg_ids(&mut decl.long_id.generic_args);
105 }
106 for decl in &mut program.libfunc_declarations {
107 self.try_replace_libfunc_id(&mut decl.id);
108 self.try_replace_generic_arg_ids(&mut decl.long_id.generic_args);
109 }
110 for func in &mut program.funcs {
111 self.try_replace_function_id(&mut func.id);
112 for param in &mut func.params {
113 self.try_replace_type_id(&mut param.ty);
114 }
115 for id in &mut func.signature.param_types {
116 self.try_replace_type_id(id);
117 }
118 for id in &mut func.signature.ret_types {
119 self.try_replace_type_id(id);
120 }
121 }
122 for statement in &mut program.statements {
123 match statement {
124 Statement::Invocation(invocation) => {
125 self.try_replace_libfunc_id(&mut invocation.libfunc_id)
126 }
127 Statement::Return(_) => {}
128 }
129 }
130 }
131
132 fn try_replace_generic_arg_ids(&self, generic_args: &mut Vec<GenericArg>) {
134 for generic_arg in generic_args {
135 match generic_arg {
136 GenericArg::Type(id) => self.try_replace_type_id(id),
137 GenericArg::Libfunc(id) => self.try_replace_libfunc_id(id),
138 GenericArg::UserFunc(id) => self.try_replace_function_id(id),
139 GenericArg::Value(_) | GenericArg::UserType(_) => {}
140 }
141 }
142 }
143
144 fn try_replace_type_id(&self, id: &mut ConcreteTypeId) {
146 if let Some(name) = self.type_names.get(id).cloned() {
147 let _ = id.debug_name.insert(name);
148 }
149 }
150
151 fn try_replace_libfunc_id(&self, id: &mut ConcreteLibfuncId) {
153 if let Some(name) = self.libfunc_names.get(id).cloned() {
154 let _ = id.debug_name.insert(name);
155 }
156 }
157
158 fn try_replace_function_id(&self, id: &mut FunctionId) {
160 if let Some(name) = self.user_func_names.get(id).cloned() {
161 let _ = id.debug_name.insert(name);
162 }
163 }
164}
165
166pub trait IdAsHashKey: Hash + Eq {
168 fn get(&self) -> u64;
170 fn new(id: u64) -> Self;
172}
173
174impl IdAsHashKey for ConcreteTypeId {
175 fn get(&self) -> u64 {
176 self.id
177 }
178
179 fn new(id: u64) -> Self {
180 Self::new(id)
181 }
182}
183impl IdAsHashKey for ConcreteLibfuncId {
184 fn get(&self) -> u64 {
185 self.id
186 }
187
188 fn new(id: u64) -> Self {
189 Self::new(id)
190 }
191}
192impl IdAsHashKey for FunctionId {
193 fn get(&self) -> u64 {
194 self.id
195 }
196
197 fn new(id: u64) -> Self {
198 Self::new(id)
199 }
200}
201
202fn serialize_map<Id: IdAsHashKey, S: serde::Serializer>(
203 m: &HashMap<Id, SmolStr>,
204 serializer: S,
205) -> Result<S::Ok, S::Error> {
206 let v: Vec<_> = m.iter().map(|(id, name)| (id.get(), name)).sorted().collect();
207 v.serialize(serializer)
208}
209
210fn deserialize_map<'de, Id: IdAsHashKey, D: serde::Deserializer<'de>>(
211 deserializer: D,
212) -> Result<HashMap<Id, SmolStr>, D::Error> {
213 Ok(Vec::<(u64, SmolStr)>::deserialize(deserializer)?
214 .into_iter()
215 .map(|(id, name)| (Id::new(id), name))
216 .collect())
217}