]>
git.proxmox.com Git - rustc.git/blob - src/vendor/regex-syntax/src/error.rs
9 /// A type alias for dealing with errors returned by this crate.
10 pub type Result
<T
> = result
::Result
<T
, Error
>;
12 /// This error type encompasses any error that can be returned by this crate.
13 #[derive(Clone, Debug, Eq, PartialEq)]
15 /// An error that occurred while translating concrete syntax into abstract
18 /// An error that occurred while translating abstract syntax into a high
19 /// level intermediate representation (HIR).
20 Translate(hir
::Error
),
21 /// Hints that destructuring should not be exhaustive.
23 /// This enum may grow additional variants, so this makes sure clients
24 /// don't count on exhaustive matching. (Otherwise, adding a new variant
25 /// could break existing code.)
30 impl From
<ast
::Error
> for Error
{
31 fn from(err
: ast
::Error
) -> Error
{
36 impl From
<hir
::Error
> for Error
{
37 fn from(err
: hir
::Error
) -> Error
{
42 impl error
::Error
for Error
{
43 fn description(&self) -> &str {
45 Error
::Parse(ref x
) => x
.description(),
46 Error
::Translate(ref x
) => x
.description(),
52 impl fmt
::Display
for Error
{
53 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
55 Error
::Parse(ref x
) => x
.fmt(f
),
56 Error
::Translate(ref x
) => x
.fmt(f
),
62 /// A helper type for formatting nice error messages.
64 /// This type is responsible for reporting regex parse errors in a nice human
65 /// readable format. Most of its complexity is from interspersing notational
66 /// markers pointing out the position where an error occurred.
68 pub struct Formatter
<'e
, E
: 'e
> {
69 /// The original regex pattern in which the error occurred.
71 /// The error kind. It must impl fmt::Display.
73 /// The primary span of the error.
75 /// An auxiliary and optional span, in case the error needs to point to
76 /// two locations (e.g., when reporting a duplicate capture group name).
77 aux_span
: Option
<&'e ast
::Span
>,
80 impl<'e
> From
<&'e ast
::Error
> for Formatter
<'e
, ast
::ErrorKind
> {
81 fn from(err
: &'e ast
::Error
) -> Self {
83 pattern
: err
.pattern(),
86 aux_span
: err
.auxiliary_span(),
91 impl<'e
> From
<&'e hir
::Error
> for Formatter
<'e
, hir
::ErrorKind
> {
92 fn from(err
: &'e hir
::Error
) -> Self {
94 pattern
: err
.pattern(),
102 impl<'e
, E
: fmt
::Display
> fmt
::Display
for Formatter
<'e
, E
> {
103 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
104 let spans
= Spans
::from_formatter(self);
105 if self.pattern
.contains('
\n'
) {
106 let divider
= repeat_char('
~'
, 79);
108 writeln
!(f
, "regex parse error:")?
;
109 writeln
!(f
, "{}", divider
)?
;
110 let notated
= spans
.notate();
111 write
!(f
, "{}", notated
)?
;
112 writeln
!(f
, "{}", divider
)?
;
113 // If we have error spans that cover multiple lines, then we just
114 // note the line numbers.
115 if !spans
.multi_line
.is_empty() {
116 let mut notes
= vec
![];
117 for span
in &spans
.multi_line
{
119 "on line {} (column {}) through line {} (column {})",
120 span
.start
.line
, span
.start
.column
,
121 span
.end
.line
, span
.end
.column
- 1));
123 writeln
!(f
, "{}", notes
.join("\n"))?
;
125 write
!(f
, "error: {}", self.err
)?
;
127 writeln
!(f
, "regex parse error:")?
;
128 let notated
= Spans
::from_formatter(self).notate();
129 write
!(f
, "{}", notated
)?
;
130 write
!(f
, "error: {}", self.err
)?
;
136 /// This type represents an arbitrary number of error spans in a way that makes
137 /// it convenient to notate the regex pattern. ("Notate" means "point out
138 /// exactly where the error occurred in the regex pattern.")
140 /// Technically, we can only ever have two spans given our current error
141 /// structure. However, after toiling with a specific algorithm for handling
142 /// two spans, it became obvious that an algorithm to handle an arbitrary
143 /// number of spans was actually much simpler.
145 /// The original regex pattern string.
147 /// The total width that should be used for line numbers. The width is
148 /// used for left padding the line numbers for alignment.
150 /// A value of `0` means line numbers should not be displayed. That is,
151 /// the pattern is itself only one line.
152 line_number_width
: usize,
153 /// All error spans that occur on a single line. This sequence always has
154 /// length equivalent to the number of lines in `pattern`, where the index
155 /// of the sequence represents a line number, starting at `0`. The spans
156 /// in each line are sorted in ascending order.
157 by_line
: Vec
<Vec
<ast
::Span
>>,
158 /// All error spans that occur over one or more lines. That is, the start
159 /// and end position of the span have different line numbers. The spans are
160 /// sorted in ascending order.
161 multi_line
: Vec
<ast
::Span
>,
165 /// Build a sequence of spans from a formatter.
166 fn from_formatter
<'e
, E
: fmt
::Display
>(
167 fmter
: &'p Formatter
<'e
, E
>,
169 let mut line_count
= fmter
.pattern
.lines().count();
170 // If the pattern ends with a `\n` literal, then our line count is
171 // off by one, since a span can occur immediately after the last `\n`,
172 // which is consider to be an additional line.
173 if fmter
.pattern
.ends_with('
\n'
) {
176 let line_number_width
=
180 line_count
.to_string().len()
182 let mut spans
= Spans
{
183 pattern
: &fmter
.pattern
,
184 line_number_width
: line_number_width
,
185 by_line
: vec
![vec
![]; line_count
],
188 spans
.add(fmter
.span
.clone());
189 if let Some(span
) = fmter
.aux_span
{
190 spans
.add(span
.clone());
195 /// Add the given span to this sequence, putting it in the right place.
196 fn add(&mut self, span
: ast
::Span
) {
197 // This is grossly inefficient since we sort after each add, but right
198 // now, we only ever add two spans at most.
199 if span
.is_one_line() {
200 let i
= span
.start
.line
- 1; // because lines are 1-indexed
201 self.by_line
[i
].push(span
);
202 self.by_line
[i
].sort();
204 self.multi_line
.push(span
);
205 self.multi_line
.sort();
209 /// Notate the pattern string with carents (`^`) pointing at each span
210 /// location. This only applies to spans that occur within a single line.
211 fn notate(&self) -> String
{
212 let mut notated
= String
::new();
213 for (i
, line
) in self.pattern
.lines().enumerate() {
214 if self.line_number_width
> 0 {
215 notated
.push_str(&self.left_pad_line_number(i
+ 1));
216 notated
.push_str(": ");
218 notated
.push_str(" ");
220 notated
.push_str(line
);
222 if let Some(notes
) = self.notate_line(i
) {
223 notated
.push_str(¬es
);
230 /// Return notes for the line indexed at `i` (zero-based). If there are no
231 /// spans for the given line, then `None` is returned. Otherwise, an
232 /// appropriately space padded string with correctly positioned `^` is
233 /// returned, accounting for line numbers.
234 fn notate_line(&self, i
: usize) -> Option
<String
> {
235 let spans
= &self.by_line
[i
];
236 if spans
.is_empty() {
239 let mut notes
= String
::new();
240 for _
in 0..self.line_number_padding() {
245 for _
in pos
..(span
.start
.column
- 1) {
249 let note_len
= span
.end
.column
.saturating_sub(span
.start
.column
);
250 for _
in 0..cmp
::max(1, note_len
) {
258 /// Left pad the given line number with spaces such that it is aligned with
259 /// other line numbers.
260 fn left_pad_line_number(&self, n
: usize) -> String
{
261 let n
= n
.to_string();
262 let pad
= self.line_number_width
.checked_sub(n
.len()).unwrap();
263 let mut result
= repeat_char(' '
, pad
);
268 /// Return the line number padding beginning at the start of each line of
271 /// If the pattern is only one line, then this returns a fixed padding
272 /// for visual indentation.
273 fn line_number_padding(&self) -> usize {
274 if self.line_number_width
== 0 {
277 2 + self.line_number_width
282 fn repeat_char(c
: char, count
: usize) -> String
{
283 ::std
::iter
::repeat(c
).take(count
).collect()
288 use ast
::parse
::Parser
;
290 // See: https://github.com/rust-lang/regex/issues/464
292 fn regression_464() {
293 let err
= Parser
::new().parse("a{\n").unwrap_err();
294 // This test checks that the error formatter doesn't panic.
295 assert
!(!err
.to_string().is_empty());