sudachi/dic/build/
error.rs

1/*
2 *  Copyright (c) 2021-2024 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 crate::error::SudachiError;
18use crate::prelude::SudachiResult;
19use thiserror::Error;
20
21/// Dictionary building-process related parent error.
22/// Captures file/line information and underlying cause.
23#[derive(Error, Debug)]
24#[error("{file}:{line}\t{cause}")]
25pub struct DicBuildError {
26    pub file: String,
27    pub line: usize,
28    pub cause: BuildFailure,
29}
30
31/// Actual specific errors for dictionary compilation
32#[derive(Error, Debug)]
33#[non_exhaustive]
34pub enum BuildFailure {
35    #[error("The actual size {actual} was larger than expected {expected}")]
36    InvalidSize { actual: usize, expected: usize },
37
38    #[error("The actual size of {field} {actual} was larger than expected {expected}")]
39    InvalidFieldSize {
40        actual: usize,
41        expected: usize,
42        field: &'static str,
43    },
44
45    // this one should be rewrapped to SudachiError by the Context
46    #[error(transparent)]
47    Io(#[from] std::io::Error),
48
49    #[error("Field {0} did not exist in CSV lexicon")]
50    NoRawField(&'static str),
51
52    #[error(transparent)]
53    CsvError(csv::Error),
54
55    #[error("Invalid character literal {0}")]
56    InvalidCharLiteral(String),
57
58    #[error("Invalid i16 literal {0}")]
59    InvalidI16Literal(String),
60
61    #[error("Invalid u32 literal {0}")]
62    InvalidU32Literal(String),
63
64    #[error("Invalid word id: {0}")]
65    InvalidWordId(String),
66
67    #[error("Invalid word split {0}")]
68    InvalidSplit(String),
69
70    #[error("Invalid word split format - field {field} did not exist in {original}")]
71    SplitFormatError {
72        field: &'static str,
73        original: String,
74    },
75
76    #[error("Surface can't be empty")]
77    EmptySurface,
78
79    #[error("Maximum number of POS (2^15-1) exceeded with {0}")]
80    PosLimitExceeded(String),
81
82    #[error("Split reference {0} was incorrect")]
83    InvalidSplitWordReference(String),
84
85    #[error("Lexicon contains unresolved splits, call resolve()")]
86    UnresolvedSplits,
87
88    #[error("Connection size {0} was invalid: {1}")]
89    InvalidConnSize(&'static str, i16),
90
91    #[error("WordId table is not built, call build_word_id_table()")]
92    WordIdTableNotBuilt,
93
94    #[error("Failed to build trie")]
95    TrieBuildFailure,
96}
97
98#[derive(Default)]
99pub(crate) struct DicCompilationCtx {
100    name: String,
101    line: usize,
102}
103
104impl DicCompilationCtx {
105    pub fn memory() -> Self {
106        DicCompilationCtx {
107            name: "<memory>".to_owned(),
108            line: 0,
109        }
110    }
111
112    #[inline]
113    pub fn err<T, E: Into<BuildFailure>>(&self, reason: E) -> SudachiResult<T> {
114        Err(self.to_sudachi_err(reason))
115    }
116
117    #[inline(always)]
118    pub fn to_sudachi_err<E: Into<BuildFailure>>(&self, reason: E) -> SudachiError {
119        match reason.into() {
120            BuildFailure::Io(e) => e.into(),
121            reason => {
122                let err = DicBuildError {
123                    file: self.name.clone(),
124                    line: self.line,
125                    cause: reason,
126                };
127                err.into()
128            }
129        }
130    }
131
132    #[inline(never)]
133    #[cold]
134    pub fn to_sudachi_err_cold<E: Into<BuildFailure>>(&self, reason: E) -> SudachiError {
135        self.to_sudachi_err(reason)
136    }
137
138    #[inline(always)]
139    pub fn transform<T>(&self, result: DicWriteResult<T>) -> SudachiResult<T> {
140        match result {
141            Ok(v) => Ok(v),
142            Err(e) => Err(self.to_sudachi_err_cold(e)),
143        }
144    }
145
146    #[inline(always)]
147    pub fn apply<T, F: FnOnce() -> DicWriteResult<T>>(&self, f: F) -> SudachiResult<T> {
148        match f() {
149            Ok(v) => Ok(v),
150            Err(e) => Err(self.to_sudachi_err_cold(e)),
151        }
152    }
153
154    pub fn set_filename(&mut self, new_name: String) -> String {
155        std::mem::replace(&mut self.name, new_name)
156    }
157
158    pub fn add_line(&mut self, offset: usize) {
159        self.line += offset;
160    }
161
162    pub fn set_line(&mut self, line: usize) -> usize {
163        std::mem::replace(&mut self.line, line)
164    }
165}
166
167pub type DicWriteResult<T> = std::result::Result<T, BuildFailure>;