//! Filter expression language. //! //! This module contains methods to parse a given string into an abstract filter tree, check its //! type and convert it to a [`Filter`][super::filters::Filter]. // Make it available in the grammar mod. use super::{filters, FightOutcome, SearchField}; use std::{error, fmt}; use lalrpop_util::{lalrpop_mod, lexer::Token, ParseError}; use thiserror::Error; lalrpop_mod!(#[allow(clippy::all)] pub grammar, "/fexpr/grammar.rs"); #[derive(Debug)] pub struct FError { location: usize, data: String, kind: FErrorKind, } impl fmt::Display for FError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} (at {})", self.kind, self.location) } } impl error::Error for FError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(&self.kind) } } #[derive(Debug, Error)] pub enum FErrorKind { #[error("invalid regular expression: {0}")] InvalidRegex(#[from] regex::Error), #[error("invalid fight outcome")] InvalidFightOutcome, #[error("invalid weekday")] InvalidWeekday, #[error("invalid timestamp: {0}")] InvalidTimestamp(#[from] chrono::format::ParseError), #[error("invalid boss name")] InvalidBoss, } /// Shortcut to create a new parser and parse the given input. pub fn parse_logfilter<'a>( input: &'a str, ) -> Result, ParseError, FError>> { grammar::LogFilterParser::new().parse(input) } /// Extract the location from the given error. pub fn location(err: &ParseError) -> usize { match *err { ParseError::InvalidToken { location } => location, ParseError::UnrecognizedEOF { location, .. } => location, ParseError::UnrecognizedToken { token: (l, _, _), .. } => l, ParseError::ExtraToken { token: (l, _, _) } => l, ParseError::User { ref error } => error.location, } }