ferment_sys/
formatter.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt::{Display, Formatter, Write};
3use proc_macro2::{Spacing, TokenTree};
4use quote::{quote, ToTokens};
5use syn::{Attribute, Ident, ItemUse, Path, Signature, Type};
6use crate::ast::{PathHolder, TypeHolder, TypePathHolder};
7use crate::composable::{GenericBoundsModel, GenericConversion, TraitModelPart1, TraitDecompositionPart1, TraitTypeModel};
8use crate::context::{GlobalContext, ScopeChain};
9use crate::conversion::{MixinKind, ObjectKind};
10use crate::tree::{ScopeTreeExportID, ScopeTreeExportItem, ScopeTreeItem};
11
12#[allow(unused)]
13pub fn format_imported_set(dict: &HashSet<ItemUse>) -> String {
14    let debug_imports = dict.iter().map(|i| {
15        i.to_token_stream()
16    }).collect::<Vec<_>>();
17    let all = quote!(#(#debug_imports,)*);
18    all.to_string()
19}
20
21#[allow(unused)]
22pub fn format_scope_refinement(dict: &Vec<(ScopeChain, HashMap<TypeHolder, ObjectKind>)>) -> String {
23    let mut iter = dict.iter()
24        .map(|(scope, types)|
25            format!("\t{}: \n\t\t{}", scope.self_path_holder_ref(), types.iter().map(scope_type_conversion_pair).collect::<Vec<_>>()
26                .join("\n\t")))
27        .collect::<Vec<String>>();
28    iter.sort();
29    iter.join("\n")
30
31}
32
33#[allow(unused)]
34pub fn format_type_holders(dict: &HashSet<TypeHolder>) -> String {
35    dict.iter()
36        // .map(|item| format_token_stream(&item.0))
37        .map(|item| item.0.to_token_stream().to_string())
38        .collect::<Vec<_>>()
39        .join("\n\n")
40}
41#[allow(unused)]
42pub fn format_type_holders_vec(dict: &Vec<TypeHolder>) -> String {
43    dict.iter()
44        // .map(|item| format_token_stream(&item.0))
45        .map(|item| item.0.to_token_stream().to_string())
46        .collect::<Vec<_>>()
47        .join("\n\n")
48}
49#[allow(unused)]
50pub fn format_types(dict: &HashSet<Type>) -> String {
51    dict.iter()
52        // .map(|item| format_token_stream(item))
53        .map(|item| item.to_token_stream().to_string())
54        .collect::<Vec<_>>()
55        .join("\n\n")
56}
57
58#[allow(unused)]
59pub fn format_generic_conversions(dict: &HashMap<GenericConversion, HashSet<Option<Attribute>>>) -> String {
60    dict.iter()
61        .map(|(item, attrs)| format!("{}: {}", format_unique_attrs(attrs), item.object.to_token_stream()))
62        .collect::<Vec<_>>()
63        .join("\n\t")
64}
65#[allow(unused)]
66pub fn format_mixin_kinds(dict: &HashMap<MixinKind, HashSet<Option<Attribute>>>) -> String {
67    dict.iter()
68        .map(|(item, attrs)| format!("{}:\t {}", item, format_unique_attrs(attrs)))
69        .collect::<Vec<_>>()
70        .join("\n\t")
71}
72#[allow(unused)]
73pub fn format_mixin_conversions(dict: &HashMap<GenericBoundsModel, HashSet<Option<Attribute>>>) -> String {
74    dict.iter()
75        .map(|(item, attrs)| format!("{}:\n\t {}", item, format_unique_attrs(attrs)))
76        .collect::<Vec<_>>()
77        .join("\n\t")
78}
79
80#[allow(unused)]
81pub fn format_unique_attrs(dict: &HashSet<Option<Attribute>>) -> String {
82    dict.iter()
83        .map(|item| item.as_ref().map_or("[None]".to_string(), |a| a.to_token_stream().to_string()))
84        .collect::<Vec<_>>()
85        .join("\n\t")
86}
87
88pub fn format_attrs(dict: &Vec<Attribute>) -> String {
89    dict.iter()
90        .map(|item| item.to_token_stream().to_string())
91        .collect::<Vec<_>>()
92        .join("\n\t")
93}
94
95#[allow(unused)]
96pub fn format_imports(dict: &HashMap<ScopeChain, HashMap<PathHolder, Path>>) -> String {
97    let vec = scope_imports_dict(dict);
98    let expanded = quote!(#(#vec),*);
99    expanded.to_string()
100}
101
102#[allow(unused)]
103pub fn format_tree_exported_dict(dict: &HashMap<ScopeTreeExportID, ScopeTreeExportItem>) -> String {
104    dict.iter()
105        .map(|(ident, tree_item)| format!("{}: {}", ident, tree_item))
106        .collect::<Vec<_>>()
107        .join("\n\n")
108}
109
110#[allow(unused)]
111pub fn format_tree_item_dict(dict: &HashMap<ScopeTreeExportID, ScopeTreeItem>) -> String {
112    dict.iter()
113        .map(|(ident, tree_item)| format!("\t{}: {:?}", ident, tree_item))
114        .collect::<Vec<_>>()
115        .join("\n\n")
116}
117
118#[allow(unused)]
119pub fn scope_type_conversion_pair(dict: (&TypeHolder, &ObjectKind)) -> String {
120    format!("\t{}: {}", dict.0.to_token_stream(), dict.1)
121    // format!("\t{}: {}", format_token_stream(dict.0), dict.1)
122}
123
124#[allow(unused)]
125pub fn refinement_pair(dict: (&TypeHolder, &Vec<ObjectKind>)) -> String {
126    format!("\t{}: \n\t\t{}", dict.0.to_token_stream(), dict.1.iter().map(|i| i.to_string()).collect::<Vec<_>>()
127        .join("\n\t"))
128    // format!("\t{}: {}", format_token_stream(dict.0), dict.1)
129}
130// #[allow(unused)]
131// pub fn scope_refinement_pair(dict: &(&ScopeChain, HashMap<TypeHolder, ObjectKind>)) -> String {
132//     format!("\t{}: \n\t\t{}", dict.0.to_token_stream(), dict.1.iter().map(scope_type_conversion_pair).collect::<Vec<_>>()
133//         .join("\n\t"))
134//     // format!("\t{}: {}", format_token_stream(dict.0), dict.1)
135// }
136
137#[allow(unused)]
138pub fn ident_type_conversion_pair(dict: (&Ident, &Type)) -> String {
139    format!("\t{}: {}", format_token_stream(dict.0), format_token_stream(dict.1))
140}
141
142#[allow(unused)]
143pub fn ident_signature_conversion_pair(dict: (&Ident, &Signature)) -> String {
144    format!("\t{}: {}", format_token_stream(dict.0), format_token_stream(dict.1))
145}
146
147#[allow(unused)]
148pub fn ident_trait_type_decomposition_conversion_pair(dict: (&Ident, &TraitTypeModel)) -> String {
149    format!("\t{}: {}", format_token_stream(dict.0), {
150        let TraitTypeModel { ident, trait_bounds, generics } = dict.1;
151        quote!(#ident: [bounds: #(#trait_bounds)*, generics: #generics])
152    })
153}
154fn format_ident_path_pair(pair: (&PathHolder, &Path)) -> String {
155    format!("\t{}: {}", format_token_stream(pair.0), format_token_stream(pair.1))
156}
157
158pub fn format_path_vec(vec: &Vec<Path>) -> String {
159    vec.iter().map(|p| p.to_token_stream().to_string()).collect::<Vec<_>>().join(",")
160}
161pub fn format_obj_vec(vec: &Vec<ObjectKind>) -> String {
162    vec.iter().map(|p| p.to_token_stream().to_string()).collect::<Vec<_>>().join(",")
163}
164
165#[allow(unused)]
166pub fn type_vec_path_conversion_pair(pair: (&Type, &Vec<Path>)) -> String {
167    format!("\t{}: [{}]", format_token_stream(pair.0), format_path_vec(pair.1))
168}
169#[allow(unused)]
170pub fn type_vec_obj_conversion_pair(pair: (&Type, &Vec<ObjectKind>)) -> String {
171    format!("\t{}: [{}]", format_token_stream(pair.0), format_obj_vec(pair.1))
172}
173#[allow(unused)]
174pub fn format_predicates_dict(vec: &HashMap<Type, Vec<Path>>) -> String {
175    vec.iter()
176        .map(type_vec_path_conversion_pair)
177        .collect::<Vec<_>>()
178        .join(",")
179}
180#[allow(unused)]
181pub fn format_predicates_obj_dict(vec: &HashMap<Type, Vec<ObjectKind>>) -> String {
182    vec.iter()
183        .map(type_vec_obj_conversion_pair)
184        .collect::<Vec<_>>()
185        .join(",")
186}
187
188#[allow(unused)]
189fn format_generic_bounds_pair(pair: (&TypePathHolder, &Vec<Path>)) -> String {
190    format!("\t{}: [{}]", format_token_stream(pair.0), format_path_vec(pair.1))
191}
192
193fn format_ident_trait_pair(pair: (&Ident, &TraitModelPart1)) -> String {
194    let implementors = &pair.1.implementors;
195    format!("\t{}: {}: [{}]", format_token_stream(pair.0), "...", quote!(#(#implementors),*))
196}
197
198#[allow(unused)]
199pub fn format_types_dict(dict: &HashMap<TypeHolder, ObjectKind>) -> String {
200    types_dict(dict)
201        .join("\n")
202}
203#[allow(unused)]
204pub fn format_types_to_refine(dict: &HashMap<TypeHolder, Vec<ObjectKind>>) -> String {
205    let mut iter = dict.iter()
206        .map(refinement_pair)
207        .collect::<Vec<String>>();
208    iter.sort();
209    iter.join("\n")
210}
211
212#[allow(unused)]
213pub fn format_ident_types_dict(dict: &HashMap<Ident, Type>) -> String {
214    ident_types_dict(dict)
215        .join("\n")
216}
217
218// #[allow(unused)]
219// pub fn format_scope_types_dict(dict: &HashMap<ScopeChain, TypeChain>) -> String {
220//     scope_types_dict(dict)
221//         .join("\n\n")
222// }
223//
224#[allow(unused)]
225pub fn format_used_traits(dict: &HashMap<ScopeChain, HashMap<Ident, TraitModelPart1>>) -> String {
226    scope_traits_dict(dict).join("\n")
227}
228
229// fn format_fn_signature_decomposition(sig: &FnSignatureDecomposition) -> String {
230//     let FnSignatureDecomposition { is_async, ident, scope, return_type, arguments } = sig;
231// }
232
233pub fn format_token_stream<TT: ToTokens>(token_stream: TT) -> String {
234    // println!("format_token_stream2222: {}", token_stream.to_token_stream());
235    let token_stream = token_stream.into_token_stream();
236    let mut formatted_string = String::new();
237    let mut space_needed = false;
238    let mut inside_angle_brackets = 0;
239    let mut inside_round_brackets = 0;
240    // let mut inside_square_brackets = 0;
241    let mut last_token_was_ampersand = false;
242    let mut last_token_was_comma = false;
243    // let mut last_token_was_sq_bracket = false;
244    // let mut last_token_was_round_bracket = false;
245    for token in token_stream {
246        if last_token_was_comma {
247            formatted_string.push(' ');
248        }
249        last_token_was_comma = false;
250        match token {
251            TokenTree::Ident(ident) => {
252                // Check for 'mut' or lifetime after '&'
253                if last_token_was_ampersand && (ident == "mut" || ident.to_string().starts_with('\'')) {
254                    formatted_string.pop(); // Remove the space after '&'
255                } else if space_needed {
256                    formatted_string.push(' ');
257                }
258                formatted_string.push_str(&ident.to_string());
259                space_needed = true;
260                last_token_was_ampersand = false;
261            }
262            TokenTree::Punct(punct) => {
263                match punct.as_char() {
264                    ';' => {
265                        formatted_string.push(';');
266                        space_needed = true;
267                    }
268                    ':' => {
269                        formatted_string.push(':');
270                        space_needed = false;
271                    }
272                    '(' => {
273                        inside_round_brackets += 1;
274                        formatted_string.push('(');
275                        space_needed = false;
276                    }
277                    ')' => {
278                        inside_round_brackets -= 1;
279                        formatted_string.push(')');
280                        space_needed = true;
281                    }
282                    '<' => {
283                        inside_angle_brackets += 1;
284                        formatted_string.push('<');
285                        space_needed = false;
286                    }
287                    '>' => {
288                        inside_angle_brackets -= 1;
289                        formatted_string.push('>');
290                        space_needed = true;
291                    }
292                    // '[' => {
293                    //     inside_square_brackets += 1;
294                    //     formatted_string.push('[');
295                    //     space_needed = false;
296                    // }
297                    // ']' => {
298                    //     inside_square_brackets -= 1;
299                    //     formatted_string.push(']');
300                    //     space_needed = false;
301                    // }
302                    ',' => {
303                        formatted_string.push(',');
304                        last_token_was_comma = true;
305                        space_needed = true; // Add space after comma
306                    }
307                    '&' => {
308                        formatted_string.push('&');
309                        last_token_was_ampersand = true;
310                        space_needed = false;
311                    }
312                    _ => {
313                        if space_needed {
314                            formatted_string.push(' ');
315                        }
316                        formatted_string.push(punct.as_char());
317                        space_needed = punct.spacing() == Spacing::Alone;
318                    }
319                }
320            }
321            TokenTree::Literal(literal) => {
322                if space_needed {
323                    formatted_string.push(' ');
324                }
325                formatted_string.push_str(&literal.to_string());
326                space_needed = true;
327                last_token_was_ampersand = false;
328            }
329            TokenTree::Group(group) => {
330                if space_needed && (inside_angle_brackets == 0 || inside_round_brackets == 0) {
331                    formatted_string.push(' ');
332                }
333                formatted_string.push_str(&format_token_stream(group.stream()));
334                space_needed = true;
335                last_token_was_ampersand = false;
336            }
337        }
338    }
339
340    formatted_string
341}
342
343
344
345/// Helpers
346
347pub fn imports_dict(dict: &HashMap<PathHolder, Path>) -> Vec<String> {
348    dict.iter()
349        .map(format_ident_path_pair)
350        .collect()
351}
352
353#[allow(unused)]
354pub fn generic_bounds_dict(dict: &HashMap<TypePathHolder, Vec<Path>>) -> Vec<String> {
355    dict.iter()
356        .map(format_generic_bounds_pair)
357        .collect()
358}
359
360pub fn types_dict(dict: &HashMap<TypeHolder, ObjectKind>) -> Vec<String> {
361    let mut iter = dict.iter()
362        .map(scope_type_conversion_pair)
363        .collect::<Vec<String>>();
364    iter.sort();
365    iter
366}
367fn ident_signatures_dict(dict: &HashMap<Ident, Signature>) -> Vec<String> {
368    let mut iter = dict.iter()
369        .map(ident_signature_conversion_pair)
370        .collect::<Vec<String>>();
371    iter.sort();
372    iter
373}
374
375
376fn ident_trait_type_decomposition_dict(dict: &HashMap<Ident, TraitTypeModel>) -> Vec<String> {
377    let mut iter = dict.iter()
378        .map(ident_trait_type_decomposition_conversion_pair)
379        .collect::<Vec<String>>();
380    iter.sort();
381    iter
382}
383
384fn ident_types_dict(dict: &HashMap<Ident, Type>) -> Vec<String> {
385    let mut iter = dict.iter()
386        .map(ident_type_conversion_pair)
387        .collect::<Vec<String>>();
388    iter.sort();
389    iter
390}
391
392fn traits_dict(dict: &HashMap<Ident, TraitModelPart1>) -> Vec<String> {
393    let mut iter = dict.iter()
394        .map(format_ident_trait_pair)
395        .collect::<Vec<String>>();
396    iter.sort();
397    iter
398}
399
400
401fn nested_scope_dict<K, K2, V2, F: Fn(&K, &HashMap<K2, V2>) -> String>(dict: &HashMap<K, HashMap<K2, V2>>, mapper: F) -> Vec<String> {
402    let mut iter = dict.iter()
403        .map(|(key, value)| mapper(key, value))
404        .collect::<Vec<String>>();
405    iter.sort();
406    iter
407}
408
409fn format_scope_dict<K2, V2, F: Fn(&HashMap<K2, V2>) -> Vec<String>>(dict: &HashMap<ScopeChain, HashMap<K2, V2>>, mapper: F) -> Vec<String>  {
410    nested_scope_dict(dict, |scope, sub_dict|
411        format!("\t{}:\n\t\t{}", scope.fmt_short(), mapper(sub_dict).join("\n\t\t")))
412}
413
414pub fn scope_imports_dict(dict: &HashMap<ScopeChain, HashMap<PathHolder, Path>>) -> Vec<String> {
415    format_scope_dict(dict, imports_dict)
416}
417
418#[allow(unused)]
419pub fn scope_generics_dict(dict: &HashMap<ScopeChain, HashMap<TypePathHolder, Vec<Path>>>) -> Vec<String> {
420    format_scope_dict(dict, generic_bounds_dict)
421}
422
423
424fn scope_traits_dict(dict: &HashMap<ScopeChain, HashMap<Ident, TraitModelPart1>>) -> Vec<String> {
425    format_scope_dict(dict, traits_dict)
426}
427
428
429
430fn traits_impl_dict(dict: &HashMap<ScopeChain, Vec<PathHolder>>) -> Vec<String> {
431    // nested_scope_dict(dict, |scope, sub_dict|
432    //     format!("\t{}:\n\t\t{}", scope, mapper(sub_dict).join("\n\t\t")))
433    let mut iter = dict.iter()
434        .filter_map(|(key, value)| {
435            let scopes = quote!(#(#value),*);
436            if value.is_empty() {
437                None
438            } else {
439                Some(format!("\t{}:\n\t\t{}", format_token_stream(key), format_token_stream(&scopes)))
440            }
441        })
442        .collect::<Vec<String>>();
443    iter.sort();
444    iter
445}
446
447fn format_complex_obj(vec: Vec<Vec<String>>) -> String {
448    vec.into_iter()
449        .flatten()
450        .collect::<Vec<String>>()
451        .join("\n\t")
452}
453
454pub fn format_global_context(context: &GlobalContext) -> String {
455    format_complex_obj(vec![
456        vec!["-- types:".to_string(), context.scope_register.to_string()],
457        vec!["-- traits:".to_string()], scope_traits_dict(&context.traits.inner),
458        vec!["-- traits_impl:".to_string()], traits_impl_dict(&context.traits.used_traits_dictionary),
459        vec!["-- custom:".to_string(), context.custom.to_string()],
460        vec!["-- imports:".to_string()], scope_imports_dict(&context.imports.inner),
461        vec!["-- generics:".to_string()], scope_generics_dict(&context.generics.inner),
462    ])
463}
464
465#[allow(unused)]
466pub fn format_trait_decomposition_part1(dict: &TraitDecompositionPart1) -> String {
467    format_complex_obj(vec![
468        vec!["\n-- ident:".to_string()], vec![format_token_stream(&dict.ident)],
469        vec!["-- consts:".to_string()], ident_types_dict(&dict.consts),
470        vec!["-- methods:".to_string()], ident_signatures_dict(&dict.methods),
471        vec!["-- types:".to_string()], ident_trait_type_decomposition_dict(&dict.types),
472    ])
473}
474
475// #[allow(unused)]
476// pub fn format_type_composition(dict: &TypeComposition) -> String {
477//     format_complex_obj(vec![
478//         vec!["-- type:".to_string(), format_token_stream(&dict.ty), "-- generics:".to_string(), dict.generics.as_ref().map_or(format!("None"), |generics| format_token_stream(generics))],
479//     ])
480// }
481
482// #[allow(unused)]
483// pub fn format_trait_decomposition_part2(dict: &TraitDecompositionPart2) -> String {
484//     format_complex_obj(vec![
485//         vec!["-- methods: ".to_string()], ident_signatures_dict(&dict.methods),
486//         vec!["-- types: ".to_string()], ident_trait_type_decomposition_dict(&dict.types),
487//     ])
488// }
489
490#[allow(dead_code)]
491pub enum Emoji {
492    Branch,
493    Question,
494    Local,
495    Nothing,
496    Ok,
497    Error,
498    Plus,
499    Node,
500    Folder,
501    File
502}
503
504impl Display for Emoji {
505    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
506        f.write_char(
507        match self {
508            Emoji::Question => '\u{2753}',
509            Emoji::Branch => '\u{1D30E}',
510            Emoji::Local => '\u{1F501}',
511            Emoji::Ok => '\u{2705}',
512            Emoji::Error => '\u{274C}',
513            Emoji::Nothing => '\u{1F502}',
514            Emoji::Plus => '\u{271A}',
515            Emoji::Node => '\u{1F491}',
516            Emoji::Folder => '\u{1f4c1}',
517            Emoji::File => '\u{1f4c4}'
518        })
519    }
520}
521
522#[macro_export]
523macro_rules! nprint {
524    ($counter:expr, $emoji:expr, $($arg:tt)*) => {
525        //println!("cargo:warning={}", format!("{}{} {}", " ".repeat($counter*2), $emoji, format!($($arg)*)))
526
527        // log::warn!("{}", ansi_term::Colour::Green.paint(format!("{}{} {}", " ".repeat($counter*2), $emoji, format!($($arg)*))))
528        //ansi_term::Colour::Green.paint(format!("{}{} {}", " ".repeat($counter*2), $emoji, format!($($arg)*)))
529        //println!("{}{} {}", " ".repeat($counter*2), $emoji, format!($($arg)*));
530    };
531}
532
533#[macro_export]
534macro_rules! print_phase {
535    ($label:expr, $($arg:tt)*) => {
536        println!("\n########################################################################################################################");
537        println!("# {}", $label);
538        println!("########################################################################################################################");
539        println!("{}", format!($($arg)*));
540        println!("########################################################################################################################\n");
541    }
542}
543