Skip to main content

shrub_parser/
source.rs

1use std::fmt::Display;
2use std::sync::Arc;
3
4/// Represents a position in source text.
5#[derive(Clone, Default, Debug)]
6#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
7#[cfg_attr(
8    any(test, feature = "serde"),
9    derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)
10)]
11pub struct SourcePosition {
12    /// The 0-based index of the character in the input stream.
13    pub index: usize,
14    /// The 1-based line number.
15    pub line: usize,
16    /// The 1-based column number.
17    pub column: usize,
18}
19
20impl Display for SourcePosition {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        f.write_fmt(format_args!("{},{}", self.line, self.column))
23    }
24}
25
26impl SourcePosition {
27    /// Returns a new `SourcePosition` offset by the given
28    /// `SourcePositionOffset`.
29    ///
30    /// # Arguments
31    ///
32    /// * `offset` - The offset to apply.
33    #[must_use]
34    pub const fn offset(&self, offset: &SourcePositionOffset) -> Self {
35        Self {
36            index: self.index + offset.index,
37            line: self.line + offset.line,
38            column: if offset.line == 0 {
39                self.column + offset.column
40            } else {
41                offset.column + 1
42            },
43        }
44    }
45}
46
47#[cfg(feature = "diagnostics")]
48impl From<&SourcePosition> for miette::SourceOffset {
49    #[allow(clippy::cast_sign_loss)]
50    fn from(position: &SourcePosition) -> Self {
51        position.index.into()
52    }
53}
54
55/// Represents an offset in source text.
56#[derive(Clone, Default, Debug)]
57#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
58#[cfg_attr(
59    any(test, feature = "serde"),
60    derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)
61)]
62pub struct SourcePositionOffset {
63    /// The 0-based character offset.
64    pub index: usize,
65    /// The 0-based line offset.
66    pub line: usize,
67    /// The 0-based column offset.
68    pub column: usize,
69}
70
71/// Represents a span within source text.
72#[derive(Clone, Default, Debug)]
73#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
74#[cfg_attr(
75    any(test, feature = "serde"),
76    derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)
77)]
78pub struct SourceSpan {
79    /// The start position.
80    pub start: Arc<SourcePosition>,
81    /// The end position of the span (exclusive).
82    pub end: Arc<SourcePosition>,
83}
84
85impl SourceSpan {
86    /// Returns the length of the token in characters.
87    pub fn length(&self) -> usize {
88        self.end.index - self.start.index
89    }
90    pub(crate) fn within(start: &Self, end: &Self) -> Self {
91        Self {
92            start: start.start.clone(),
93            end: end.end.clone(),
94        }
95    }
96}