use std::fmt; #[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] pub struct Pos { pub idx: u32, pub line: u32, pub col: u32, } impl std::cmp::PartialOrd for Pos { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl std::cmp::Ord for Pos { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.idx.cmp(&other.idx) } } impl Pos { pub const fn new() -> Self { Self { idx: 0, line: 1, col: 1, } } #[must_use] pub fn advance(self, c: char) -> Self { let idx = self.idx + u32::try_from(c.len_utf8()).unwrap_or_default(); if c == '\n' { Self { idx, line: self.line + 1, col: 1, } } else { Self { idx, line: self.line, col: self.col + 1, } } } } impl fmt::Display for Pos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", self.line, self.col) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Span { pub start: Pos, pub end: Pos, } impl Span { pub const fn new(start: Pos, end: Pos) -> Self { if end.idx < start.idx { Self { start: end, end: start, } } else { Self { start, end } } } pub fn of<'a>(&self, s: &'a str) -> &'a str { &s[(self.start.idx as usize)..(self.end.idx as usize)] } } impl fmt::Display for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}-{}", self.start, self.end) } }