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