1use std::{
2 fmt::{Debug, Display},
3 ops::Deref,
4};
5
6#[derive(PartialEq, Eq, Debug, Copy, Clone)]
8pub struct LineColumn {
9 pub line: usize,
10 pub column: usize,
11}
12
13#[derive(PartialEq, Eq, Debug, Copy, Clone)]
15pub enum Position {
16 Position(usize),
17 LineBased(LineColumn),
18}
19
20impl Position {
21 pub fn from_lc(line: usize, column: usize) -> Self {
22 Self::LineBased(LineColumn { line, column })
23 }
24
25 pub fn from_pos(pos: usize) -> Self {
26 Self::Position(pos)
27 }
28
29 #[inline]
30 pub fn line(&self) -> usize {
31 match self {
32 Position::Position(pos) => *pos,
33 Position::LineBased(lb) => lb.line,
34 }
35 }
36
37 #[inline]
38 pub fn column(&self) -> usize {
39 match self {
40 Position::Position(_) => 0,
41 Position::LineBased(lb) => lb.column,
42 }
43 }
44
45 #[inline]
46 pub fn position(&self) -> usize {
47 match self {
48 Position::Position(pos) => *pos,
49 Position::LineBased(lb) => lb.line,
50 }
51 }
52}
53
54impl Default for Position {
55 fn default() -> Self {
56 Position::Position(0)
57 }
58}
59
60impl Display for Position {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 match self {
63 Position::Position(pos) => write!(f, "{pos}"),
64 Position::LineBased(lb) => write!(f, "{},{}", lb.line, lb.column),
65 }
66 }
67}
68
69impl From<Location> for Position {
70 fn from(value: Location) -> Self {
71 value.end.unwrap_or(value.start)
72 }
73}
74
75#[derive(PartialEq, Eq, Clone, Copy, Default)]
87pub struct Location {
88 pub start: Position,
90 pub end: Option<Position>,
92}
93
94impl Location {
95 pub fn new(start: Position, end: Position) -> Self {
96 Self {
97 start,
98 end: Some(end),
99 }
100 }
101 pub fn from_start(start: Position) -> Self {
102 Self { start, end: None }
103 }
104
105 pub fn to(&self, loc_to: Self) -> Self {
108 Self {
109 start: self.start,
110 end: loc_to.end.or(Some(loc_to.start)),
111 }
112 }
113}
114
115impl Debug for Location {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 match self.end {
118 Some(ref end) => write!(f, "[{}-{}]", self.start, end),
119 None => write!(f, "[{}]", self.start),
120 }
121 }
122}
123
124#[derive(Debug, Clone)]
137pub struct ValLoc<T> {
138 value: T,
139 pub location: Option<Location>,
140}
141
142impl<T: Display> Display for ValLoc<T> {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(f, "{}", self.value)
145 }
146}
147
148impl<T> AsRef<T> for ValLoc<T> {
149 fn as_ref(&self) -> &T {
150 &self.value
151 }
152}
153
154impl<T> From<T> for ValLoc<T> {
155 fn from(value: T) -> Self {
156 Self {
157 value,
158 location: None,
159 }
160 }
161}
162
163impl<T> Deref for ValLoc<T> {
164 type Target = T;
165
166 fn deref(&self) -> &Self::Target {
167 &self.value
168 }
169}
170
171impl From<ValLoc<String>> for String {
172 fn from(value: ValLoc<String>) -> Self {
173 value.value
174 }
175}
176impl<T> ValLoc<T> {
177 pub fn new(value: T, location: Option<Location>) -> Self {
178 Self { value, location }
179 }
180}
181macro_rules! from_valloc {
182 ($type:ty) => {
183 impl From<$crate::location::ValLoc<$type>> for $type {
184 fn from(value: $crate::location::ValLoc<Self>) -> Self {
185 value.value
186 }
187 }
188 impl From<&$crate::location::ValLoc<$type>> for $type
189 where $type: Copy
190 {
191 fn from(value: &$crate::location::ValLoc<Self>) -> Self {
192 value.value
193 }
194 }
195 };
196 ($($type:ty),+) => {
197 $(from_valloc!($type);)+
198 };
199}
200from_valloc!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool, char);
202
203#[cfg(test)]
204mod tests {
205 use super::{Location, Position};
206
207 #[test]
208 pub fn test_position_linebased() {
209 let p = Position::from_lc(2, 4);
210
211 assert_eq!(p.line(), 2);
212 assert_eq!(p.column(), 4);
213 assert_eq!(format!("{p}"), "2,4");
214 }
215
216 #[test]
217 pub fn test_position() {
218 let p = Position::from_pos(5);
219
220 assert_eq!(p.line(), 5);
221 assert_eq!(p.column(), 0);
222 assert_eq!(p.position(), 5);
223 assert_eq!(format!("{p}"), "5");
224 }
225
226 #[test]
227 pub fn test_location() {
228 let r = Location::new(Position::from_lc(5, 15), Position::from_lc(13, 27));
229
230 assert_eq!(format!("{r:?}"), "[5,15-13,27]");
231
232 let r = Location::new(Position::from_lc(5, 15), Position::from_pos(49));
233
234 assert_eq!(format!("{r:?}"), "[5,15-49]");
235 }
236}