use thiserror::Error;
use std::{error::Error, fmt::Display};
use crate::parser::{
command_spec::{checked::Identifier, unchecked::Attribute},
error::{AdditionalHelp, ErrorContext, ErrorContextDisplay},
lexing::TokenSpan,
parsing::unchecked::error::SpannedParsingError as OldSpannedParsingError,
};
#[derive(Error, Debug)]
pub enum ParsingError {
#[error("The type ('{r#type}') was not declared before!")]
TypeNotDeclared { r#type: Identifier, span: TokenSpan },
#[error(transparent)]
PreParseError(#[from] OldSpannedParsingError),
#[error("The enum ('{name}') has the same name as it's namespace")]
EnumWithNamespaceName {
name: Identifier,
enum_span: TokenSpan,
namespace_span: TokenSpan,
},
#[error("The enum ('{name}') has the same name as it's namespace if it's in Pascal case")]
EnumWithNamespaceNamePascal {
name: Identifier,
enum_span: TokenSpan,
namespace_span: TokenSpan,
},
#[error("The enum ('{name}') has no variants. This is not supported by c")]
EnumWithoutVariants {
name: Identifier,
enum_span: TokenSpan,
},
#[error(
"The enum ('{name}') is marked as an error enumeration, but has a variant ('{variant}'), which has no display derived on it."
)]
EnumWithoutMarkedState {
name: Identifier,
variant: Identifier,
enum_span: TokenSpan,
state_span: TokenSpan,
},
#[error("Your provided type ('{r#type}') has {got} generic args, but I expected at least: {expected_min}")]
NotEnoughGenericArgs {
expected_min: usize,
got: usize,
r#type: Identifier,
span: TokenSpan,
},
#[error("Your provided type ('{r#type}') has {got} generic args, but I expected at most: {expected_max}")]
TooManyGenericArgs {
expected_max: usize,
got: usize,
r#type: Identifier,
span: TokenSpan,
},
#[error("The {specified} attribute can't be used here!")]
WrongAttributeInPosition {
specified: Attribute,
span: TokenSpan,
},
#[error("The structure named: {structure} has been used multiple times")]
StructureCopied {
structure: Identifier,
span: TokenSpan,
},
#[error("The enumeration named: {enumeration} has been used multiple times")]
EnumerationCopied {
enumeration: Identifier,
span: TokenSpan,
},
}
impl ParsingError {
pub fn span(&self) -> &TokenSpan {
match self {
ParsingError::TypeNotDeclared { span, .. } => span,
ParsingError::PreParseError(err) => err.source.span(),
ParsingError::EnumWithNamespaceName { enum_span, .. } => enum_span,
ParsingError::EnumWithNamespaceNamePascal { enum_span, .. } => enum_span,
ParsingError::NotEnoughGenericArgs { span, .. } => span,
ParsingError::TooManyGenericArgs { span, .. } => span,
ParsingError::WrongAttributeInPosition { span, .. } => span,
ParsingError::StructureCopied { span, .. } => span,
ParsingError::EnumerationCopied { span, .. } => span,
ParsingError::EnumWithoutVariants { enum_span, .. } => enum_span,
ParsingError::EnumWithoutMarkedState { state_span, .. } => state_span,
}
}
}
impl AdditionalHelp for ParsingError {
fn additional_help(&self) -> String {
match self {
ParsingError::TypeNotDeclared { .. } => "This type should have been mentioned in the namespaces above, or in the namespace of this type usage".to_owned(),
ParsingError::PreParseError(err) => ErrorContextDisplay::source(err).additional_help(),
ParsingError::EnumWithNamespaceNamePascal {..}
| ParsingError::EnumWithNamespaceName {..} => "Change the name of this Enumeration as the generation process in trixy-macros needs to use this name".to_owned(),
ParsingError::NotEnoughGenericArgs { got, expected_min, .. } => format!("Add generic args until you have gone from {} to {}", got, expected_min),
ParsingError::TooManyGenericArgs { got, expected_max, .. } => format!("Remove generic args until you have gone from {} to {}", got, expected_max),
ParsingError::WrongAttributeInPosition { .. } => format!("Remove this attribute"),
ParsingError::StructureCopied {..} => format!("Change this name to be something else, or delete the struct"),
ParsingError::EnumerationCopied {..} => format!("Change this name to be something else, or delete the enum"),
ParsingError::EnumWithoutVariants {..} => format!("Add an variant to this enumeration (for example: `__never`, if you want an enumeration that should not be constructed)"),
ParsingError::EnumWithoutMarkedState {..} => format!("Add an `#[error = \"...\"]` attribute before the variant.")
}
}
}
#[derive(Debug)]
pub struct SpannedParsingError {
pub source: Box<ParsingError>,
pub context: ErrorContext,
}
impl Error for SpannedParsingError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.source)
}
}
impl Display for SpannedParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.error_fmt(f)
}
}
impl ErrorContextDisplay for SpannedParsingError {
type Error = ParsingError;
fn context(&self) -> &crate::parser::error::ErrorContext {
&self.context
}
fn line_number(&self) -> usize {
self.context.line_number
}
fn line_above(&self) -> &str {
&self.context.line_above
}
fn line_below(&self) -> &str {
&self.context.line_below
}
fn line(&self) -> &str {
&self.context.line
}
fn source(&self) -> &<SpannedParsingError as ErrorContextDisplay>::Error {
&self.source
}
}