194 lines
6.6 KiB
Rust
194 lines
6.6 KiB
Rust
//! Contains the error types that can occur while parsing the syntax of the language.
|
|
|
|
use std::fmt::Display;
|
|
|
|
use crate::{
|
|
base::{
|
|
log::{Message, Severity, SourceCodeDisplay},
|
|
source_file::{SourceElement as _, Span},
|
|
},
|
|
lexical::token::{KeywordKind, Token},
|
|
};
|
|
|
|
/// Result type for parsing operations.
|
|
pub type ParseResult<T> = Result<T, Error>;
|
|
|
|
/// An enumeration containing all kinds of syntactic errors that can occur while parsing the
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, thiserror::Error)]
|
|
#[allow(missing_docs)]
|
|
pub enum Error {
|
|
#[error(transparent)]
|
|
UnexpectedSyntax(#[from] UnexpectedSyntax),
|
|
#[error(transparent)]
|
|
InvalidArgument(#[from] InvalidArgument),
|
|
#[error(transparent)]
|
|
InvalidAnnotation(#[from] InvalidAnnotation),
|
|
}
|
|
|
|
/// Enumeration containing all kinds of syntax that can be failed to parse.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[allow(missing_docs)]
|
|
pub enum SyntaxKind {
|
|
Either(&'static [SyntaxKind]),
|
|
Punctuation(char),
|
|
Keyword(KeywordKind),
|
|
Identifier,
|
|
Declaration,
|
|
Integer,
|
|
Boolean,
|
|
StringLiteral,
|
|
MacroStringLiteral,
|
|
AnyStringLiteral,
|
|
Statement,
|
|
Expression,
|
|
Operator,
|
|
Type,
|
|
ExecuteBlock,
|
|
ExecuteBlockTail,
|
|
}
|
|
|
|
impl SyntaxKind {
|
|
fn expected_binding_str(&self) -> String {
|
|
match self {
|
|
Self::Either(variants) => {
|
|
if variants.is_empty() {
|
|
"end of file".to_string()
|
|
} else if variants.len() == 1 {
|
|
variants[0].expected_binding_str()
|
|
} else {
|
|
let comma_range = ..variants.len() - 2;
|
|
let comma_elements = variants[comma_range]
|
|
.iter()
|
|
.map(Self::expected_binding_str)
|
|
.collect::<Vec<_>>()
|
|
.join(", ");
|
|
format!(
|
|
"{}, or {}",
|
|
comma_elements,
|
|
variants.last().unwrap().expected_binding_str()
|
|
)
|
|
}
|
|
}
|
|
Self::Identifier => "an identifier token".to_string(),
|
|
Self::Punctuation(char) => format!("a punctuation token `{char}`"),
|
|
Self::Keyword(keyword) => format!("a keyword token `{}`", keyword.as_str()),
|
|
Self::Declaration => "a declaration token".to_string(),
|
|
Self::Integer => "an integer token".to_string(),
|
|
Self::Boolean => "a boolean token".to_string(),
|
|
Self::StringLiteral => "a string literal".to_string(),
|
|
Self::MacroStringLiteral => "a macro string literal".to_string(),
|
|
Self::AnyStringLiteral => "a (macro) string literal".to_string(),
|
|
Self::Statement => "a statement syntax".to_string(),
|
|
Self::Expression => "an expression syntax".to_string(),
|
|
Self::Operator => "an operator".to_string(),
|
|
Self::Type => "a type syntax".to_string(),
|
|
Self::ExecuteBlock => "an execute block syntax".to_string(),
|
|
Self::ExecuteBlockTail => "an execute block tail syntax".to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A syntax/token is expected but found an other invalid token.
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct UnexpectedSyntax {
|
|
/// The kind of syntax that was expected.
|
|
pub expected: SyntaxKind,
|
|
|
|
/// The invalid token that was found.
|
|
pub found: Option<Token>,
|
|
}
|
|
|
|
impl Display for UnexpectedSyntax {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let expected_binding = self.expected.expected_binding_str();
|
|
let found_binding = match self.found.clone() {
|
|
Some(Token::Comment(..)) => "a comment token".to_string(),
|
|
Some(Token::DocComment(..)) => "a doc comment token".to_string(),
|
|
Some(Token::Identifier(..)) => "an identifier token".to_string(),
|
|
Some(Token::Keyword(keyword)) => {
|
|
format!("a keyword token `{}`", keyword.keyword.as_str())
|
|
}
|
|
Some(Token::WhiteSpaces(..)) => "a white spaces token".to_string(),
|
|
Some(Token::Punctuation(punctuation)) => {
|
|
format!("a punctuation token `{}`", punctuation.punctuation)
|
|
}
|
|
Some(Token::Integer(..)) => "an integer token".to_string(),
|
|
Some(Token::Boolean(..)) => "a boolean token".to_string(),
|
|
Some(Token::CommandLiteral(..)) => "a literal command token".to_string(),
|
|
Some(Token::StringLiteral(..)) => "a string literal token".to_string(),
|
|
Some(Token::MacroStringLiteral(..)) => "a macro string literal token".to_string(),
|
|
|
|
None => "EOF".to_string(),
|
|
};
|
|
|
|
let message = format!("expected {expected_binding}, but found {found_binding}");
|
|
|
|
write!(f, "{}", Message::new(Severity::Error, message))?;
|
|
|
|
self.found.as_ref().map_or(Ok(()), |span| {
|
|
write!(
|
|
f,
|
|
"\n{}",
|
|
SourceCodeDisplay::new(&span.span(), Option::<u8>::None)
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for UnexpectedSyntax {}
|
|
|
|
/// An error that occurred due to an invalid argument.
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct InvalidArgument {
|
|
/// The error message.
|
|
pub message: String,
|
|
/// The span of the invalid argument.
|
|
pub span: Span,
|
|
}
|
|
|
|
impl Display for InvalidArgument {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", Message::new(Severity::Error, &self.message))?;
|
|
write!(
|
|
f,
|
|
"\n{}",
|
|
SourceCodeDisplay::new(&self.span, Option::<u8>::None)
|
|
)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for InvalidArgument {}
|
|
|
|
/// An error that occurred due to an invalid annotation.
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct InvalidAnnotation {
|
|
/// The invalid annotation identifier.
|
|
pub annotation: Span,
|
|
/// The target of the annotation.
|
|
pub target: String,
|
|
}
|
|
|
|
impl Display for InvalidAnnotation {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"{}",
|
|
Message::new(
|
|
Severity::Error,
|
|
format!(
|
|
"Annotation '{}' cannot be applied to {}",
|
|
self.annotation.str(),
|
|
self.target
|
|
)
|
|
)
|
|
)?;
|
|
write!(
|
|
f,
|
|
"\n{}",
|
|
SourceCodeDisplay::new(&self.annotation, Option::<u8>::None)
|
|
)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for InvalidAnnotation {}
|