gluon_base/
pos.rs

1//! Source code locations (borrowed from rustc's [libsyntax_pos])
2//!
3//! [libsyntax_pos]: https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/lib.rs
4
5use std::{cmp, cmp::Ordering, fmt};
6
7pub use codespan::{
8    ByteIndex, ByteIndex as BytePos, ByteOffset, ColumnIndex as Column, ColumnOffset, Index,
9    LineIndex as Line, LineOffset, RawIndex,
10};
11
12use crate::source::CodeMap;
13
14/// A location in a source file
15#[derive(Copy, Clone, Default, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
16pub struct Location {
17    pub line: Line,
18    pub column: Column,
19    pub absolute: BytePos,
20}
21
22impl Location {
23    pub fn shift(&mut self, ch: u8) {
24        if ch == b'\n' {
25            self.line += LineOffset(1);
26            self.column = Column(1);
27        } else {
28            self.column += ColumnOffset(1);
29        }
30        self.absolute += ByteOffset(1);
31    }
32}
33
34impl fmt::Display for Location {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        write!(
37            f,
38            "Line: {}, Column: {}",
39            self.line.number(),
40            self.column.number()
41        )
42    }
43}
44
45#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
46pub struct Positioned<T, Pos> {
47    pub pos: Pos,
48    pub value: T,
49}
50
51/// A region of code in a source file
52#[derive(Clone, Copy, Default, PartialEq, Eq, Ord, PartialOrd)]
53#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
54#[cfg_attr(feature = "memory_usage", derive(HeapSizeOf))]
55pub struct Span<I> {
56    start: I,
57    end: I,
58}
59
60impl<I: fmt::Debug> fmt::Debug for Span<I> {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(f, "{:?}..{:?}", self.start, self.end)
63    }
64}
65
66impl<I: Ord> Span<I> {
67    /// Create a new span
68    ///
69    /// ```rust
70    /// use gluon_base::pos::{ByteIndex, Span};
71    ///
72    /// let span = Span::new(ByteIndex(3), ByteIndex(6));
73    /// assert_eq!(span.start(), ByteIndex(3));
74    /// assert_eq!(span.end(), ByteIndex(6));
75    /// ```
76    ///
77    /// `start` and `end` are reordered to maintain the invariant that `start <= end`
78    ///
79    /// ```rust
80    /// use gluon_base::pos::{ByteIndex, Span};
81    ///
82    /// let span = Span::new(ByteIndex(6), ByteIndex(3));
83    /// assert_eq!(span.start(), ByteIndex(3));
84    /// assert_eq!(span.end(), ByteIndex(6));
85    /// ```
86    pub fn new(start: I, end: I) -> Span<I> {
87        if start <= end {
88            Span { start, end }
89        } else {
90            Span {
91                start: end,
92                end: start,
93            }
94        }
95    }
96
97    pub fn map<F, J>(self, mut f: F) -> Span<J>
98    where
99        F: FnMut(I) -> J,
100        J: Ord,
101    {
102        Span::new(f(self.start), f(self.end))
103    }
104}
105
106impl<I> Span<I> {
107    /// Create a span like `new` but does not check that `start <= end`
108    pub const fn new_unchecked(start: I, end: I) -> Span<I> {
109        Span { start, end }
110    }
111}
112
113impl<I> Span<I> {
114    /// Get the start index
115    pub fn start(self) -> I {
116        self.start
117    }
118
119    /// Get the end index
120    pub fn end(self) -> I {
121        self.end
122    }
123}
124
125impl<I: Index> Span<I> {
126    /// Makes a span from offsets relative to the start of this span.
127    pub fn subspan(&self, begin: I::Offset, end: I::Offset) -> Span<I> {
128        assert!(end >= begin);
129        assert!(self.start() + end <= self.end());
130        Span {
131            start: self.start() + begin,
132            end: self.start() + end,
133        }
134    }
135
136    /// Create a new span from a byte start and an offset
137    pub fn from_offset(start: I, off: I::Offset) -> Span<I> {
138        Span::new(start, start + off)
139    }
140
141    /// Return a new span with the low byte position replaced with the supplied byte position
142    ///
143    /// ```rust
144    /// use gluon_base::pos::{ByteIndex, Span};
145    ///
146    /// let span = Span::new(ByteIndex(3), ByteIndex(6));
147    /// assert_eq!(span.with_start(ByteIndex(2)), Span::new(ByteIndex(2), ByteIndex(6)));
148    /// assert_eq!(span.with_start(ByteIndex(5)), Span::new(ByteIndex(5), ByteIndex(6)));
149    /// assert_eq!(span.with_start(ByteIndex(7)), Span::new(ByteIndex(6), ByteIndex(7)));
150    /// ```
151    pub fn with_start(self, start: I) -> Span<I> {
152        Span::new(start, self.end())
153    }
154
155    /// Return a new span with the high byte position replaced with the supplied byte position
156    ///
157    /// ```rust
158    /// use gluon_base::pos::{ByteIndex, Span};
159    ///
160    /// let span = Span::new(ByteIndex(3), ByteIndex(6));
161    /// assert_eq!(span.with_end(ByteIndex(7)), Span::new(ByteIndex(3), ByteIndex(7)));
162    /// assert_eq!(span.with_end(ByteIndex(5)), Span::new(ByteIndex(3), ByteIndex(5)));
163    /// assert_eq!(span.with_end(ByteIndex(2)), Span::new(ByteIndex(2), ByteIndex(3)));
164    /// ```
165    pub fn with_end(self, end: I) -> Span<I> {
166        Span::new(self.start(), end)
167    }
168
169    /// Return true if `self` fully encloses `other`.
170    ///
171    /// ```rust
172    /// use gluon_base::pos::{ByteIndex, Span};
173    ///
174    /// let a = Span::new(ByteIndex(5), ByteIndex(8));
175    ///
176    /// assert_eq!(a.contains(a), true);
177    /// assert_eq!(a.contains(Span::new(ByteIndex(6), ByteIndex(7))), true);
178    /// assert_eq!(a.contains(Span::new(ByteIndex(6), ByteIndex(10))), false);
179    /// assert_eq!(a.contains(Span::new(ByteIndex(3), ByteIndex(6))), false);
180    /// ```
181    pub fn contains(self, other: Span<I>) -> bool {
182        self.start() <= other.start() && other.end() <= self.end()
183    }
184
185    pub fn contains_pos(self, other: I) -> bool {
186        self.start() <= other && other <= self.end()
187    }
188
189    /// Return `Equal` if `self` contains `pos`, otherwise it returns `Less` if `pos` is before
190    /// `start` or `Greater` if `pos` is after or at `end`.
191    ///
192    /// ```rust
193    /// use gluon_base::pos::{ByteIndex, Span};
194    /// use std::cmp::Ordering::*;
195    ///
196    /// let a = Span::new(ByteIndex(5), ByteIndex(8));
197    ///
198    /// assert_eq!(a.containment(ByteIndex(4)), Less);
199    /// assert_eq!(a.containment(ByteIndex(5)), Equal);
200    /// assert_eq!(a.containment(ByteIndex(6)), Equal);
201    /// assert_eq!(a.containment(ByteIndex(8)), Equal);
202    /// assert_eq!(a.containment(ByteIndex(9)), Greater);
203    /// ```
204    pub fn containment(self, pos: I) -> Ordering {
205        use std::cmp::Ordering::*;
206
207        match (pos.cmp(&self.start), pos.cmp(&self.end)) {
208            (Equal, _) | (_, Equal) | (Greater, Less) => Equal,
209            (Less, _) => Less,
210            (_, Greater) => Greater,
211        }
212    }
213
214    /// Return `Equal` if `self` contains `pos`, otherwise it returns `Less` if `pos` is before
215    /// `start` or `Greater` if `pos` is *strictly* after `end`.
216    ///
217    /// ```rust
218    /// use gluon_base::pos::{ByteIndex, Span};
219    /// use std::cmp::Ordering::*;
220    ///
221    /// let a = Span::new(ByteIndex(5), ByteIndex(8));
222    ///
223    /// assert_eq!(a.containment_exclusive(ByteIndex(4)), Less);
224    /// assert_eq!(a.containment_exclusive(ByteIndex(5)), Equal);
225    /// assert_eq!(a.containment_exclusive(ByteIndex(6)), Equal);
226    /// assert_eq!(a.containment_exclusive(ByteIndex(8)), Greater);
227    /// assert_eq!(a.containment_exclusive(ByteIndex(9)), Greater);
228    /// ```
229    pub fn containment_exclusive(self, pos: I) -> Ordering {
230        if self.end == pos {
231            Ordering::Greater
232        } else {
233            self.containment(pos)
234        }
235    }
236
237    /// Return a `Span` that would enclose both `self` and `end`.
238    ///
239    /// ```plain
240    /// self     ~~~~~~~
241    /// end                     ~~~~~~~~
242    /// returns  ~~~~~~~~~~~~~~~~~~~~~~~
243    /// ```
244    ///
245    /// ```rust
246    /// use gluon_base::pos::{ByteIndex, Span};
247    ///
248    /// let a = Span::new(ByteIndex(2), ByteIndex(5));
249    /// let b = Span::new(ByteIndex(10), ByteIndex(14));
250    ///
251    /// assert_eq!(a.to(b), Span::new(ByteIndex(2), ByteIndex(14)));
252    /// ```
253    pub fn to(self, end: Span<I>) -> Span<I> {
254        Span::new(
255            cmp::min(self.start(), end.start()),
256            cmp::max(self.end(), end.end()),
257        )
258    }
259
260    /// Return a `Span` between the end of `self` to the beginning of `end`.
261    ///
262    /// ```plain
263    /// self     ~~~~~~~
264    /// end                     ~~~~~~~~
265    /// returns         ~~~~~~~~~
266    /// ```
267    ///
268    /// ```rust
269    /// use gluon_base::pos::{ByteIndex, Span};
270    ///
271    /// let a = Span::new(ByteIndex(2), ByteIndex(5));
272    /// let b = Span::new(ByteIndex(10), ByteIndex(14));
273    ///
274    /// assert_eq!(a.between(b), Span::new(ByteIndex(5), ByteIndex(10)));
275    /// ```
276    pub fn between(self, end: Span<I>) -> Span<I> {
277        Span::new(self.end(), end.start())
278    }
279
280    /// Return a `Span` between the beginning of `self` to the beginning of `end`.
281    ///
282    /// ```plain
283    /// self     ~~~~~~~
284    /// end                     ~~~~~~~~
285    /// returns  ~~~~~~~~~~~~~~~~
286    /// ```
287    ///
288    /// ```rust
289    /// use gluon_base::pos::{ByteIndex, Span};
290    ///
291    /// let a = Span::new(ByteIndex(2), ByteIndex(5));
292    /// let b = Span::new(ByteIndex(10), ByteIndex(14));
293    ///
294    /// assert_eq!(a.until(b), Span::new(ByteIndex(2), ByteIndex(10)));
295    /// ```
296    pub fn until(self, end: Span<I>) -> Span<I> {
297        Span::new(self.start(), end.start())
298    }
299}
300
301impl Span<BytePos> {
302    pub fn to_range(self, source: &CodeMap) -> Option<std::ops::Range<usize>> {
303        Some(source.to_usize(self.start())?..source.to_usize(self.end())?)
304    }
305}
306
307impl<I: fmt::Display> fmt::Display for Span<I> {
308    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
309        self.start.fmt(f)?;
310        write!(f, "..")?;
311        self.end.fmt(f)?;
312        Ok(())
313    }
314}
315
316#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
317pub struct Spanned<T, Pos> {
318    pub span: Span<Pos>,
319    pub value: T,
320}
321
322impl<T, Pos> From<(T, Span<Pos>)> for Spanned<T, Pos> {
323    fn from((value, span): (T, Span<Pos>)) -> Self {
324        Spanned { span, value }
325    }
326}
327
328impl<T, Pos> From<T> for Spanned<T, Pos>
329where
330    Pos: Default,
331{
332    fn from(value: T) -> Self {
333        Spanned {
334            span: Span::default(),
335            value,
336        }
337    }
338}
339
340impl<T, Pos> PartialEq<T> for Spanned<T, Pos>
341where
342    T: PartialEq,
343{
344    fn eq(&self, other: &T) -> bool {
345        self.value == *other
346    }
347}
348
349impl<T, Pos> std::ops::Deref for Spanned<T, Pos> {
350    type Target = T;
351    fn deref(&self) -> &T {
352        &self.value
353    }
354}
355
356impl<T, Pos> std::ops::DerefMut for Spanned<T, Pos> {
357    fn deref_mut(&mut self) -> &mut T {
358        &mut self.value
359    }
360}
361
362impl<T, U, Pos> AsRef<U> for Spanned<T, Pos>
363where
364    T: AsRef<U>,
365    U: ?Sized,
366{
367    fn as_ref(&self) -> &U {
368        self.value.as_ref()
369    }
370}
371
372impl<T, Pos> std::hash::Hash for Spanned<T, Pos>
373where
374    T: std::hash::Hash,
375    Pos: std::hash::Hash + Copy,
376{
377    fn hash<H>(&self, state: &mut H)
378    where
379        H: std::hash::Hasher,
380    {
381        self.span.start().hash(state);
382        self.span.end().hash(state);
383        self.value.hash(state);
384    }
385}
386
387impl<T, Pos> Spanned<T, Pos> {
388    pub fn map<U, F>(self, mut f: F) -> Spanned<U, Pos>
389    where
390        F: FnMut(T) -> U,
391    {
392        Spanned {
393            span: self.span,
394            value: f(self.value),
395        }
396    }
397}
398
399impl<T: fmt::Display, Pos: fmt::Display + Copy> fmt::Display for Spanned<T, Pos> {
400    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
401        write!(f, "{}: {}", self.span.start(), self.value)
402    }
403}
404
405pub fn span<Pos>(start: Pos, end: Pos) -> Span<Pos>
406where
407    Pos: Ord,
408{
409    Span::new(start, end)
410}
411
412pub fn spanned<T, Pos>(span: Span<Pos>, value: T) -> Spanned<T, Pos> {
413    Spanned { span, value }
414}
415
416pub fn spanned2<T, Pos>(start: Pos, end: Pos, value: T) -> Spanned<T, Pos>
417where
418    Pos: Ord,
419{
420    spanned(span(start, end), value)
421}
422
423pub trait HasSpan {
424    fn span(&self) -> Span<BytePos>;
425}