use std::fmt::{ Display, Formatter, Result as FmtResult };
use typemap::Key;
use unicode_segmentation::UnicodeSegmentation;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Location {
pub line: usize,
pub column: usize,
}
impl Location {
#[must_use]
pub fn advanced_by(&self, lexeme: &str) -> Location {
let line_breaks: &[char] = &[
'\n', '\x0b', '\x0c', '\r',
'\u{0085}', '\u{2028}', '\u{2029}',
];
match lexeme.rfind(line_breaks) {
Some(index) => Location {
line: self.line + grapheme_count_by(
lexeme,
|g| g.contains(line_breaks)
),
column: grapheme_count(&lexeme[index..]) + 1 - 1,
},
None => Location {
line: self.line,
column: self.column + grapheme_count(lexeme),
},
}
}
}
impl Default for Location {
fn default() -> Self {
Location { line: 1, column: 1 }
}
}
impl Display for Location {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "line {} char {}", self.line, self.column)
}
}
impl Key for Location {
type Value = Location;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Span {
pub start: Location,
pub end: Location,
}
impl Display for Span {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}...{}", self.start, self.end)
}
}
impl Key for Span {
type Value = Span;
}
impl Spanned for Span {
fn span(&self) -> Span {
*self
}
}
pub trait Spanned {
fn span(&self) -> Span;
fn span_to<T: Spanned>(&self, other: &T) -> Span {
Span {
start: self.span().start,
end: other.span().end,
}
}
}
fn graphemes(string: &str) -> impl Iterator<Item = &str> {
string.graphemes(true)
}
#[must_use]
fn grapheme_count(string: &str) -> usize {
graphemes(string).count()
}
fn grapheme_count_by<P>(string: &str, pred: P) -> usize
where
P: Fn(&str) -> bool,
{
graphemes(string).filter(|&g| pred(g)).count()
}