mod miette;
#[cfg(feature = "miette")]
use ::miette::LabeledSpan;
use std::cmp;
use std::fmt::{self, Display, Formatter};
#[cfg(feature = "miette")]
pub use crate::diagnostics::miette::diagnose;
pub type Span = (usize, usize);
pub trait SpanExt {
fn union(&self, other: &Self) -> Self;
}
impl SpanExt for Span {
fn union(&self, other: &Self) -> Self {
let start = cmp::min(self.0, other.0);
let end = cmp::max(self.0 + self.1, other.0 + other.1);
(start, end - start)
}
}
pub trait LocatedError: Display {
fn span(&self) -> Span;
}
#[derive(Clone, Copy, Debug)]
pub struct CompositeSpan {
label: &'static str,
kind: CompositeSpanKind,
}
impl CompositeSpan {
pub fn spanned(label: &'static str, span: Span) -> Self {
CompositeSpan {
label,
kind: CompositeSpanKind::Span(span),
}
}
pub fn correlated(label: &'static str, span: Span, correlated: CorrelatedSpan) -> Self {
CompositeSpan {
label,
kind: CompositeSpanKind::Correlated { span, correlated },
}
}
#[cfg(feature = "miette")]
pub fn labels(&self) -> Vec<LabeledSpan> {
let label = Some(self.label.to_string());
match self.kind {
CompositeSpanKind::Span(ref span) => vec![LabeledSpan::new_with_span(label, *span)],
CompositeSpanKind::Correlated {
ref span,
ref correlated,
} => Some(LabeledSpan::new_with_span(label, *span))
.into_iter()
.chain(correlated.labels())
.collect(),
}
}
}
impl Display for CompositeSpan {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.label)
}
}
impl LocatedError for CompositeSpan {
fn span(&self) -> Span {
match self.kind {
CompositeSpanKind::Span(ref span) | CompositeSpanKind::Correlated { ref span, .. } => {
*span
},
}
}
}
#[derive(Clone, Copy, Debug)]
enum CompositeSpanKind {
Span(Span),
Correlated {
span: Span,
#[cfg_attr(not(feature = "miette"), allow(dead_code))]
correlated: CorrelatedSpan,
},
}
#[derive(Clone, Copy, Debug)]
pub enum CorrelatedSpan {
Contiguous(Span),
Split(Span, Span),
}
impl CorrelatedSpan {
pub fn split_some(left: Option<Span>, right: Span) -> Self {
if let Some(left) = left {
CorrelatedSpan::Split(left, right)
}
else {
CorrelatedSpan::Contiguous(right)
}
}
#[cfg(feature = "miette")]
pub fn labels(&self) -> Vec<LabeledSpan> {
let label = Some("here".to_string());
match self {
CorrelatedSpan::Contiguous(ref span) => {
vec![LabeledSpan::new_with_span(label, *span)]
},
CorrelatedSpan::Split(ref left, ref right) => vec![
LabeledSpan::new_with_span(label.clone(), *left),
LabeledSpan::new_with_span(label, *right),
],
}
}
}
impl From<Span> for CorrelatedSpan {
fn from(span: Span) -> Self {
CorrelatedSpan::Contiguous(span)
}
}