use miette::{Diagnostic, SourceSpan};
use nom_tracable::TracableInfo;
use std::cell::RefCell;
use thiserror::Error;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct FilterExpressionParseErrors {
pub input: String,
pub errors: Vec<ParseSingleError>,
}
impl FilterExpressionParseErrors {
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 regex")]
InvalidRegexWithoutMessage(#[label("invalid regex")] SourceSpan),
#[error("expected close regex")]
ExpectedCloseRegex(#[label("missing `/`")] 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("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(Debug, Clone)]
pub(crate) struct State<'a> {
errors: &'a RefCell<Vec<ParseSingleError>>,
tracable_info: TracableInfo,
}
impl<'a> State<'a> {
pub fn new(errors: &'a RefCell<Vec<ParseSingleError>>) -> Self {
let tracable_info = nom_tracable::TracableInfo::new()
.forward(true)
.backward(true);
Self {
errors,
tracable_info,
}
}
pub fn report_error(&self, error: ParseSingleError) {
self.errors.borrow_mut().push(error);
}
}
impl<'a> nom_tracable::HasTracableInfo for State<'a> {
fn get_tracable_info(&self) -> TracableInfo {
self.tracable_info.get_tracable_info()
}
fn set_tracable_info(mut self, info: TracableInfo) -> Self {
self.tracable_info = self.tracable_info.set_tracable_info(info);
self
}
}
pub(crate) trait ToSourceSpan {
fn to_span(&self) -> SourceSpan;
}