nextest_filtering/
errors.rs1#![allow(unused_assignments)]
7
8use crate::expression::FiltersetKind;
9use miette::{Diagnostic, SourceSpan};
10use std::fmt;
11use thiserror::Error;
12
13#[derive(Clone, Debug)]
15#[non_exhaustive]
16pub struct FiltersetParseErrors {
17    pub input: String,
19
20    pub errors: Vec<ParseSingleError>,
22}
23
24impl FiltersetParseErrors {
25    pub(crate) fn new(input: impl Into<String>, errors: Vec<ParseSingleError>) -> Self {
26        Self {
27            input: input.into(),
28            errors,
29        }
30    }
31}
32
33#[derive(Clone, Debug, Error, Diagnostic, PartialEq, Eq)]
35#[non_exhaustive]
36pub enum ParseSingleError {
37    #[error("invalid regex")]
39    InvalidRegex {
40        #[label("{}", message)]
42        span: SourceSpan,
43
44        message: String,
46    },
47
48    #[error("invalid glob")]
50    InvalidGlob {
51        #[label("{}", error)]
53        span: SourceSpan,
54
55        error: GlobConstructError,
57    },
58
59    #[error("predicate not allowed in `{kind}` expressions")]
61    BannedPredicate {
62        kind: FiltersetKind,
64
65        #[label("{reason}")]
67        span: SourceSpan,
68
69        reason: BannedPredicateReason,
71    },
72
73    #[error("invalid regex")]
75    InvalidRegexWithoutMessage(#[label("invalid regex")] SourceSpan),
76
77    #[error("expected close regex")]
79    ExpectedCloseRegex(#[label("missing `/`")] SourceSpan),
80
81    #[error("invalid OR operator")]
83    InvalidOrOperator(#[label("expected `|`, `+`, or `or`")] SourceSpan),
84
85    #[error("invalid AND operator")]
87    InvalidAndOperator(#[label("expected `&` or `and`")] SourceSpan),
88
89    #[error("unexpected argument")]
91    UnexpectedArgument(#[label("this set doesn't take an argument")] SourceSpan),
92
93    #[error("unexpected comma")]
95    UnexpectedComma(#[label("this set doesn't take multiple arguments")] SourceSpan),
96
97    #[error("invalid string")]
99    InvalidString(#[label("invalid string")] SourceSpan),
100
101    #[error("expected open parenthesis")]
103    ExpectedOpenParenthesis(#[label("missing `(`")] SourceSpan),
104
105    #[error("expected close parenthesis")]
107    ExpectedCloseParenthesis(#[label("missing `)`")] SourceSpan),
108
109    #[error("invalid escape character")]
111    InvalidEscapeCharacter(#[label("invalid escape character")] SourceSpan),
112
113    #[error("expected expression")]
115    ExpectedExpr(#[label("missing expression")] SourceSpan),
116
117    #[error("expected end of expression")]
119    ExpectedEndOfExpression(#[label("unparsed input")] SourceSpan),
120
121    #[error("operator didn't match any packages")]
123    NoPackageMatch(#[label("no packages matched this")] SourceSpan),
124
125    #[error("operator didn't match any binary IDs")]
127    NoBinaryIdMatch(#[label("no binary IDs matched this")] SourceSpan),
128
129    #[error("operator didn't match any binary names")]
131    NoBinaryNameMatch(#[label("no binary names matched this")] SourceSpan),
132
133    #[error("invalid argument for platform")]
135    InvalidPlatformArgument(#[label("expected \"target\" or \"host\"")] SourceSpan),
136
137    #[error("unsupported expression")]
139    UnsupportedExpression(#[label("contained an unsupported expression")] SourceSpan),
140
141    #[error("unknown parsing error")]
143    Unknown,
144}
145
146impl ParseSingleError {
147    pub(crate) fn invalid_regex(input: &str, start: usize, end: usize) -> Self {
148        match regex_syntax::Parser::new().parse(input) {
150            Ok(_) => {
151                Self::InvalidRegexWithoutMessage((start, end - start).into())
154            }
155            Err(err) => {
156                let (message, span) = match &err {
157                    regex_syntax::Error::Parse(err) => (format!("{}", err.kind()), err.span()),
158                    regex_syntax::Error::Translate(err) => (format!("{}", err.kind()), err.span()),
159                    _ => return Self::InvalidRegexWithoutMessage((start, end - start).into()),
160                };
161
162                let err_start = start + span.start.offset;
164                let err_end = start + span.end.offset;
165
166                Self::InvalidRegex {
167                    span: (err_start, err_end - err_start).into(),
168                    message,
169                }
170            }
171        }
172    }
173}
174
175#[derive(Clone, Debug, Error, PartialEq, Eq)]
176pub enum GlobConstructError {
177    #[error("{}", .0.kind())]
178    InvalidGlob(globset::Error),
179
180    #[error("{}", .0)]
181    RegexError(String),
182}
183
184#[derive(Debug)]
185pub(crate) struct State<'a> {
186    errors: &'a mut Vec<ParseSingleError>,
188}
189
190impl<'a> State<'a> {
191    pub fn new(errors: &'a mut Vec<ParseSingleError>) -> Self {
192        Self { errors }
193    }
194
195    pub fn report_error(&mut self, error: ParseSingleError) {
196        self.errors.push(error);
197    }
198}
199
200#[derive(Copy, Clone, Debug, PartialEq, Eq)]
201pub enum BannedPredicateReason {
202    InfiniteRecursion,
204    Unsupported,
206}
207
208impl fmt::Display for BannedPredicateReason {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        match self {
211            BannedPredicateReason::InfiniteRecursion => {
212                write!(f, "this predicate causes infinite recursion")
213            }
214            BannedPredicateReason::Unsupported => {
215                write!(f, "test() predicates are not supported while archiving")
216            }
217        }
218    }
219}