Skip to main content

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, Default, PartialEq, Eq, PartialOrd, Ord, 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}
209
210/// A supertrait of [`Span`] that specifies how a value, usually an AST node, might have a span attached to it.
211///
212/// The type for which this trait is implemented is the span type, and the `T` is the value type.
213pub trait WrappingSpan<T>: Span {
214    /// The type of a node after being wrapped in a span.
215    type Spanned;
216
217    /// Wrap a node in a span.
218    fn make_wrapped(self, inner: T) -> Self::Spanned;
219
220    /// Retrieve the inner value after it has been spanned.
221    fn inner_of(spanned: &Self::Spanned) -> &T;
222    /// Retrieve the span of a spanned value.
223    fn span_of(spanned: &Self::Spanned) -> &Self;
224}
225
226/// A utility trait that allows AST spanning to be done using method syntax.
227pub trait SpanWrap<S: WrappingSpan<Self>>: Sized {
228    /// Invokes [`WrappingSpan::make_wrapped`] to wrap an AST node in a span.
229    fn with_span(self, span: S) -> S::Spanned {
230        span.make_wrapped(self)
231    }
232}
233
234impl<T, S: WrappingSpan<T>> SpanWrap<S> for T {}
235
236/// A type that wraps a value of type `T`, usually an AST node, and a span of type `S`.
237///
238/// It is common to compose your AST out of such spanned types.
239///
240/// # Example
241///
242/// ```
243/// # use chumsky::prelude::*;
244/// enum Expr {
245///     // Integer literal
246///     Int(u64),
247///     // -x
248///     Neg(Spanned<Box<Self>>),
249///     // lhs + rhs
250///     Add { lhs: Spanned<Box<Self>>, rhs: Spanned<Box<Self>> },
251///     // |arg| body
252///     Func { arg: Spanned<String>, body: Spanned<Box<Self>> },
253/// }
254/// ```
255#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
256pub struct Spanned<T, S = SimpleSpan> {
257    /// The inner value.
258    pub inner: T,
259    /// The span covered by the inner value in the source input.
260    pub span: S,
261}
262
263/// `Spanned` for `SimpleSpan`.
264pub type SimpleSpanned<T, U = usize, C = ()> = Spanned<T, SimpleSpan<U, C>>;
265
266impl<T, U: Clone, C: Clone> WrappingSpan<T> for SimpleSpan<U, C> {
267    type Spanned = SimpleSpanned<T, U, C>;
268
269    fn make_wrapped(self, inner: T) -> Self::Spanned {
270        SimpleSpanned { inner, span: self }
271    }
272
273    fn inner_of(spanned: &Self::Spanned) -> &T {
274        &spanned.inner
275    }
276    fn span_of(spanned: &Self::Spanned) -> &Self {
277        &spanned.span
278    }
279}
280
281impl<T, S> Deref for Spanned<T, S> {
282    type Target = T;
283
284    fn deref(&self) -> &Self::Target {
285        &self.inner
286    }
287}
288
289impl<T, S> DerefMut for Spanned<T, S> {
290    fn deref_mut(&mut self) -> &mut Self::Target {
291        &mut self.inner
292    }
293}