blob: 6497a4cff8b8ecba3300897e0d2a6f529929c0f9 [file] [log] [blame]
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)
}
}
}
}