Skip to main content

regex_automata/nfa/thompson/
error.rs

1use 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 breached. 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(#[automatically_derived]
impl ::core::clone::Clone for BuildError {
    #[inline]
    fn clone(&self) -> BuildError {
        BuildError { kind: ::core::clone::Clone::clone(&self.kind) }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for BuildError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "BuildError",
            "kind", &&self.kind)
    }
}Debug)]
21pub struct BuildError {
22    kind: BuildErrorKind,
23}
24
25/// The kind of error that occurred during the construction of a thompson NFA.
26#[derive(#[automatically_derived]
impl ::core::clone::Clone for BuildErrorKind {
    #[inline]
    fn clone(&self) -> BuildErrorKind {
        match self {
            BuildErrorKind::Syntax(__self_0) =>
                BuildErrorKind::Syntax(::core::clone::Clone::clone(__self_0)),
            BuildErrorKind::Captures(__self_0) =>
                BuildErrorKind::Captures(::core::clone::Clone::clone(__self_0)),
            BuildErrorKind::Word(__self_0) =>
                BuildErrorKind::Word(::core::clone::Clone::clone(__self_0)),
            BuildErrorKind::TooManyPatterns { given: __self_0, limit: __self_1
                } =>
                BuildErrorKind::TooManyPatterns {
                    given: ::core::clone::Clone::clone(__self_0),
                    limit: ::core::clone::Clone::clone(__self_1),
                },
            BuildErrorKind::TooManyStates { given: __self_0, limit: __self_1 }
                =>
                BuildErrorKind::TooManyStates {
                    given: ::core::clone::Clone::clone(__self_0),
                    limit: ::core::clone::Clone::clone(__self_1),
                },
            BuildErrorKind::ExceededSizeLimit { limit: __self_0 } =>
                BuildErrorKind::ExceededSizeLimit {
                    limit: ::core::clone::Clone::clone(__self_0),
                },
            BuildErrorKind::InvalidCaptureIndex { index: __self_0 } =>
                BuildErrorKind::InvalidCaptureIndex {
                    index: ::core::clone::Clone::clone(__self_0),
                },
            BuildErrorKind::UnsupportedCaptures =>
                BuildErrorKind::UnsupportedCaptures,
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for BuildErrorKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            BuildErrorKind::Syntax(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Syntax",
                    &__self_0),
            BuildErrorKind::Captures(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Captures", &__self_0),
            BuildErrorKind::Word(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Word",
                    &__self_0),
            BuildErrorKind::TooManyPatterns { given: __self_0, limit: __self_1
                } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "TooManyPatterns", "given", __self_0, "limit", &__self_1),
            BuildErrorKind::TooManyStates { given: __self_0, limit: __self_1 }
                =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "TooManyStates", "given", __self_0, "limit", &__self_1),
            BuildErrorKind::ExceededSizeLimit { limit: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "ExceededSizeLimit", "limit", &__self_0),
            BuildErrorKind::InvalidCaptureIndex { index: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "InvalidCaptureIndex", "index", &__self_0),
            BuildErrorKind::UnsupportedCaptures =>
                ::core::fmt::Formatter::write_str(f, "UnsupportedCaptures"),
        }
    }
}Debug)]
27enum 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
78impl 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")]
133impl 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) => Some(err),
138            BuildErrorKind::Captures(ref err) => Some(err),
139            _ => None,
140        }
141    }
142}
143
144impl 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(_) => f.write_fmt(format_args!("error parsing regex"))write!(f, "error parsing regex"),
149            BuildErrorKind::Captures(_) => {
150                f.write_fmt(format_args!("error with capture groups"))write!(f, "error with capture groups")
151            }
152            BuildErrorKind::Word(_) => {
153                f.write_fmt(format_args!("NFA contains Unicode word boundary"))write!(f, "NFA contains Unicode word boundary")
154            }
155            BuildErrorKind::TooManyPatterns { given, limit } => f.write_fmt(format_args!("attempted to compile {0} patterns, which exceeds the limit of {1}",
        given, limit))write!(
156                f,
157                "attempted to compile {given} patterns, \
158                 which exceeds the limit of {limit}",
159            ),
160            BuildErrorKind::TooManyStates { given, limit } => f.write_fmt(format_args!("attempted to compile {0} NFA states, which exceeds the limit of {1}",
        given, limit))write!(
161                f,
162                "attempted to compile {given} NFA states, \
163                 which exceeds the limit of {limit}",
164            ),
165            BuildErrorKind::ExceededSizeLimit { limit } => f.write_fmt(format_args!("heap usage during NFA compilation exceeded limit of {0}",
        limit))write!(
166                f,
167                "heap usage during NFA compilation exceeded limit of {limit}",
168            ),
169            BuildErrorKind::InvalidCaptureIndex { index } => f.write_fmt(format_args!("capture group index {0} is invalid (too big or discontinuous)",
        index))write!(
170                f,
171                "capture group index {index} is invalid \
172                 (too big or discontinuous)",
173            ),
174            #[cfg(feature = "syntax")]
175            BuildErrorKind::UnsupportedCaptures => f.write_fmt(format_args!("currently captures must be disabled when compiling a reverse NFA"))write!(
176                f,
177                "currently captures must be disabled when compiling \
178                 a reverse NFA",
179            ),
180        }
181    }
182}