use crate::expression::FiltersetKind;
use miette::{Diagnostic, SourceSpan};
use std::fmt;
use thiserror::Error;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct FiltersetParseErrors {
pub input: String,
pub errors: Vec<ParseSingleError>,
}
impl FiltersetParseErrors {
pub(crate) fn new(input: impl Into<String>, errors: Vec<ParseSingleError>) -> Self {
Self {
input: input.into(),
errors,
}
}
}
#[derive(Clone, Debug, Error, Diagnostic, PartialEq, Eq)]
#[non_exhaustive]
pub enum ParseSingleError {
#[error("invalid regex")]
InvalidRegex {
#[label("{}", message)]
span: SourceSpan,
message: String,
},
#[error("invalid glob")]
InvalidGlob {
#[label("{}", error)]
span: SourceSpan,
error: GlobConstructError,
},
#[error("predicate not allowed in `{kind}` expressions")]
BannedPredicate {
kind: FiltersetKind,
#[label("this predicate causes {reason}")]
span: SourceSpan,
reason: BannedPredicateReason,
},
#[error("invalid regex")]
InvalidRegexWithoutMessage(#[label("invalid regex")] SourceSpan),
#[error("expected close regex")]
ExpectedCloseRegex(#[label("missing `/`")] SourceSpan),
#[error("invalid OR operator")]
InvalidOrOperator(#[label("expected `|`, `+`, or `or`")] SourceSpan),
#[error("invalid AND operator")]
InvalidAndOperator(#[label("expected `&` or `and`")] SourceSpan),
#[error("unexpected argument")]
UnexpectedArgument(#[label("this set doesn't take an argument")] SourceSpan),
#[error("unexpected comma")]
UnexpectedComma(#[label("this set doesn't take multiple arguments")] SourceSpan),
#[error("invalid string")]
InvalidString(#[label("invalid string")] SourceSpan),
#[error("expected open parenthesis")]
ExpectedOpenParenthesis(#[label("missing `(`")] SourceSpan),
#[error("expected close parenthesis")]
ExpectedCloseParenthesis(#[label("missing `)`")] SourceSpan),
#[error("invalid escape character")]
InvalidEscapeCharacter(#[label("invalid escape character")] SourceSpan),
#[error("expected expression")]
ExpectedExpr(#[label("missing expression")] SourceSpan),
#[error("expected end of expression")]
ExpectedEndOfExpression(#[label("unparsed input")] SourceSpan),
#[error("operator didn't match any packages")]
NoPackageMatch(#[label("no packages matched this")] SourceSpan),
#[error("invalid argument for platform")]
InvalidPlatformArgument(#[label("expected \"target\" or \"host\"")] SourceSpan),
#[error("unknown parsing error")]
Unknown,
}
impl ParseSingleError {
pub(crate) fn invalid_regex(input: &str, start: usize, end: usize) -> Self {
match regex_syntax::Parser::new().parse(input) {
Ok(_) => {
Self::InvalidRegexWithoutMessage((start, end - start).into())
}
Err(err) => {
let (message, span) = match &err {
regex_syntax::Error::Parse(err) => (format!("{}", err.kind()), err.span()),
regex_syntax::Error::Translate(err) => (format!("{}", err.kind()), err.span()),
_ => return Self::InvalidRegexWithoutMessage((start, end - start).into()),
};
let err_start = start + span.start.offset;
let err_end = start + span.end.offset;
Self::InvalidRegex {
span: (err_start, err_end - err_start).into(),
message,
}
}
}
}
}
#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum GlobConstructError {
#[error("{}", .0.kind())]
InvalidGlob(globset::Error),
#[error("{}", .0)]
RegexError(String),
}
#[derive(Debug)]
pub(crate) struct State<'a> {
errors: &'a mut Vec<ParseSingleError>,
}
impl<'a> State<'a> {
pub fn new(errors: &'a mut Vec<ParseSingleError>) -> Self {
Self { errors }
}
pub fn report_error(&mut self, error: ParseSingleError) {
self.errors.push(error);
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum BannedPredicateReason {
InfiniteRecursion,
}
impl fmt::Display for BannedPredicateReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BannedPredicateReason::InfiniteRecursion => {
write!(f, "infinite recursion")
}
}
}
}