use crate::{
error::{ErrorKind, ScanError},
input::{str::StrInput, BorrowedInput, BufferedInput},
parser::{Event, ParseResult, Parser, ParserTrait, SpannedEventReceiver},
scanner::Span,
};
use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
pub struct ReplayParser<'input> {
events: alloc::vec::IntoIter<(Event<'input>, Span)>,
anchor_offset: usize,
}
impl<'input> ReplayParser<'input> {
#[must_use]
pub fn new(events: Vec<(Event<'input>, Span)>, anchor_offset: usize) -> Self {
Self {
events: events.into_iter(),
anchor_offset,
}
}
#[must_use]
pub fn anchor_offset(&self) -> usize {
self.anchor_offset
}
pub fn set_anchor_offset(&mut self, offset: usize) {
self.anchor_offset = offset;
}
fn advance_anchor_offset(&mut self, event: &Event<'input>) {
let anchor_id = match event {
Event::Scalar(_, _, anchor_id, _)
| Event::SequenceStart(_, anchor_id, _)
| Event::MappingStart(_, anchor_id, _) => *anchor_id,
_ => 0,
};
if anchor_id > 0 {
self.anchor_offset = self.anchor_offset.max(anchor_id.saturating_add(1));
}
}
}
impl<'input> ParserTrait<'input> for ReplayParser<'input> {
fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>> {
self.events.as_slice().first().map(Ok)
}
fn next_event(&mut self) -> Option<ParseResult<'input>> {
let event = self.events.next()?;
self.advance_anchor_offset(&event.0);
Some(Ok(event))
}
fn load<R: SpannedEventReceiver<'input>>(
&mut self,
recv: &mut R,
multi: bool,
) -> Result<(), ScanError> {
while let Some(res) = self.next_event() {
let (ev, span) = res?;
let is_doc_end = matches!(ev, Event::DocumentEnd);
let is_stream_end = matches!(ev, Event::StreamEnd);
recv.on_event(ev, span);
if is_stream_end {
break;
}
if !multi && is_doc_end {
break;
}
}
Ok(())
}
}
impl<'input> Iterator for ReplayParser<'input> {
type Item = ParseResult<'input>;
fn next(&mut self) -> Option<Self::Item> {
self.next_event()
}
}
impl core::iter::FusedIterator for ReplayParser<'_> {}
enum AnyParser<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
String {
parser: Parser<'input, StrInput<'input>>,
name: String,
},
Iter {
parser: Parser<'static, BufferedInput<I>>,
name: String,
},
Custom {
parser: Parser<'input, T>,
name: String,
},
Replay {
parser: ReplayParser<'input>,
name: String,
},
}
impl<'input, I, T> AnyParser<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
fn anchor_offset(&self) -> usize {
match self {
AnyParser::String { parser, .. } => parser.anchor_offset(),
AnyParser::Iter { parser, .. } => parser.anchor_offset(),
AnyParser::Custom { parser, .. } => parser.anchor_offset(),
AnyParser::Replay { parser, .. } => parser.anchor_offset(),
}
}
fn set_anchor_offset(&mut self, offset: usize) {
match self {
AnyParser::String { parser, .. } => parser.set_anchor_offset(offset),
AnyParser::Iter { parser, .. } => parser.set_anchor_offset(offset),
AnyParser::Custom { parser, .. } => parser.set_anchor_offset(offset),
AnyParser::Replay { parser, .. } => parser.set_anchor_offset(offset),
}
}
}
pub struct ParserStack<'input, I = core::iter::Empty<char>, T = StrInput<'input>>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
parsers: Vec<AnyParser<'input, I, T>>,
current: Option<(Event<'input>, Span)>,
current_error: Option<ScanError>,
stream_end_emitted: bool,
#[allow(clippy::type_complexity)]
include_resolver: Option<Box<dyn FnMut(&str) -> Result<Cow<'input, str>, ScanError> + 'input>>,
}
impl<'input, I, T> ParserStack<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
#[must_use]
pub fn new() -> Self {
Self {
parsers: Vec::new(),
current: None,
current_error: None,
stream_end_emitted: false,
include_resolver: None,
}
}
pub fn set_resolver(
&mut self,
mut resolver: impl FnMut(&str) -> Result<String, ScanError> + 'input,
) {
self.include_resolver = Some(Box::new(move |name| resolver(name).map(Cow::Owned)));
}
pub fn set_borrowed_resolver(
&mut self,
mut resolver: impl FnMut(&str) -> Result<&'input str, ScanError> + 'input,
) {
self.include_resolver = Some(Box::new(move |name| resolver(name).map(Cow::Borrowed)));
}
pub fn push_include(&mut self, include_str: &str) -> Result<(), ScanError> {
let resolved = match &mut self.include_resolver {
Some(resolver) => resolver(include_str),
None => {
return Err(self.contextualize_include_error(
ScanError::from_kind(
crate::scanner::Marker::new(0, 1, 0),
ErrorKind::MissingIncludeResolver,
),
include_str,
));
}
};
let content = match resolved {
Ok(content) => content,
Err(error) => return Err(self.contextualize_include_error(error, include_str)),
};
let inherited_anchor_offset = self.parsers.last().map(AnyParser::anchor_offset);
let (events, next_anchor_offset) = match content {
Cow::Borrowed(content) => {
let mut parser = Parser::new_from_str(content);
if let Some(anchor_offset) = inherited_anchor_offset {
parser.set_anchor_offset(anchor_offset);
}
let mut events = Vec::new();
while let Some(event) = parser.next_event() {
match event {
Ok(event) => events.push(event),
Err(error) => {
return Err(self.contextualize_include_error(error, include_str));
}
}
}
(events, parser.anchor_offset())
}
Cow::Owned(content) => {
let mut parser =
Parser::new_from_iter(content.chars().collect::<Vec<_>>().into_iter());
if let Some(anchor_offset) = inherited_anchor_offset {
parser.set_anchor_offset(anchor_offset);
}
let mut events = Vec::new();
while let Some(event) = parser.next_event() {
match event {
Ok(event) => events.push(event),
Err(error) => {
return Err(self.contextualize_include_error(error, include_str));
}
}
}
(events, parser.anchor_offset())
}
};
self.push_replay_parser(
ReplayParser::new(events, next_anchor_offset),
include_str.into(),
);
Ok(())
}
fn contextualize_include_error(&self, error: ScanError, include_str: &str) -> ScanError {
let mut source_stack = self.stack();
source_stack.push(include_str.into());
error.with_source_stack(source_stack)
}
fn prepare_for_push(&mut self) {
if matches!(self.current.as_ref(), Some((Event::StreamEnd, _))) {
self.current = None;
}
}
pub fn push_str_parser(&mut self, mut parser: Parser<'input, StrInput<'input>>, name: String) {
self.prepare_for_push();
if let Some(parent) = self.parsers.last() {
parser.set_anchor_offset(parent.anchor_offset());
}
self.parsers.push(AnyParser::String { parser, name });
}
pub fn push_iter_parser(
&mut self,
mut parser: Parser<'static, BufferedInput<I>>,
name: String,
) {
self.prepare_for_push();
if let Some(parent) = self.parsers.last() {
parser.set_anchor_offset(parent.anchor_offset());
}
self.parsers.push(AnyParser::Iter { parser, name });
}
pub fn push_custom_parser(&mut self, mut parser: Parser<'input, T>, name: String) {
self.prepare_for_push();
if let Some(parent) = self.parsers.last() {
parser.set_anchor_offset(parent.anchor_offset());
}
self.parsers.push(AnyParser::Custom { parser, name });
}
pub fn push_replay_parser(&mut self, mut parser: ReplayParser<'input>, name: String) {
self.prepare_for_push();
if let Some(parent) = self.parsers.last() {
let inherited = parent.anchor_offset();
parser.set_anchor_offset(parser.anchor_offset().max(inherited));
}
self.parsers.push(AnyParser::Replay { parser, name });
}
pub fn push_custom_parser_with_current(
&mut self,
mut parser: Parser<'input, T>,
name: String,
current: (Event<'input>, Span),
) {
self.prepare_for_push();
if let Some(parent) = self.parsers.last() {
parser.set_anchor_offset(parent.anchor_offset());
}
self.parsers.push(AnyParser::Custom { parser, name });
self.current = Some(current);
}
#[must_use]
pub fn current_anchor_offset(&self) -> usize {
self.parsers.last().map_or(0, AnyParser::anchor_offset)
}
#[must_use]
pub fn stack(&self) -> Vec<String> {
self.parsers
.iter()
.map(|p| match p {
AnyParser::String { name, .. }
| AnyParser::Iter { name, .. }
| AnyParser::Custom { name, .. }
| AnyParser::Replay { name, .. } => name.clone(),
})
.collect()
}
fn contextualize_error(&self, error: ScanError) -> ScanError {
if self.parsers.len() > 1 {
error.with_source_stack(self.stack())
} else {
error
}
}
fn propagate_anchor_offset_from_popped(&mut self, popped: &AnyParser<'input, I, T>) {
if let Some(parent) = self.parsers.last_mut() {
let next_offset = parent.anchor_offset().max(popped.anchor_offset());
parent.set_anchor_offset(next_offset);
}
}
fn pop_parser_and_propagate_anchor_offset(&mut self) {
let popped = self.parsers.pop().unwrap();
self.propagate_anchor_offset_from_popped(&popped);
}
fn next_event_impl(&mut self) -> Result<(Event<'input>, Span), ScanError> {
loop {
let Some(any_parser) = self.parsers.last_mut() else {
return Ok((
Event::StreamEnd,
Span::empty(crate::scanner::Marker::new(0, 1, 0)),
));
};
let res = match any_parser {
AnyParser::String { parser, .. } => parser.next_event(),
AnyParser::Iter { parser, .. } => parser.next_event(),
AnyParser::Custom { parser, .. } => parser.next_event(),
AnyParser::Replay { parser, .. } => parser.next_event(),
};
match res {
Some(Ok((Event::StreamEnd, span))) => {
if self.parsers.len() == 1 {
self.parsers.pop();
return Ok((Event::StreamEnd, span));
}
self.pop_parser_and_propagate_anchor_offset();
}
None => {
if self.parsers.len() == 1 {
self.parsers.pop();
return Ok((
Event::StreamEnd,
Span::empty(crate::scanner::Marker::new(0, 1, 0)),
));
}
self.pop_parser_and_propagate_anchor_offset();
}
Some(Err(e)) => {
let e = self.contextualize_error(e);
self.pop_parser_and_propagate_anchor_offset();
return e.into_result();
}
Some(Ok((Event::DocumentEnd, span))) => {
if self.parsers.len() == 1 {
return Ok((Event::DocumentEnd, span));
}
let peek_res = match self.parsers.last_mut().unwrap() {
AnyParser::String { parser, .. } => parser.peek(),
AnyParser::Iter { parser, .. } => parser.peek(),
AnyParser::Custom { parser, .. } => parser.peek(),
AnyParser::Replay { parser, .. } => parser.peek(),
};
match peek_res {
Some(Ok((Event::StreamEnd, _))) | None => {
self.pop_parser_and_propagate_anchor_offset();
}
Some(Ok(_)) => {
let error = self.contextualize_error(ScanError::from_kind(
span.start,
ErrorKind::MultipleDocumentsUnsupported,
));
self.pop_parser_and_propagate_anchor_offset();
return Err(error);
}
Some(Err(e)) => {
let e = self.contextualize_error(e);
self.pop_parser_and_propagate_anchor_offset();
return Err(e);
}
}
}
Some(Ok(event)) => {
if self.parsers.len() > 1
&& matches!(event.0, Event::StreamStart | Event::DocumentStart(..))
{
continue;
}
return Ok(event);
}
}
}
}
}
impl<'input, I, T> Default for ParserStack<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
fn default() -> Self {
Self::new()
}
}
impl<'input, I, T> ParserTrait<'input> for ParserStack<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>> {
if let Some(ref x) = self.current {
Some(Ok(x))
} else if let Some(error) = &self.current_error {
Some(Err(error.clone()))
} else {
if self.stream_end_emitted {
return None;
}
match self.next_event_impl() {
Ok(token) => {
self.current = Some(token);
Some(Ok(self.current.as_ref().unwrap()))
}
Err(e) => {
self.current_error = Some(e.clone());
Some(Err(e))
}
}
}
}
fn next_event(&mut self) -> Option<ParseResult<'input>> {
if let Some(error) = self.current_error.take() {
self.stream_end_emitted = true;
return Some(Err(error));
}
if let Some(token) = self.current.take() {
if let Event::StreamEnd = token.0 {
self.stream_end_emitted = true;
}
return Some(Ok(token));
}
if self.stream_end_emitted {
return None;
}
match self.next_event_impl() {
Ok(token) => {
if let Event::StreamEnd = token.0 {
self.stream_end_emitted = true;
}
Some(Ok(token))
}
Err(e) => {
self.stream_end_emitted = true;
Some(Err(e))
}
}
}
fn load<R: SpannedEventReceiver<'input>>(
&mut self,
recv: &mut R,
multi: bool,
) -> Result<(), ScanError> {
while let Some(res) = self.next_event() {
let (ev, span) = res?;
let is_doc_end = matches!(ev, Event::DocumentEnd);
let is_stream_end = matches!(ev, Event::StreamEnd);
recv.on_event(ev, span);
if is_stream_end {
break;
}
if !multi && is_doc_end {
break;
}
}
Ok(())
}
}
impl<'input, I, T> Iterator for ParserStack<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
type Item = Result<(Event<'input>, Span), ScanError>;
fn next(&mut self) -> Option<Self::Item> {
self.next_event()
}
}
impl<'input, I, T> core::iter::FusedIterator for ParserStack<'input, I, T>
where
I: Iterator<Item = char>,
T: BorrowedInput<'input>,
{
}