use std::fmt::{self, Debug, Formatter}; use std::ops::{Add, Range}; use serde::{Deserialize, Serialize}; /// A value with the span it corresponds to in the source code. #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Serialize, Deserialize)] pub struct Spanned { /// The spanned value. pub v: T, /// The location in source code of the value. pub span: Span, } impl Spanned { /// Create a new instance from a value and its span. pub fn new(v: T, span: impl Into) -> Self { Self { v, span: span.into() } } /// Create a new instance from a value with the zero span. pub fn zero(v: T) -> Self { Self { v, span: Span::ZERO } } /// Convert from `&Spanned` to `Spanned<&T>` pub fn as_ref(&self) -> Spanned<&T> { Spanned { v: &self.v, span: self.span } } /// Map the value using a function keeping the span. pub fn map(self, f: F) -> Spanned where F: FnOnce(T) -> U, { Spanned { v: f(self.v), span: self.span } } } impl Debug for Spanned { fn fmt(&self, f: &mut Formatter) -> fmt::Result { self.v.fmt(f)?; if f.alternate() { f.write_str(" <")?; self.span.fmt(f)?; f.write_str(">")?; } Ok(()) } } /// Bounds of a slice of source code. #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Serialize, Deserialize)] pub struct Span { /// The inclusive start position. pub start: Pos, /// The inclusive end position. pub end: Pos, } impl Span { /// The zero span. pub const ZERO: Self = Self { start: Pos::ZERO, end: Pos::ZERO }; /// Create a new span from start and end positions. pub fn new(start: impl Into, end: impl Into) -> Self { Self { start: start.into(), end: end.into() } } /// Create a span including just a single position. pub fn at(pos: impl Into + Copy) -> Self { Self::new(pos, pos) } /// Create a new span with the earlier start and later end position. pub fn join(self, other: Self) -> Self { Self { start: self.start.min(other.start), end: self.end.max(other.end), } } /// Expand a span by merging it with another span. pub fn expand(&mut self, other: Self) { *self = self.join(other) } /// Test whether one span complete contains the other span. pub fn contains(self, other: Self) -> bool { self.start <= other.start && self.end >= other.end } /// Convert to a `Range` for indexing. pub fn to_range(self) -> Range { self.start.to_usize() .. self.end.to_usize() } } impl From for Span where T: Into + Copy, { fn from(pos: T) -> Self { Self::at(pos) } } impl From> for Span where T: Into, { fn from(range: Range) -> Self { Self::new(range.start, range.end) } } impl Debug for Span { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}-{:?}", self.start, self.end) } } /// A byte position in source code. #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Serialize, Deserialize)] pub struct Pos(pub u32); impl Pos { /// The zero position. pub const ZERO: Self = Self(0); /// Convert to a usize for indexing. pub fn to_usize(self) -> usize { self.0 as usize } } impl From for Pos { fn from(index: u32) -> Self { Self(index) } } impl From for Pos { fn from(index: usize) -> Self { Self(index as u32) } } impl Debug for Pos { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Debug::fmt(&self.0, f) } } impl Add for Pos where T: Into, { type Output = Self; fn add(self, rhs: T) -> Self { Pos(self.0 + rhs.into().0) } }