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