1use std::fmt::Display;
23
24use super::*;
25use crate::ast::*;
26use pretty::{DocAllocator, DocBuilder};
27
28use crate::symbol::Symbol;
29use identifiers::*;
30use literals::*;
31use resugared::*;
32
33pub struct DebugJSON<T: serde::Serialize>(pub T);
59
60impl<T: serde::Serialize> Display for DebugJSON<T> {
61 #[cfg(not(unix))]
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(f, "<unknown, DebugJSON supported on unix plateforms only>")
64 }
65 #[cfg(unix)]
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 const PATH: &str = "/tmp/hax-ast-debug.json";
68 fn append_line_json(value: &serde_json::Value) -> std::io::Result<usize> {
70 use std::io::{BufRead, BufReader, Write};
71 cleanup();
72 let file = std::fs::OpenOptions::new()
73 .read(true)
74 .append(true)
75 .create(true)
76 .open(PATH)?;
77 let count = BufReader::new(&file).lines().count();
78 writeln!(&file, "{value}")?;
79 Ok(count)
80 }
81
82 fn cleanup() {
84 static DID_RUN: AtomicBool = AtomicBool::new(false);
85 use std::sync::atomic::{AtomicBool, Ordering};
86 if DID_RUN
87 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
88 .is_ok()
89 {
90 let _ignored = std::fs::remove_file(PATH);
91 }
92 }
93
94 if let Ok(id) = append_line_json(&serde_json::to_value(&self.0).unwrap()) {
95 write!(f, "`just debug-json {id}`")
96 } else {
97 write!(f, "<DebugJSON failed>")
98 }
99 }
100}
101
102impl<'a, 'b, A: 'a + Clone, P: PrettyAst<'a, 'b, A>, T: 'b + serde::Serialize> Pretty<'a, P, A>
103 for DebugJSON<T>
104{
105 fn pretty(self, allocator: &'a P) -> DocBuilder<'a, P, A> {
106 allocator.as_string(format!("{self}"))
107 }
108}
109
110#[macro_export]
111macro_rules! todo_document {
113 ($allocator:ident,) => {
114 {return $allocator.todo_document(&format!("TODO_LINE_{}", std::line!()));}
115 };
116 ($allocator:ident, $($tt:tt)*) => {
117 {
118 let message = format!($($tt)*);
119 return $allocator.todo_document(&message);
120 }
121 };
122}
123pub use todo_document;
124
125#[macro_export]
126macro_rules! install_pretty_helpers {
156 ($allocator:ident : $allocator_type:ty) => {
157 $crate::printer::pretty_ast::install_pretty_helpers!(
158 @$allocator,
159 #[doc = ::std::concat!("Proxy macro for [`", stringify!($crate), "::printer::pretty_ast::todo_document`] that automatically uses `", stringify!($allocator),"` as allocator.")]
160 disambiguated_todo{$crate::printer::pretty_ast::todo_document!},
161 #[doc = ::std::concat!("Proxy macro for [`pretty::docs`] that automatically uses `", stringify!($allocator),"` as allocator.")]
162 docs{pretty::docs!},
163 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::nil`] that automatically uses `", stringify!($allocator),"` as allocator.")]
164 nil{<$allocator_type as ::pretty::DocAllocator<'_, _>>::nil},
165 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::fail`] that automatically uses `", stringify!($allocator),"` as allocator.")]
166 fail{<$allocator_type as ::pretty::DocAllocator<'_, _>>::fail},
167 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::hardline`] that automatically uses `", stringify!($allocator),"` as allocator.")]
168 hardline{<$allocator_type as ::pretty::DocAllocator<'_, _>>::hardline},
169 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::space`] that automatically uses `", stringify!($allocator),"` as allocator.")]
170 space{<$allocator_type as ::pretty::DocAllocator<'_, _>>::space},
171 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::line`] that automatically uses `", stringify!($allocator),"` as allocator.")]
172 disambiguated_line{<$allocator_type as ::pretty::DocAllocator<'_, _>>::line},
173 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::line_`] that automatically uses `", stringify!($allocator),"` as allocator.")]
174 line_{<$allocator_type as ::pretty::DocAllocator<'_, _>>::line_},
175 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::softline`] that automatically uses `", stringify!($allocator),"` as allocator.")]
176 softline{<$allocator_type as ::pretty::DocAllocator<'_, _>>::softline},
177 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::softline_`] that automatically uses `", stringify!($allocator),"` as allocator.")]
178 softline_{<$allocator_type as ::pretty::DocAllocator<'_, _>>::softline_},
179 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::as_string`] that automatically uses `", stringify!($allocator),"` as allocator.")]
180 as_string{<$allocator_type as ::pretty::DocAllocator<'_, _>>::as_string},
181 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::text`] that automatically uses `", stringify!($allocator),"` as allocator.")]
182 text{<$allocator_type as ::pretty::DocAllocator<'_, _>>::text},
183 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::concat`] that automatically uses `", stringify!($allocator),"` as allocator.")]
184 disambiguated_concat{<$allocator_type as ::pretty::DocAllocator<'_, _>>::concat},
185 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::intersperse`] that automatically uses `", stringify!($allocator),"` as allocator.")]
186 intersperse{<$allocator_type as ::pretty::DocAllocator<'_, _>>::intersperse},
187 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::column`] that automatically uses `", stringify!($allocator),"` as allocator.")]
188 column{<$allocator_type as ::pretty::DocAllocator<'_, _>>::column},
189 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::nesting`] that automatically uses `", stringify!($allocator),"` as allocator.")]
190 nesting{<$allocator_type as ::pretty::DocAllocator<'_, _>>::nesting},
191 #[doc = ::std::concat!("Proxy macro for [`pretty::DocAllocator::reflow`] that automatically uses `", stringify!($allocator),"` as allocator.")]
192 reflow{<$allocator_type as ::pretty::DocAllocator<'_, _>>::reflow}
193 );
194 };
195 (@$allocator:ident, $($(#[$($attrs:tt)*])*$name:ident{$($callable:tt)*}),*) => {
196 $(
197 #[hax_rust_engine_macros::partial_apply($($callable)*, $allocator,)]
198 #[allow(unused)]
199 $(#[$($attrs)*])*
200 macro_rules! $name {}
201 )*
202 };
203}
204pub use install_pretty_helpers;
205
206macro_rules! mk {
207 ($($ty:ident),*) => {
208 pastey::paste! {
209 pub trait PrettyAst<'a, 'b, A: 'a + Clone>: DocAllocator<'a, A> + Sized {
240 fn todo_document(&'a self, message: &str) -> DocBuilder<'a, Self, A> {
242 self.as_string(message)
243 }
244 fn unimplemented_method(&'a self, method: &str, ast: ast::fragment::FragmentRef<'_>) -> DocBuilder<'a, Self, A> {
253 self.text(format!("`{method}` unimpl, {}", DebugJSON(ast))).parens()
254 }
255 $(
256 #[doc = "Define how the printer formats a value of this AST type."]
257 #[doc = "Do not call this method directly. Use [`pretty::Pretty::pretty`] instead, so annotations/spans are preserved correctly."]
258 #[deprecated = "Do not call this method directly. Use [`pretty::Pretty::pretty`] instead, so annotations/spans are preserved correctly."]
259 fn [<$ty:snake>](&'a self, [<$ty:snake>]: &'b $ty) -> DocBuilder<'a, Self, A> {
260 mk!(@method_body $ty [<$ty:snake>] self [<$ty:snake>])
261 }
262 )*
263 }
264
265 $(
266 impl<'a, 'b, A: 'a + Clone, P: PrettyAst<'a, 'b, A>> Pretty<'a, P, A> for &'b $ty {
267 fn pretty(self, allocator: &'a P) -> DocBuilder<'a, P, A> {
268 #[allow(deprecated)]
272 let print = <P as PrettyAst<'_, '_, _>>::[<$ty:snake>];
273 print(allocator, self)
274 }
275 }
276 )*
277 }
278 };
279 (@method_body Symbol $meth:ident $self:ident $value:ident) => {
281 $self.text($value.to_string())
282 };
283 (@method_body LocalId $meth:ident $self:ident $value:ident) => {
284 ::pretty::docs![$self, &$value.0]
285 };
286 (@method_body $ty:ident $meth:ident $self:ident $value:ident) => {
287 $self.unimplemented_method(stringify!($meth), ast::fragment::FragmentRef::from($meth))
288 };
289}
290
291#[hax_rust_engine_macros::replace(AstNodes => include(VisitableAstNodes))]
292mk!(GlobalId, AstNodes);