| 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: &Error) => Some(err), |
| 138 | BuildErrorKind::Captures(ref err: &GroupInfoError) => 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 | |