sudachi/
error.rs

1/*
2 * Copyright (c) 2021 Works Applications Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use std::fmt::Debug;
18use std::io::Error;
19use thiserror::Error;
20
21use crate::config::ConfigError;
22use crate::dic::build::error::DicBuildError;
23use crate::dic::character_category::Error as CharacterCategoryError;
24use crate::dic::header::HeaderError;
25use crate::dic::lexicon_set::LexiconSetError;
26use crate::plugin::PluginError;
27
28pub type SudachiResult<T> = Result<T, SudachiError>;
29
30/// Sudachi error
31#[derive(Error, Debug)]
32#[non_exhaustive]
33pub enum SudachiError {
34    #[error("{context}: {cause}")]
35    ErrWithContext {
36        context: String,
37        cause: Box<SudachiError>,
38    },
39
40    #[error("{context}: {cause}")]
41    Io {
42        cause: std::io::Error,
43        context: String,
44    },
45
46    #[error("Parse Int Error")]
47    ParseIntError(#[from] std::num::ParseIntError),
48
49    #[error("Invalid UTF-16: {0}")]
50    FromUtf16(#[from] std::string::FromUtf16Error),
51
52    #[error("Regex error")]
53    RegexError(#[from] fancy_regex::Error),
54
55    #[error("Error from nom {0}")]
56    NomParseError(String),
57
58    #[error("Invalid utf16 string from nom")]
59    InvalidUtf16FromNom,
60
61    #[error("Serde error: {0}")]
62    SerdeError(#[from] serde_json::Error),
63
64    #[error("Invalid character category definition: {0}")]
65    InvalidCharacterCategory(#[from] CharacterCategoryError),
66
67    #[error("Config Error: {0}")]
68    ConfigError(#[from] ConfigError),
69
70    #[error("Invalid header: {0}")]
71    InvalidHeader(#[from] HeaderError),
72
73    #[error("Lecicon error")]
74    LexiconSetError(#[from] LexiconSetError),
75
76    #[error("Plugin error")]
77    PluginError(#[from] PluginError),
78
79    #[error("End of sentence (EOS) is not connected to beginning of sentence (BOS)")]
80    EosBosDisconnect,
81
82    #[error("Invalid character category type: {0}")]
83    InvalidCharacterCategoryType(String),
84
85    #[error("Invalid data format: {1} at line {0}")]
86    InvalidDataFormat(usize, String),
87
88    #[error("Invalid grammar")]
89    InvalidDictionaryGrammar,
90
91    #[error("Invalid part of speech: {0}")]
92    InvalidPartOfSpeech(String),
93
94    #[error("Invalid range: {0}..{1}")]
95    InvalidRange(usize, usize),
96
97    #[error("No out of vocabulary plugin provided")]
98    NoOOVPluginProvided,
99
100    #[error("Input is too long, it can't be more than {1} bytes, was {0}")]
101    InputTooLong(usize, usize),
102
103    #[error(transparent)]
104    DictionaryCompilationError(#[from] DicBuildError),
105
106    #[error("MorphemeList is borrowed, make sure that all Ref<> are dropped")]
107    MorphemeListBorrowed,
108}
109
110impl From<std::io::Error> for SudachiError {
111    fn from(e: Error) -> Self {
112        SudachiError::Io {
113            cause: e,
114            context: String::from("IO Error"),
115        }
116    }
117}
118
119impl SudachiError {
120    pub fn with_context<S: Into<String>>(self, ctx: S) -> Self {
121        match self {
122            SudachiError::Io { cause, .. } => SudachiError::Io {
123                cause,
124                context: ctx.into(),
125            },
126            cause => SudachiError::ErrWithContext {
127                cause: Box::new(cause),
128                context: ctx.into(),
129            },
130        }
131    }
132}
133
134pub type SudachiNomResult<I, O> = nom::IResult<I, O, SudachiNomError<I>>;
135
136/// Custum nom error
137#[derive(Debug, PartialEq)]
138pub enum SudachiNomError<I> {
139    /// Failed to parse utf16 string
140    Utf16String,
141    Nom(I, nom::error::ErrorKind),
142    OutOfBounds(String, usize, usize),
143}
144
145impl<I> nom::error::ParseError<I> for SudachiNomError<I> {
146    fn from_error_kind(input: I, kind: nom::error::ErrorKind) -> Self {
147        SudachiNomError::Nom(input, kind)
148    }
149    fn append(_: I, _: nom::error::ErrorKind, other: Self) -> Self {
150        other
151    }
152}
153
154impl<I: Debug> From<nom::Err<SudachiNomError<I>>> for SudachiError {
155    fn from(err: nom::Err<SudachiNomError<I>>) -> Self {
156        if let nom::Err::Failure(SudachiNomError::Utf16String) = err {
157            return SudachiError::InvalidUtf16FromNom;
158        }
159        SudachiError::NomParseError(format!("{}", err))
160    }
161}