aboutsummaryrefslogtreecommitdiff
path: root/src/fexpr/grammar.lalrpop
diff options
context:
space:
mode:
authorDaniel <kingdread@gmx.de>2020-04-26 11:45:37 +0200
committerDaniel <kingdread@gmx.de>2020-04-26 11:45:37 +0200
commit13053073e3336b8e6ffefd6a056d159239550be7 (patch)
tree63544e8764b55563a48d3f9fd530b0381f42a277 /src/fexpr/grammar.lalrpop
parent3c429432382dfad6d4ac97349c96e4a4eb292089 (diff)
parent9bbd5db2a6caae10f0ab2cf2625fbc34485a4ce9 (diff)
downloadraidgrep-13053073e3336b8e6ffefd6a056d159239550be7.tar.gz
raidgrep-13053073e3336b8e6ffefd6a056d159239550be7.tar.bz2
raidgrep-13053073e3336b8e6ffefd6a056d159239550be7.zip
Merge branch 'new-filters'
The new filter system (includes both the internal rewrite and the command line parsing) is now being included in master. This gives a lot more flexibility.
Diffstat (limited to 'src/fexpr/grammar.lalrpop')
-rw-r--r--src/fexpr/grammar.lalrpop171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/fexpr/grammar.lalrpop b/src/fexpr/grammar.lalrpop
new file mode 100644
index 0000000..58ec052
--- /dev/null
+++ b/src/fexpr/grammar.lalrpop
@@ -0,0 +1,171 @@
+use super::{
+ FError,
+ FErrorKind,
+ FightOutcome,
+ filters,
+ SearchField,
+ Weekday,
+};
+use evtclib::statistics::gamedata::Boss;
+use std::collections::HashSet;
+use lalrpop_util::ParseError;
+
+use chrono::NaiveDateTime;
+use regex::Regex;
+
+grammar;
+
+extern {
+ type Error = FError;
+}
+
+pub LogFilter: Box<dyn filters::log::LogFilter> = {
+ Disjunction<LogPredicate>,
+}
+
+PlayerFilter: Box<dyn filters::player::PlayerFilter> = {
+ Disjunction<PlayerPredicate>,
+}
+
+Disjunction<T>: T = {
+ <a:Disjunction<T>> "or" <b:Conjunction<T>> => a | b,
+ Conjunction<T>,
+}
+
+Conjunction<T>: T = {
+ <a:Conjunction<T>> "and"? <b:Negation<T>> => a & b,
+ Negation<T>,
+}
+
+Negation<T>: T = {
+ "not" <Negation<T>> => ! <>,
+ "!" <Negation<T>> => ! <>,
+ T,
+}
+
+LogPredicate: Box<dyn filters::log::LogFilter> = {
+ "-success" => filters::log::success(),
+ "-wipe" => filters::log::wipe(),
+ "-outcome" <Comma<FightOutcome>> => filters::log::outcome(<>),
+
+ "-weekday" <Comma<Weekday>> => filters::log::weekday(<>),
+ "-before" <Date> => filters::log::before(<>),
+ "-after" <Date> => filters::log::after(<>),
+
+ "-boss" <Comma<Boss>> => filters::log::boss(<>),
+
+ "-include" => filters::constant(true),
+ "-exclude" => filters::constant(false),
+
+ "-player" <Regex> => filters::player::any(
+ filters::player::character(<>.clone())
+ | filters::player::account(<>)
+ ),
+
+ "all" "(" "player" ":" <PlayerFilter> ")" => filters::player::all(<>),
+ "any" "(" "player" ":" <PlayerFilter> ")" => filters::player::any(<>),
+ "exists" "(" "player" ":" <PlayerFilter> ")" => filters::player::any(<>),
+
+ "(" <LogFilter> ")",
+}
+
+PlayerPredicate: Box<dyn filters::player::PlayerFilter> = {
+ "-character" <Regex> => filters::player::character(<>),
+ "-account" <Regex> => filters::player::account(<>),
+ "-name" <Regex> =>
+ filters::player::account(<>.clone())
+ | filters::player::character(<>),
+
+ "(" <PlayerFilter> ")",
+}
+
+Regex: Regex = {
+ <l:@L> <s:regex> =>? Regex::new(&s[1..s.len() - 1]).map_err(|error| ParseError::User {
+ error: FError {
+ location: l,
+ data: s.to_string(),
+ kind: error.into(),
+ }
+ }),
+ <l:@L> <s:word> =>? Regex::new(s).map_err(|error| ParseError::User {
+ error: FError {
+ location: l,
+ data: s.to_string(),
+ kind: error.into(),
+ }
+ }),
+}
+
+FightOutcome: FightOutcome = {
+ <l:@L> <w:word> =>? w.parse().map_err(|_| ParseError::User {
+ error: FError {
+ location: l,
+ data: w.into(),
+ kind: FErrorKind::InvalidFightOutcome,
+ }
+ }),
+}
+
+Weekday: Weekday = {
+ <l:@L> <w:word> =>? w.parse().map_err(|_| ParseError::User {
+ error: FError {
+ location: l,
+ data: w.into(),
+ kind: FErrorKind::InvalidWeekday,
+ }
+ }),
+}
+
+Boss: Boss = {
+ <l:@L> <w:word> =>? w.parse().map_err(|_| ParseError::User {
+ error: FError {
+ location: l,
+ data: w.into(),
+ kind: FErrorKind::InvalidBoss,
+ }
+ }),
+}
+
+Date: NaiveDateTime = {
+ <l:@L> <d:datetime> =>? NaiveDateTime::parse_from_str(d, "%Y-%m-%d %H:%M:%S")
+ .map_err(|error| ParseError::User {
+ error: FError {
+ location: l,
+ data: d.into(),
+ kind: error.into(),
+ }
+ }),
+ <l:@L> <d:date> =>? NaiveDateTime::parse_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(),
+ }
+ }),
+}
+
+Comma<T>: HashSet<T> = {
+ <v:(<T> ",")*> <e:T> => {
+ let mut result = v.into_iter().collect::<HashSet<_>>();
+ 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#""[^"]*""# => regex,
+
+ _
+}