teleparse/lex/
span.rs

1use std::fmt::Debug;
2use std::ops::Range;
3
4/// Position in the source code
5pub type Pos = usize;
6
7///////////////////////////////////////////////////////////
8// Span
9///////////////////////////////////////////////////////////
10
11/// A span of source code
12#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Span {
15    /// Start of the span, inclusive
16    pub lo: Pos,
17    /// End of the span, exclusive
18    pub hi: Pos,
19}
20
21impl From<Range<Pos>> for Span {
22    #[inline]
23    fn from(range: Range<Pos>) -> Self {
24        Self {
25            lo: range.start,
26            hi: range.end,
27        }
28    }
29}
30
31impl From<(Pos, Pos)> for Span {
32    #[inline]
33    fn from((lo, hi): (Pos, Pos)) -> Self {
34        Self { lo, hi }
35    }
36}
37
38impl Span {
39    /// Create a new span
40    #[inline]
41    pub fn new(lo: Pos, hi: Pos) -> Self {
42        Self { lo, hi }
43    }
44
45    /// Get the content of this span from the entire source input
46    pub fn get<'s>(&self, input: &'s str) -> &'s str {
47        if self.hi <= self.lo {
48            return "";
49        }
50        let hi = self.hi.min(input.len());
51        &input[self.lo..hi]
52    }
53}
54
55impl Debug for Span {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        if self.hi <= self.lo {
58            write!(f, "{}", self.lo)
59        } else {
60            write!(f, "{}..{}", self.lo, self.hi)
61        }
62    }
63}
64
65///////////////////////////////////////////////////////////
66// ToSpan
67///////////////////////////////////////////////////////////
68
69/// Trait for types that can be converted to a [`Span`]
70///
71/// [`Token`](super::Token)s and derived syntax nodes all implement this trait
72pub trait ToSpan {
73    fn lo(&self) -> Pos;
74    fn hi(&self) -> Pos;
75    fn span(&self) -> Span {
76        Span::new(self.lo(), self.hi())
77    }
78}
79pub use teleparse_macros::ToSpan;
80
81impl ToSpan for Span {
82    fn lo(&self) -> Pos {
83        self.lo
84    }
85    fn hi(&self) -> Pos {
86        self.hi
87    }
88    fn span(&self) -> Span {
89        *self
90    }
91}
92
93impl<T: ToSpan> ToSpan for &T {
94    fn lo(&self) -> Pos {
95        T::lo(self)
96    }
97    fn hi(&self) -> Pos {
98        T::hi(self)
99    }
100    fn span(&self) -> Span {
101        T::span(self)
102    }
103}
104
105macro_rules! derive_to_span_tuple {
106    ($last:tt, $($n:ident),*) => {
107        impl<$($n: ToSpan),*> ToSpan for ($($n,)*) {
108            #[inline]
109            fn lo(&self) -> Pos {
110                self.0.lo()
111            }
112            #[inline]
113            fn hi(&self) -> Pos {
114                self.$last.hi()
115            }
116        }
117    };
118}
119
120derive_to_span_tuple!(1, A, B);
121derive_to_span_tuple!(2, A, B, C);
122derive_to_span_tuple!(3, A, B, C, D);
123derive_to_span_tuple!(4, A, B, C, D, E);
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128    #[test]
129    fn ref_to_span() {
130        let span = Span::new(1, 2);
131        let span_ref = &span;
132
133        assert_eq!(span_ref.span(), Span::new(1, 2));
134    }
135}