use std::collections::VecDeque;
use std::iter::Peekable;
use crate::cst::{Event, SyntaxKind};
pub struct ErrorMerger<I>
where
I: Iterator<Item = Event>,
{
inner: Peekable<I>,
open_begins: Vec<usize>,
output_buffer: VecDeque<Event>,
}
impl<I> ErrorMerger<I>
where
I: Iterator<Item = Event>,
{
pub fn new(inner: I) -> Self {
Self {
inner: inner.peekable(),
open_begins: Vec::new(),
output_buffer: VecDeque::new(),
}
}
}
impl<I> Iterator for ErrorMerger<I>
where
I: Iterator<Item = Event>,
{
type Item = Event;
fn next(&mut self) -> Option<Self::Item> {
if let Some(event) = self.output_buffer.pop_front() {
return Some(event);
}
while let Some(event) = self.inner.next() {
match event {
event @ Event::Begin { kind: SyntaxKind::ERROR, .. } => {
self.open_begins.push(self.output_buffer.len());
self.output_buffer.push_back(event);
}
Event::End { kind: SyntaxKind::ERROR, .. } => {
match self.inner.peek() {
Some(Event::Begin {
kind: SyntaxKind::ERROR,
span: next_error_span,
}) => {
let begin_idx = self.open_begins.last().unwrap();
match &mut self.output_buffer[*begin_idx] {
Event::Begin {
kind: SyntaxKind::ERROR,
span,
} => {
*span = span.combine(next_error_span);
}
_ => unreachable!(),
}
self.inner.next();
}
_ => {
let begin_idx = self.open_begins.pop().unwrap();
let span = match &self.output_buffer[begin_idx] {
Event::Begin {
kind: SyntaxKind::ERROR,
span,
} => span.clone(),
_ => unreachable!(),
};
self.output_buffer.push_back(Event::End {
kind: SyntaxKind::ERROR,
span,
});
}
}
}
event => {
self.output_buffer.push_back(event);
if self.open_begins.is_empty() {
break;
}
}
}
}
assert!(self.open_begins.is_empty());
self.output_buffer.pop_front()
}
}
#[cfg(test)]
mod tests {
use crate::cst::error_merger::ErrorMerger;
use crate::cst::Event;
use crate::cst::SyntaxKind;
use crate::Span;
#[test]
fn error_merger() {
let events = vec![
Event::Begin { kind: SyntaxKind::ERROR, span: Span(0..20) },
Event::Token { kind: SyntaxKind::WHITESPACE, span: Span(0..10) },
Event::Begin { kind: SyntaxKind::ERROR, span: Span(10..20) },
Event::Token { kind: SyntaxKind::WHITESPACE, span: Span(10..20) },
Event::End { kind: SyntaxKind::ERROR, span: Span(10..20) },
Event::End { kind: SyntaxKind::ERROR, span: Span(0..20) },
Event::Begin { kind: SyntaxKind::ERROR, span: Span(20..30) },
Event::Token { kind: SyntaxKind::WHITESPACE, span: Span(20..30) },
Event::End { kind: SyntaxKind::ERROR, span: Span(20..30) },
Event::Begin { kind: SyntaxKind::ERROR, span: Span(30..40) },
Event::Token { kind: SyntaxKind::WHITESPACE, span: Span(30..40) },
Event::End { kind: SyntaxKind::ERROR, span: Span(30..40) },
];
let mut stream = ErrorMerger::new(events.into_iter());
assert_eq!(
stream.next(),
Some(Event::Begin { kind: SyntaxKind::ERROR, span: Span(0..40) })
);
assert_eq!(
stream.next(),
Some(Event::Token {
kind: SyntaxKind::WHITESPACE,
span: Span(0..10)
})
);
assert_eq!(
stream.next(),
Some(Event::Begin { kind: SyntaxKind::ERROR, span: Span(10..20) })
);
assert_eq!(
stream.next(),
Some(Event::Token {
kind: SyntaxKind::WHITESPACE,
span: Span(10..20)
})
);
assert_eq!(
stream.next(),
Some(Event::End { kind: SyntaxKind::ERROR, span: Span(10..20) })
);
assert_eq!(
stream.next(),
Some(Event::Token {
kind: SyntaxKind::WHITESPACE,
span: Span(20..30)
})
);
assert_eq!(
stream.next(),
Some(Event::Token {
kind: SyntaxKind::WHITESPACE,
span: Span(30..40)
})
);
assert_eq!(
stream.next(),
Some(Event::End { kind: SyntaxKind::ERROR, span: Span(0..40) })
);
}
}