1use std::fmt;
4use thiserror::Error;
5
6#[derive(Error, Debug, Clone, PartialEq, Eq)]
8pub enum Error {
9 #[error("parse error at position {position}: {message}")]
11 Parse {
12 position: usize,
14 message: String,
16 },
17
18 #[error("invalid escape sequence '\\{char}' at position {position}")]
20 InvalidEscape {
21 char: char,
23 position: usize,
25 },
26
27 #[error("unclosed {kind} starting at position {position}")]
29 Unclosed {
30 kind: &'static str,
32 position: usize,
34 },
35
36 #[error("invalid quantifier at position {position}: {message}")]
38 InvalidQuantifier {
39 position: usize,
41 message: String,
43 },
44
45 #[error("invalid character class at position {position}: {message}")]
47 InvalidCharClass {
48 position: usize,
50 message: String,
52 },
53
54 #[error("invalid fuzziness specification at position {position}: {message}")]
56 InvalidFuzziness {
57 position: usize,
59 message: String,
61 },
62
63 #[error("invalid backreference \\{group} at position {position}: {message}")]
65 InvalidBackreference {
66 group: usize,
68 position: usize,
70 message: String,
72 },
73
74 #[error("empty pattern not allowed")]
76 EmptyPattern,
77
78 #[error("pattern too complex: {message}")]
80 TooComplex {
81 message: String,
83 },
84
85 #[error("match timed out after {duration:?}")]
87 Timeout {
88 duration: std::time::Duration,
90 },
91}
92
93impl Error {
94 #[must_use]
96 pub fn parse(position: usize, message: impl Into<String>) -> Self {
97 Error::Parse {
98 position,
99 message: message.into(),
100 }
101 }
102
103 #[must_use]
105 pub fn invalid_escape(char: char, position: usize) -> Self {
106 Error::InvalidEscape { char, position }
107 }
108
109 #[must_use]
111 pub fn unclosed(kind: &'static str, position: usize) -> Self {
112 Error::Unclosed { kind, position }
113 }
114
115 #[must_use]
117 pub fn invalid_quantifier(position: usize, message: impl Into<String>) -> Self {
118 Error::InvalidQuantifier {
119 position,
120 message: message.into(),
121 }
122 }
123
124 #[must_use]
126 pub fn invalid_char_class(position: usize, message: impl Into<String>) -> Self {
127 Error::InvalidCharClass {
128 position,
129 message: message.into(),
130 }
131 }
132
133 #[must_use]
135 pub fn invalid_fuzziness(position: usize, message: impl Into<String>) -> Self {
136 Error::InvalidFuzziness {
137 position,
138 message: message.into(),
139 }
140 }
141
142 #[must_use]
144 pub fn invalid_backreference(
145 group: usize,
146 position: usize,
147 message: impl Into<String>,
148 ) -> Self {
149 Error::InvalidBackreference {
150 group,
151 position,
152 message: message.into(),
153 }
154 }
155}
156
157pub type Result<T> = std::result::Result<T, Error>;
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub struct Span {
163 pub start: usize,
165 pub end: usize,
167}
168
169impl Span {
170 #[must_use]
172 pub fn new(start: usize, end: usize) -> Self {
173 Span { start, end }
174 }
175
176 #[must_use]
178 pub fn at(position: usize) -> Self {
179 Span {
180 start: position,
181 end: position + 1,
182 }
183 }
184}
185
186impl fmt::Display for Span {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 if self.start == self.end || self.start + 1 == self.end {
189 write!(f, "position {}", self.start)
190 } else {
191 write!(f, "positions {}-{}", self.start, self.end)
192 }
193 }
194}