1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Utils for handling and converting [`Span`]s

use std::ops::Range;
use std::fmt::Debug;

/// Position in the source code
pub type Pos = usize;

///////////////////////////////////////////////////////////
// Span
///////////////////////////////////////////////////////////

/// A span of source code
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span {
    /// Start of the span, inclusive
    pub lo: Pos,
    /// End of the span, exclusive
    pub hi: Pos,
}

impl From<Range<Pos>> for Span {
    #[inline]
    fn from(range: Range<Pos>) -> Self {
        Self {
            lo: range.start,
            hi: range.end,
        }
    }
}

impl From<(Pos, Pos)> for Span {
    #[inline]
    fn from((lo, hi): (Pos, Pos)) -> Self {
        Self { lo, hi }
    }
}

impl Span {
    /// Create a new span
    #[inline]
    pub fn new(lo: Pos, hi: Pos) -> Self {
        Self { lo, hi }
    }

    /// Get the content of this span from the entire source input
    pub fn get<'s>(&self, input: &'s str) -> &'s str {
        if self.hi <= self.lo {
            return "";
        }
        let hi = self.hi.min(input.len());
        &input[self.lo..hi]
    }
}

impl Debug for Span {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.hi <= self.lo {
            write!(f, "{}", self.lo)
        } else {
            write!(f, "{}..{}", self.lo, self.hi)
        }
    }
}

///////////////////////////////////////////////////////////
// ToSpan
///////////////////////////////////////////////////////////

/// Trait for types that can be converted to a [`Span`]
///
/// [`Token`]s and derived syntax nodes all implement this trait
pub trait ToSpan {
    /// Get the span of this type
    fn span(&self) -> Span;
}
pub use teleparse_macros::ToSpan;

impl ToSpan for Span {
    #[inline]
    fn span(&self) -> Span {
        *self
    }
}

macro_rules! derive_to_span_tuple {
    ($last:tt, $($n:ident),*) => {
        impl<$($n: ToSpan),*> ToSpan for ($($n,)*) {
            #[inline]
            fn span(&self) -> Span {
                (self.0.span().lo, self.$last.span().hi).into()
            }
        }
    };
}

derive_to_span_tuple!(1, A, B);
derive_to_span_tuple!(2, A, B, C);
derive_to_span_tuple!(3, A, B, C, D);
derive_to_span_tuple!(4, A, B, C, D, E);