use crate::{Diagnostic, Severity, SrcPos};
use enum_map::{enum_map, Enum, EnumMap};
use std::fmt::{Display, Formatter};
use std::ops::{Index, IndexMut};
use strum::{EnumString, IntoStaticStr};
#[derive(PartialEq, Debug, Clone, Copy, Eq, Hash, EnumString, IntoStaticStr, Enum)]
#[strum(serialize_all = "snake_case")]
pub enum ErrorCode {
SyntaxError,
CircularDependency,
InvalidFormal,
InvalidFormalConversion,
TypeMismatch,
AmbiguousCall,
NamedBeforePositional,
TooManyArguments,
Unassociated,
AlreadyAssociated,
InterfaceModeMismatch,
DisallowedInSensitivityList,
DeclarationNotAllowed,
MismatchedEntityClass,
MismatchedObjectClass,
MisplacedAttributeSpec,
NoOverloadedWithSignature,
IllegalSignature,
SignatureRequired,
AmbiguousExpression,
Duplicate,
ConflictingUseClause,
MissingProtectedBodyType,
IllegalDeferredConstant,
SignatureMismatch,
AmbiguousInstantiation,
MismatchedSubprogramInstantiation,
VoidReturn,
NonVoidReturn,
IllegalReturn,
ExitOutsideLoop,
NextOutsideLoop,
InvalidLoopLabel,
MismatchedKinds,
TooManyConstraints,
TooFewConstraints,
IllegalConstraint,
InvalidOperatorSymbol,
Unresolved,
DimensionMismatch,
InvalidLiteral,
DeclaredBefore,
ConfigNotInSameLibrary,
NoImplicitConversion,
ExpectedSubAggregate,
IllegalAttribute,
CannotBePrefixed,
NonScalarInRange,
UnexpectedSignature,
MissingDeferredDeclaration,
MissingFullTypeDeclaration,
InvalidCall,
Unused,
UnnecessaryWorkLibrary,
UnassociatedContext,
MissingInSensitivityList,
SuperfluousInSensitivityList,
Internal,
Related,
}
#[derive(Clone, PartialEq, Eq, Debug, Copy)]
pub struct SeverityMap {
inner: EnumMap<ErrorCode, Option<Severity>>,
}
impl Default for SeverityMap {
fn default() -> Self {
use ErrorCode::*;
use Severity::*;
let map = enum_map! {
SyntaxError
| CircularDependency
| InvalidFormal
| InvalidFormalConversion
| TypeMismatch
| AmbiguousCall
| NamedBeforePositional
| TooManyArguments
| Unassociated
| AlreadyAssociated
| InterfaceModeMismatch
| DisallowedInSensitivityList
| DeclarationNotAllowed
| MismatchedEntityClass
| MisplacedAttributeSpec
| NoOverloadedWithSignature
| IllegalSignature
| SignatureRequired
| AmbiguousExpression
| Duplicate
| ConflictingUseClause
| MissingProtectedBodyType
| IllegalDeferredConstant
| SignatureMismatch
| AmbiguousInstantiation
| MismatchedSubprogramInstantiation
| MismatchedObjectClass
| VoidReturn
| NonVoidReturn
| IllegalReturn
| ExitOutsideLoop
| NextOutsideLoop
| InvalidLoopLabel
| MismatchedKinds
| TooManyConstraints
| TooFewConstraints
| IllegalConstraint
| InvalidOperatorSymbol
| Unresolved
| DimensionMismatch
| InvalidLiteral
| DeclaredBefore
| ConfigNotInSameLibrary
| NoImplicitConversion
| ExpectedSubAggregate
| IllegalAttribute
| CannotBePrefixed
| NonScalarInRange
| UnexpectedSignature
| MissingDeferredDeclaration
| MissingFullTypeDeclaration
| InvalidCall => Some(Error),
Unused
| UnnecessaryWorkLibrary
| UnassociatedContext
| MissingInSensitivityList
| SuperfluousInSensitivityList => Some(Warning),
Internal => Some(Error),
Related => Some(Hint)
};
SeverityMap { inner: map }
}
}
impl Index<ErrorCode> for SeverityMap {
type Output = Option<Severity>;
fn index(&self, key: ErrorCode) -> &Self::Output {
self.inner.index(key)
}
}
impl IndexMut<ErrorCode> for SeverityMap {
fn index_mut(&mut self, key: ErrorCode) -> &mut Self::Output {
self.inner.index_mut(key)
}
}
impl ErrorCode {
pub fn as_str(&self) -> &str {
self.into()
}
}
#[test]
fn serialize_from_string() {
assert_eq!(
ErrorCode::try_from("void_return"),
Ok(ErrorCode::VoidReturn)
);
assert_eq!(
ErrorCode::try_from("misplaced_attribute_spec"),
Ok(ErrorCode::MisplacedAttributeSpec)
);
assert_eq!(
ErrorCode::try_from("syntax_error"),
Ok(ErrorCode::SyntaxError)
);
assert_eq!(
ErrorCode::try_from("not_an_error_code"),
Err(strum::ParseError::VariantNotFound)
);
}
#[test]
fn serialize_to_string() {
assert_eq!(ErrorCode::VoidReturn.as_str(), "void_return");
assert_eq!(
ErrorCode::MisplacedAttributeSpec.as_str(),
"misplaced_attribute_spec"
);
assert_eq!(ErrorCode::SyntaxError.as_str(), "syntax_error");
}
impl Diagnostic {
pub fn syntax_error(item: impl AsRef<SrcPos>, msg: impl Into<String>) -> Diagnostic {
Self::new(item, msg, ErrorCode::SyntaxError)
}
pub fn circular_dependency(item: impl AsRef<SrcPos>) -> Diagnostic {
Self::new(
item,
"Found circular dependency",
ErrorCode::CircularDependency,
)
}
pub fn internal(item: impl AsRef<SrcPos>, msg: impl Into<String>) -> Diagnostic {
Self::new(item, msg, ErrorCode::Internal)
}
pub fn illegal_attribute(item: impl AsRef<SrcPos>, msg: impl Into<String>) -> Diagnostic {
Self::new(item, msg, ErrorCode::IllegalAttribute)
}
pub fn mismatched_kinds(item: impl AsRef<SrcPos>, msg: impl Into<String>) -> Diagnostic {
Self::new(item, msg, ErrorCode::MismatchedKinds)
}
}
impl Display for ErrorCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}