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.
size_limit(&self) -> Option<usize>84     pub fn size_limit(&self) -> Option<usize> {
85         match self.kind {
86             BuildErrorKind::ExceededSizeLimit { limit } => Some(limit),
87             _ => None,
88         }
89     }
90 
kind(&self) -> &BuildErrorKind91     fn kind(&self) -> &BuildErrorKind {
92         &self.kind
93     }
94 
95     #[cfg(feature = "syntax")]
syntax(err: regex_syntax::Error) -> BuildError96     pub(crate) fn syntax(err: regex_syntax::Error) -> BuildError {
97         BuildError { kind: BuildErrorKind::Syntax(err) }
98     }
99 
captures(err: captures::GroupInfoError) -> BuildError100     pub(crate) fn captures(err: captures::GroupInfoError) -> BuildError {
101         BuildError { kind: BuildErrorKind::Captures(err) }
102     }
103 
word(err: look::UnicodeWordBoundaryError) -> BuildError104     pub(crate) fn word(err: look::UnicodeWordBoundaryError) -> BuildError {
105         BuildError { kind: BuildErrorKind::Word(err) }
106     }
107 
too_many_patterns(given: usize) -> BuildError108     pub(crate) fn too_many_patterns(given: usize) -> BuildError {
109         let limit = PatternID::LIMIT;
110         BuildError { kind: BuildErrorKind::TooManyPatterns { given, limit } }
111     }
112 
too_many_states(given: usize) -> BuildError113     pub(crate) fn too_many_states(given: usize) -> BuildError {
114         let limit = StateID::LIMIT;
115         BuildError { kind: BuildErrorKind::TooManyStates { given, limit } }
116     }
117 
exceeded_size_limit(limit: usize) -> BuildError118     pub(crate) fn exceeded_size_limit(limit: usize) -> BuildError {
119         BuildError { kind: BuildErrorKind::ExceededSizeLimit { limit } }
120     }
121 
invalid_capture_index(index: u32) -> BuildError122     pub(crate) fn invalid_capture_index(index: u32) -> BuildError {
123         BuildError { kind: BuildErrorKind::InvalidCaptureIndex { index } }
124     }
125 
126     #[cfg(feature = "syntax")]
unsupported_captures() -> BuildError127     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 {
source(&self) -> Option<&(dyn std::error::Error + 'static)>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 {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result145     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