use crate::{
reporting::{Diagnostic, Highlight},
source_tracking::fragment::Fragment,
};
use std::borrow::Cow;
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ParserErrorKind {
EncounteredUnknownToken,
EncounteredUnterminatedComment,
EncounteredUnterminatedString,
ExpectedIdentifier,
ExpectedPath,
ExpectedWhitespace,
ExpectedIntegerLiteral,
ExpectedBooleanLiteral,
ExpectedImportDeclaration,
ImportMustEndWithSemicolon,
}
impl ParserErrorKind {
pub const fn describe(self) -> &'static str {
use ParserErrorKind::*;
match self {
EncounteredUnknownToken => "encountered unknown token",
EncounteredUnterminatedComment => {
"encountered unterminated multiline comment while parsing"
}
EncounteredUnterminatedString => {
"encountered unterminated string literal while parsing"
}
ExpectedIdentifier => "expected identifier",
ExpectedIntegerLiteral => "expected integer literal",
ExpectedBooleanLiteral => "expected boolean literal",
ExpectedPath => "expected path or identifier",
ExpectedWhitespace => "expected whitespace character(s)",
ExpectedImportDeclaration => "expected import declaration",
ImportMustEndWithSemicolon => "import declarations must end with a semicolon",
}
}
pub const fn at(self, f: Fragment) -> ParserError {
ParserError {
kind: self,
location: f,
help: None,
}
}
}
#[derive(Debug)]
pub struct ParserError {
pub kind: ParserErrorKind,
pub location: Fragment,
pub help: Option<Cow<'static, str>>,
}
impl ParserError {
pub fn with_help(mut self, help: impl Into<Cow<'static, str>>) -> Self {
self.help = Some(help.into());
self
}
pub fn as_diagnostic(self) -> Diagnostic {
let description = self.kind.describe();
let message = if self.location.is_empty_at_end_of_source() {
Cow::Borrowed("found end of source here")
} else {
Cow::Borrowed("")
};
let mut diagnostic = Diagnostic::error()
.with_message(description)
.with_highlights([Highlight::primary(self.location.clone(), message)]);
if let Some(help) = self.help {
diagnostic = diagnostic.with_notes([help]);
}
diagnostic
}
}