#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Pos { pub source: usize, pub line: usize, pub col: usize, pub byte: usize, pub len: usize, } impl Default for Pos { fn default() -> Self { Pos { source: 0, line: 0, col: 0, byte: 0, len: 1, } } } impl Pos { pub fn from_char(c: char, source: usize, line: usize, col: usize, byte: usize) -> Self { Pos { source, line, col, byte, len: c.len_utf8(), } } pub fn next_char(&self, c: char) -> Self { Pos { source: self.source + 1, line: self.line, col: self.col + 1, byte: self.byte + self.len, len: c.len_utf8(), } } pub fn adv_char(&mut self, c: char) { *self = self.next_char(c); } pub fn adv_str(&mut self, s: &str) { for c in s.chars() { self.adv_char(c); } } pub fn min(self, other: Self) -> Self { if self.byte < other.byte { self } else { other } } pub fn max(self, other: Self) -> Self { if self.byte > other.byte { self } else { other } } } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub struct Span { pub start: Pos, pub end: Pos, } impl Span { pub fn union(self, other: Self) -> Self { let start = self.start.min(other.start); let end = self.end.max(other.end); Span { start, end } } } pub trait Spanned { fn span(&self) -> Span; fn text_at<'t>(&self, text: &'t str) -> &'t str { let Span { start, end } = self.span(); &text[start.byte .. end.byte] } } impl Spanned for Span { fn span(&self) -> Span { *self } } #[cfg(test)] mod test { use super::*; #[test] fn test_pos_min() { let small = Pos::default(); let large = Pos { source: 1, byte: 1, ..Default::default() }; assert_eq!(small.min(large), small); assert_eq!(large.min(small), small); } #[test] fn test_pos_max() { let small = Pos::default(); let large = Pos { source: 1, byte: 1, ..Default::default() }; assert_eq!(small.max(large), large); assert_eq!(large.max(small), large); } #[test] fn test_span_union() { let first = Span { start: Pos::default(), end: Pos { source: 15, col: 15, byte: 15, ..Default::default() } }; let second = Span { start: Pos { source: 25, col: 25, byte: 25, ..Default::default() }, end: Pos { source: 27, col: 27, byte: 27, ..Default::default() } }; let expected = Span { start: first.start, end: second.end, }; assert_eq!(first.union(second), expected); assert_eq!(second.union(first), expected); } }