| use std::{error::Error, fmt}; |
| |
| /// An error related to parsing of a cfg expression |
| #[derive(Debug, PartialEq, Eq)] |
| pub struct ParseError { |
| /// The string that was parsed |
| pub original: String, |
| /// The range of characters in the original string that result |
| /// in this error |
| pub span: std::ops::Range<usize>, |
| /// The specific reason for the error |
| pub reason: Reason, |
| } |
| |
| /// The particular reason for a `ParseError` |
| #[derive(Debug, PartialEq, Eq)] |
| pub enum Reason { |
| /// `not()` takes exactly 1 predicate, unlike `all()` and `any()` |
| InvalidNot(usize), |
| /// The characters are not valid in an cfg expression |
| InvalidCharacters, |
| /// An opening parens was unmatched with a closing parens |
| UnclosedParens, |
| /// A closing parens was unmatched with an opening parens |
| UnopenedParens, |
| /// An opening quotes was unmatched with a closing quotes |
| UnclosedQuotes, |
| /// A closing quotes was unmatched with an opening quotes |
| UnopenedQuotes, |
| /// The expression does not contain any valid terms |
| Empty, |
| /// Found an unexpected term, which wasn't one of the expected terms that |
| /// is listed |
| Unexpected(&'static [&'static str]), |
| /// Failed to parse an integer value |
| InvalidInteger, |
| /// The root `cfg()` may only contain a single predicate |
| MultipleRootPredicates, |
| /// A `target_has_atomic` predicate didn't correctly parse. |
| InvalidHasAtomic, |
| /// An element was not part of the builtin information in rustc |
| UnknownBuiltin, |
| } |
| |
| impl fmt::Display for ParseError { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| f.write_str(&self.original)?; |
| f.write_str("\n")?; |
| |
| for _ in 0..self.span.start { |
| f.write_str(" ")?; |
| } |
| |
| // Mismatched parens/quotes have a slightly different output |
| // than the other errors |
| match &self.reason { |
| r @ (Reason::UnclosedParens | Reason::UnclosedQuotes) => { |
| f.write_fmt(format_args!("- {r}")) |
| } |
| r @ (Reason::UnopenedParens | Reason::UnopenedQuotes) => { |
| f.write_fmt(format_args!("^ {r}")) |
| } |
| other => { |
| for _ in self.span.start..self.span.end { |
| f.write_str("^")?; |
| } |
| |
| f.write_fmt(format_args!(" {other}")) |
| } |
| } |
| } |
| } |
| |
| impl fmt::Display for Reason { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| use Reason::{ |
| Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot, |
| MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin, |
| UnopenedParens, UnopenedQuotes, |
| }; |
| |
| match self { |
| InvalidCharacters => f.write_str("invalid character(s)"), |
| UnclosedParens => f.write_str("unclosed parens"), |
| UnopenedParens => f.write_str("unopened parens"), |
| UnclosedQuotes => f.write_str("unclosed quotes"), |
| UnopenedQuotes => f.write_str("unopened quotes"), |
| Empty => f.write_str("empty expression"), |
| Unexpected(expected) => { |
| if expected.len() > 1 { |
| f.write_str("expected one of ")?; |
| |
| for (i, exp) in expected.iter().enumerate() { |
| f.write_fmt(format_args!("{}`{exp}`", if i > 0 { ", " } else { "" }))?; |
| } |
| f.write_str(" here") |
| } else if !expected.is_empty() { |
| f.write_fmt(format_args!("expected a `{}` here", expected[0])) |
| } else { |
| f.write_str("the term was not expected here") |
| } |
| } |
| InvalidNot(np) => f.write_fmt(format_args!("not() takes 1 predicate, found {np}")), |
| InvalidInteger => f.write_str("invalid integer"), |
| MultipleRootPredicates => f.write_str("multiple root predicates"), |
| InvalidHasAtomic => f.write_str("expected integer or \"ptr\""), |
| UnknownBuiltin => f.write_str("unknown built-in"), |
| } |
| } |
| } |
| |
| impl Error for ParseError { |
| fn description(&self) -> &str { |
| use Reason::{ |
| Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot, |
| MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin, |
| UnopenedParens, UnopenedQuotes, |
| }; |
| |
| match self.reason { |
| InvalidCharacters => "invalid character(s)", |
| UnclosedParens => "unclosed parens", |
| UnopenedParens => "unopened parens", |
| UnclosedQuotes => "unclosed quotes", |
| UnopenedQuotes => "unopened quotes", |
| Empty => "empty expression", |
| Unexpected(_) => "unexpected term", |
| InvalidNot(_) => "not() takes 1 predicate", |
| InvalidInteger => "invalid integer", |
| MultipleRootPredicates => "multiple root predicates", |
| InvalidHasAtomic => "expected integer or \"ptr\"", |
| UnknownBuiltin => "unknown built-in", |
| } |
| } |
| } |
| |
| /// Error parsing a `target_has_atomic` predicate. |
| #[derive(Clone, Debug, Eq, PartialEq)] |
| pub struct HasAtomicParseError { |
| pub(crate) input: String, |
| } |
| |
| impl fmt::Display for HasAtomicParseError { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(f, "expected integer or \"ptr\", found {}", self.input) |
| } |
| } |
| |
| impl Error for HasAtomicParseError {} |