charon_lib/pretty/
formatter.rs1use std::borrow::Cow;
2use std::fmt;
3use std::fmt::Display;
4
5use index_vec::Idx;
6
7use crate::ast::*;
8use crate::common::TAB_INCR;
9use crate::ids::Vector;
10use crate::pretty::FmtWithCtx;
11
12pub trait IntoFormatter {
13 type C: AstFormatter;
14 fn into_fmt(self) -> Self::C;
15}
16
17pub trait AstFormatter: Sized {
20 type Reborrow<'a>: AstFormatter + 'a
21 where
22 Self: 'a;
23
24 fn get_crate(&self) -> Option<&TranslatedCrate>;
25
26 fn no_generics<'a>(&'a self) -> Self::Reborrow<'a>;
27 fn set_generics<'a>(&'a self, generics: &'a GenericParams) -> Self::Reborrow<'a>;
28 fn set_locals<'a>(&'a self, locals: &'a Locals) -> Self::Reborrow<'a>;
29 fn push_binder<'a>(&'a self, new_params: Cow<'a, GenericParams>) -> Self::Reborrow<'a>;
30 fn push_bound_regions<'a>(
31 &'a self,
32 regions: &'a Vector<RegionId, RegionParam>,
33 ) -> Self::Reborrow<'a> {
34 self.push_binder(Cow::Owned(GenericParams {
35 regions: regions.clone(),
36 ..Default::default()
37 }))
38 }
39 fn binder_depth(&self) -> usize;
41
42 fn increase_indent<'a>(&'a self) -> Self::Reborrow<'a>;
43 fn indent(&self) -> String;
44
45 fn format_local_id(&self, f: &mut fmt::Formatter<'_>, id: LocalId) -> fmt::Result;
46 fn format_bound_var<Id: Idx + Display, T>(
47 &self,
48 f: &mut fmt::Formatter<'_>,
49 var: DeBruijnVar<Id>,
50 var_prefix: &str,
51 fmt_var: impl Fn(&T) -> Option<String>,
52 ) -> fmt::Result
53 where
54 GenericParams: HasVectorOf<Id, Output = T>;
55
56 fn format_enum_variant(
57 &self,
58 f: &mut fmt::Formatter<'_>,
59 type_id: TypeDeclId,
60 variant_id: VariantId,
61 ) -> fmt::Result {
62 let variant = if let Some(translated) = self.get_crate()
63 && let Some(def) = translated.type_decls.get(type_id)
64 && let Some(variants) = def.kind.as_enum()
65 {
66 &variants.get(variant_id).unwrap().name
67 } else {
68 &variant_id.to_pretty_string()
69 };
70 write!(f, "{}::{variant}", type_id.with_ctx(self))
71 }
72
73 fn format_field_name(
74 &self,
75 f: &mut fmt::Formatter<'_>,
76 type_id: TypeDeclId,
77 opt_variant_id: Option<VariantId>,
78 field_id: FieldId,
79 ) -> fmt::Result {
80 let field_name = if let Some(translated) = self.get_crate()
81 && let Some(def) = translated.type_decls.get(type_id)
82 {
83 match (&def.kind, opt_variant_id) {
84 (TypeDeclKind::Enum(variants), Some(variant_id)) => {
85 variants[variant_id].fields[field_id].name.as_ref()
86 }
87 (TypeDeclKind::Struct(fields) | TypeDeclKind::Union(fields), None) => {
88 fields[field_id].name.as_ref()
89 }
90 _ => None,
91 }
92 } else {
93 None
94 };
95 if let Some(field_name) = field_name {
96 write!(f, "{field_name}")
97 } else {
98 write!(f, "{field_id}")
99 }
100 }
101}
102
103#[derive(Default)]
105pub struct FmtCtx<'a> {
106 pub translated: Option<&'a TranslatedCrate>,
107 pub generics: BindingStack<Cow<'a, GenericParams>>,
110 pub locals: Option<&'a Locals>,
111 pub indent_level: usize,
112}
113
114impl<'c> AstFormatter for FmtCtx<'c> {
115 type Reborrow<'a>
116 = FmtCtx<'a>
117 where
118 Self: 'a;
119
120 fn get_crate(&self) -> Option<&TranslatedCrate> {
121 self.translated
122 }
123
124 fn no_generics<'a>(&'a self) -> Self::Reborrow<'a> {
125 FmtCtx {
126 generics: BindingStack::empty(),
127 ..self.reborrow()
128 }
129 }
130 fn set_generics<'a>(&'a self, generics: &'a GenericParams) -> Self::Reborrow<'a> {
131 FmtCtx {
132 generics: BindingStack::new(Cow::Borrowed(generics)),
133 ..self.reborrow()
134 }
135 }
136 fn set_locals<'a>(&'a self, locals: &'a Locals) -> Self::Reborrow<'a> {
137 FmtCtx {
138 locals: Some(locals),
139 ..self.reborrow()
140 }
141 }
142 fn push_binder<'a>(&'a self, new_params: Cow<'a, GenericParams>) -> Self::Reborrow<'a> {
143 let mut ret = self.reborrow();
144 ret.generics.push(new_params);
145 ret
146 }
147 fn binder_depth(&self) -> usize {
148 self.generics.len()
149 }
150
151 fn increase_indent<'a>(&'a self) -> Self::Reborrow<'a> {
152 FmtCtx {
153 indent_level: self.indent_level + 1,
154 ..self.reborrow()
155 }
156 }
157 fn indent(&self) -> String {
158 TAB_INCR.repeat(self.indent_level)
159 }
160
161 fn format_local_id(&self, f: &mut fmt::Formatter<'_>, id: LocalId) -> fmt::Result {
162 if let Some(locals) = &self.locals
163 && let Some(v) = locals.locals.get(id)
164 {
165 write!(f, "{v}")
166 } else {
167 write!(f, "{}", id.to_pretty_string())
168 }
169 }
170
171 fn format_bound_var<Id: Idx + Display, T>(
172 &self,
173 f: &mut fmt::Formatter<'_>,
174 var: DeBruijnVar<Id>,
175 var_prefix: &str,
176 fmt_var: impl Fn(&T) -> Option<String>,
177 ) -> fmt::Result
178 where
179 GenericParams: HasVectorOf<Id, Output = T>,
180 {
181 if self.generics.is_empty() {
182 return write!(f, "{var_prefix}{var}");
183 }
184 match self.generics.get_var::<_, GenericParams>(var) {
185 None => write!(f, "missing({var_prefix}{var})"),
186 Some(v) => match fmt_var(v) {
187 Some(name) => write!(f, "{name}"),
188 None => {
189 write!(f, "{var_prefix}")?;
190 let (dbid, varid) = self.generics.as_bound_var(var);
191 let depth = self.generics.depth().index - dbid.index;
192 if depth == 0 {
193 write!(f, "{varid}")
194 } else {
195 write!(f, "{varid}_{depth}")
196 }
197 }
198 },
199 }
200 }
201}
202
203impl<'a> FmtCtx<'a> {
204 pub fn new() -> Self {
205 FmtCtx::default()
206 }
207
208 pub fn get_item(&self, id: ItemId) -> Result<ItemRef<'_>, Option<&Name>> {
209 let Some(translated) = &self.translated else {
210 return Err(None);
211 };
212 translated
213 .get_item(id)
214 .ok_or_else(|| translated.item_short_name(id))
215 }
216
217 pub fn format_decl_id(&self, id: impl Into<ItemId>) -> String {
219 let id = id.into();
220 match self.get_item(id) {
221 Ok(d) => d.to_string_with_ctx(self),
222 Err(opt_name) => {
223 let opt_name = opt_name
224 .map(|n| format!(" ({})", n.with_ctx(self)))
225 .unwrap_or_default();
226 format!("Missing decl: {id:?}{opt_name}")
227 }
228 }
229 }
230
231 fn reborrow<'b>(&'b self) -> FmtCtx<'b> {
232 FmtCtx {
233 translated: self.translated.as_deref(),
234 generics: self.generics.clone(),
235 locals: self.locals.as_deref(),
236 indent_level: self.indent_level,
237 }
238 }
239}