1use std::{error::Error, fmt};
2
3/// An error related to parsing of a cfg expression
4#[derive(Debug, PartialEq, Eq)]
5pub struct ParseError {
6 /// The string that was parsed
7 pub original: String,
8 /// The range of characters in the original string that result
9 /// in this error
10 pub span: std::ops::Range<usize>,
11 /// The specific reason for the error
12 pub reason: Reason,
13}
14
15/// The particular reason for a `ParseError`
16#[derive(Debug, PartialEq, Eq)]
17pub enum Reason {
18 /// not() takes exactly 1 predicate, unlike all() and any()
19 InvalidNot(usize),
20 /// The characters are not valid in an cfg expression
21 InvalidCharacters,
22 /// An opening parens was unmatched with a closing parens
23 UnclosedParens,
24 /// A closing parens was unmatched with an opening parens
25 UnopenedParens,
26 /// An opening quotes was unmatched with a closing quotes
27 UnclosedQuotes,
28 /// A closing quotes was unmatched with an opening quotes
29 UnopenedQuotes,
30 /// The expression does not contain any valid terms
31 Empty,
32 /// Found an unexpected term, which wasn't one of the expected terms that
33 /// is listed
34 Unexpected(&'static [&'static str]),
35 /// Failed to parse an integer value
36 InvalidInteger,
37 /// The root cfg() may only contain a single predicate
38 MultipleRootPredicates,
39 /// A `target_has_atomic` predicate didn't correctly parse.
40 InvalidHasAtomic,
41 /// An element was not part of the builtin information in rustc
42 UnknownBuiltin,
43}
44
45impl fmt::Display for ParseError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.write_str(&self.original)?;
48 f.write_str("\n")?;
49
50 for _ in 0..self.span.start {
51 f.write_str(" ")?;
52 }
53
54 // Mismatched parens/quotes have a slightly different output
55 // than the other errors
56 match &self.reason {
57 r @ (Reason::UnclosedParens | Reason::UnclosedQuotes) => {
58 f.write_fmt(format_args!("- {r}"))
59 }
60 r @ (Reason::UnopenedParens | Reason::UnopenedQuotes) => {
61 f.write_fmt(format_args!("^ {r}"))
62 }
63 other => {
64 for _ in self.span.start..self.span.end {
65 f.write_str("^")?;
66 }
67
68 f.write_fmt(format_args!(" {other}"))
69 }
70 }
71 }
72}
73
74impl fmt::Display for Reason {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 use Reason::{
77 Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot,
78 MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin,
79 UnopenedParens, UnopenedQuotes,
80 };
81
82 match self {
83 InvalidCharacters => f.write_str("invalid character(s)"),
84 UnclosedParens => f.write_str("unclosed parens"),
85 UnopenedParens => f.write_str("unopened parens"),
86 UnclosedQuotes => f.write_str("unclosed quotes"),
87 UnopenedQuotes => f.write_str("unopened quotes"),
88 Empty => f.write_str("empty expression"),
89 Unexpected(expected) => {
90 if expected.len() > 1 {
91 f.write_str("expected one of ")?;
92
93 for (i, exp) in expected.iter().enumerate() {
94 f.write_fmt(format_args!("{}`{exp}`", if i > 0 { ", " } else { "" }))?;
95 }
96 f.write_str(" here")
97 } else if !expected.is_empty() {
98 f.write_fmt(format_args!("expected a `{}` here", expected[0]))
99 } else {
100 f.write_str("the term was not expected here")
101 }
102 }
103 InvalidNot(np) => f.write_fmt(format_args!("not() takes 1 predicate, found {np}")),
104 InvalidInteger => f.write_str("invalid integer"),
105 MultipleRootPredicates => f.write_str("multiple root predicates"),
106 InvalidHasAtomic => f.write_str("expected integer or \"ptr\""),
107 UnknownBuiltin => f.write_str("unknown built-in"),
108 }
109 }
110}
111
112impl Error for ParseError {
113 fn description(&self) -> &str {
114 use Reason::{
115 Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot,
116 MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin,
117 UnopenedParens, UnopenedQuotes,
118 };
119
120 match self.reason {
121 InvalidCharacters => "invalid character(s)",
122 UnclosedParens => "unclosed parens",
123 UnopenedParens => "unopened parens",
124 UnclosedQuotes => "unclosed quotes",
125 UnopenedQuotes => "unopened quotes",
126 Empty => "empty expression",
127 Unexpected(_) => "unexpected term",
128 InvalidNot(_) => "not() takes 1 predicate",
129 InvalidInteger => "invalid integer",
130 MultipleRootPredicates => "multiple root predicates",
131 InvalidHasAtomic => "expected integer or \"ptr\"",
132 UnknownBuiltin => "unknown built-in",
133 }
134 }
135}
136
137/// Error parsing a `target_has_atomic` predicate.
138#[derive(Clone, Debug, Eq, PartialEq)]
139pub struct HasAtomicParseError {
140 pub(crate) input: String,
141}
142
143impl fmt::Display for HasAtomicParseError {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "expected integer or \"ptr\", found {}", self.input)
146 }
147}
148
149impl Error for HasAtomicParseError {}
150