//! Spans map elements to the part of source code they originate from. use std::fmt::{self, Debug, Display, Formatter}; use serde::Serialize; /// Annotates a value with the part of the source code it corresponds to. #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] pub struct Spanned { pub v: T, pub span: Span, } impl Spanned { pub fn new(v: T, span: Span) -> Spanned { Spanned { v, span } } pub fn value(self) -> T { self.v } pub fn map(self, f: F) -> Spanned where F: FnOnce(T) -> V { Spanned { v: f(self.v), span: self.span } } pub fn map_v(&self, new_v: V) -> Spanned { Spanned { v: new_v, span: self.span } } } impl Display for Spanned where T: std::fmt::Display { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "({}, {}, ", self.span.start, self.span.end)?; self.v.fmt(f)?; write!(f, ")") } } impl Debug for Spanned where T: std::fmt::Debug { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "({}, {}, ", self.span.start, self.span.end)?; self.v.fmt(f)?; write!(f, ")") } } /// Describes a slice of source code. #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] pub struct Span { pub start: Position, pub end: Position, } impl Span { pub const ZERO: Span = Span { start: Position::ZERO, end: Position::ZERO }; pub fn new(start: Position, end: Position) -> Span { Span { start, end } } pub fn merge(a: Span, b: Span) -> Span { Span { start: a.start.min(b.start), end: a.end.max(b.end), } } pub fn at(pos: Position) -> Span { Span { start: pos, end: pos } } pub fn expand(&mut self, other: Span) { *self = Span::merge(*self, other) } } impl Display for Span { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "({}, {})", self.start, self.end) } } debug_display!(Span); /// A line-column position in source code. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)] pub struct Position { /// The 0-indexed line (inclusive). pub line: usize, /// The 0-indexed column (inclusive). pub column: usize, } impl Position { pub const ZERO: Position = Position { line: 0, column: 0 }; pub fn new(line: usize, column: usize) -> Position { Position { line, column } } } impl Display for Position { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}:{}", self.line, self.column) } } debug_display!(Position);