From e23af286b81f4c9df0e0ca9d71113caeb909cb0f Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 12 Jun 2020 13:21:35 +0200 Subject: implement count(player: ...) construct --- src/fexpr/grammar.lalrpop | 9 +++++++++ src/fexpr/mod.rs | 1 + src/filters/values.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/fexpr/grammar.lalrpop b/src/fexpr/grammar.lalrpop index 9584536..9eef21a 100644 --- a/src/fexpr/grammar.lalrpop +++ b/src/fexpr/grammar.lalrpop @@ -7,6 +7,7 @@ use super::{ DateProducer, DurationProducer, + CountProducer, }; use evtclib::Boss; use std::collections::HashSet; @@ -73,6 +74,7 @@ LogPredicate: Box = { >, >, + >, "(" ")", } @@ -215,6 +217,11 @@ DurationProducer: Box = { "-duration" => filters::values::duration(), } +CountProducer: Box = { + => filters::values::constant(<>.parse().unwrap()), + "count" "(" "player" ":" ")" => filters::values::player_count(<>), +} + match { "player" => "player", "not" => "not", @@ -223,10 +230,12 @@ match { "any" => "any", "all" => "all", "exists" => "exists", + "count" => "count", 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"((\d+m ?)?\d+s)|(\d+m)" => duration, + r"\d+" => integer, r"[[:alpha:]][\w]*" => word, r#""[^"]*""# => string, diff --git a/src/fexpr/mod.rs b/src/fexpr/mod.rs index 1738e44..f765acf 100644 --- a/src/fexpr/mod.rs +++ b/src/fexpr/mod.rs @@ -13,6 +13,7 @@ use thiserror::Error; trait DateProducer = filters::values::Producer>; trait DurationProducer = filters::values::Producer; +trait CountProducer = filters::values::Producer; lalrpop_mod!(#[allow(clippy::all)] pub grammar, "/fexpr/grammar.rs"); diff --git a/src/filters/values.rs b/src/filters/values.rs index 141aecd..df5b805 100644 --- a/src/filters/values.rs +++ b/src/filters/values.rs @@ -13,12 +13,14 @@ //! the two resulting values with the given comparison operator. use std::{ cmp::Ordering, + convert::TryFrom, fmt::{self, Debug}, }; use chrono::{DateTime, Duration, Utc}; +use evtclib::Agent; -use super::{log::LogFilter, Filter, Inclusion}; +use super::{log::LogFilter, player::PlayerFilter, Filter, Inclusion}; use crate::{EarlyLogResult, LogResult}; /// A producer for a given value. @@ -194,6 +196,44 @@ pub fn duration() -> Box> { Box::new(DurationProducer) } +#[derive(Debug)] +struct PlayerCountProducer(Box); + +impl Producer for PlayerCountProducer { + type Output = u8; + + fn produce_early(&self, early_log: &EarlyLogResult) -> Option { + let mut count = 0; + for agent in &early_log.evtc.agents { + if !agent.is_player() { + continue; + } + + let agent = Agent::try_from(agent); + if let Ok(agent) = agent { + let result = self.0.filter_early(&agent); + match result { + Inclusion::Include => count += 1, + Inclusion::Exclude => (), + Inclusion::Unknown => return None, + } + } else { + return None; + } + } + Some(count) + } + + fn produce(&self, log: &LogResult) -> Self::Output { + log.players.iter().filter(|p| self.0.filter(p)).count() as u8 + } +} + +/// A producer that counts the players matching the given filter. +pub fn player_count(filter: Box) -> Box> { + Box::new(PlayerCountProducer(filter)) +} + #[cfg(test)] mod tests { use super::*; -- cgit v1.2.3