use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorCode {
E0101,
E0102,
E0103,
E0104,
E0201,
E0202,
E0203,
E0204,
E0205,
E0206,
E0207,
E0301,
E0302,
E0303,
E0304,
E0305,
E0306,
E0307,
E0401,
E0402,
E0403,
E0404,
E0405,
E0406,
E0501,
E0502,
E0503,
E0504,
E0601,
E0602,
E0701,
E0702,
E0703,
E0704,
E0801,
E0802,
E0901,
E0902,
E0999,
}
impl ErrorCode {
pub fn as_str(&self) -> &'static str {
match self {
Self::E0101 => "E0101",
Self::E0102 => "E0102",
Self::E0103 => "E0103",
Self::E0104 => "E0104",
Self::E0201 => "E0201",
Self::E0202 => "E0202",
Self::E0203 => "E0203",
Self::E0204 => "E0204",
Self::E0205 => "E0205",
Self::E0206 => "E0206",
Self::E0207 => "E0207",
Self::E0301 => "E0301",
Self::E0302 => "E0302",
Self::E0303 => "E0303",
Self::E0304 => "E0304",
Self::E0305 => "E0305",
Self::E0306 => "E0306",
Self::E0307 => "E0307",
Self::E0401 => "E0401",
Self::E0402 => "E0402",
Self::E0403 => "E0403",
Self::E0404 => "E0404",
Self::E0405 => "E0405",
Self::E0406 => "E0406",
Self::E0501 => "E0501",
Self::E0502 => "E0502",
Self::E0503 => "E0503",
Self::E0504 => "E0504",
Self::E0601 => "E0601",
Self::E0602 => "E0602",
Self::E0701 => "E0701",
Self::E0702 => "E0702",
Self::E0703 => "E0703",
Self::E0704 => "E0704",
Self::E0801 => "E0801",
Self::E0802 => "E0802",
Self::E0901 => "E0901",
Self::E0902 => "E0902",
Self::E0999 => "E0999",
}
}
pub fn category_description(&self) -> &'static str {
match self {
Self::E0101 | Self::E0102 | Self::E0103 | Self::E0104 => "lexical error",
Self::E0201
| Self::E0202
| Self::E0203
| Self::E0204
| Self::E0205
| Self::E0206
| Self::E0207 => "structural error",
Self::E0301
| Self::E0302
| Self::E0303
| Self::E0304
| Self::E0305
| Self::E0306
| Self::E0307 => "declaration error",
Self::E0401 | Self::E0402 | Self::E0403 | Self::E0404 | Self::E0405 | Self::E0406 => {
"expression error"
}
Self::E0501 | Self::E0502 | Self::E0503 | Self::E0504 => "import error",
Self::E0601 | Self::E0602 => "relationship error",
Self::E0701 | Self::E0702 | Self::E0703 | Self::E0704 => "action/state error",
Self::E0801 | Self::E0802 => "requirement error",
Self::E0901 | Self::E0902 | Self::E0999 => "syntax error",
}
}
pub fn default_message(&self) -> &'static str {
match self {
Self::E0101 => "invalid character",
Self::E0102 => "unterminated string literal",
Self::E0103 => "unterminated block comment",
Self::E0104 => "invalid numeric literal",
Self::E0201 => "missing semicolon",
Self::E0202 => "unclosed brace",
Self::E0203 => "unclosed parenthesis",
Self::E0204 => "unclosed bracket",
Self::E0205 => "unexpected closing delimiter",
Self::E0206 => "empty body",
Self::E0207 => "mismatched delimiters",
Self::E0301 => "missing identifier",
Self::E0302 => "missing 'def' keyword",
Self::E0303 => "invalid definition prefix",
Self::E0304 => "unexpected token in definition",
Self::E0305 => "missing type annotation",
Self::E0306 => "invalid usage declaration",
Self::E0307 => "missing body",
Self::E0401 => "invalid expression",
Self::E0402 => "missing operand",
Self::E0403 => "invalid operator",
Self::E0404 => "unclosed function call",
Self::E0405 => "invalid argument",
Self::E0406 => "expected expression",
Self::E0501 => "invalid import path",
Self::E0502 => "missing package name",
Self::E0503 => "invalid alias",
Self::E0504 => "invalid filter expression",
Self::E0601 => "invalid relationship target",
Self::E0602 => "missing relationship operand",
Self::E0701 => "invalid action body element",
Self::E0702 => "invalid state body element",
Self::E0703 => "invalid transition syntax",
Self::E0704 => "missing 'then' keyword",
Self::E0801 => "invalid requirement body element",
Self::E0802 => "invalid constraint expression",
Self::E0901 => "unexpected token",
Self::E0902 => "expected token",
Self::E0999 => "internal parser error",
}
}
pub fn is_structural(&self) -> bool {
matches!(
self,
Self::E0201
| Self::E0202
| Self::E0203
| Self::E0204
| Self::E0205
| Self::E0206
| Self::E0207
)
}
pub fn is_recoverable(&self) -> bool {
!matches!(self, Self::E0999)
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_code_as_str() {
assert_eq!(ErrorCode::E0201.as_str(), "E0201");
assert_eq!(ErrorCode::E0901.as_str(), "E0901");
}
#[test]
fn test_error_code_display() {
assert_eq!(format!("{}", ErrorCode::E0201), "E0201");
}
#[test]
fn test_error_code_default_message() {
assert_eq!(ErrorCode::E0201.default_message(), "missing semicolon");
assert_eq!(ErrorCode::E0202.default_message(), "unclosed brace");
}
#[test]
fn test_error_code_category() {
assert_eq!(ErrorCode::E0201.category_description(), "structural error");
assert_eq!(ErrorCode::E0301.category_description(), "declaration error");
assert_eq!(ErrorCode::E0401.category_description(), "expression error");
}
#[test]
fn test_is_structural() {
assert!(ErrorCode::E0201.is_structural());
assert!(ErrorCode::E0202.is_structural());
assert!(!ErrorCode::E0301.is_structural());
}
#[test]
fn test_is_recoverable() {
assert!(ErrorCode::E0201.is_recoverable());
assert!(!ErrorCode::E0999.is_recoverable());
}
}