1use guppy::graph::cargo::BuildPlatform;
17use miette::SourceSpan;
18use std::fmt;
19use winnow::{
20 LocatingSlice, ModalParser, Parser,
21 ascii::line_ending,
22 combinator::{alt, delimited, eof, peek, preceded, repeat, terminated, trace},
23 stream::{Location, SliceLen, Stream},
24 token::{literal, take_till},
25};
26
27mod glob;
28mod unicode_string;
29use crate::{NameMatcher, errors::*};
30pub(crate) use glob::GenericGlob;
31pub(crate) use unicode_string::DisplayParsedString;
32
33pub(crate) type Span<'a> = winnow::Stateful<LocatingSlice<&'a str>, State<'a>>;
34type Error = ();
35type PResult<T> = winnow::ModalResult<T, Error>;
36
37pub(crate) fn new_span<'a>(input: &'a str, errors: &'a mut Vec<ParseSingleError>) -> Span<'a> {
38 Span {
39 input: LocatingSlice::new(input),
40 state: State::new(errors),
41 }
42}
43
44#[derive(Clone, Debug, PartialEq, Eq)]
48#[doc(hidden)]
49pub enum SetDef<S = SourceSpan> {
50 Package(NameMatcher, S),
51 Deps(NameMatcher, S),
52 Rdeps(NameMatcher, S),
53 Kind(NameMatcher, S),
54 Binary(NameMatcher, S),
55 BinaryId(NameMatcher, S),
56 Platform(BuildPlatform, S),
57 Test(NameMatcher, S),
58 Default(S),
59 All,
60 None,
61}
62
63impl SetDef {
64 #[cfg(test)]
65 fn drop_source_span(self) -> SetDef<()> {
66 match self {
67 Self::Package(matcher, _) => SetDef::Package(matcher, ()),
68 Self::Deps(matcher, _) => SetDef::Deps(matcher, ()),
69 Self::Rdeps(matcher, _) => SetDef::Rdeps(matcher, ()),
70 Self::Kind(matcher, _) => SetDef::Kind(matcher, ()),
71 Self::Binary(matcher, _) => SetDef::Binary(matcher, ()),
72 Self::BinaryId(matcher, _) => SetDef::BinaryId(matcher, ()),
73 Self::Platform(platform, _) => SetDef::Platform(platform, ()),
74 Self::Test(matcher, _) => SetDef::Test(matcher, ()),
75 Self::Default(_) => SetDef::Default(()),
76 Self::All => SetDef::All,
77 Self::None => SetDef::None,
78 }
79 }
80}
81
82impl<S> fmt::Display for SetDef<S> {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 match self {
85 Self::Package(matcher, _) => write!(f, "package({matcher})"),
86 Self::Deps(matcher, _) => write!(f, "deps({matcher})"),
87 Self::Rdeps(matcher, _) => write!(f, "rdeps({matcher})"),
88 Self::Kind(matcher, _) => write!(f, "kind({matcher})"),
89 Self::Binary(matcher, _) => write!(f, "binary({matcher})"),
90 Self::BinaryId(matcher, _) => write!(f, "binary_id({matcher})"),
91 Self::Platform(platform, _) => write!(f, "platform({platform})"),
92 Self::Test(matcher, _) => write!(f, "test({matcher})"),
93 Self::Default(_) => write!(f, "default()"),
94 Self::All => write!(f, "all()"),
95 Self::None => write!(f, "none()"),
96 }
97 }
98}
99
100#[derive(Clone, Debug, PartialEq, Eq)]
105pub enum ParsedExpr<S = SourceSpan> {
106 Not(NotOperator, Box<ParsedExpr<S>>),
107 Union(OrOperator, Box<ParsedExpr<S>>, Box<ParsedExpr<S>>),
108 Intersection(AndOperator, Box<ParsedExpr<S>>, Box<ParsedExpr<S>>),
109 Difference(DifferenceOperator, Box<ParsedExpr<S>>, Box<ParsedExpr<S>>),
110 Parens(Box<ParsedExpr<S>>),
111 Set(SetDef<S>),
112}
113
114impl ParsedExpr {
115 pub fn parse(input: &str) -> Result<Self, Vec<ParseSingleError>> {
116 let mut errors = Vec::new();
117 let span = new_span(input, &mut errors);
118 match parse(span).unwrap() {
119 ExprResult::Valid(expr) => Ok(expr),
120 ExprResult::Error => Err(errors),
121 }
122 }
123
124 fn boxed(self) -> Box<Self> {
125 Box::new(self)
126 }
127
128 fn not(self, op: NotOperator) -> Self {
129 ParsedExpr::Not(op, self.boxed())
130 }
131
132 fn union(op: OrOperator, expr_1: Self, expr_2: Self) -> Self {
133 ParsedExpr::Union(op, expr_1.boxed(), expr_2.boxed())
134 }
135
136 fn intersection(op: AndOperator, expr_1: Self, expr_2: Self) -> Self {
137 ParsedExpr::Intersection(op, expr_1.boxed(), expr_2.boxed())
138 }
139
140 fn difference(op: DifferenceOperator, expr_1: Self, expr_2: Self) -> Self {
141 ParsedExpr::Difference(op, expr_1.boxed(), expr_2.boxed())
142 }
143
144 fn parens(self) -> Self {
145 ParsedExpr::Parens(self.boxed())
146 }
147
148 #[cfg(test)]
149 fn all() -> ParsedExpr {
150 ParsedExpr::Set(SetDef::All)
151 }
152
153 #[cfg(test)]
154 fn none() -> ParsedExpr {
155 ParsedExpr::Set(SetDef::None)
156 }
157
158 #[cfg(test)]
159 fn drop_source_span(self) -> ParsedExpr<()> {
160 match self {
161 Self::Not(op, expr) => ParsedExpr::Not(op, Box::new(expr.drop_source_span())),
162 Self::Union(op, a, b) => ParsedExpr::Union(
163 op,
164 Box::new(a.drop_source_span()),
165 Box::new(b.drop_source_span()),
166 ),
167 Self::Intersection(op, a, b) => ParsedExpr::Intersection(
168 op,
169 Box::new(a.drop_source_span()),
170 Box::new(b.drop_source_span()),
171 ),
172 Self::Difference(op, a, b) => ParsedExpr::Difference(
173 op,
174 Box::new(a.drop_source_span()),
175 Box::new(b.drop_source_span()),
176 ),
177 Self::Parens(a) => ParsedExpr::Parens(Box::new(a.drop_source_span())),
178 Self::Set(set) => ParsedExpr::Set(set.drop_source_span()),
179 }
180 }
181}
182
183impl<S> fmt::Display for ParsedExpr<S> {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 match self {
186 Self::Not(op, expr) => write!(f, "{op} {expr}"),
187 Self::Union(op, expr_1, expr_2) => write!(f, "{expr_1} {op} {expr_2}"),
188 Self::Intersection(op, expr_1, expr_2) => write!(f, "{expr_1} {op} {expr_2}"),
189 Self::Difference(op, expr_1, expr_2) => write!(f, "{expr_1} {op} {expr_2}"),
190 Self::Parens(expr) => write!(f, "({expr})"),
191 Self::Set(set) => write!(f, "{set}"),
192 }
193 }
194}
195
196pub(crate) enum ExprResult {
197 Valid(ParsedExpr),
198 Error,
199}
200
201impl ExprResult {
202 fn combine(self, op: impl FnOnce(ParsedExpr, ParsedExpr) -> ParsedExpr, other: Self) -> Self {
203 match (self, other) {
204 (Self::Valid(expr_1), Self::Valid(expr_2)) => Self::Valid(op(expr_1, expr_2)),
205 _ => Self::Error,
206 }
207 }
208
209 fn negate(self, op: NotOperator) -> Self {
210 match self {
211 Self::Valid(expr) => Self::Valid(expr.not(op)),
212 _ => Self::Error,
213 }
214 }
215
216 fn parens(self) -> Self {
217 match self {
218 Self::Valid(expr) => Self::Valid(expr.parens()),
219 _ => Self::Error,
220 }
221 }
222}
223
224enum SpanLength {
225 Unknown,
226 Exact(usize),
227 Offset(isize, usize),
228}
229
230fn expect_inner<'a, F, T>(
231 mut parser: F,
232 make_err: fn(SourceSpan) -> ParseSingleError,
233 limit: SpanLength,
234) -> impl ModalParser<Span<'a>, Option<T>, Error>
235where
236 F: ModalParser<Span<'a>, T, Error>,
237{
238 move |input: &mut _| match parser.parse_next(input) {
239 Ok(out) => Ok(Some(out)),
240 Err(winnow::error::ErrMode::Backtrack(_)) | Err(winnow::error::ErrMode::Cut(_)) => {
241 let fragment_start = input.current_token_start();
242 let fragment_length = input.slice_len();
243 let span = match limit {
244 SpanLength::Unknown => (fragment_start, fragment_length).into(),
245 SpanLength::Exact(x) => (fragment_start, x.min(fragment_length)).into(),
246 SpanLength::Offset(offset, x) => {
247 let effective_start = fragment_start.saturating_add_signed(offset);
250 let effective_end = effective_start + fragment_length;
252 let len = (effective_end - effective_start).min(x);
254 (effective_start, len).into()
255 }
256 };
257 let err = make_err(span);
258 input.state.report_error(err);
259 Ok(None)
260 }
261 Err(err) => Err(err),
262 }
263}
264
265fn expect<'a, F, T>(
266 parser: F,
267 make_err: fn(SourceSpan) -> ParseSingleError,
268) -> impl ModalParser<Span<'a>, Option<T>, Error>
269where
270 F: ModalParser<Span<'a>, T, Error>,
271{
272 expect_inner(parser, make_err, SpanLength::Unknown)
273}
274
275fn expect_n<'a, F, T>(
276 parser: F,
277 make_err: fn(SourceSpan) -> ParseSingleError,
278 limit: SpanLength,
279) -> impl ModalParser<Span<'a>, Option<T>, Error>
280where
281 F: ModalParser<Span<'a>, T, Error>,
282{
283 expect_inner(parser, make_err, limit)
284}
285
286fn expect_char<'a>(
287 c: char,
288 make_err: fn(SourceSpan) -> ParseSingleError,
289) -> impl ModalParser<Span<'a>, Option<char>, Error> {
290 expect_inner(ws(c), make_err, SpanLength::Exact(0))
291}
292
293fn silent_expect<'a, F, T>(mut parser: F) -> impl ModalParser<Span<'a>, Option<T>, Error>
294where
295 F: ModalParser<Span<'a>, T, Error>,
296{
297 move |input: &mut _| match parser.parse_next(input) {
298 Ok(out) => Ok(Some(out)),
299 Err(winnow::error::ErrMode::Backtrack(_)) | Err(winnow::error::ErrMode::Cut(_)) => Ok(None),
300 Err(err) => Err(err),
301 }
302}
303
304fn ws<'a, T, P: ModalParser<Span<'a>, T, Error>>(
305 mut inner: P,
306) -> impl ModalParser<Span<'a>, T, Error> {
307 move |input: &mut Span<'a>| {
308 let start = input.checkpoint();
309 () = repeat(
310 0..,
311 alt((
312 ' '.void(),
314 line_ending.void(),
317 )),
318 )
319 .parse_next(input)?;
320 match inner.parse_next(input) {
321 Ok(res) => Ok(res),
322 Err(winnow::error::ErrMode::Backtrack(err)) => {
323 input.reset(&start);
324 Err(winnow::error::ErrMode::Backtrack(err))
325 }
326 Err(winnow::error::ErrMode::Cut(err)) => {
327 input.reset(&start);
328 Err(winnow::error::ErrMode::Cut(err))
329 }
330 Err(err) => Err(err),
331 }
332 }
333}
334
335fn parse_matcher_text<'i>(input: &mut Span<'i>) -> PResult<Option<String>> {
337 trace("parse_matcher_text", |input: &mut Span<'i>| {
338 let res = match expect(
339 unicode_string::parse_string,
340 ParseSingleError::InvalidString,
341 )
342 .parse_next(input)
343 {
344 Ok(res) => res.flatten(),
345 Err(_) => unreachable!(),
346 };
347
348 if res.as_ref().map(|s| s.is_empty()).unwrap_or(false) {
349 let start = input.current_token_start();
350 input
351 .state
352 .report_error(ParseSingleError::InvalidString((start..0).into()));
353 }
354
355 Ok(res)
356 })
357 .parse_next(input)
358}
359
360fn parse_contains_matcher(input: &mut Span<'_>) -> PResult<Option<NameMatcher>> {
361 trace(
362 "parse_contains_matcher",
363 preceded('~', parse_matcher_text).map(|res: Option<String>| {
364 res.map(|value| NameMatcher::Contains {
365 value,
366 implicit: false,
367 })
368 }),
369 )
370 .parse_next(input)
371}
372
373fn parse_equal_matcher(input: &mut Span<'_>) -> PResult<Option<NameMatcher>> {
374 trace(
375 "parse_equal_matcher",
376 ws(
377 preceded('=', parse_matcher_text).map(|res: Option<String>| {
378 res.map(|value| NameMatcher::Equal {
379 value,
380 implicit: false,
381 })
382 }),
383 ),
384 )
385 .parse_next(input)
386}
387
388fn parse_regex_inner(input: &mut Span<'_>) -> PResult<String> {
389 trace("parse_regex_inner", |input: &mut _| {
390 enum Frag<'a> {
391 Literal(&'a str),
392 Escape(char),
393 }
394
395 let parse_escape = alt((r"\/".value('/'), '\\')).map(Frag::Escape);
396 let parse_literal = take_till(1.., ('\\', '/'))
397 .verify(|s: &str| !s.is_empty())
398 .map(|s: &str| Frag::Literal(s));
399 let parse_frag = alt((parse_escape, parse_literal));
400
401 let res = repeat(0.., parse_frag)
402 .fold(String::new, |mut string, frag| {
403 match frag {
404 Frag::Escape(c) => string.push(c),
405 Frag::Literal(s) => string.push_str(s),
406 }
407 string
408 })
409 .parse_next(input)?;
410
411 let _ = peek('/').parse_next(input)?;
412
413 Ok(res)
414 })
415 .parse_next(input)
416}
417
418pub(crate) struct DisplayParsedRegex<'a>(pub(crate) &'a regex::Regex);
420
421impl fmt::Display for DisplayParsedRegex<'_> {
422 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423 let regex = self.0.as_str();
424 let mut escaped = false;
425 for c in regex.chars() {
426 if escaped {
427 escaped = false;
428 write!(f, "{c}")?;
429 } else if c == '\\' {
430 escaped = true;
431 write!(f, "{c}")?;
432 } else if c == '/' {
433 write!(f, "\\/")?;
435 } else {
436 write!(f, "{c}")?;
437 }
438 }
439 Ok(())
440 }
441}
442
443fn parse_regex<'i>(input: &mut Span<'i>) -> PResult<Option<NameMatcher>> {
444 trace("parse_regex", |input: &mut Span<'i>| {
445 let start = input.checkpoint();
446 let res = match parse_regex_inner.parse_next(input) {
447 Ok(res) => res,
448 Err(_) => {
449 input.reset(&start);
450 match take_till::<_, _, Error>(0.., ')').parse_next(input) {
451 Ok(_) => {
452 let start = input.current_token_start();
453 let err = ParseSingleError::ExpectedCloseRegex((start, 0).into());
454 input.state.report_error(err);
455 return Ok(None);
456 }
457 Err(_) => unreachable!(),
458 }
459 }
460 };
461 match regex::Regex::new(&res).map(NameMatcher::Regex) {
462 Ok(res) => Ok(Some(res)),
463 Err(_) => {
464 let end = input.checkpoint();
465
466 input.reset(&start);
467 let start = input.current_token_start();
468
469 input.reset(&end);
470 let end = input.current_token_start();
471
472 let err = ParseSingleError::invalid_regex(&res, start, end);
473 input.state.report_error(err);
474 Ok(None)
475 }
476 }
477 })
478 .parse_next(input)
479}
480
481fn parse_regex_matcher(input: &mut Span<'_>) -> PResult<Option<NameMatcher>> {
482 trace(
483 "parse_regex_matcher",
484 ws(delimited('/', parse_regex, silent_expect(ws('/')))),
485 )
486 .parse_next(input)
487}
488
489fn parse_glob_matcher(input: &mut Span<'_>) -> PResult<Option<NameMatcher>> {
490 trace(
491 "parse_glob_matcher",
492 ws(preceded('#', glob::parse_glob(false))),
493 )
494 .parse_next(input)
495}
496
497fn set_matcher<'a>(
499 default_matcher: DefaultMatcher,
500) -> impl ModalParser<Span<'a>, Option<NameMatcher>, Error> {
501 ws(alt((
502 parse_regex_matcher,
503 parse_glob_matcher,
504 parse_equal_matcher,
505 parse_contains_matcher,
506 default_matcher.into_parser(),
507 )))
508}
509
510fn recover_unexpected_comma<'i>(input: &mut Span<'i>) -> PResult<()> {
511 trace("recover_unexpected_comma", |input: &mut Span<'i>| {
512 let start = input.checkpoint();
513 match peek(ws(',')).parse_next(input) {
514 Ok(_) => {
515 let pos = input.current_token_start();
516 input
517 .state
518 .report_error(ParseSingleError::UnexpectedComma((pos..0).into()));
519 match take_till::<_, _, Error>(0.., ')').parse_next(input) {
520 Ok(_) => Ok(()),
521 Err(_) => unreachable!(),
522 }
523 }
524 Err(_) => {
525 input.reset(&start);
526 Ok(())
527 }
528 }
529 })
530 .parse_next(input)
531}
532
533fn nullary_set_def<'a>(
534 name: &'static str,
535 make_set: fn(SourceSpan) -> SetDef,
536) -> impl ModalParser<Span<'a>, Option<SetDef>, Error> {
537 move |i: &mut Span<'_>| {
538 let start = i.current_token_start();
539 let _ = literal(name).parse_next(i)?;
540 let _ = expect_char('(', ParseSingleError::ExpectedOpenParenthesis).parse_next(i)?;
541 let err_loc = i.current_token_start();
542 match take_till::<_, _, Error>(0.., ')').parse_next(i) {
543 Ok(res) => {
544 if !res.trim().is_empty() {
545 let span = (err_loc, res.len()).into();
546 let err = ParseSingleError::UnexpectedArgument(span);
547 i.state.report_error(err);
548 }
549 }
550 Err(_) => unreachable!(),
551 };
552 let _ = expect_char(')', ParseSingleError::ExpectedCloseParenthesis).parse_next(i)?;
553 let end = i.current_token_start();
554 Ok(Some(make_set((start, end - start).into())))
555 }
556}
557
558#[derive(Copy, Clone, Debug)]
559enum DefaultMatcher {
560 Equal,
562 Contains,
563 Glob,
564}
565
566impl DefaultMatcher {
567 fn into_parser<'a>(self) -> impl ModalParser<Span<'a>, Option<NameMatcher>, Error> {
568 move |input: &mut _| match self {
569 Self::Equal => parse_matcher_text
570 .map(|res: Option<String>| res.map(NameMatcher::implicit_equal))
571 .parse_next(input),
572 Self::Contains => parse_matcher_text
573 .map(|res: Option<String>| res.map(NameMatcher::implicit_contains))
574 .parse_next(input),
575 Self::Glob => glob::parse_glob(true).parse_next(input),
576 }
577 }
578}
579
580fn unary_set_def<'a>(
581 name: &'static str,
582 default_matcher: DefaultMatcher,
583 make_set: fn(NameMatcher, SourceSpan) -> SetDef,
584) -> impl ModalParser<Span<'a>, Option<SetDef>, Error> {
585 move |i: &mut _| {
586 let _ = literal(name).parse_next(i)?;
587 let _ = expect_char('(', ParseSingleError::ExpectedOpenParenthesis).parse_next(i)?;
588 let start = i.current_token_start();
589 let res = set_matcher(default_matcher).parse_next(i)?;
590 let end = i.current_token_start();
591 recover_unexpected_comma.parse_next(i)?;
592 let _ = expect_char(')', ParseSingleError::ExpectedCloseParenthesis).parse_next(i)?;
593 Ok(res.map(|matcher| make_set(matcher, (start, end - start).into())))
594 }
595}
596
597fn platform_def(i: &mut Span<'_>) -> PResult<Option<SetDef>> {
598 let _ = "platform".parse_next(i)?;
599 let _ = expect_char('(', ParseSingleError::ExpectedOpenParenthesis).parse_next(i)?;
600 let start = i.current_token_start();
601 let res = ws(parse_matcher_text).parse_next(i)?;
603 let end = i.current_token_start();
604 recover_unexpected_comma.parse_next(i)?;
605 let _ = expect_char(')', ParseSingleError::ExpectedCloseParenthesis).parse_next(i)?;
606
607 let platform = match res.as_deref().map(|res| res.trim()) {
609 Some("host") => Some(BuildPlatform::Host),
610 Some("target") => Some(BuildPlatform::Target),
611 Some(_) => {
612 i.state
613 .report_error(ParseSingleError::InvalidPlatformArgument(
614 (start, end - start).into(),
615 ));
616 None
617 }
618 None => {
619 None
621 }
622 };
623 Ok(platform.map(|platform| SetDef::Platform(platform, (start, end - start).into())))
624}
625
626fn parse_set_def(input: &mut Span<'_>) -> PResult<Option<SetDef>> {
627 trace(
628 "parse_set_def",
629 ws(alt((
630 unary_set_def("package", DefaultMatcher::Glob, SetDef::Package),
631 unary_set_def("deps", DefaultMatcher::Glob, SetDef::Deps),
632 unary_set_def("rdeps", DefaultMatcher::Glob, SetDef::Rdeps),
633 unary_set_def("kind", DefaultMatcher::Equal, SetDef::Kind),
634 unary_set_def("binary_id", DefaultMatcher::Glob, SetDef::BinaryId),
636 unary_set_def("binary", DefaultMatcher::Glob, SetDef::Binary),
637 unary_set_def("test", DefaultMatcher::Contains, SetDef::Test),
638 platform_def,
639 nullary_set_def("default", SetDef::Default),
640 nullary_set_def("all", |_| SetDef::All),
641 nullary_set_def("none", |_| SetDef::None),
642 ))),
643 )
644 .parse_next(input)
645}
646
647fn expect_expr<'a, P: ModalParser<Span<'a>, ExprResult, Error>>(
648 inner: P,
649) -> impl ModalParser<Span<'a>, ExprResult, Error> {
650 expect(inner, ParseSingleError::ExpectedExpr).map(|res| res.unwrap_or(ExprResult::Error))
651}
652
653fn parse_parentheses_expr(input: &mut Span<'_>) -> PResult<ExprResult> {
654 trace(
655 "parse_parentheses_expr",
656 delimited(
657 '(',
658 expect_expr(parse_expr),
659 expect_char(')', ParseSingleError::ExpectedCloseParenthesis),
660 )
661 .map(|expr| expr.parens()),
662 )
663 .parse_next(input)
664}
665
666fn parse_basic_expr(input: &mut Span<'_>) -> PResult<ExprResult> {
667 trace(
668 "parse_basic_expr",
669 ws(alt((
670 parse_set_def.map(|set| {
671 set.map(|set| ExprResult::Valid(ParsedExpr::Set(set)))
672 .unwrap_or(ExprResult::Error)
673 }),
674 parse_expr_not,
675 parse_parentheses_expr,
676 ))),
677 )
678 .parse_next(input)
679}
680
681#[derive(Clone, Copy, Debug, Eq, PartialEq)]
682#[cfg_attr(
683 any(test, feature = "internal-testing"),
684 derive(test_strategy::Arbitrary)
685)]
686pub enum NotOperator {
687 LiteralNot,
688 Exclamation,
689}
690
691impl fmt::Display for NotOperator {
692 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 match self {
694 NotOperator::LiteralNot => f.write_str("not"),
695 NotOperator::Exclamation => f.write_str("!"),
696 }
697 }
698}
699
700fn parse_expr_not(input: &mut Span<'_>) -> PResult<ExprResult> {
701 trace(
702 "parse_expr_not",
703 (
704 alt((
705 "not ".value(NotOperator::LiteralNot),
706 '!'.value(NotOperator::Exclamation),
707 )),
708 expect_expr(ws(parse_basic_expr)),
709 )
710 .map(|(op, expr)| expr.negate(op)),
711 )
712 .parse_next(input)
713}
714
715#[derive(Clone, Copy, Debug, Eq, PartialEq)]
718#[cfg_attr(
719 any(test, feature = "internal-testing"),
720 derive(test_strategy::Arbitrary)
721)]
722pub enum OrOperator {
723 LiteralOr,
724 Pipe,
725 Plus,
726}
727
728impl fmt::Display for OrOperator {
729 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730 match self {
731 OrOperator::LiteralOr => f.write_str("or"),
732 OrOperator::Pipe => f.write_str("|"),
733 OrOperator::Plus => f.write_str("+"),
734 }
735 }
736}
737
738fn parse_expr(input: &mut Span<'_>) -> PResult<ExprResult> {
739 trace("parse_expr", |input: &mut _| {
740 let expr = expect_expr(parse_and_or_difference_expr).parse_next(input)?;
742
743 let ops = repeat(
744 0..,
745 (parse_or_operator, expect_expr(parse_and_or_difference_expr)),
746 )
747 .fold(Vec::new, |mut ops, (op, expr)| {
748 ops.push((op, expr));
749 ops
750 })
751 .parse_next(input)?;
752
753 let expr = ops.into_iter().fold(expr, |expr_1, (op, expr_2)| {
754 if let Some(op) = op {
755 expr_1.combine(
756 |expr_1, expr_2| ParsedExpr::union(op, expr_1, expr_2),
757 expr_2,
758 )
759 } else {
760 ExprResult::Error
761 }
762 });
763
764 Ok(expr)
765 })
766 .parse_next(input)
767}
768
769fn parse_or_operator<'i>(input: &mut Span<'i>) -> PResult<Option<OrOperator>> {
770 trace(
771 "parse_or_operator",
772 ws(alt((
773 |input: &mut Span<'i>| {
774 let start = input.current_token_start();
775 let op = alt(("||", "OR ")).parse_next(input)?;
778 let length = op.len();
780 let err = ParseSingleError::InvalidOrOperator((start, length).into());
781 input.state.report_error(err);
782 Ok(None)
783 },
784 "or ".value(Some(OrOperator::LiteralOr)),
785 '|'.value(Some(OrOperator::Pipe)),
786 '+'.value(Some(OrOperator::Plus)),
787 ))),
788 )
789 .parse_next(input)
790}
791
792#[derive(Clone, Copy, Debug, Eq, PartialEq)]
795#[cfg_attr(
796 any(test, feature = "internal-testing"),
797 derive(test_strategy::Arbitrary)
798)]
799pub enum AndOperator {
800 LiteralAnd,
801 Ampersand,
802}
803
804impl fmt::Display for AndOperator {
805 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806 match self {
807 AndOperator::LiteralAnd => f.write_str("and"),
808 AndOperator::Ampersand => f.write_str("&"),
809 }
810 }
811}
812
813#[derive(Clone, Copy, Debug, Eq, PartialEq)]
814#[cfg_attr(
815 any(test, feature = "internal-testing"),
816 derive(test_strategy::Arbitrary)
817)]
818pub enum DifferenceOperator {
819 Minus,
820}
821
822impl fmt::Display for DifferenceOperator {
823 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824 match self {
825 DifferenceOperator::Minus => f.write_str("-"),
826 }
827 }
828}
829
830#[derive(Clone, Copy, Debug, Eq, PartialEq)]
831enum AndOrDifferenceOperator {
832 And(AndOperator),
833 Difference(DifferenceOperator),
834}
835
836fn parse_and_or_difference_expr(input: &mut Span<'_>) -> PResult<ExprResult> {
837 trace("parse_and_or_difference_expr", |input: &mut _| {
838 let expr = expect_expr(parse_basic_expr).parse_next(input)?;
839
840 let ops = repeat(
841 0..,
842 (
843 parse_and_or_difference_operator,
844 expect_expr(parse_basic_expr),
845 ),
846 )
847 .fold(Vec::new, |mut ops, (op, expr)| {
848 ops.push((op, expr));
849 ops
850 })
851 .parse_next(input)?;
852
853 let expr = ops.into_iter().fold(expr, |expr_1, (op, expr_2)| match op {
854 Some(AndOrDifferenceOperator::And(op)) => expr_1.combine(
855 |expr_1, expr_2| ParsedExpr::intersection(op, expr_1, expr_2),
856 expr_2,
857 ),
858 Some(AndOrDifferenceOperator::Difference(op)) => expr_1.combine(
859 |expr_1, expr_2| ParsedExpr::difference(op, expr_1, expr_2),
860 expr_2,
861 ),
862 None => ExprResult::Error,
863 });
864
865 Ok(expr)
866 })
867 .parse_next(input)
868}
869
870fn parse_and_or_difference_operator<'i>(
871 input: &mut Span<'i>,
872) -> PResult<Option<AndOrDifferenceOperator>> {
873 trace(
874 "parse_and_or_difference_operator",
875 ws(alt((
876 |input: &mut Span<'i>| {
877 let start = input.current_token_start();
878 let op = alt(("&&", "AND ")).parse_next(input)?;
879 let length = op.len();
881 let err = ParseSingleError::InvalidAndOperator((start, length).into());
882 input.state.report_error(err);
883 Ok(None)
884 },
885 "and ".value(Some(AndOrDifferenceOperator::And(AndOperator::LiteralAnd))),
886 '&'.value(Some(AndOrDifferenceOperator::And(AndOperator::Ampersand))),
887 '-'.value(Some(AndOrDifferenceOperator::Difference(
888 DifferenceOperator::Minus,
889 ))),
890 ))),
891 )
892 .parse_next(input)
893}
894
895pub(crate) fn parse(input: Span<'_>) -> Result<ExprResult, winnow::error::ErrMode<Error>> {
898 let (_, expr) = terminated(
899 parse_expr,
900 expect(ws(eof), ParseSingleError::ExpectedEndOfExpression),
901 )
902 .parse_peek(input)?;
903 Ok(expr)
904}
905
906#[cfg(test)]
907mod tests {
908 use super::*;
909
910 #[track_caller]
911 fn parse_regex(input: &str) -> NameMatcher {
912 let mut errors = Vec::new();
913 let span = new_span(input, &mut errors);
914 parse_regex_matcher.parse_peek(span).unwrap().1.unwrap()
915 }
916
917 #[test]
918 fn test_parse_regex() {
919 assert_eq!(
920 NameMatcher::Regex(regex::Regex::new(r"some.*").unwrap()),
921 parse_regex(r"/some.*/")
922 );
923
924 assert_eq!(
925 NameMatcher::Regex(regex::Regex::new(r"a/a").unwrap()),
926 parse_regex(r"/a\/a/")
927 );
928
929 assert_eq!(
930 NameMatcher::Regex(regex::Regex::new(r"\w/a").unwrap()),
931 parse_regex(r"/\w\/a/")
932 );
933
934 assert_eq!(
935 NameMatcher::Regex(regex::Regex::new(r"\w\\/a").unwrap()),
936 parse_regex(r"/\w\\\/a/")
937 );
938
939 assert_eq!(
940 NameMatcher::Regex(regex::Regex::new(r"\p{Greek}\\/a").unwrap()),
941 parse_regex(r"/\p{Greek}\\\/a/")
942 );
943 }
944
945 #[track_caller]
946 fn parse_glob(input: &str) -> NameMatcher {
947 let mut errors = Vec::new();
948 let span = new_span(input, &mut errors);
949 let matcher = parse_glob_matcher
950 .parse_peek(span)
951 .unwrap_or_else(|error| {
952 panic!("for input {input}, parse_glob_matcher returned an error: {error}")
953 })
954 .1
955 .unwrap_or_else(|| {
956 panic!(
957 "for input {input}, parse_glob_matcher returned None \
958 (reported errors: {errors:?})"
959 )
960 });
961 if !errors.is_empty() {
962 panic!("for input {input}, parse_glob_matcher reported errors: {errors:?}");
963 }
964
965 matcher
966 }
967
968 fn make_glob_matcher(glob: &str, implicit: bool) -> NameMatcher {
969 NameMatcher::Glob {
970 glob: GenericGlob::new(glob.to_owned()).unwrap(),
971 implicit,
972 }
973 }
974
975 #[test]
976 fn test_parse_glob_matcher() {
977 #[track_caller]
978 fn assert_glob(input: &str, expected: &str) {
979 assert_eq!(
980 make_glob_matcher(expected, false),
981 parse_glob(input),
982 "expected matches actual for input {input:?}",
983 );
984 }
985
986 assert_glob(r"#something)", "something");
988 assert_glob(r"#something*)", "something*");
989 assert_glob(r"#something?)", "something?");
990 assert_glob(r"#something[abc])", "something[abc]");
991 assert_glob(r"#something[!abc])", "something[!abc]");
992 assert_glob(r"#something[a-c])", "something[a-c]");
993 assert_glob(r"#foobar\b)", "foobar\u{08}");
994 assert_glob(r"#foobar\\b)", "foobar\\b");
995 assert_glob(r"#foobar\))", "foobar)");
996 }
997
998 #[track_caller]
999 fn parse_set(input: &str) -> SetDef {
1000 let mut errors = Vec::new();
1001 let span = new_span(input, &mut errors);
1002 parse_set_def.parse_peek(span).unwrap().1.unwrap()
1003 }
1004
1005 macro_rules! assert_set_def {
1006 ($input: expr, $name:ident, $matches:expr) => {
1007 assert!(matches!($input, SetDef::$name(x, _) if x == $matches));
1008 };
1009 }
1010
1011 #[test]
1012 fn test_parse_name_matcher() {
1013 assert_set_def!(
1015 parse_set("test(~something)"),
1016 Test,
1017 NameMatcher::Contains {
1018 value: "something".to_string(),
1019 implicit: false,
1020 }
1021 );
1022
1023 assert_set_def!(
1024 parse_set("test(=something)"),
1025 Test,
1026 NameMatcher::Equal {
1027 value: "something".to_string(),
1028 implicit: false,
1029 }
1030 );
1031 assert_set_def!(
1032 parse_set("test(/some.*/)"),
1033 Test,
1034 NameMatcher::Regex(regex::Regex::new("some.*").unwrap())
1035 );
1036 assert_set_def!(
1037 parse_set("test(#something)"),
1038 Test,
1039 make_glob_matcher("something", false)
1040 );
1041 assert_set_def!(
1042 parse_set("test(#something*)"),
1043 Test,
1044 make_glob_matcher("something*", false)
1045 );
1046 assert_set_def!(
1047 parse_set(r"test(#something/[?])"),
1048 Test,
1049 make_glob_matcher("something/[?]", false)
1050 );
1051
1052 assert_set_def!(
1054 parse_set("test(something)"),
1055 Test,
1056 NameMatcher::Contains {
1057 value: "something".to_string(),
1058 implicit: true,
1059 }
1060 );
1061 assert_set_def!(
1062 parse_set("package(something)"),
1063 Package,
1064 make_glob_matcher("something", true)
1065 );
1066
1067 assert_set_def!(
1069 parse_set("test(~something)"),
1070 Test,
1071 NameMatcher::Contains {
1072 value: "something".to_string(),
1073 implicit: false,
1074 }
1075 );
1076 assert_set_def!(
1077 parse_set("test(~~something)"),
1078 Test,
1079 NameMatcher::Contains {
1080 value: "~something".to_string(),
1081 implicit: false,
1082 }
1083 );
1084 assert_set_def!(
1085 parse_set("test(~=something)"),
1086 Test,
1087 NameMatcher::Contains {
1088 value: "=something".to_string(),
1089 implicit: false,
1090 }
1091 );
1092 assert_set_def!(
1093 parse_set("test(~/something/)"),
1094 Test,
1095 NameMatcher::Contains {
1096 value: "/something/".to_string(),
1097 implicit: false,
1098 }
1099 );
1100 assert_set_def!(
1101 parse_set("test(~#something)"),
1102 Test,
1103 NameMatcher::Contains {
1104 value: "#something".to_string(),
1105 implicit: false,
1106 }
1107 );
1108
1109 assert_set_def!(
1111 parse_set("test(=something)"),
1112 Test,
1113 NameMatcher::Equal {
1114 value: "something".to_string(),
1115 implicit: false,
1116 }
1117 );
1118 assert_set_def!(
1119 parse_set("test(=~something)"),
1120 Test,
1121 NameMatcher::Equal {
1122 value: "~something".to_string(),
1123 implicit: false,
1124 }
1125 );
1126 assert_set_def!(
1127 parse_set("test(==something)"),
1128 Test,
1129 NameMatcher::Equal {
1130 value: "=something".to_string(),
1131 implicit: false,
1132 }
1133 );
1134 assert_set_def!(
1135 parse_set("test(=/something/)"),
1136 Test,
1137 NameMatcher::Equal {
1138 value: "/something/".to_string(),
1139 implicit: false,
1140 }
1141 );
1142 assert_set_def!(
1143 parse_set("test(=#something)"),
1144 Test,
1145 NameMatcher::Equal {
1146 value: "#something".to_string(),
1147 implicit: false,
1148 }
1149 );
1150
1151 assert_set_def!(
1153 parse_set("test(#~something)"),
1154 Test,
1155 make_glob_matcher("~something", false)
1156 );
1157 assert_set_def!(
1158 parse_set("test(#=something)"),
1159 Test,
1160 make_glob_matcher("=something", false)
1161 );
1162 assert_set_def!(
1163 parse_set("test(#/something/)"),
1164 Test,
1165 make_glob_matcher("/something/", false)
1166 );
1167 assert_set_def!(
1168 parse_set("test(##something)"),
1169 Test,
1170 make_glob_matcher("#something", false)
1171 );
1172 }
1173
1174 #[test]
1175 fn test_parse_name_matcher_quote() {
1176 assert_set_def!(
1177 parse_set(r"test(some'thing)"),
1178 Test,
1179 NameMatcher::Contains {
1180 value: r"some'thing".to_string(),
1181 implicit: true,
1182 }
1183 );
1184 assert_set_def!(
1185 parse_set(r"test(some(thing\))"),
1186 Test,
1187 NameMatcher::Contains {
1188 value: r"some(thing)".to_string(),
1189 implicit: true,
1190 }
1191 );
1192 assert_set_def!(
1193 parse_set(r"test(some \u{55})"),
1194 Test,
1195 NameMatcher::Contains {
1196 value: r"some U".to_string(),
1197 implicit: true,
1198 }
1199 );
1200 }
1201
1202 #[test]
1203 fn test_parse_set_def() {
1204 assert_eq!(SetDef::All, parse_set("all()"));
1205 assert_eq!(SetDef::All, parse_set(" all ( ) "));
1206
1207 assert_eq!(SetDef::None, parse_set("none()"));
1208
1209 assert_set_def!(
1210 parse_set("package(=something)"),
1211 Package,
1212 NameMatcher::Equal {
1213 value: "something".to_string(),
1214 implicit: false,
1215 }
1216 );
1217 assert_set_def!(
1218 parse_set("deps(something)"),
1219 Deps,
1220 make_glob_matcher("something", true)
1221 );
1222 assert_set_def!(
1223 parse_set("rdeps(something)"),
1224 Rdeps,
1225 make_glob_matcher("something", true)
1226 );
1227 assert_set_def!(
1228 parse_set("test(something)"),
1229 Test,
1230 NameMatcher::Contains {
1231 value: "something".to_string(),
1232 implicit: true,
1233 }
1234 );
1235 assert_set_def!(parse_set("platform(host)"), Platform, BuildPlatform::Host);
1236 assert_set_def!(
1237 parse_set("platform(target)"),
1238 Platform,
1239 BuildPlatform::Target
1240 );
1241 assert_set_def!(
1242 parse_set("platform( host )"),
1243 Platform,
1244 BuildPlatform::Host
1245 );
1246 }
1247
1248 #[track_caller]
1249 fn parse(input: &str) -> ParsedExpr {
1250 match ParsedExpr::parse(input) {
1251 Ok(expr) => expr,
1252 Err(errors) => {
1253 for single_error in &errors {
1254 let report = miette::Report::new(single_error.clone())
1255 .with_source_code(input.to_owned());
1256 eprintln!("{report:?}");
1257 }
1258 panic!("Not a valid expression!")
1259 }
1260 }
1261 }
1262
1263 #[test]
1264 fn test_parse_expr_set() {
1265 let expr = ParsedExpr::all();
1266 assert_eq!(expr, parse("all()"));
1267 assert_eq!(expr, parse(" all ( ) "));
1268 assert_eq!(format!("{expr}"), "all()");
1269 }
1270
1271 #[test]
1272 fn test_parse_expr_not() {
1273 let expr = ParsedExpr::all().not(NotOperator::LiteralNot);
1274 assert_eq_both_ways(&expr, "not all()");
1275 assert_eq!(expr, parse("not all()"));
1276
1277 let expr = ParsedExpr::all().not(NotOperator::Exclamation);
1278 assert_eq_both_ways(&expr, "! all()");
1279 assert_eq!(expr, parse("!all()"));
1280
1281 let expr = ParsedExpr::all()
1282 .not(NotOperator::LiteralNot)
1283 .not(NotOperator::LiteralNot);
1284 assert_eq_both_ways(&expr, "not not all()");
1285 }
1286
1287 #[test]
1288 fn test_parse_expr_intersection() {
1289 let expr = ParsedExpr::intersection(
1290 AndOperator::LiteralAnd,
1291 ParsedExpr::all(),
1292 ParsedExpr::none(),
1293 );
1294 assert_eq_both_ways(&expr, "all() and none()");
1295 assert_eq!(expr, parse("all()and none()"));
1296
1297 let expr = ParsedExpr::intersection(
1298 AndOperator::Ampersand,
1299 ParsedExpr::all(),
1300 ParsedExpr::none(),
1301 );
1302 assert_eq_both_ways(&expr, "all() & none()");
1303 assert_eq!(expr, parse("all()&none()"));
1304 }
1305
1306 #[test]
1307 fn test_parse_expr_union() {
1308 let expr = ParsedExpr::union(OrOperator::LiteralOr, ParsedExpr::all(), ParsedExpr::none());
1309 assert_eq_both_ways(&expr, "all() or none()");
1310 assert_eq!(expr, parse("all()or none()"));
1311
1312 let expr = ParsedExpr::union(OrOperator::Pipe, ParsedExpr::all(), ParsedExpr::none());
1313 assert_eq_both_ways(&expr, "all() | none()");
1314 assert_eq!(expr, parse("all()|none()"));
1315
1316 let expr = ParsedExpr::union(OrOperator::Plus, ParsedExpr::all(), ParsedExpr::none());
1317 assert_eq_both_ways(&expr, "all() + none()");
1318 assert_eq!(expr, parse("all()+none()"));
1319 }
1320
1321 #[test]
1322 fn test_parse_expr_difference() {
1323 let expr = ParsedExpr::difference(
1324 DifferenceOperator::Minus,
1325 ParsedExpr::all(),
1326 ParsedExpr::none(),
1327 );
1328 assert_eq_both_ways(&expr, "all() - none()");
1329 assert_eq!(expr, parse("all()-none()"));
1330 }
1331
1332 #[test]
1333 fn test_parse_expr_precedence() {
1334 let expr = ParsedExpr::intersection(
1335 AndOperator::LiteralAnd,
1336 ParsedExpr::all().not(NotOperator::LiteralNot),
1337 ParsedExpr::none(),
1338 );
1339 assert_eq_both_ways(&expr, "not all() and none()");
1340
1341 let expr = ParsedExpr::intersection(
1342 AndOperator::LiteralAnd,
1343 ParsedExpr::all(),
1344 ParsedExpr::none().not(NotOperator::LiteralNot),
1345 );
1346 assert_eq_both_ways(&expr, "all() and not none()");
1347
1348 let expr = ParsedExpr::intersection(
1349 AndOperator::Ampersand,
1350 ParsedExpr::all(),
1351 ParsedExpr::none(),
1352 );
1353 let expr = ParsedExpr::union(OrOperator::Pipe, expr, ParsedExpr::all());
1354 assert_eq_both_ways(&expr, "all() & none() | all()");
1355
1356 let expr = ParsedExpr::intersection(
1357 AndOperator::Ampersand,
1358 ParsedExpr::none(),
1359 ParsedExpr::all(),
1360 );
1361 let expr = ParsedExpr::union(OrOperator::Pipe, ParsedExpr::all(), expr);
1362 assert_eq_both_ways(&expr, "all() | none() & all()");
1363
1364 let expr =
1365 ParsedExpr::union(OrOperator::Pipe, ParsedExpr::all(), ParsedExpr::none()).parens();
1366 let expr = ParsedExpr::intersection(AndOperator::Ampersand, expr, ParsedExpr::all());
1367 assert_eq_both_ways(&expr, "(all() | none()) & all()");
1368
1369 let expr = ParsedExpr::intersection(
1370 AndOperator::Ampersand,
1371 ParsedExpr::none(),
1372 ParsedExpr::all(),
1373 )
1374 .parens();
1375 let expr = ParsedExpr::union(OrOperator::Pipe, ParsedExpr::all(), expr);
1376 assert_eq_both_ways(&expr, "all() | (none() & all())");
1377
1378 let expr = ParsedExpr::difference(
1379 DifferenceOperator::Minus,
1380 ParsedExpr::all(),
1381 ParsedExpr::none(),
1382 );
1383 let expr = ParsedExpr::intersection(AndOperator::Ampersand, expr, ParsedExpr::all());
1384 assert_eq_both_ways(&expr, "all() - none() & all()");
1385
1386 let expr = ParsedExpr::intersection(
1387 AndOperator::Ampersand,
1388 ParsedExpr::all(),
1389 ParsedExpr::none(),
1390 );
1391 let expr = ParsedExpr::difference(DifferenceOperator::Minus, expr, ParsedExpr::all());
1392 assert_eq_both_ways(&expr, "all() & none() - all()");
1393
1394 let expr = ParsedExpr::intersection(
1395 AndOperator::Ampersand,
1396 ParsedExpr::none(),
1397 ParsedExpr::all(),
1398 )
1399 .parens()
1400 .not(NotOperator::LiteralNot);
1401 assert_eq_both_ways(&expr, "not (none() & all())");
1402 }
1403
1404 #[test]
1405 fn test_parse_comma() {
1406 let expr = ParsedExpr::Set(SetDef::Test(
1408 NameMatcher::Contains {
1409 value: "a,".to_string(),
1410 implicit: false,
1411 },
1412 (5, 4).into(),
1413 ));
1414 assert_eq_both_ways(&expr, r"test(~a\,)");
1415
1416 fn parse_future_syntax(
1418 input: &mut Span<'_>,
1419 ) -> PResult<(Option<NameMatcher>, Option<NameMatcher>)> {
1420 let _ = "something".parse_next(input)?;
1421 let _ = '('.parse_next(input)?;
1422 let n1 = set_matcher(DefaultMatcher::Contains).parse_next(input)?;
1423 let _ = ws(',').parse_next(input)?;
1424 let n2 = set_matcher(DefaultMatcher::Contains).parse_next(input)?;
1425 let _ = ')'.parse_next(input)?;
1426 Ok((n1, n2))
1427 }
1428
1429 let mut errors = Vec::new();
1430 let mut span = new_span("something(aa, bb)", &mut errors);
1431 if parse_future_syntax.parse_next(&mut span).is_err() {
1432 panic!("Failed to parse comma separated matchers");
1433 }
1434 }
1435
1436 #[track_caller]
1437 fn parse_err(input: &str) -> Vec<ParseSingleError> {
1438 let mut errors = Vec::new();
1439 let span = new_span(input, &mut errors);
1440 super::parse(span).unwrap();
1441 errors
1442 }
1443
1444 macro_rules! assert_error {
1445 ($error:ident, $name:ident, $start:literal, $end:literal) => {{
1446 let matches = matches!($error, ParseSingleError::$name(span) if span == ($start, $end).into());
1447 assert!(
1448 matches,
1449 "expected: {:?}, actual: error: {:?}",
1450 ParseSingleError::$name(($start, $end).into()),
1451 $error,
1452 );
1453 }};
1454 }
1455
1456 #[test]
1457 fn test_invalid_and_operator() {
1458 let src = "all() && none()";
1459 let mut errors = parse_err(src);
1460 assert_eq!(1, errors.len());
1461 let error = errors.remove(0);
1462 assert_error!(error, InvalidAndOperator, 6, 2);
1463
1464 let src = "all() AND none()";
1465 let mut errors = parse_err(src);
1466 assert_eq!(1, errors.len());
1467 let error = errors.remove(0);
1468 assert_error!(error, InvalidAndOperator, 6, 4);
1469 }
1470
1471 #[test]
1472 fn test_invalid_or_operator() {
1473 let src = "all() || none()";
1474 let mut errors = parse_err(src);
1475 assert_eq!(1, errors.len());
1476 let error = errors.remove(0);
1477 assert_error!(error, InvalidOrOperator, 6, 2);
1478
1479 let src = "all() OR none()";
1480 let mut errors = parse_err(src);
1481 assert_eq!(1, errors.len());
1482 let error = errors.remove(0);
1483 assert_error!(error, InvalidOrOperator, 6, 3);
1484 }
1485
1486 #[test]
1487 fn test_missing_close_parentheses() {
1488 let src = "all(";
1489 let mut errors = parse_err(src);
1490 assert_eq!(1, errors.len());
1491 let error = errors.remove(0);
1492 assert_error!(error, ExpectedCloseParenthesis, 4, 0);
1493 }
1494
1495 #[test]
1496 fn test_missing_open_parentheses() {
1497 let src = "all)";
1498 let mut errors = parse_err(src);
1499 assert_eq!(1, errors.len());
1500 let error = errors.remove(0);
1501 assert_error!(error, ExpectedOpenParenthesis, 3, 0);
1502 }
1503
1504 #[test]
1505 fn test_missing_parentheses() {
1506 let src = "all";
1507 let mut errors = parse_err(src);
1508 assert_eq!(2, errors.len());
1509 let error = errors.remove(0);
1510 assert_error!(error, ExpectedOpenParenthesis, 3, 0);
1511 let error = errors.remove(0);
1512 assert_error!(error, ExpectedCloseParenthesis, 3, 0);
1513 }
1514
1515 #[test]
1516 fn test_invalid_escapes() {
1517 let src = r"package(foobar\$\#\@baz)";
1518 let mut errors = parse_err(src);
1519 assert_eq!(3, errors.len());
1520
1521 let error = errors.remove(0);
1523 assert_error!(error, InvalidEscapeCharacter, 14, 2);
1524
1525 let error = errors.remove(0);
1526 assert_error!(error, InvalidEscapeCharacter, 16, 2);
1527
1528 let error = errors.remove(0);
1529 assert_error!(error, InvalidEscapeCharacter, 18, 2);
1530 }
1531
1532 #[test]
1533 fn test_invalid_regex() {
1534 let src = "package(/)/)";
1535 let mut errors = parse_err(src);
1536 assert_eq!(1, errors.len());
1537 let error = errors.remove(0);
1538 assert!(
1539 matches!(error, ParseSingleError::InvalidRegex { span, .. } if span == (9, 1).into())
1540 );
1541
1542 let src = "package(/foo(ab/)";
1544 let mut errors = parse_err(src);
1545 assert_eq!(1, errors.len());
1546 let error = errors.remove(0);
1547 let (span, message) = match error {
1548 ParseSingleError::InvalidRegex { span, message } => (span, message),
1549 other => panic!("expected invalid regex with details, found {other}"),
1550 };
1551 assert_eq!(span, (12, 1).into(), "span matches");
1552 assert_eq!(message, "unclosed group");
1553 }
1554
1555 #[test]
1556 fn test_invalid_glob() {
1557 let src = "package(#)";
1558 let mut errors = parse_err(src);
1559 assert_eq!(1, errors.len());
1560 let error = errors.remove(0);
1561 assert_error!(error, InvalidString, 9, 0);
1562
1563 let src = "package(#foo[)";
1564 let mut errors = parse_err(src);
1565 assert_eq!(1, errors.len());
1566 let error = errors.remove(0);
1567 let (span, error) = match error {
1568 ParseSingleError::InvalidGlob { span, error } => (span, error),
1569 other => panic!("expected InvalidGlob with details, found {other}"),
1570 };
1571 assert_eq!(span, (9, 4).into(), "span matches");
1572 assert_eq!(error.to_string(), "unclosed character class; missing ']'");
1573 }
1574
1575 #[test]
1576 fn test_invalid_platform() {
1577 let src = "platform(foo)";
1578 let mut errors = parse_err(src);
1579 assert_eq!(1, errors.len());
1580 let error = errors.remove(0);
1581 assert_error!(error, InvalidPlatformArgument, 9, 3);
1582
1583 let src = "platform( bar\\t)";
1584 let mut errors = parse_err(src);
1585 assert_eq!(1, errors.len());
1586 let error = errors.remove(0);
1587 assert_error!(error, InvalidPlatformArgument, 9, 8);
1588 }
1589
1590 #[test]
1591 fn test_missing_close_regex() {
1592 let src = "package(/aaa)";
1593 let mut errors = parse_err(src);
1594 assert_eq!(1, errors.len());
1595 let error = errors.remove(0);
1596 assert_error!(error, ExpectedCloseRegex, 12, 0);
1597 }
1598
1599 #[test]
1600 fn test_unexpected_argument() {
1601 let src = "all(aaa)";
1602 let mut errors = parse_err(src);
1603 assert_eq!(1, errors.len());
1604 let error = errors.remove(0);
1605 assert_error!(error, UnexpectedArgument, 4, 3);
1606 }
1607
1608 #[test]
1609 fn test_expected_expr() {
1610 let src = "all() + ";
1611 let mut errors = parse_err(src);
1612 assert_eq!(1, errors.len());
1613 let error = errors.remove(0);
1614 assert_error!(error, ExpectedExpr, 7, 1);
1615 }
1616
1617 #[test]
1618 fn test_expected_eof() {
1619 let src = "all() blabla";
1620 let mut errors = parse_err(src);
1621 assert_eq!(1, errors.len());
1622 let error = errors.remove(0);
1623 assert_error!(error, ExpectedEndOfExpression, 5, 7);
1624 }
1625
1626 #[test]
1627 fn test_missing_argument() {
1628 let src = "test()";
1629 let mut errors = parse_err(src);
1630 assert_eq!(1, errors.len());
1631 let error = errors.remove(0);
1632 assert_error!(error, InvalidString, 5, 0);
1633 }
1634
1635 #[test]
1636 fn test_unexpected_comma() {
1637 let src = "test(aa, )";
1638 let mut errors = parse_err(src);
1639 assert_eq!(1, errors.len());
1640 let error = errors.remove(0);
1641 assert_error!(error, UnexpectedComma, 7, 0);
1642 }
1643
1644 #[test]
1645 fn test_complex_error() {
1646 let src = "all) + package(/not) - deps(expr none)";
1647 let mut errors = parse_err(src);
1648 assert_eq!(2, errors.len(), "{errors:?}");
1649 let error = errors.remove(0);
1650 assert_error!(error, ExpectedOpenParenthesis, 3, 0);
1651 let error = errors.remove(0);
1652 assert_error!(error, ExpectedCloseRegex, 19, 0);
1653 }
1654
1655 #[test_strategy::proptest]
1656 fn proptest_expr_roundtrip(#[strategy(ParsedExpr::strategy())] expr: ParsedExpr<()>) {
1657 let expr_string = expr.to_string();
1658 eprintln!("expr string: {expr_string}");
1659 let expr_2 = parse(&expr_string).drop_source_span();
1660
1661 assert_eq!(expr, expr_2, "exprs must roundtrip");
1662 }
1663
1664 #[track_caller]
1665 fn assert_eq_both_ways(expr: &ParsedExpr, string: &str) {
1666 assert_eq!(expr, &parse(string));
1667 assert_eq!(format!("{expr}"), string);
1668 }
1669}