use std::{fmt, cmp}; use std::fmt::{Formatter, Debug}; /// Position in the input string #[derive(PartialEq, Clone, Default)] pub struct SourcePosition { /// The line number on which the error occurred. pub line: u32, /// The column number on which the error occurred. pub column: u32, /// The index in the given string which caused the error. pub index: u32, /// File index if there are multiple files pub file: u32, } impl fmt::Display for SourcePosition { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}:{}", self.line, self.column) } } impl SourcePosition { pub fn with_file(mut self, file: u32) -> Self { self.file = file; self } } impl Debug for SourcePosition { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { if f.alternate() { f.debug_struct("SourcePosition") .field("line", &self.line) .field("column", &self.column) .field("index", &self.index) .field("file", &self.file) .finish() } else { // shorter version write!(f, "Pos({}|{}:{})", self.file, self.line, self.column) } } } pub(crate) fn get_line_and_column(s: &str, pos: usize) -> SourcePosition { let mut line: usize = 1; let mut col: isize = -1; for c in s.chars().take(pos + 1) { if c == '\n' { line += 1; col = -1; } else { col += 1; } } SourcePosition { line: line as u32, column: cmp::max(col, 0) as u32, index: pos as u32, file: 0 } } /// Build a span pub(crate) fn spos(s: &str, pos: usize) -> SourcePosition { if pos >= s.len() { Default::default() } else { get_line_and_column(s, pos) } }