1 | use crate::util::{ |
2 | captures, look, |
3 | primitives::{PatternID, StateID}, |
4 | }; |
5 | |
6 | /// An error that can occurred during the construction of a thompson NFA. |
7 | /// |
8 | /// This error does not provide many introspection capabilities. There are |
9 | /// generally only two things you can do with it: |
10 | /// |
11 | /// * Obtain a human readable message via its `std::fmt::Display` impl. |
12 | /// * Access an underlying [`regex_syntax::Error`] type from its `source` |
13 | /// method via the `std::error::Error` trait. This error only occurs when using |
14 | /// convenience routines for building an NFA directly from a pattern string. |
15 | /// |
16 | /// Otherwise, errors typically occur when a limit has been breeched. For |
17 | /// example, if the total heap usage of the compiled NFA exceeds the limit |
18 | /// set by [`Config::nfa_size_limit`](crate::nfa::thompson::Config), then |
19 | /// building the NFA will fail. |
20 | #[derive(Clone, Debug)] |
21 | pub struct BuildError { |
22 | kind: BuildErrorKind, |
23 | } |
24 | |
25 | /// The kind of error that occurred during the construction of a thompson NFA. |
26 | #[derive(Clone, Debug)] |
27 | enum BuildErrorKind { |
28 | /// An error that occurred while parsing a regular expression. Note that |
29 | /// this error may be printed over multiple lines, and is generally |
30 | /// intended to be end user readable on its own. |
31 | #[cfg (feature = "syntax" )] |
32 | Syntax(regex_syntax::Error), |
33 | /// An error that occurs if the capturing groups provided to an NFA builder |
34 | /// do not satisfy the documented invariants. For example, things like |
35 | /// too many groups, missing groups, having the first (zeroth) group be |
36 | /// named or duplicate group names within the same pattern. |
37 | Captures(captures::GroupInfoError), |
38 | /// An error that occurs when an NFA contains a Unicode word boundary, but |
39 | /// where the crate was compiled without the necessary data for dealing |
40 | /// with Unicode word boundaries. |
41 | Word(look::UnicodeWordBoundaryError), |
42 | /// An error that occurs if too many patterns were given to the NFA |
43 | /// compiler. |
44 | TooManyPatterns { |
45 | /// The number of patterns given, which exceeds the limit. |
46 | given: usize, |
47 | /// The limit on the number of patterns. |
48 | limit: usize, |
49 | }, |
50 | /// An error that occurs if too states are produced while building an NFA. |
51 | TooManyStates { |
52 | /// The minimum number of states that are desired, which exceeds the |
53 | /// limit. |
54 | given: usize, |
55 | /// The limit on the number of states. |
56 | limit: usize, |
57 | }, |
58 | /// An error that occurs when NFA compilation exceeds a configured heap |
59 | /// limit. |
60 | ExceededSizeLimit { |
61 | /// The configured limit, in bytes. |
62 | limit: usize, |
63 | }, |
64 | /// An error that occurs when an invalid capture group index is added to |
65 | /// the NFA. An "invalid" index can be one that would otherwise overflow |
66 | /// a `usize` on the current target. |
67 | InvalidCaptureIndex { |
68 | /// The invalid index that was given. |
69 | index: u32, |
70 | }, |
71 | /// An error that occurs when one tries to build a reverse NFA with |
72 | /// captures enabled. Currently, this isn't supported, but we probably |
73 | /// should support it at some point. |
74 | #[cfg (feature = "syntax" )] |
75 | UnsupportedCaptures, |
76 | } |
77 | |
78 | impl BuildError { |
79 | /// If this error occurred because the NFA exceeded the configured size |
80 | /// limit before being built, then this returns the configured size limit. |
81 | /// |
82 | /// The limit returned is what was configured, and corresponds to the |
83 | /// maximum amount of heap usage in bytes. |
84 | pub fn size_limit(&self) -> Option<usize> { |
85 | match self.kind { |
86 | BuildErrorKind::ExceededSizeLimit { limit } => Some(limit), |
87 | _ => None, |
88 | } |
89 | } |
90 | |
91 | fn kind(&self) -> &BuildErrorKind { |
92 | &self.kind |
93 | } |
94 | |
95 | #[cfg (feature = "syntax" )] |
96 | pub(crate) fn syntax(err: regex_syntax::Error) -> BuildError { |
97 | BuildError { kind: BuildErrorKind::Syntax(err) } |
98 | } |
99 | |
100 | pub(crate) fn captures(err: captures::GroupInfoError) -> BuildError { |
101 | BuildError { kind: BuildErrorKind::Captures(err) } |
102 | } |
103 | |
104 | pub(crate) fn word(err: look::UnicodeWordBoundaryError) -> BuildError { |
105 | BuildError { kind: BuildErrorKind::Word(err) } |
106 | } |
107 | |
108 | pub(crate) fn too_many_patterns(given: usize) -> BuildError { |
109 | let limit = PatternID::LIMIT; |
110 | BuildError { kind: BuildErrorKind::TooManyPatterns { given, limit } } |
111 | } |
112 | |
113 | pub(crate) fn too_many_states(given: usize) -> BuildError { |
114 | let limit = StateID::LIMIT; |
115 | BuildError { kind: BuildErrorKind::TooManyStates { given, limit } } |
116 | } |
117 | |
118 | pub(crate) fn exceeded_size_limit(limit: usize) -> BuildError { |
119 | BuildError { kind: BuildErrorKind::ExceededSizeLimit { limit } } |
120 | } |
121 | |
122 | pub(crate) fn invalid_capture_index(index: u32) -> BuildError { |
123 | BuildError { kind: BuildErrorKind::InvalidCaptureIndex { index } } |
124 | } |
125 | |
126 | #[cfg (feature = "syntax" )] |
127 | pub(crate) fn unsupported_captures() -> BuildError { |
128 | BuildError { kind: BuildErrorKind::UnsupportedCaptures } |
129 | } |
130 | } |
131 | |
132 | #[cfg (feature = "std" )] |
133 | impl std::error::Error for BuildError { |
134 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
135 | match self.kind() { |
136 | #[cfg (feature = "syntax" )] |
137 | BuildErrorKind::Syntax(ref err) => Some(err), |
138 | BuildErrorKind::Captures(ref err) => Some(err), |
139 | _ => None, |
140 | } |
141 | } |
142 | } |
143 | |
144 | impl core::fmt::Display for BuildError { |
145 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
146 | match self.kind() { |
147 | #[cfg (feature = "syntax" )] |
148 | BuildErrorKind::Syntax(_) => write!(f, "error parsing regex" ), |
149 | BuildErrorKind::Captures(_) => { |
150 | write!(f, "error with capture groups" ) |
151 | } |
152 | BuildErrorKind::Word(_) => { |
153 | write!(f, "NFA contains Unicode word boundary" ) |
154 | } |
155 | BuildErrorKind::TooManyPatterns { given, limit } => write!( |
156 | f, |
157 | "attempted to compile {} patterns, \ |
158 | which exceeds the limit of {}" , |
159 | given, limit, |
160 | ), |
161 | BuildErrorKind::TooManyStates { given, limit } => write!( |
162 | f, |
163 | "attempted to compile {} NFA states, \ |
164 | which exceeds the limit of {}" , |
165 | given, limit, |
166 | ), |
167 | BuildErrorKind::ExceededSizeLimit { limit } => write!( |
168 | f, |
169 | "heap usage during NFA compilation exceeded limit of {}" , |
170 | limit, |
171 | ), |
172 | BuildErrorKind::InvalidCaptureIndex { index } => write!( |
173 | f, |
174 | "capture group index {} is invalid (too big or discontinuous)" , |
175 | index, |
176 | ), |
177 | #[cfg (feature = "syntax" )] |
178 | BuildErrorKind::UnsupportedCaptures => write!( |
179 | f, |
180 | "currently captures must be disabled when compiling \ |
181 | a reverse NFA" , |
182 | ), |
183 | } |
184 | } |
185 | } |
186 | |