grep_regex/error.rs
1/// An error that can occur in this crate.
2///
3/// Generally, this error corresponds to problems building a regular
4/// expression, whether it's in parsing, compilation or a problem with
5/// guaranteeing a configured optimization.
6#[derive(Clone, Debug)]
7pub struct Error {
8 kind: ErrorKind,
9}
10
11impl Error {
12 pub(crate) fn new(kind: ErrorKind) -> Error {
13 Error { kind }
14 }
15
16 pub(crate) fn regex(err: regex_automata::meta::BuildError) -> Error {
17 if let Some(size_limit) = err.size_limit() {
18 let kind = ErrorKind::Regex(format!(
19 "compiled regex exceeds size limit of {size_limit}",
20 ));
21 Error { kind }
22 } else if let Some(ref err) = err.syntax_error() {
23 Error::generic(err)
24 } else {
25 Error::generic(err)
26 }
27 }
28
29 pub(crate) fn generic<E: std::error::Error>(err: E) -> Error {
30 Error { kind: ErrorKind::Regex(err.to_string()) }
31 }
32
33 /// Return the kind of this error.
34 pub fn kind(&self) -> &ErrorKind {
35 &self.kind
36 }
37}
38
39/// The kind of an error that can occur.
40#[derive(Clone, Debug)]
41#[non_exhaustive]
42pub enum ErrorKind {
43 /// An error that occurred as a result of parsing a regular expression.
44 /// This can be a syntax error or an error that results from attempting to
45 /// compile a regular expression that is too big.
46 ///
47 /// The string here is the underlying error converted to a string.
48 Regex(String),
49 /// An error that occurs when a building a regex that isn't permitted to
50 /// match a line terminator. In general, building the regex will do its
51 /// best to make matching a line terminator impossible (e.g., by removing
52 /// `\n` from the `\s` character class), but if the regex contains a
53 /// `\n` literal, then there is no reasonable choice that can be made and
54 /// therefore an error is reported.
55 ///
56 /// The string is the literal sequence found in the regex that is not
57 /// allowed.
58 NotAllowed(String),
59 /// This error occurs when a non-ASCII line terminator was provided.
60 ///
61 /// The invalid byte is included in this error.
62 InvalidLineTerminator(u8),
63 /// Occurs when a banned byte was found in a pattern.
64 Banned(u8),
65}
66
67impl std::error::Error for Error {}
68
69impl std::fmt::Display for Error {
70 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
71 use bstr::ByteSlice;
72
73 match self.kind {
74 ErrorKind::Regex(ref s) => write!(f, "{}", s),
75 ErrorKind::NotAllowed(ref lit) => {
76 write!(f, "the literal {:?} is not allowed in a regex", lit)
77 }
78 ErrorKind::InvalidLineTerminator(byte) => {
79 write!(
80 f,
81 "line terminators must be ASCII, but {byte:?} is not",
82 byte = [byte].as_bstr(),
83 )
84 }
85 ErrorKind::Banned(byte) => {
86 write!(
87 f,
88 "pattern contains {byte:?} but it is impossible to match",
89 byte = [byte].as_bstr(),
90 )
91 }
92 }
93 }
94}