1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
use super::{
FError,
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:Conjunction<T>> "or" <b:Conjunction<T>> => a | b,
Conjunction<T>,
}
Conjunction<T>: T = {
<a:Negation<T>> "and"? <b:Negation<T>> => a & b,
Negation<T>,
}
Negation<T>: T = {
"not" <T> => ! <>,
"!" <T> => ! <>,
T,
}
LogPredicate: Box<dyn filters::log::LogFilter> = {
"-success" => filters::log::OutcomeFilter::success(),
"-wipe" => filters::log::OutcomeFilter::wipe(),
"-outcome" <Comma<FightOutcome>> => filters::log::OutcomeFilter::new(<>),
"-weekday" <Comma<Weekday>> => filters::log::WeekdayFilter::new(<>),
"-before" <Date> => filters::log::TimeFilter::new(None, Some(<>)),
"-after" <Date> => filters::log::TimeFilter::new(Some(<>), None),
"-boss" <Comma<Boss>> => filters::log::BossFilter::new(<>),
"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::NameFilter::new(SearchField::Character, <>),
"-account" <Regex> => filters::player::NameFilter::new(SearchField::Account, <>),
"-name" <Regex> =>
filters::player::NameFilter::new(SearchField::Account, <>.clone())
| filters::player::NameFilter::new(SearchField::Character, <>),
"(" <PlayerFilter> ")",
}
Regex: Regex = {
<s:r#""[^"]*""#> =>? Regex::new(&s[1..s.len() - 1]).map_err(|_| ParseError::User {
error: FError::InvalidRegex(s.into()),
}),
<s:word> =>? Regex::new(s).map_err(|e| ParseError::User {
error: FError::InvalidRegex(s.into()),
}),
}
FightOutcome: FightOutcome = {
<word> =>? <>.parse().map_err(|_| ParseError::User {
error: FError::InvalidFightOutcome(<>.into()),
}),
}
Weekday: Weekday = {
<word> =>? <>.parse().map_err(|_| ParseError::User {
error: FError::InvalidWeekday(<>.into()),
}),
}
Boss: Boss = {
<word> =>? <>.parse().map_err(|_| ParseError::User {
error: FError::InvalidBoss(<>.into()),
}),
}
Date: NaiveDateTime = {
<datetime> =>? NaiveDateTime::parse_from_str(<>, "%Y-%m-%d %H:%M:%S")
.map_err(|_| ParseError::User {
error: FError::InvalidTimestamp(<>.into()),
}),
<date> =>? NaiveDateTime::parse_from_str(&format!("{} 00:00:00", <>), "%Y-%m-%d %H:%M:%S")
.map_err(|_| ParseError::User {
error: FError::InvalidTimestamp(<>.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",
"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,
_
}
|