1use std::fmt::Debug;
18use thiserror::Error;
19
20use crate::config::ConfigError;
21use crate::dic::build::error::DicBuildError;
22use crate::dic::character_category::Error as CharacterCategoryError;
23use crate::dic::description::DescriptionError;
24use crate::dic::error::DictionaryCompatibilityError;
25use crate::dic::header::HeaderError;
26use crate::dic::lexicon_set::LexiconSetError;
27use crate::dic::read::error::SudachiNomError;
28use crate::dic::word_id::WordId;
29use crate::dic::word_info::WordInfoError;
30use crate::plugin::PluginError;
31
32pub type SudachiResult<T> = Result<T, SudachiError>;
33
34#[derive(Error, Debug)]
36#[non_exhaustive]
37pub enum SudachiError {
38 #[error("{context}: {cause}")]
39 ErrWithContext {
40 context: String,
41 cause: Box<SudachiError>,
42 },
43
44 #[error("{context}: {cause}")]
45 Io {
46 cause: std::io::Error,
47 context: String,
48 },
49
50 #[error("Parse Int Error")]
51 ParseIntError(#[from] std::num::ParseIntError),
52
53 #[error("Invalid UTF-16: {0}")]
54 FromUtf16(#[from] std::string::FromUtf16Error),
55
56 #[error("Regex error")]
57 RegexError { cause: Box<fancy_regex::Error> },
58
59 #[error("Error from nom {0}")]
60 NomParseError(String),
61
62 #[error("Invalid utf16 string from nom")]
63 InvalidUtf16FromNom,
64
65 #[error("Serde error: {0}")]
66 SerdeError(#[from] serde_json::Error),
67
68 #[error("Invalid character category definition: {0}")]
69 InvalidCharacterCategory(#[from] CharacterCategoryError),
70
71 #[error("Config Error: {0}")]
72 ConfigError(#[from] ConfigError),
73
74 #[error("Invalid header: {0}")]
75 InvalidHeader(#[from] HeaderError),
76
77 #[error("Invalid description: {0}")]
78 InvalidDescription(#[from] DescriptionError),
79
80 #[error("Lexicon error")]
81 LexiconSetError(#[from] LexiconSetError),
82
83 #[error("Plugin error")]
84 PluginError(#[from] PluginError),
85
86 #[error("End of sentence (EOS) is not connected to beginning of sentence (BOS)")]
87 EosBosDisconnect,
88
89 #[error("Invalid character category type: {0}")]
90 InvalidCharacterCategoryType(String),
91
92 #[error("Invalid data format: {1} at line {0}")]
93 InvalidDataFormat(usize, String),
94
95 #[error(transparent)]
96 WordInfo(#[from] WordInfoError),
97
98 #[error("Invalid grammar")]
99 InvalidDictionaryGrammar,
100
101 #[error("Connection matrix is missing")]
102 ConnectionMatrixMissing,
103
104 #[error("Invalid part of speech: {0}")]
105 InvalidPartOfSpeech(String),
106
107 #[error("Invalid word id: {0}")]
108 InvalidWordId(WordId),
109
110 #[error("Invalid range: {0}..{1}")]
111 InvalidRange(usize, usize),
112
113 #[error("No out of vocabulary plugin provided")]
114 NoOOVPluginProvided,
115
116 #[error(transparent)]
117 DictionaryCompatibility(#[from] DictionaryCompatibilityError),
118
119 #[error("Input is too long, it can't be more than {1} bytes, was {0}")]
120 InputTooLong(usize, usize),
121
122 #[error(transparent)]
123 DictionaryCompilationError(#[from] DicBuildError),
124
125 #[error("MorphemeList is borrowed, make sure that all Ref<> are dropped")]
126 MorphemeListBorrowed,
127}
128
129impl From<std::io::Error> for SudachiError {
130 fn from(e: std::io::Error) -> Self {
131 SudachiError::Io {
132 cause: e,
133 context: String::from("IO Error"),
134 }
135 }
136}
137
138impl From<fancy_regex::Error> for SudachiError {
139 fn from(e: fancy_regex::Error) -> Self {
140 SudachiError::RegexError { cause: Box::new(e) }
141 }
142}
143
144impl SudachiError {
145 pub fn with_context<S: Into<String>>(self, ctx: S) -> Self {
146 match self {
147 SudachiError::Io { cause, .. } => SudachiError::Io {
148 cause,
149 context: ctx.into(),
150 },
151 cause => SudachiError::ErrWithContext {
152 cause: Box::new(cause),
153 context: ctx.into(),
154 },
155 }
156 }
157}
158
159impl<I: Debug> From<nom::Err<SudachiNomError<I>>> for SudachiError {
160 fn from(err: nom::Err<SudachiNomError<I>>) -> Self {
161 if let nom::Err::Failure(SudachiNomError::Utf16String) = err {
162 return SudachiError::InvalidUtf16FromNom;
163 }
164 SudachiError::NomParseError(format!("{}", err))
165 }
166}