]>
Commit | Line | Data |
---|---|---|
487cf647 FG |
1 | use crate::{ |
2 | nfa, | |
3 | util::{ | |
4 | id::{PatternID, StateID}, | |
5 | start::Start, | |
6 | }, | |
7 | }; | |
8 | ||
9 | /// An error that occurred during the construction of a DFA. | |
10 | /// | |
11 | /// This error does not provide many introspection capabilities. There are | |
12 | /// generally only two things you can do with it: | |
13 | /// | |
14 | /// * Obtain a human readable message via its `std::fmt::Display` impl. | |
15 | /// * Access an underlying [`nfa::thompson::Error`] type from its `source` | |
16 | /// method via the `std::error::Error` trait. This error only occurs when using | |
17 | /// convenience routines for building a DFA directly from a pattern string. | |
18 | /// | |
19 | /// When the `std` feature is enabled, this implements the `std::error::Error` | |
20 | /// trait. | |
21 | #[derive(Clone, Debug)] | |
22 | pub struct Error { | |
23 | kind: ErrorKind, | |
24 | } | |
25 | ||
26 | /// The kind of error that occurred during the construction of a DFA. | |
27 | /// | |
28 | /// Note that this error is non-exhaustive. Adding new variants is not | |
29 | /// considered a breaking change. | |
30 | #[derive(Clone, Debug)] | |
31 | enum ErrorKind { | |
32 | /// An error that occurred while constructing an NFA as a precursor step | |
33 | /// before a DFA is compiled. | |
34 | NFA(nfa::thompson::Error), | |
35 | /// An error that occurred because an unsupported regex feature was used. | |
36 | /// The message string describes which unsupported feature was used. | |
37 | /// | |
38 | /// The primary regex feature that is unsupported by DFAs is the Unicode | |
39 | /// word boundary look-around assertion (`\b`). This can be worked around | |
40 | /// by either using an ASCII word boundary (`(?-u:\b)`) or by enabling the | |
41 | /// [`dense::Builder::allow_unicode_word_boundary`](dense/struct.Builder.html#method.allow_unicode_word_boundary) | |
42 | /// option when building a DFA. | |
43 | Unsupported(&'static str), | |
44 | /// An error that occurs if too many states are produced while building a | |
45 | /// DFA. | |
46 | TooManyStates, | |
47 | /// An error that occurs if too many start states are needed while building | |
48 | /// a DFA. | |
49 | /// | |
50 | /// This is a kind of oddball error that occurs when building a DFA with | |
51 | /// start states enabled for each pattern and enough patterns to cause | |
52 | /// the table of start states to overflow `usize`. | |
53 | TooManyStartStates, | |
54 | /// This is another oddball error that can occur if there are too many | |
55 | /// patterns spread out across too many match states. | |
56 | TooManyMatchPatternIDs, | |
57 | /// An error that occurs if the DFA got too big during determinization. | |
58 | DFAExceededSizeLimit { limit: usize }, | |
59 | /// An error that occurs if auxiliary storage (not the DFA) used during | |
60 | /// determinization got too big. | |
61 | DeterminizeExceededSizeLimit { limit: usize }, | |
62 | } | |
63 | ||
64 | impl Error { | |
65 | /// Return the kind of this error. | |
66 | fn kind(&self) -> &ErrorKind { | |
67 | &self.kind | |
68 | } | |
69 | ||
70 | pub(crate) fn nfa(err: nfa::thompson::Error) -> Error { | |
71 | Error { kind: ErrorKind::NFA(err) } | |
72 | } | |
73 | ||
74 | pub(crate) fn unsupported_dfa_word_boundary_unicode() -> Error { | |
75 | let msg = "cannot build DFAs for regexes with Unicode word \ | |
76 | boundaries; switch to ASCII word boundaries, or \ | |
77 | heuristically enable Unicode word boundaries or use a \ | |
78 | different regex engine"; | |
79 | Error { kind: ErrorKind::Unsupported(msg) } | |
80 | } | |
81 | ||
82 | pub(crate) fn too_many_states() -> Error { | |
83 | Error { kind: ErrorKind::TooManyStates } | |
84 | } | |
85 | ||
86 | pub(crate) fn too_many_start_states() -> Error { | |
87 | Error { kind: ErrorKind::TooManyStartStates } | |
88 | } | |
89 | ||
90 | pub(crate) fn too_many_match_pattern_ids() -> Error { | |
91 | Error { kind: ErrorKind::TooManyMatchPatternIDs } | |
92 | } | |
93 | ||
94 | pub(crate) fn dfa_exceeded_size_limit(limit: usize) -> Error { | |
95 | Error { kind: ErrorKind::DFAExceededSizeLimit { limit } } | |
96 | } | |
97 | ||
98 | pub(crate) fn determinize_exceeded_size_limit(limit: usize) -> Error { | |
99 | Error { kind: ErrorKind::DeterminizeExceededSizeLimit { limit } } | |
100 | } | |
101 | } | |
102 | ||
103 | #[cfg(feature = "std")] | |
104 | impl std::error::Error for Error { | |
105 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { | |
106 | match self.kind() { | |
107 | ErrorKind::NFA(ref err) => Some(err), | |
108 | ErrorKind::Unsupported(_) => None, | |
109 | ErrorKind::TooManyStates => None, | |
110 | ErrorKind::TooManyStartStates => None, | |
111 | ErrorKind::TooManyMatchPatternIDs => None, | |
112 | ErrorKind::DFAExceededSizeLimit { .. } => None, | |
113 | ErrorKind::DeterminizeExceededSizeLimit { .. } => None, | |
114 | } | |
115 | } | |
116 | } | |
117 | ||
118 | impl core::fmt::Display for Error { | |
119 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | |
120 | match self.kind() { | |
121 | ErrorKind::NFA(_) => write!(f, "error building NFA"), | |
122 | ErrorKind::Unsupported(ref msg) => { | |
123 | write!(f, "unsupported regex feature for DFAs: {}", msg) | |
124 | } | |
125 | ErrorKind::TooManyStates => write!( | |
126 | f, | |
127 | "number of DFA states exceeds limit of {}", | |
128 | StateID::LIMIT, | |
129 | ), | |
130 | ErrorKind::TooManyStartStates => { | |
131 | let stride = Start::count(); | |
132 | // The start table has `stride` entries for starting states for | |
133 | // the entire DFA, and then `stride` entries for each pattern | |
134 | // if start states for each pattern are enabled (which is the | |
135 | // only way this error can occur). Thus, the total number of | |
136 | // patterns that can fit in the table is `stride` less than | |
137 | // what we can allocate. | |
138 | let limit = ((core::isize::MAX as usize) - stride) / stride; | |
139 | write!( | |
140 | f, | |
141 | "compiling DFA with start states exceeds pattern \ | |
142 | pattern limit of {}", | |
143 | limit, | |
144 | ) | |
145 | } | |
146 | ErrorKind::TooManyMatchPatternIDs => write!( | |
147 | f, | |
148 | "compiling DFA with total patterns in all match states \ | |
149 | exceeds limit of {}", | |
150 | PatternID::LIMIT, | |
151 | ), | |
152 | ErrorKind::DFAExceededSizeLimit { limit } => write!( | |
153 | f, | |
154 | "DFA exceeded size limit of {:?} during determinization", | |
155 | limit, | |
156 | ), | |
157 | ErrorKind::DeterminizeExceededSizeLimit { limit } => { | |
158 | write!(f, "determinization exceeded size limit of {:?}", limit) | |
159 | } | |
160 | } | |
161 | } | |
162 | } |