Skip to main content

huff_neo_utils/ast/
span.rs

1use crate::prelude::Span;
2use itertools::Itertools;
3use std::collections::BTreeMap;
4use std::ops::Index;
5
6/// An AST-level Span
7#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
8pub struct AstSpan(pub Vec<Span>);
9
10impl AstSpan {
11    /// Coalesce Multiple Spans Into an error string
12    pub fn error(&self, hint: Option<&String>) -> String {
13        let file_to_source_map = self.0.iter().fold(BTreeMap::<String, Vec<&Span>>::new(), |mut m, s| {
14            let file_name = s.file.as_ref().map(|f2| f2.path.clone()).unwrap_or_default();
15            let mut new_vec: Vec<&Span> = m.get(&file_name).cloned().unwrap_or_default();
16            new_vec.push(s);
17            m.insert(file_name, new_vec);
18            m
19        });
20        let source_str = file_to_source_map.iter().filter(|fs| !fs.0.is_empty()).fold("".to_string(), |s, fs| {
21            let start = fs.1.iter().map(|fs2| fs2.start).min().unwrap_or(0);
22            let end = fs.1.iter().map(|fs2| fs2.end).max().unwrap_or(0);
23            let newline_s = if s.is_empty() { "".to_string() } else { format!("{s}\n") };
24            if start.eq(&0) && end.eq(&0) {
25                format!("{newline_s}-> {}\n   > 0|", fs.0)
26            } else {
27                format!(
28                    "{}-> {}:{}",
29                    newline_s,
30                    fs.0,
31                    fs.1.iter()
32                        .map(|sp| sp.source_seg())
33                        .filter(|ss| !ss.is_empty())
34                        .collect::<Vec<String>>()
35                        .into_iter()
36                        .unique()
37                        .fold("".to_string(), |acc, ss| { format!("{acc}{ss}") })
38                )
39            }
40        });
41
42        // Add in optional hint message
43        format!("{}{source_str}", hint.map(|msg| format!("{msg}\n")).unwrap_or_default())
44    }
45
46    /// Print just the file for missing
47    pub fn file(&self) -> String {
48        self.0.iter().fold("".to_string(), |acc, span| match &span.file {
49            Some(fs) => format!("-> {}\n{acc}", fs.path),
50            None => Default::default(),
51        })
52    }
53
54    /// Retrieve the underlying vector of spans
55    pub fn inner_ref(&self) -> &Vec<Span> {
56        &self.0
57    }
58
59    /// Box self
60    pub fn boxed(self) -> Box<Self> {
61        Box::new(self)
62    }
63
64    /// Clone into a boxed version
65    pub fn clone_box(&self) -> Box<Self> {
66        Box::new(self.clone())
67    }
68}
69
70/// Allows AstSpan to be indexed into
71impl Index<usize> for AstSpan {
72    type Output = Span;
73    fn index(&self, index: usize) -> &Self::Output {
74        &self.0[index]
75    }
76}