use super::{ FError, FErrorKind, FightOutcome, filters, PlayerClass, }; use evtclib::Boss; use std::collections::HashSet; use lalrpop_util::ParseError; use chrono::{DateTime, Local, TimeZone, Utc, Weekday}; use regex::{Regex, RegexBuilder}; grammar; extern { type Error = FError; } pub LogFilter: Box = { Disjunction, } PlayerFilter: Box = { Disjunction, } Disjunction: T = { > "or" > => a | b, Conjunction, } Conjunction: T = { > "and"? > => a & b, Negation, } Negation: T = { "not" > => ! <>, "!" > => ! <>, T, } LogPredicate: Box = { "-success" => filters::log::success(), "-wipe" => filters::log::wipe(), "-outcome" > => filters::log::outcome(<>), "-weekday" > => filters::log::weekday(<>), "-before" => filters::log::before(<>), "-after" => filters::log::after(<>), "-log-before" => filters::log::log_before(<>), "-log-after" => filters::log::log_after(<>), "-boss" > => filters::log::boss(<>), "-cm" => filters::log::challenge_mote(), "-include" => filters::constant(true), "-exclude" => filters::constant(false), "-player" => filters::player::any( filters::player::character(<>.clone()) | filters::player::account(<>) ), "all" "(" "player" ":" ")" => filters::player::all(<>), "any" "(" "player" ":" ")" => filters::player::any(<>), "exists" "(" "player" ":" ")" => filters::player::any(<>), "(" ")", } PlayerPredicate: Box = { "-character" => filters::player::character(<>), "-account" => filters::player::account(<>), "-name" => filters::player::account(<>.clone()) | filters::player::character(<>), "-class" > => filters::player::class(<>), "(" ")", } Regex: Regex = { =>? RegexBuilder::new(&s[1..s.len() - 1]) .case_insensitive(true) .build() .map_err(|error| ParseError::User { error: FError { location: l, data: s.to_string(), kind: error.into(), } }), =>? RegexBuilder::new(s) .case_insensitive(true) .build() .map_err(|error| ParseError::User { error: FError { location: l, data: s.to_string(), kind: error.into(), } }), } FightOutcome: FightOutcome = { =>? w.parse().map_err(|_| ParseError::User { error: FError { location: l, data: w.into(), kind: FErrorKind::InvalidFightOutcome, } }), } Weekday: Weekday = { =>? w.parse().map_err(|_| ParseError::User { error: FError { location: l, data: w.into(), kind: FErrorKind::InvalidWeekday, } }), } Boss: Boss = { =>? w.parse().map_err(|_| ParseError::User { error: FError { location: l, data: w.into(), kind: FErrorKind::InvalidBoss, } }), =>? s[1..s.len() -1].parse().map_err(|_| ParseError::User { error: FError { location: l, data: s.into(), kind: FErrorKind::InvalidBoss, } }), } PlayerClass: PlayerClass = { =>? w.parse().map_err(|_| ParseError::User { error: FError { location: l, data: w.into(), kind: FErrorKind::InvalidClass, } }), } Date: DateTime = { =>? Local.datetime_from_str(d, "%Y-%m-%d %H:%M:%S") .map_err(|error| ParseError::User { error: FError { location: l, data: d.into(), kind: error.into(), } }) .map(|d| d.with_timezone(&Utc)), =>? Local.datetime_from_str(&format!("{} 00:00:00", d), "%Y-%m-%d %H:%M:%S") .map_err(|error| ParseError::User { error: FError { location: l, data: d.into(), kind: error.into(), } }) .map(|d| d.with_timezone(&Utc)), } Comma: HashSet = { ",")*> => { let mut result = v.into_iter().collect::>(); result.insert(e); result }, } match { "player" => "player", "not" => "not", "or" => "or", "and" => "and", "any" => "any", "all" => "all", "exists" => "exists", r"\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d" => datetime, r"\d\d\d\d-\d\d-\d\d" => date, r"[\w]+" => word, r#""[^"]*""# => string, _ }