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