1use super::framework::*;
2
3use std::fmt::Error as E;
4use std::fmt::Result as R;
5use std::fmt::Write;
6
7struct Out<'c> {
8 out: String,
9 subset_only: Option<&'c WithinVariant<'c>>,
10}
11
12impl Write for Out<'_> {
13 fn write_str(&mut self, s: &str) -> fmt::Result {
14 self.out.write_str(s)
15 }
16}
17
18pub fn dump(ctx: &Context) {
19 let w = (|| {
20 let out = String::new();
21 let subset_only = match ctx.within_loop {
22 WithinLoop::None => None,
23 WithinLoop::When | WithinLoop::Body => {
24 Some(ctx.variant.expect("within loop, but not variant!"))
25 }
26 };
27 let mut w = Out { out, subset_only };
28
29 let description =
30 format!("derive-deftly expansions dump {}", ctx.display_for_dbg());
31
32 writeln!(w, "---------- {} (start) ----------", description)?;
33 dump_whole(&mut w, ctx)?;
34 writeln!(w, "---------- {} (end) ----------", description)?;
35
36 Ok::<_, E>(w.out)
37 })()
38 .expect("write to String failed");
39
40 eprint!("{}", w);
41}
42
43fn template_result(ctx: &Context, templ: TokenStream) -> String {
44 let parser = |input: &ParseBuffer<'_>| Template::parse(input);
45 let templ: Template<TokenAccumulator> =
46 parser.parse2(templ).expect("failed to parse own template");
47 let result = (|| {
48 let mut output = TokenAccumulator::new();
49 templ.expand(ctx.as_general(), &mut output);
50 output.tokens()
51 })();
52 match result {
53 Ok(result) => result.to_string(),
54 Err(e) => format!("<error: {}>", e),
55 }
56}
57
58fn dump_any_one(
59 w: &mut Out,
60 ctx: &Context,
61 show_templ: TokenStream,
62 show_op: &str,
63 make_real_templ: &dyn Fn(TokenStream) -> TokenStream,
64) -> R {
65 let show_templ_string = {
66 let mut s = show_templ.to_string();
67 if let Some(inner) = {
68 s.strip_prefix("$ {")
69 .or_else(|| s.strip_prefix("${"))
70 .and_then(|s| s.strip_suffix('}'))
71 } {
72 s = format!("${{{}}}", inner.trim());
73 }
74 s
75 };
76 let lh = format!("{:12} {}", show_templ_string, show_op);
77 let templ = make_real_templ(show_templ);
78 writeln!(w, " {:16} {}", lh, template_result(ctx, templ))?;
79 Ok(())
80}
81
82fn dump_expand_one(w: &mut Out, ctx: &Context, templ: TokenStream) -> R {
83 dump_any_one(w, ctx, templ, "=>", &|t| t)
84}
85
86fn dump_bool_one(w: &mut Out, ctx: &Context, templ: TokenStream) -> R {
87 let make_real = |templ| quote! { ${if #templ { true } else { false }} };
88 dump_any_one(w, ctx, templ, "=", &make_real)
89}
90
91macro_rules! expand { { $w_ctx:expr, $($t:tt)* } => {
92 dump_expand_one($w_ctx.0, $w_ctx.1, quote!{ $($t)* })?;
93} }
94macro_rules! bool { { $w_ctx:expr, $($t:tt)* } => {
95 dump_bool_one($w_ctx.0, $w_ctx.1, quote!{ $($t)* })?;
96} }
97
98fn dump_whole(mut w: &mut Out, ctx: &Context) -> R {
99 writeln!(w, "top-level:")?;
100 let c = (&mut w, ctx);
101
102 expand! { c, $tname }
103 expand! { c, $ttype }
104 expand! { c, $tvis }
105 expand! { c, $tgens }
106 expand! { c, $tgnames }
107 expand! { c, $twheres }
108 expand! { c, $tdeftype }
109 expand! { c, $tdefgens }
110 expand! { c, $tdefkwd }
111 expand! { c, ${tdefvariants VARIANTS..} }
112
113 bool! { c, is_struct }
114 bool! { c, is_enum }
115 bool! { c, is_union }
116 bool! { c, tvis }
117 bool! { c, tgens }
118
119 expand! { c, $tattrs }
120
121 if false {
125 expand! { c, $tmeta }
127 expand! { c, $vmeta }
128 expand! { c, $fmeta }
129 bool! { c, tmeta }
130 bool! { c, vmeta }
131 bool! { c, fmeta }
132 expand! { c, $paste }
134 expand! { c, $paste_spanned }
135 expand! { c, $concat }
136 expand! { c, $crate }
138 expand! { c, $dbg_all_keywords }
140 expand! { c, $error }
142 expand! { c, $when }
144 expand! { c, $if }
145 expand! { c, $select1 }
146 expand! { c, $define }
147 expand! { c, $defcond }
148 expand! { c, $ignore }
149 expand! { c, $dbg }
150 bool! { c, not }
151 bool! { c, all }
152 bool! { c, any }
153 bool! { c, dbg }
155 bool! { c, is_empty }
156 bool! { c, approx_equal }
157 bool! { c, true }
159 bool! { c, false }
160 }
161
162 if let Some(wv) = w.subset_only {
163 dump_variant(w, ctx, wv)?;
164 dump_user_defined(w, ctx)?;
165 } else {
166 WithinVariant::for_each(ctx, |ctx, wv| dump_variant(w, ctx, wv))?;
167 }
168
169 Ok(())
170}
171
172fn variant_heading(w: &mut Out, wv: &WithinVariant) -> R {
173 match wv.variant {
174 None => write!(w, "value")?,
175 Some(v) => write!(w, "variant {}", v.ident)?,
176 };
177 Ok(())
178}
179
180fn dump_variant(mut w: &mut Out, ctx: &Context, wv: &WithinVariant) -> R {
181 variant_heading(w, wv)?;
182 writeln!(w, ":")?;
183 let c = (&mut w, ctx);
184
185 expand! { c, $vname }
186 expand! { c, $vtype }
187 if false {
188 expand! { c, $vindex }
190 }
191 expand! { c, $vpat }
192 expand! { c, ${vdefbody VNAME FIELDS..} }
193
194 bool! { c, v_is_unit }
195 bool! { c, v_is_tuple }
196 bool! { c, v_is_named }
197
198 expand! { c, $vattrs }
199
200 if let Some(_) = w.subset_only {
201 dump_field(w, ctx, ctx.field)?;
202 } else {
203 WithinField::for_each(ctx, |ctx, wf| dump_field(w, ctx, Some(wf)))?;
204 }
205
206 Ok(())
207}
208
209fn dump_field(mut w: &mut Out, ctx: &Context, wf: Option<&WithinField>) -> R {
210 variant_heading(w, ctx.variant.expect("heading but not variant!"))?;
211 if let Some(wf) = wf {
212 let fname = wf.fname(Span::call_site()).to_token_stream();
213 writeln!(w, ", field {}:", fname)?;
214 } else {
215 writeln!(w, ", no field:")?;
216 }
217 let c = (&mut w, ctx);
218
219 expand! { c, $fname }
220 expand! { c, $ftype }
221 if false {
222 expand! { c, $findex }
224 }
225 expand! { c, $fvis }
226 expand! { c, $fdefvis }
227 expand! { c, $fpatname }
228 expand! { c, $fdefine }
229
230 bool! { c, fvis }
231 bool! { c, fdefvis }
232
233 expand! { c, $fattrs }
234
235 Ok(())
236}
237
238fn dump_user_defined(mut w: &mut Out, ctx: &Context) -> R {
239 let mut c;
241 let mut name;
242
243 macro_rules! print_definitions { {
244 $heading:expr, $B:ty, $body:stmt
245 } => { {
246 let mut set = BTreeSet::new();
247 for def in ctx.defs.defs.iter::<$B>().flatten() {
248 set.insert(&def.name);
249 }
250 if !set.is_empty() {
251 writeln!(w, "{}", $heading)?;
252 c = (&mut w, ctx);
253 for n in set {
254 name = n;
255 $body
256 }
257 }
258 } } }
259
260 print_definitions! {
261 "user-defined expansions:", DefinitionBody,
262 expand! { c, $#name }
263 }
264 print_definitions! {
265 "user-defined conditions:", DefCondBody,
266 bool! { c, #name }
267 }
268
269 Ok(())
270}