use mago_database::file::FileId;
use mago_span::HasSpan;
use mago_span::Position;
use mago_span::Span;
use mago_syntax_core::ast::TokenSeparatedSequence as CoreTokenSeparatedSequence;
use crate::token::Token;
pub use mago_syntax_core::ast::Sequence;
pub type TokenSeparatedSequence<'arena, T> = CoreTokenSeparatedSequence<'arena, T, Token<'arena>>;
pub trait TokenSeparatedSequenceExt<'arena, T: HasSpan> {
fn first_span(&self, file_id: FileId) -> Option<Span>;
fn last_span(&self, file_id: FileId) -> Option<Span>;
fn span(&self, file_id: FileId, from: Position) -> Span;
}
impl<'arena, T: HasSpan> TokenSeparatedSequenceExt<'arena, T> for TokenSeparatedSequence<'arena, T> {
#[inline]
fn first_span(&self, file_id: FileId) -> Option<Span> {
match (self.tokens.first(), self.nodes.first()) {
(Some(token), Some(node)) => {
let token_end = token.start.offset + token.value.len() as u32;
if token_end <= node.span().start.offset { Some(token.span_for(file_id)) } else { Some(node.span()) }
}
(Some(token), None) => Some(token.span_for(file_id)),
(None, Some(node)) => Some(node.span()),
(None, None) => None,
}
}
#[inline]
fn last_span(&self, file_id: FileId) -> Option<Span> {
match (self.tokens.last(), self.nodes.last()) {
(Some(token), Some(node)) => {
if token.start.offset >= node.span().end.offset {
Some(token.span_for(file_id))
} else {
Some(node.span())
}
}
(Some(token), None) => Some(token.span_for(file_id)),
(None, Some(node)) => Some(node.span()),
(None, None) => None,
}
}
#[inline]
fn span(&self, file_id: FileId, from: Position) -> Span {
match (self.first_span(file_id), self.last_span(file_id)) {
(Some(first), Some(last)) => Span::new(file_id, first.start, last.end),
_ => Span::new(file_id, from, from),
}
}
}