sizzle_parser/
src_pos.rs

1//! Source code position logic.
2
3use std::fmt::{Debug, Display};
4
5/// Describes a line and column position in some source string.
6///
7/// This is both 0 indexed, so the first line is 0 and the first col on a line is 0.
8#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
9pub struct LineColPos {
10    line: u16,
11    col: u16,
12}
13
14impl LineColPos {
15    /// Creates a new line and column position.
16    pub fn new(line: u16, col: u16) -> Self {
17        Self { line, col }
18    }
19
20    /// Creates a dummy line and column position.
21    pub fn dummy() -> Self {
22        Self::new(0, 0)
23    }
24
25    /// Gets the line of the line and column position.
26    pub fn line(&self) -> u16 {
27        self.line
28    }
29
30    /// Gets the column of the line and column position.
31    pub fn col(&self) -> u16 {
32        self.col
33    }
34}
35
36/// A table of line and column positions for a source string.
37#[derive(Clone, Debug)]
38pub struct PosTbl {
39    chars: Vec<LineColPos>,
40}
41
42impl PosTbl {
43    /// Creates a new line and column position table.
44    pub fn new(chars: Vec<LineColPos>) -> Self {
45        Self { chars }
46    }
47
48    /// Generates a line and column position table from a source string.
49    pub fn generate(src: impl Iterator<Item = char>) -> Self {
50        let mut buf = Vec::new();
51
52        let mut line = 0;
53        let mut chr = 0;
54
55        for c in src {
56            let lcp = if c == '\n' {
57                let p = LineColPos::new(line, chr);
58                line += 1;
59                chr = 0;
60                p
61            } else {
62                let p = LineColPos::new(line, chr);
63                chr += 1;
64                p
65            };
66
67            buf.push(lcp);
68        }
69
70        Self::new(buf)
71    }
72
73    /// Gets the line and column position for a given byte index.
74    pub fn get(&self, idx: usize) -> Option<LineColPos> {
75        self.chars.get(idx).copied()
76    }
77
78    /// Gets the source position for a given byte index.
79    pub fn get_srcpos(&self, idx: usize) -> Option<SrcPos> {
80        self.get(idx).map(|lcp| SrcPos::new(idx as i32, lcp))
81    }
82
83    /// Gets the source position for a given byte index, panicking if out of bounds.
84    pub fn expect_srcpos(&self, idx: usize) -> SrcPos {
85        self.get_srcpos(idx).expect("srcpos: out of bounds")
86    }
87
88    /// Gets the source position for the end of the source string, panicking if the source string is empty.
89    pub fn expect_end(&self) -> SrcPos {
90        let last_lcp = *self.chars.last().expect("srcpos: empty");
91        SrcPos::new(self.chars.len() as i32, last_lcp)
92    }
93}
94
95/// A source position.
96#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
97pub struct SrcPos {
98    /// The byte index in the source file.
99    off: i32,
100
101    /// The line and column.
102    lc: LineColPos,
103}
104
105impl SrcPos {
106    /// Creates a new source position.
107    pub fn new(off: i32, lc: LineColPos) -> Self {
108        Self { off, lc }
109    }
110
111    /// Creates a dummy source position.
112    pub fn dummy() -> Self {
113        Self::new(-1, LineColPos::dummy())
114    }
115
116    /// Gets the byte index of the source position.
117    pub fn off(&self) -> i32 {
118        self.off
119    }
120
121    /// Gets the line and column position of the source position.
122    pub fn line_col_pos(&self) -> LineColPos {
123        self.lc
124    }
125
126    /// Gets the line of the source position.
127    pub fn line(&self) -> u16 {
128        self.lc.line
129    }
130
131    /// Gets the column of the source position.
132    pub fn col(&self) -> u16 {
133        self.lc.col
134    }
135}
136
137impl Display for SrcPos {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        write!(f, "L{}:C{}", self.line(), self.col())
140    }
141}
142
143impl Debug for SrcPos {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        write!(f, "L{}:C{}:#{}", self.line(), self.col(), self.off())
146    }
147}
148
149/// A source span.
150#[derive(Copy, Clone, Debug, Eq, PartialEq)]
151pub struct SrcSpan {
152    start: SrcPos,
153    end: SrcPos,
154}
155
156impl SrcSpan {
157    /// Creates a new source span.
158    pub fn new(start: SrcPos, end: SrcPos) -> Self {
159        Self { start, end }
160    }
161
162    /// Gets the start of the source span.
163    pub fn start(&self) -> SrcPos {
164        self.start
165    }
166
167    /// Gets the end of the source span.
168    pub fn end(&self) -> SrcPos {
169        self.end
170    }
171}