use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};
pub trait HasSpan {
fn span(&self) -> Span;
}
impl<T: HasSpan> HasSpan for Box<T> {
fn span(&self) -> Span {
(**self).span()
}
}
impl<T: HasSpan> HasSpan for &T {
fn span(&self) -> Span {
(*self).span()
}
}
impl HasSpan for Span {
fn span(&self) -> Span {
*self
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default)]
pub struct Span {
pub start: Position,
pub end: Position,
}
impl Display for Span {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.start == self.end {
write!(formatter, "{}", self.start)
} else {
write!(formatter, "{} to {}", self.start, self.end)
}
}
}
impl Span {
pub fn new(start: Position, end: Position) -> Span {
Span { start, end }
}
pub fn consecutive(start: impl HasSpan, end: impl HasSpan) -> Span {
Span::new(start.span().start, end.span().end)
}
pub fn substr<'a>(&self, s: &'a str) -> &'a str {
&s[self.start.byte..=self.end.byte]
}
}
#[derive(Clone, Copy, Debug, Eq)]
pub struct Position {
pub byte: usize,
pub line: u32,
pub col: u32,
}
impl Position {
pub fn new(byte: usize, line: u32, col: u32) -> Position {
Position { byte, line, col }
}
}
impl Default for Position {
fn default() -> Position {
Position::new(0, 1, 1)
}
}
impl PartialEq for Position {
fn eq(&self, other: &Self) -> bool {
self.byte == other.byte
}
}
impl PartialOrd for Position {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.byte.partial_cmp(&other.byte)
}
}
impl Ord for Position {
fn cmp(&self, other: &Self) -> Ordering {
self.byte.cmp(&other.byte)
}
}
impl Hash for Position {
fn hash<H: Hasher>(&self, state: &mut H) {
self.byte.hash(state)
}
}
impl Display for Position {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}:{}", self.line, self.col)
}
}