use crate::span::Span;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseErrorKind {
UnexpectedEof,
UnclosedDelimiter,
InvalidSyntax,
UnknownDirective,
InvalidMetadata,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseError {
pub message: String,
pub span: Option<Span>,
pub kind: ParseErrorKind,
pub recoverable: bool,
}
impl ParseError {
pub fn new(message: impl Into<String>, span: Option<Span>) -> Self {
Self {
message: message.into(),
span,
kind: ParseErrorKind::Other,
recoverable: true,
}
}
pub fn unexpected_eof(span: Option<Span>) -> Self {
Self {
message: "unexpected end of input".to_string(),
span,
kind: ParseErrorKind::UnexpectedEof,
recoverable: false,
}
}
pub fn unclosed_delimiter(delimiter: &str, span: Option<Span>) -> Self {
Self {
message: format!("unclosed {}", delimiter),
span,
kind: ParseErrorKind::UnclosedDelimiter,
recoverable: true,
}
}
pub fn invalid_syntax(context: &str, span: Option<Span>) -> Self {
Self {
message: format!("invalid syntax in {}", context),
span,
kind: ParseErrorKind::InvalidSyntax,
recoverable: true,
}
}
pub fn unknown_directive(directive: &str, span: Option<Span>) -> Self {
Self {
message: format!("unknown directive: {}", directive),
span,
kind: ParseErrorKind::UnknownDirective,
recoverable: true,
}
}
pub fn with_kind(mut self, kind: ParseErrorKind) -> Self {
self.kind = kind;
self
}
pub fn non_recoverable(mut self) -> Self {
self.recoverable = false;
self
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)?;
if let Some(span) = self.span {
write!(f, " at bytes {}..{}", span.start, span.end)?;
}
Ok(())
}
}
impl std::error::Error for ParseError {}
#[derive(Debug, Clone, Default)]
pub struct ParseErrors {
errors: Vec<ParseError>,
}
impl ParseErrors {
pub fn new() -> Self {
Self { errors: Vec::new() }
}
pub fn push(&mut self, error: ParseError) {
self.errors.push(error);
}
pub fn is_empty(&self) -> bool {
self.errors.is_empty()
}
pub fn len(&self) -> usize {
self.errors.len()
}
pub fn iter(&self) -> impl Iterator<Item = &ParseError> {
self.errors.iter()
}
pub fn has_fatal(&self) -> bool {
self.errors.iter().any(|e| !e.recoverable)
}
}
impl IntoIterator for ParseErrors {
type Item = ParseError;
type IntoIter = std::vec::IntoIter<ParseError>;
fn into_iter(self) -> Self::IntoIter {
self.errors.into_iter()
}
}