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 core::ops::Range;
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: Clone {
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: Clone;
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 prioritise 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
48impl<T: Clone + Ord> Span for Range<T> {
49 type Context = ();
50 type Offset = T;
51
52 fn new((): Self::Context, range: Self) -> Self {
53 range
54 }
55 fn context(&self) -> Self::Context {}
56 fn start(&self) -> Self::Offset {
57 self.start.clone()
58 }
59 fn end(&self) -> Self::Offset {
60 self.end.clone()
61 }
62}
63
64impl<C: Clone, T: Clone> Span for (C, Range<T>) {
65 type Context = C;
66 type Offset = T;
67
68 fn new(context: Self::Context, range: Range<T>) -> Self {
69 (context, range)
70 }
71 fn context(&self) -> Self::Context {
72 self.0.clone()
73 }
74 fn start(&self) -> Self::Offset {
75 self.1.start.clone()
76 }
77 fn end(&self) -> Self::Offset {
78 self.1.end.clone()
79 }
80}