even less nom

This commit is contained in:
Robin Appelman 2023-03-10 21:48:15 +01:00
commit 19f9c9f973
4 changed files with 74 additions and 56 deletions

View file

@ -337,6 +337,16 @@ pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)>
}) })
} }
pub fn take_until(input: &str, delim: u8) -> (&str, &str) {
debug_assert!(delim < 128); // only basic ascii
if let Some(end) = memchr(delim, input.as_bytes()) {
// safety, memchr returns indices that are inside the input length and we only split on ascii
unsafe { (input.get_unchecked(end..), input.get_unchecked(..end)) }
} else {
("", input)
}
}
pub fn skip(input: &str, count: usize) -> Result<&str> { pub fn skip(input: &str, count: usize) -> Result<&str> {
input.get(count..).ok_or(Error::Incomplete) input.get(count..).ok_or(Error::Incomplete)
} }

View file

@ -1,9 +1,8 @@
use crate::event::{param_parse, param_parse_with, parse_field, ParamIter}; use crate::event::{param_parse_with, parse_field, ParamIter};
use crate::raw_event::RawSubject; use crate::raw_event::RawSubject;
use crate::{Event, IResult}; use crate::{Error, Event, IResult};
use nom::bytes::complete::{tag, take_while}; use crate::common::{skip, take_until};
use nom::combinator::opt;
#[derive(Debug, Event)] #[derive(Debug, Event)]
pub struct RoundWinEvent<'a> { pub struct RoundWinEvent<'a> {
@ -32,10 +31,10 @@ pub struct TournamentModeStartedEvent<'a> {
impl<'a> Event<'a> for TournamentModeStartedEvent<'a> { impl<'a> Event<'a> for TournamentModeStartedEvent<'a> {
fn parse(input: &'a str) -> IResult<Self> { fn parse(input: &'a str) -> IResult<Self> {
let (input, _) = tag("\nBlue Team: ")(input)?; let input = skip(input, "\nBlue Team: ".len())?;
let (input, blue) = take_while(|c| c != '\n')(input)?; let (input, blue) = take_until(input, b'\n');
let (input, _) = tag("\nRed Team: ")(input)?; let input = skip(input, "\nRed Team: ".len())?;
let (input, red) = take_while(|c| c != '\n')(input)?; let (input, red) = take_until(input, b'\n');
Ok((input, TournamentModeStartedEvent { blue, red })) Ok((input, TournamentModeStartedEvent { blue, red }))
} }
} }
@ -58,20 +57,41 @@ pub struct PointCapturedEvent<'a> {
impl<'a> Event<'a> for PointCapturedEvent<'a> { impl<'a> Event<'a> for PointCapturedEvent<'a> {
fn parse(input: &'a str) -> IResult<Self> { fn parse(input: &'a str) -> IResult<Self> {
let (input, cp) = opt(param_parse("cp"))(input)?; let mut cp = Default::default();
let (input, cp_name) = opt(param_parse("cpname"))(input)?; let mut cp_name = Default::default();
let (input, num_cappers) = opt(param_parse("numcappers"))(input)?; let mut num_cappers = Default::default();
let mut players = Vec::new(); let mut players = Vec::new();
let mut params = ParamIter::new(input); let mut params = ParamIter::new(input).peekable();
match (params.next(), params.next()) { while let Some((name, value)) = params.peek() {
(Some((subject_key, subject)), Some((position_key, position_str))) match *name {
if subject_key.starts_with("player") && position_key.starts_with("position") => "cp" => {
{ cp = Some(value.parse().map_err(Error::from)?);
players.push((parse_field(subject)?.1, parse_field(position_str)?.1)); let _ = params.next();
}
"cpname" => {
cp_name = Some(*value);
let _ = params.next();
}
"numcappers" => {
num_cappers = Some(value.parse().map_err(Error::from)?);
let _ = params.next();
}
_ => {
break;
}
}
}
loop {
match (params.next(), params.next()) {
(Some((subject_key, subject)), Some((position_key, position_str)))
if subject_key.starts_with("player")
&& position_key.starts_with("position") =>
{
players.push((parse_field(subject)?.1, parse_field(position_str)?.1));
}
_ => break,
} }
_ => {}
} }
Ok(( Ok((

View file

@ -2,15 +2,12 @@ mod game;
mod medic; mod medic;
mod player; mod player;
use crate::common::{skip, skip_matches, split_once}; use crate::common::{skip, skip_matches, split_once, take_until};
use crate::event::game::{RoundLengthEvent, RoundWinEvent}; use crate::event::game::{RoundLengthEvent, RoundWinEvent};
use crate::raw_event::{against_subject_parser, RawSubject}; use crate::raw_event::{against_subject_parser, RawSubject};
use crate::{err_incomplete, IResult, RawEvent, RawEventType, SubjectId}; use crate::{err_incomplete, IResult, RawEvent, RawEventType, SubjectId};
pub use game::*; pub use game::*;
pub use medic::*; pub use medic::*;
use nom::bytes::complete::{tag, take_while};
use nom::character::complete::digit1;
use nom::combinator::opt;
use nom::error::{ErrorKind, ParseError}; use nom::error::{ErrorKind, ParseError};
use nom::number::complete::float; use nom::number::complete::float;
use nom::Err; use nom::Err;
@ -253,9 +250,9 @@ fn quoted<'a, T, P: Fn(&'a str) -> IResult<'a, T>>(
parser: P, parser: P,
) -> impl Fn(&'a str) -> IResult<'a, T> { ) -> impl Fn(&'a str) -> IResult<'a, T> {
move |input| { move |input| {
let (input, _) = tag(r#"""#)(input)?; let input = skip(input, 1)?;
let (input, res) = parser(input)?; let (inner, input) = split_once(input, b'"', 1)?;
let (input, _) = tag(r#"""#)(input)?; let (_, res) = parser(inner)?;
Ok((input, res)) Ok((input, res))
} }
} }
@ -297,45 +294,29 @@ fn parse_from_str<'a, T: FromStr + 'a>(input: &'a str) -> IResult<T> {
} }
fn int(input: &str) -> IResult<i32> { fn int(input: &str) -> IResult<i32> {
let (input, sign) = opt(tag("-"))(input)?; let (input, sign) = skip_matches(input, b'-');
let (input, raw) = digit1(input)?; let (input, unsigned) = u_int(input)?;
let val: i32 = raw let signed = unsigned as i32;
.parse() Ok((input, if sign { -signed } else { signed }))
.map_err(|_| Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?;
Ok((input, if sign.is_some() { -val } else { val }))
} }
fn u_int(input: &str) -> IResult<u32> { fn u_int(input: &str) -> IResult<u32> {
let (input, quote) = opt(tag("\""))(input)?; let (input, raw) = take_until(input, b' ');
let (input, raw) = digit1(input)?;
let val = raw.parse().map_err(|_| err_incomplete())?; let val = raw.parse().map_err(|_| err_incomplete())?;
let input = if quote.is_some() {
tag("\"")(input)?.0
} else {
input
};
Ok((input, val)) Ok((input, val))
} }
pub fn position(input: &str) -> IResult<(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)))
}
pub trait EventField<'a>: Sized + 'a { pub trait EventField<'a>: Sized + 'a {
fn parse_field(input: &'a str) -> IResult<Self>; fn parse_field(input: &'a str) -> IResult<Self>;
} }
impl<'a> EventField<'a> for &'a str { impl<'a> EventField<'a> for &'a str {
fn parse_field(input: &'a str) -> IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
if input.starts_with('"') { let (input, quoted) = skip_matches(input, b'"');
quoted(take_while(|c| c != '"'))(input) if quoted {
let (value, input) = split_once(input, b'"', 1)?;
Ok((input, value))
} else { } else {
Ok(("", input)) Ok(("", input))
} }
@ -384,11 +365,11 @@ impl EventFieldFromStr for SocketAddr {}
impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) { impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) {
fn parse_field(input: &'a str) -> IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
let (input, x) = T::parse_field(input)?; let (input, x) = parse_field(input)?;
let (input, _) = tag(" ")(input)?; let input = skip(input, 1)?;
let (input, y) = T::parse_field(input)?; let (input, y) = parse_field(input)?;
let (input, _) = tag(" ")(input)?; let input = skip(input, 1)?;
let (input, z) = T::parse_field(input)?; let (input, z) = parse_field(input)?;
Ok((input, (x, y, z))) Ok((input, (x, y, z)))
} }
} }

View file

@ -14,6 +14,7 @@ pub use raw_event::{RawEvent, RawEventType};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::num::ParseIntError;
pub use tf_log_parser_derive::Event; pub use tf_log_parser_derive::Event;
use thiserror::Error; use thiserror::Error;
@ -64,6 +65,12 @@ impl From<nom::error::Error<&'_ str>> for Error {
} }
} }
impl From<ParseIntError> for Error {
fn from(_: ParseIntError) -> Self {
Error::Malformed
}
}
type Result<O, E = Error> = std::result::Result<O, E>; type Result<O, E = Error> = std::result::Result<O, E>;
#[doc(hidden)] #[doc(hidden)]