blob: 87cd11d3464c85c7135b9bc9b813bc408a862c23 [file] [log] [blame]
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 {}