some event parsing

This commit is contained in:
Robin Appelman 2021-08-07 22:07:59 +02:00
commit e83f7928aa
7 changed files with 282 additions and 61 deletions

View file

@ -1,7 +1,5 @@
use crate::event::{param_parse_with, quoted, u_int};
use crate::raw_event::{subject_parser, RawSubject};
use nom::bytes::complete::tag;
use nom::character::complete::digit1;
use nom::error::ErrorKind;
use nom::IResult;
#[derive(Debug)]
@ -11,12 +9,7 @@ pub struct HealedEvent<'a> {
}
pub fn healed_event_parser(input: &str) -> IResult<&str, HealedEvent> {
let (input, _) = tag("against ")(input)?;
let (input, subject) = subject_parser(input)?;
let (input, _) = tag(r#" (healing ""#)(input)?;
let (input, raw_amount) = digit1(input)?;
let amount = raw_amount
.parse()
.map_err(|_| nom::Err::Error(nom::error::Error::new(raw_amount, ErrorKind::Digit)))?;
let (input, subject) = param_parse_with("against", subject_parser)(input)?;
let (input, amount) = param_parse_with("healing", quoted(u_int))(input)?;
Ok((input, HealedEvent { subject, amount }))
}

View file

@ -1,3 +1,104 @@
mod medic;
mod player;
pub use medic::{healed_event_parser, HealedEvent};
pub use medic::*;
use nom::bytes::complete::{tag, take_while};
use nom::character::complete::{alpha1, digit1};
use nom::combinator::opt;
use nom::error::ErrorKind;
use nom::IResult;
pub use player::*;
struct ParamIter<'a> {
input: &'a str,
}
impl<'a> ParamIter<'a> {
pub fn new(input: &'a str) -> Self {
ParamIter { input }
}
}
impl<'a> Iterator for ParamIter<'a> {
type Item = (&'a str, &'a str);
fn next(&mut self) -> Option<Self::Item> {
let (input, res) = param_pair_parse(self.input).ok()?;
self.input = input;
Some(res)
}
}
fn param_pair_parse(input: &str) -> IResult<&str, (&str, &str)> {
let (input, open_tag) = opt(tag("("))(input)?;
let (input, key) = alpha1(input)?;
let (input, _) = tag(r#" ""#)(input)?;
let (input, value) = take_while(|c| c != '"')(input)?;
let (input, _) = tag(r#"""#)(input)?;
if open_tag.is_some() {
let (_input, _) = tag("(")(input)?;
}
Ok((input, (key, value)))
}
fn quoted<'a, T, P: Fn(&'a str) -> IResult<&'a str, T>>(
parser: P,
) -> impl Fn(&'a str) -> IResult<&'a str, T> {
move |input| {
let (input, _) = tag(r#"""#)(input)?;
let (input, res) = parser(input)?;
let (input, _) = tag(r#"""#)(input)?;
Ok((input, res))
}
}
fn param_parse<'a>(key: &'a str) -> impl Fn(&'a str) -> IResult<&'a str, &'a str> {
param_parse_with(key, quoted(take_while(|c| c != '"')))
}
fn param_parse_with<'a, T, P: Fn(&'a str) -> IResult<&'a str, T>>(
key: &'a str,
parser: P,
) -> impl Fn(&'a str) -> IResult<&'a str, T> {
move |input: &str| {
let (input, open_tag) = opt(tag("("))(input)?;
let (input, _) = tag(key)(input)?;
let (input, _) = tag(r#" "#)(input)?;
let (input, value) = parser(input)?;
if open_tag.is_some() {
let (_input, _) = tag(")")(input)?;
}
Ok((input.trim_start(), value))
}
}
fn int(input: &str) -> IResult<&str, i32> {
let (input, sign) = opt(tag("-"))(input)?;
let (input, raw) = digit1(input)?;
let val: i32 = raw
.parse()
.map_err(|_| nom::Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?;
Ok((input, if sign.is_some() { -val } else { val }))
}
fn u_int(input: &str) -> IResult<&str, u32> {
let (input, raw) = digit1(input)?;
let val = raw
.parse()
.map_err(|_| nom::Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?;
Ok((input, val))
}
fn position(input: &str) -> IResult<&str, (i32, i32, i32)> {
let (input, x) = int(input)?;
let (input, _) = tag(" ")(input)?;
let (input, y) = int(input)?;
let (input, _) = tag(" ")(input)?;
let (input, z) = int(input)?;
Ok((input, (x, y, z)))
}

103
src/event/player.rs Normal file
View file

@ -0,0 +1,103 @@
use crate::event::{param_parse, param_parse_with, position, quoted, u_int, ParamIter};
use crate::raw_event::{subject_parser, RawSubject};
use nom::combinator::opt;
use nom::IResult;
use std::num::NonZeroU32;
#[derive(Debug)]
pub struct ShotFiredEvent<'a> {
pub weapon: Option<&'a str>,
}
pub fn shot_fired_event_parser(input: &str) -> IResult<&str, ShotFiredEvent> {
let (input, weapon) = opt(param_parse("weapon"))(input)?;
Ok((input, ShotFiredEvent { weapon }))
}
#[derive(Debug)]
pub struct ShotHitEvent<'a> {
pub weapon: Option<&'a str>,
}
pub fn shot_hit_event_parser(input: &str) -> IResult<&str, ShotFiredEvent> {
let (input, weapon) = opt(param_parse("weapon"))(input)?;
Ok((input, ShotFiredEvent { weapon }))
}
#[derive(Debug)]
pub struct DamageEvent<'a> {
pub target: RawSubject<'a>,
pub damage: Option<NonZeroU32>,
pub real_damage: Option<NonZeroU32>,
pub weapon: Option<&'a str>,
}
pub fn damage_event_parser(input: &str) -> IResult<&str, DamageEvent> {
let (input, target) = param_parse_with("against", subject_parser)(input)?;
let mut event = DamageEvent {
target,
damage: None,
real_damage: None,
weapon: None,
};
for (key, value) in ParamIter::new(input) {
match key {
"damage" => event.damage = NonZeroU32::new(quoted(u_int)(value)?.1),
"realdamage" => event.real_damage = NonZeroU32::new(quoted(u_int)(value)?.1),
"weapon" => event.weapon = Some(value.trim_matches('"')),
_ => {}
}
}
Ok(("", event))
}
#[derive(Debug)]
pub struct KillEvent<'a> {
pub target: RawSubject<'a>,
pub weapon: &'a str,
pub attacker_position: Option<(i32, i32, i32)>,
pub victim_position: Option<(i32, i32, i32)>,
}
pub fn kill_event_parser(input: &str) -> IResult<&str, KillEvent> {
let (input, target) = param_parse_with("against", subject_parser)(input)?;
let (input, weapon) = param_parse("with")(input)?;
let mut event = KillEvent {
target,
weapon,
attacker_position: None,
victim_position: None,
};
for (key, value) in ParamIter::new(input) {
match key {
"attacker_position" => event.attacker_position = Some(position(value)?.1),
"victim_position" => event.victim_position = Some(position(value)?.1),
_ => {}
}
}
Ok(("", event))
}
#[derive(Debug)]
pub struct KillAssistEvent<'a> {
pub target: RawSubject<'a>,
pub attacker_position: Option<(i32, i32, i32)>,
pub victim_position: Option<(i32, i32, i32)>,
}
pub fn kill_assist_event_parser(input: &str) -> IResult<&str, KillAssistEvent> {
let (input, target) = param_parse_with("against", subject_parser)(input)?;
let mut event = KillAssistEvent {
target,
attacker_position: None,
victim_position: None,
};
for (key, value) in ParamIter::new(input) {
match key {
"attacker_position" => event.attacker_position = Some(position(value)?.1),
"victim_position" => event.victim_position = Some(position(value)?.1),
_ => {}
}
}
Ok(("", event))
}