use std::{collections::VecDeque, fmt};
use compact_str::{CompactString, format_compact};
use derive_more::with_trait::{Display, Error};
use crate::parser::{Lexer, LexerError, Spanning, Token};
#[derive(Clone, Debug, Display, Eq, Error, PartialEq)]
pub enum ParseError {
#[display("Unexpected \"{_0}\"")]
UnexpectedToken(#[error(not(source))] CompactString),
#[display("Unexpected end of input")]
UnexpectedEndOfFile,
LexerError(LexerError),
ExpectedScalarError(#[error(not(source))] &'static str),
#[display("Document nesting exceeds the limit of {_0} levels")]
DepthLimitExceeded(#[error(not(source))] usize),
#[display("Document exceeds the limit of {_0} tokens")]
TokenLimitExceeded(#[error(not(source))] usize),
#[display("Document exceeds the limit of {_0} fields")]
FieldLimitExceeded(#[error(not(source))] usize),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct Limits {
pub(crate) max_depth: usize,
pub(crate) max_tokens: usize,
pub(crate) max_fields: usize,
}
impl Limits {
pub(crate) const DEFAULT_MAX_DEPTH: usize = 64;
pub(crate) const DEFAULT_MAX_TOKENS: usize = 15_000;
pub(crate) const DEFAULT_MAX_FIELDS: usize = Self::DEFAULT_MAX_TOKENS;
}
impl Default for Limits {
fn default() -> Self {
Self {
max_depth: Self::DEFAULT_MAX_DEPTH,
max_tokens: Self::DEFAULT_MAX_TOKENS,
max_fields: Self::DEFAULT_MAX_FIELDS,
}
}
}
impl ParseError {
#[must_use]
pub fn unexpected_token(token: Token<'_>) -> Self {
Self::UnexpectedToken(format_compact!("{token}"))
}
}
#[doc(hidden)]
pub type ParseResult<T> = Result<Spanning<T>, Spanning<ParseError>>;
#[doc(hidden)]
pub type UnlocatedParseResult<T> = Result<T, Spanning<ParseError>>;
#[doc(hidden)]
pub type OptionParseResult<T> = Result<Option<Spanning<T>>, Spanning<ParseError>>;
#[doc(hidden)]
#[derive(Debug)]
pub struct Parser<'a> {
tokens: VecDeque<Spanning<Token<'a>>>,
limits: Limits,
depth: usize,
}
impl<'a> Parser<'a> {
#[doc(hidden)]
pub fn new(lexer: &mut Lexer<'a>) -> Result<Self, Spanning<ParseError>> {
Self::with_limits(lexer, Limits::default())
}
pub(crate) fn with_limits(
lexer: &mut Lexer<'a>,
limits: Limits,
) -> Result<Self, Spanning<ParseError>> {
let mut tokens = VecDeque::new();
for token in lexer {
let token = token.map_err(|e| e.map(ParseError::LexerError))?;
if token.item != Token::EndOfFile && tokens.len() >= limits.max_tokens {
return Err(token.map(|_| ParseError::TokenLimitExceeded(limits.max_tokens)));
}
tokens.push_back(token);
}
Ok(Self {
tokens,
limits,
depth: 0,
})
}
#[doc(hidden)]
pub fn peek(&self) -> &Spanning<Token<'a>> {
&self.tokens[0]
}
#[doc(hidden)]
pub fn next_token(&mut self) -> ParseResult<Token<'a>> {
if self.tokens.len() == 1 {
Err(Spanning::new(
self.peek().span,
ParseError::UnexpectedEndOfFile,
))
} else {
Ok(self
.tokens
.pop_front()
.expect("`Token::EndOfFile` always remains in `self.tokens`"))
}
}
pub(crate) fn nested<T>(
&mut self,
parse: impl FnOnce(&mut Self) -> Result<T, Spanning<ParseError>>,
) -> Result<T, Spanning<ParseError>> {
if self.depth >= self.limits.max_depth {
return Err(Spanning::new(
self.peek().span,
ParseError::DepthLimitExceeded(self.limits.max_depth),
));
}
self.depth += 1;
let parsed = parse(self);
self.depth -= 1;
parsed
}
#[doc(hidden)]
pub fn expect(&mut self, expected: &Token) -> ParseResult<Token<'a>> {
if &self.peek().item != expected {
Err(self.next_token()?.map(ParseError::unexpected_token))
} else {
self.next_token()
}
}
#[doc(hidden)]
pub fn skip(
&mut self,
expected: &Token,
) -> Result<Option<Spanning<Token<'a>>>, Spanning<ParseError>> {
if &self.peek().item == expected {
Ok(Some(self.next_token()?))
} else if self.peek().item == Token::EndOfFile {
Err(Spanning::zero_width(
&self.peek().span.start,
ParseError::UnexpectedEndOfFile,
))
} else {
Ok(None)
}
}
#[doc(hidden)]
pub fn delimited_list<T, F>(
&mut self,
opening: &Token,
parser: F,
closing: &Token,
) -> ParseResult<Vec<Spanning<T>>>
where
T: fmt::Debug,
F: Fn(&mut Parser<'a>) -> ParseResult<T>,
{
let start_pos = &self.expect(opening)?.span.start;
let mut items = Vec::new();
loop {
if let Some(Spanning { span, .. }) = self.skip(closing)? {
return Ok(Spanning::start_end(start_pos, &span.end, items));
}
items.push(parser(self)?);
}
}
#[doc(hidden)]
pub fn delimited_nonempty_list<T, F>(
&mut self,
opening: &Token,
parser: F,
closing: &Token,
) -> ParseResult<Vec<Spanning<T>>>
where
T: fmt::Debug,
F: Fn(&mut Parser<'a>) -> ParseResult<T>,
{
let start_pos = &self.expect(opening)?.span.start;
let mut items = Vec::new();
loop {
items.push(parser(self)?);
if let Some(end_spanning) = self.skip(closing)? {
return Ok(Spanning::start_end(start_pos, &end_spanning.end(), items));
}
}
}
#[doc(hidden)]
pub fn unlocated_delimited_nonempty_list<T, F>(
&mut self,
opening: &Token,
parser: F,
closing: &Token,
) -> ParseResult<Vec<T>>
where
T: fmt::Debug,
F: Fn(&mut Parser<'a>) -> UnlocatedParseResult<T>,
{
let start_pos = &self.expect(opening)?.span.start;
let mut items = Vec::new();
loop {
items.push(parser(self)?);
if let Some(end_spanning) = self.skip(closing)? {
return Ok(Spanning::start_end(start_pos, &end_spanning.end(), items));
}
}
}
#[doc(hidden)]
pub fn expect_name(&mut self) -> ParseResult<&'a str> {
match *self.peek() {
Spanning {
item: Token::Name(_),
..
} => Ok(self.next_token()?.map(|token| {
if let Token::Name(name) = token {
name
} else {
panic!("Internal parse error in `expect_name`");
}
})),
Spanning {
item: Token::EndOfFile,
..
} => Err(Spanning::new(
self.peek().span,
ParseError::UnexpectedEndOfFile,
)),
_ => Err(self.next_token()?.map(ParseError::unexpected_token)),
}
}
}