use crate::{ nfa, util::{ id::{PatternID, StateID}, start::Start, }, }; /// An error that occurred during the construction of a DFA. /// /// This error does not provide many introspection capabilities. There are /// generally only two things you can do with it: /// /// * Obtain a human readable message via its `std::fmt::Display` impl. /// * Access an underlying [`nfa::thompson::Error`] type from its `source` /// method via the `std::error::Error` trait. This error only occurs when using /// convenience routines for building a DFA directly from a pattern string. /// /// When the `std` feature is enabled, this implements the `std::error::Error` /// trait. #[derive(Clone, Debug)] pub struct Error { kind: ErrorKind, } /// The kind of error that occurred during the construction of a DFA. /// /// Note that this error is non-exhaustive. Adding new variants is not /// considered a breaking change. #[derive(Clone, Debug)] enum ErrorKind { /// An error that occurred while constructing an NFA as a precursor step /// before a DFA is compiled. NFA(nfa::thompson::Error), /// An error that occurred because an unsupported regex feature was used. /// The message string describes which unsupported feature was used. /// /// The primary regex feature that is unsupported by DFAs is the Unicode /// word boundary look-around assertion (`\b`). This can be worked around /// by either using an ASCII word boundary (`(?-u:\b)`) or by enabling the /// [`dense::Builder::allow_unicode_word_boundary`](dense/struct.Builder.html#method.allow_unicode_word_boundary) /// option when building a DFA. Unsupported(&'static str), /// An error that occurs if too many states are produced while building a /// DFA. TooManyStates, /// An error that occurs if too many start states are needed while building /// a DFA. /// /// This is a kind of oddball error that occurs when building a DFA with /// start states enabled for each pattern and enough patterns to cause /// the table of start states to overflow `usize`. TooManyStartStates, /// This is another oddball error that can occur if there are too many /// patterns spread out across too many match states. TooManyMatchPatternIDs, /// An error that occurs if the DFA got too big during determinization. DFAExceededSizeLimit { limit: usize }, /// An error that occurs if auxiliary storage (not the DFA) used during /// determinization got too big. DeterminizeExceededSizeLimit { limit: usize }, } impl Error { /// Return the kind of this error. fn kind(&self) -> &ErrorKind { &self.kind } pub(crate) fn nfa(err: nfa::thompson::Error) -> Error { Error { kind: ErrorKind::NFA(err) } } pub(crate) fn unsupported_dfa_word_boundary_unicode() -> Error { let msg = "cannot build DFAs for regexes with Unicode word \ boundaries; switch to ASCII word boundaries, or \ heuristically enable Unicode word boundaries or use a \ different regex engine"; Error { kind: ErrorKind::Unsupported(msg) } } pub(crate) fn too_many_states() -> Error { Error { kind: ErrorKind::TooManyStates } } pub(crate) fn too_many_start_states() -> Error { Error { kind: ErrorKind::TooManyStartStates } } pub(crate) fn too_many_match_pattern_ids() -> Error { Error { kind: ErrorKind::TooManyMatchPatternIDs } } pub(crate) fn dfa_exceeded_size_limit(limit: usize) -> Error { Error { kind: ErrorKind::DFAExceededSizeLimit { limit } } } pub(crate) fn determinize_exceeded_size_limit(limit: usize) -> Error { Error { kind: ErrorKind::DeterminizeExceededSizeLimit { limit } } } } #[cfg(feature = "std")] impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self.kind() { ErrorKind::NFA(ref err) => Some(err), ErrorKind::Unsupported(_) => None, ErrorKind::TooManyStates => None, ErrorKind::TooManyStartStates => None, ErrorKind::TooManyMatchPatternIDs => None, ErrorKind::DFAExceededSizeLimit { .. } => None, ErrorKind::DeterminizeExceededSizeLimit { .. } => None, } } } impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self.kind() { ErrorKind::NFA(_) => write!(f, "error building NFA"), ErrorKind::Unsupported(ref msg) => { write!(f, "unsupported regex feature for DFAs: {}", msg) } ErrorKind::TooManyStates => write!( f, "number of DFA states exceeds limit of {}", StateID::LIMIT, ), ErrorKind::TooManyStartStates => { let stride = Start::count(); // The start table has `stride` entries for starting states for // the entire DFA, and then `stride` entries for each pattern // if start states for each pattern are enabled (which is the // only way this error can occur). Thus, the total number of // patterns that can fit in the table is `stride` less than // what we can allocate. let limit = ((core::isize::MAX as usize) - stride) / stride; write!( f, "compiling DFA with start states exceeds pattern \ pattern limit of {}", limit, ) } ErrorKind::TooManyMatchPatternIDs => write!( f, "compiling DFA with total patterns in all match states \ exceeds limit of {}", PatternID::LIMIT, ), ErrorKind::DFAExceededSizeLimit { limit } => write!( f, "DFA exceeded size limit of {:?} during determinization", limit, ), ErrorKind::DeterminizeExceededSizeLimit { limit } => { write!(f, "determinization exceeded size limit of {:?}", limit) } } } }