use std::path::PathBuf; #[derive(Clone)] pub struct SourceSpan { /// The source characters which this span represents. pub string: String, /// The location of this span in the merged source file. pub in_merged: SourceLocation, /// The location of this span in the original source file. pub in_source: Option, } impl SourceSpan { pub fn location(&self) -> &SourceLocation { self.in_source.as_ref().unwrap_or(&self.in_merged) } } #[derive(Clone)] pub struct SourceLocation { /// File path the source was loaded from. pub path: Option, /// Position of the first character of the string. pub start: Position, /// Position of the final character of the string. pub end: Position, } impl std::fmt::Display for SourceLocation { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { let y = self.start.line + 1; let x = self.start.column + 1; match &self.path { Some(path) => write!(f, "{}:{y}:{x}", path.as_os_str().to_string_lossy()), None => write!(f, ":{y}:{x}"), } } } #[derive(Clone, Copy)] pub struct Position { /// The number of lines that precede this line in the source file. pub line: usize, /// The number of characters that precede this character in the line. pub column: usize, } impl Position { pub const ZERO: Self = Self { line: 0, column: 0 }; pub fn to_next_char(&mut self) { self.column += 1; } pub fn to_next_line(&mut self) { self.line += 1; self.column = 0; } pub fn advance(&mut self, c: char) { match c { '\n' => self.to_next_line(), _ => self.to_next_char(), } } } impl std::fmt::Display for Position { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { let y = self.line + 1; let x = self.column + 1; write!(f, "{y}:{x}") } }