use core::{fmt, marker::PhantomData};
use crate::{
lexer::Span,
syntax::{Language, Syntax},
utils::SimpleSpan,
};
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Missing<T, S = SimpleSpan, Lang = ()> {
before: S,
after: Option<S>,
span: Option<S>,
_syntax: PhantomData<T>,
_lang: PhantomData<Lang>,
}
impl<T, S, Lang> Missing<T, S, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn new(before: S) -> Self {
Self {
before,
after: None,
span: None,
_syntax: PhantomData,
_lang: PhantomData,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn between(before: S, after: S) -> Self
where
S: crate::lexer::Span + Clone,
{
let start = before.end_ref();
let end = after.start_ref();
let span = if end >= start {
S::new(start.clone(), end.clone())
} else {
S::new(end.clone(), end.clone())
};
Self {
before,
after: Some(after),
span: Some(span),
_syntax: PhantomData,
_lang: PhantomData,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_after(mut self, after: S) -> Self {
self.after = Some(after);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_after(&mut self, after: S) {
self.after = Some(after);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn before(&self) -> S
where
S: Copy,
{
self.before
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn after(&self) -> Option<S>
where
S: Copy,
{
self.after
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> S
where
S: Copy,
{
match self.span.as_ref() {
Some(span) => *span,
None => self.before,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> &S {
match self.span.as_ref() {
Some(span) => span,
None => &self.before,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, offset: &S::Offset) -> &mut Self
where
S: Span,
{
self.before.bump(offset);
if let Some(after) = &mut self.after {
after.bump(offset);
self.span = Some(Self::full_span(&self.before, after));
}
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn kind(&self) -> <Lang as Language>::SyntaxKind
where
T: Syntax<Lang = Lang>,
Lang: Language,
{
T::KIND
}
fn full_span(before: &S, after: &S) -> S
where
S: Span,
{
let before_start = before.start_ref();
let before_end = before.end_ref();
let end_start = after.start_ref();
let end_end = after.end_ref();
assert!(
end_start >= before_end,
"cannot determine full span: before.end() > after.start()"
);
assert!(
end_end >= before_start,
"cannot determine full span: before.start() > after.end()"
);
assert!(
before_end >= before_start,
"cannot determine full span: before.end() < before.start()"
);
S::new(before_start.clone(), end_end.clone())
}
}
impl<T, S, Lang> fmt::Display for Missing<T, S, Lang>
where
T: Syntax<Lang = Lang>,
Lang: Language,
<Lang as Language>::SyntaxKind: fmt::Display,
S: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.after {
Some(after) => write!(
f,
"missing {} between {} and {}",
self.kind(),
self.before,
after
),
None => write!(f, "missing {} after {}", self.kind(), self.before),
}
}
}
impl<T, S, Lang> fmt::Debug for Missing<T, S, Lang>
where
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Missing")
.field("before", &self.before)
.field("after", &self.after)
.finish()
}
}
impl<T, S, Lang> core::error::Error for Missing<T, S, Lang>
where
T: Syntax<Lang = Lang>,
Lang: Language,
<Lang as Language>::SyntaxKind: fmt::Display + fmt::Debug,
S: fmt::Debug + fmt::Display,
{
}