chumsky/
span.rs

1//! Types and traits related to spans.
2//!
3//! *“We demand rigidly defined areas of doubt and uncertainty!”*
4//!
5//! You can use the [`Span`] trait to connect up chumsky to your compiler's knowledge of the input source.
6
7use super::*;
8
9/// A trait that describes a span over a particular range of inputs.
10///
11/// Spans typically consist of some context, such as the file they originated from, and a start/end offset. Spans are
12/// permitted to overlap one-another. The end offset must always be greater than or equal to the start offset.
13///
14/// Span is automatically implemented for [`Range<T>`] and [`(C, Range<T>)`].
15pub trait Span {
16    /// Extra context used in a span.
17    ///
18    /// This is usually some way to uniquely identity the source file that a span originated in such as the file's
19    /// path, URL, etc.
20    ///
21    /// NOTE: Span contexts have no inherent meaning to Chumsky and can be anything. For example, [`Range<usize>`]'s
22    /// implementation of [`Span`] simply uses `()` as its context.
23    type Context;
24
25    /// A type representing a span's start or end offset from the start of the input.
26    ///
27    /// Typically, [`usize`] is used.
28    ///
29    /// NOTE: Offsets have no inherently meaning to Chumsky and are not used to decide how to prioritize errors. This
30    /// means that it's perfectly fine for tokens to have non-continuous spans that bear no relation to their actual
31    /// location in the input stream. This is useful for languages with an AST-level macro system that need to
32    /// correctly point to symbols in the macro input when producing errors.
33    type Offset: Clone;
34
35    /// Create a new span given a context and an offset range.
36    fn new(context: Self::Context, range: Range<Self::Offset>) -> Self;
37
38    /// Return the span's context.
39    fn context(&self) -> Self::Context;
40
41    /// Return the start offset of the span.
42    fn start(&self) -> Self::Offset;
43
44    /// Return the end offset of the span.
45    fn end(&self) -> Self::Offset;
46
47    /// Turn this span into a zero-width span that starts and ends at the end of the original.
48    ///
49    /// For example, an original span like `3..7` will result in a new span of `7..7`.
50    fn to_end(&self) -> Self
51    where
52        Self: Sized,
53    {
54        Self::new(self.context(), self.end()..self.end())
55    }
56
57    /// Combine two assumed-contiguous spans together into a larger span that encompasses both (and anything between).
58    ///
59    /// For example, spans like `3..5` and `7..8` will result in a unioned span of `3..8`.
60    ///
61    /// The spans may overlap one-another, but the start offset must come before the end offset for each span (i.e:
62    /// each span must be 'well-formed'). If this is not the case, the result is unspecified.
63    ///
64    /// # Panics
65    ///
66    /// Panics if the [`Self::Context`]s of both spans are not equal.
67    fn union(&self, other: Self) -> Self
68    where
69        Self::Context: PartialEq + fmt::Debug,
70        Self::Offset: Ord,
71        Self: Sized,
72    {
73        assert_eq!(
74            self.context(),
75            other.context(),
76            "tried to union two spans with different contexts"
77        );
78        Self::new(
79            self.context(),
80            self.start().min(other.start())..self.end().max(other.end()),
81        )
82    }
83}
84
85/// The most basic implementor of `Span` - akin to `Range`, but `Copy` since it's not also
86/// an iterator. Also has a `Display` implementation
87#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
88#[derive(Copy, Clone, PartialEq, Eq, Hash)]
89pub struct SimpleSpan<T = usize, C = ()> {
90    /// The start offset of the span.
91    pub start: T,
92    /// The end (exclusive) offset of the span.
93    pub end: T,
94    /// The context of the span (usually some ID representing the file path the span relates to).
95    pub context: C,
96}
97
98impl<T, C> SimpleSpan<T, C> {
99    /// Convert this span into a [`std::ops::Range`].
100    pub fn into_range(self) -> Range<T> {
101        self.start..self.end
102    }
103}
104
105impl<T> From<Range<T>> for SimpleSpan<T> {
106    fn from(range: Range<T>) -> Self {
107        SimpleSpan {
108            start: range.start,
109            end: range.end,
110            context: (),
111        }
112    }
113}
114
115impl<T> From<SimpleSpan<T, ()>> for Range<T> {
116    fn from(span: SimpleSpan<T>) -> Self {
117        Range {
118            start: span.start,
119            end: span.end,
120        }
121    }
122}
123
124impl<T, C> fmt::Debug for SimpleSpan<T, C>
125where
126    T: fmt::Debug,
127{
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        write!(f, "{:?}..{:?}", self.start, self.end)
130    }
131}
132
133impl<T, C> fmt::Display for SimpleSpan<T, C>
134where
135    T: fmt::Display,
136{
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        write!(f, "{}..{}", self.start, self.end)
139    }
140}
141
142impl<T, C> IntoIterator for SimpleSpan<T, C>
143where
144    Range<T>: Iterator<Item = T>,
145{
146    type IntoIter = Range<T>;
147    type Item = T;
148
149    fn into_iter(self) -> Self::IntoIter {
150        self.start..self.end
151    }
152}
153
154impl<T: Clone, C: Clone> Span for SimpleSpan<T, C> {
155    type Context = C;
156    type Offset = T;
157
158    fn new(context: Self::Context, range: Range<Self::Offset>) -> Self {
159        Self {
160            start: range.start,
161            end: range.end,
162            context,
163        }
164    }
165    fn context(&self) -> Self::Context {
166        self.context.clone()
167    }
168    fn start(&self) -> Self::Offset {
169        self.start.clone()
170    }
171    fn end(&self) -> Self::Offset {
172        self.end.clone()
173    }
174}
175
176impl<C: Clone, S: Span<Context = ()>> Span for (C, S) {
177    type Context = C;
178    type Offset = S::Offset;
179
180    fn new(context: Self::Context, range: Range<Self::Offset>) -> Self {
181        (context, S::new((), range))
182    }
183    fn context(&self) -> Self::Context {
184        self.0.clone()
185    }
186    fn start(&self) -> Self::Offset {
187        self.1.start()
188    }
189    fn end(&self) -> Self::Offset {
190        self.1.end()
191    }
192}
193
194impl<T: Clone> Span for Range<T> {
195    type Context = ();
196    type Offset = T;
197
198    fn new(_context: Self::Context, range: Range<Self::Offset>) -> Self {
199        range
200    }
201    fn context(&self) -> Self::Context {}
202    fn start(&self) -> Self::Offset {
203        self.start.clone()
204    }
205    fn end(&self) -> Self::Offset {
206        self.end.clone()
207    }
208}