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 test groups")]
127 NoGroupMatch(#[label("no test groups matched this")] SourceSpan),
128
129 #[error("operator didn't match any binary IDs")]
131 NoBinaryIdMatch(#[label("no binary IDs matched this")] SourceSpan),
132
133 #[error("operator didn't match any binary names")]
135 NoBinaryNameMatch(#[label("no binary names matched this")] SourceSpan),
136
137 #[error("invalid argument for platform")]
139 InvalidPlatformArgument(#[label("expected \"target\" or \"host\"")] SourceSpan),
140
141 #[error("unsupported expression")]
143 UnsupportedExpression(#[label("contained an unsupported expression")] SourceSpan),
144
145 #[error("unknown parsing error")]
147 Unknown,
148}
149
150impl ParseSingleError {
151 pub(crate) fn invalid_regex(input: &str, start: usize, end: usize) -> Self {
152 match regex_syntax::Parser::new().parse(input) {
154 Ok(_) => {
155 Self::InvalidRegexWithoutMessage((start, end - start).into())
158 }
159 Err(err) => {
160 let (message, span) = match &err {
161 regex_syntax::Error::Parse(err) => (format!("{}", err.kind()), err.span()),
162 regex_syntax::Error::Translate(err) => (format!("{}", err.kind()), err.span()),
163 _ => return Self::InvalidRegexWithoutMessage((start, end - start).into()),
164 };
165
166 let err_start = start + span.start.offset;
168 let err_end = start + span.end.offset;
169
170 Self::InvalidRegex {
171 span: (err_start, err_end - err_start).into(),
172 message,
173 }
174 }
175 }
176 }
177}
178
179#[derive(Clone, Debug, Error, PartialEq, Eq)]
180pub enum GlobConstructError {
181 #[error("{}", .0.kind())]
182 InvalidGlob(globset::Error),
183
184 #[error("{}", .0)]
185 RegexError(String),
186}
187
188#[derive(Debug)]
189pub(crate) struct State<'a> {
190 errors: &'a mut Vec<ParseSingleError>,
192}
193
194impl<'a> State<'a> {
195 pub fn new(errors: &'a mut Vec<ParseSingleError>) -> Self {
196 Self { errors }
197 }
198
199 pub fn report_error(&mut self, error: ParseSingleError) {
200 self.errors.push(error);
201 }
202}
203
204#[derive(Copy, Clone, Debug, PartialEq, Eq)]
205pub enum BannedPredicateReason {
206 DefaultInfiniteRecursion,
208
209 GroupCircularDependency,
212
213 GroupNotAvailableInDefaultFilter,
215
216 GroupNotAvailableInArchive,
218
219 TestNotAvailableInArchive,
221}
222
223impl fmt::Display for BannedPredicateReason {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 match self {
226 BannedPredicateReason::DefaultInfiniteRecursion => {
227 write!(f, "default() causes infinite recursion")
228 }
229 BannedPredicateReason::GroupCircularDependency => {
230 write!(f, "group() creates a circular dependency with overrides")
231 }
232 BannedPredicateReason::GroupNotAvailableInDefaultFilter => {
233 write!(f, "group() is not available in default-filter expressions")
234 }
235 BannedPredicateReason::GroupNotAvailableInArchive => {
236 write!(f, "group() predicates are not supported while archiving")
237 }
238 BannedPredicateReason::TestNotAvailableInArchive => {
239 write!(f, "test() predicates are not supported while archiving")
240 }
241 }
242 }
243}