Skip to main content

bulloak_syntax/
span.rs

1//! Locations of a construct in a file.
2
3use std::{cmp::Ordering, fmt};
4
5/// Span represents the position information of a single token.
6///
7/// All span positions are absolute char offsets that can be used on the
8/// original tree that was parsed.
9#[derive(Clone, Copy, Eq, PartialEq, Default)]
10pub struct Span {
11    /// The start char offset.
12    pub start: Position,
13    /// The end char offset.
14    pub end: Position,
15}
16
17impl fmt::Debug for Span {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        write!(f, "Span({:?}, {:?})", self.start, self.end)
20    }
21}
22
23impl Ord for Span {
24    fn cmp(&self, other: &Self) -> Ordering {
25        (&self.start, &self.end).cmp(&(&other.start, &other.end))
26    }
27}
28
29impl PartialOrd for Span {
30    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
31        Some(self.cmp(other))
32    }
33}
34
35/// A single position.
36///
37/// A position encodes one half of a span, and includes the char offset, line
38/// number and column number.
39#[derive(Clone, Copy, Eq, PartialEq)]
40pub struct Position {
41    /// The absolute offset of this position, starting at `0` from the
42    /// beginning of the tree.
43    ///
44    /// Note that this is a `char` offset, which lets us use it when
45    /// indexing into the original source string.
46    pub offset: usize,
47    /// The line number, starting at `1`.
48    pub line: usize,
49    /// The approximate column number, starting at `1`.
50    pub column: usize,
51}
52
53impl Default for Position {
54    fn default() -> Self {
55        Self { offset: usize::default(), line: 1, column: 1 }
56    }
57}
58
59impl fmt::Debug for Position {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        write!(
62            f,
63            "Position(o: {:?}, l: {:?}, c: {:?})",
64            self.offset, self.line, self.column
65        )
66    }
67}
68
69impl Ord for Position {
70    fn cmp(&self, other: &Self) -> Ordering {
71        self.offset.cmp(&other.offset)
72    }
73}
74
75impl PartialOrd for Position {
76    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
77        Some(self.cmp(other))
78    }
79}
80
81impl Span {
82    /// Create a new span with the given positions.
83    pub const fn new(start: Position, end: Position) -> Self {
84        Self { start, end }
85    }
86
87    /// Create a new span using the given position as the start and end.
88    pub const fn splat(pos: Position) -> Self {
89        Self::new(pos, pos)
90    }
91
92    /// Create a new span by replacing the starting position with the one
93    /// given.
94    pub const fn with_start(self, pos: Position) -> Self {
95        Self { start: pos, ..self }
96    }
97
98    /// Create a new span by replacing the ending position with the one
99    /// given.
100    pub const fn with_end(self, pos: Position) -> Self {
101        Self { end: pos, ..self }
102    }
103}
104
105impl Position {
106    /// Create a new position with the given information.
107    ///
108    /// `offset` is the absolute offset of the position, starting at `0` from
109    /// the beginning of the tree.
110    ///
111    /// `line` is the line number, starting at `1`.
112    ///
113    /// `column` is the approximate column number, starting at `1`.
114    pub const fn new(offset: usize, line: usize, column: usize) -> Self {
115        Self { offset, line, column }
116    }
117}