From 207d099607f78d192312e215fe2421546b81023a Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 14 Sep 2023 14:47:05 -0400 Subject: [PATCH] nom parsing practice --- Cargo.lock | 8 +++ Cargo.toml | 1 + nom-training/Cargo.toml | 10 ++++ nom-training/src/lib.rs | 122 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 nom-training/Cargo.toml create mode 100644 nom-training/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7137afc..90571a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1625,6 +1625,14 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom-training" +version = "0.1.0" +dependencies = [ + "cool_asserts", + "nom", +] + [[package]] name = "num-integer" version = "0.1.45" diff --git a/Cargo.toml b/Cargo.toml index fc88da2..6060504 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,5 @@ members = [ "memorycache", "screenplay", "sgf", + "nom-training", ] diff --git a/nom-training/Cargo.toml b/nom-training/Cargo.toml new file mode 100644 index 0000000..ad70f58 --- /dev/null +++ b/nom-training/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "nom-training" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nom = { version = "7" } +cool_asserts = { version = "*" } \ No newline at end of file diff --git a/nom-training/src/lib.rs b/nom-training/src/lib.rs new file mode 100644 index 0000000..661ed70 --- /dev/null +++ b/nom-training/src/lib.rs @@ -0,0 +1,122 @@ +// Write two separate parser functions +// One function returns `impl Parser<>` +// The other function returns `FnMut(I) -> IResult>( + mut parser: impl Parser<&'a str, i32, E>, +) -> impl FnMut(&'a str) -> IResult<&'a str, Container, E> { + move |input| { + let (input, value) = parser.parse(input)?; + Ok((input, Container(value))) + } +} + +/* +// This form doesn't work. It is not possible in this case to get the ownership +// declarations correct on parser. The reason I would want to do this is for more +// concise representation of parse_container_a. It probably fails because map consumes +// the parser. +fn parse_container_b<'a, E: ParseError<&'a str>, P>( + mut parser: P, +) -> impl Parser<&'a str, Container, E> +where + P: Parser<&'a str, i32, E>, +{ + move |input| parser.map(|val| Container(val)).parse(input) +} +*/ + +#[allow(dead_code)] +fn parse_container_c<'a, E: ParseError<&'a str>>( + parser: impl Parser<&'a str, i32, E>, +) -> impl Parser<&'a str, Container, E> { + parser.map(|val| Container(val)) +} + +/* +// This form also doesn't work, for the same reason as parse_container_b doesn't work. +fn parse_container_d<'a, E: ParseError<&'a str>>( + parser: impl Parser<&'a str, i32, E>, +) -> impl FnMut(&'a str) -> IResult<&'a str, Container, E> { + |input| parser.map(|val| Container(val)).parse(input) +} +*/ + +// If I really want to do forms b and d, this works. I do the parser combination before +// creating the resulting function. +#[allow(dead_code)] +fn parse_container_e<'a, E: ParseError<&'a str>>( + parser: impl Parser<&'a str, i32, E>, +) -> impl Parser<&'a str, Container, E> { + let mut parser = parser.map(|val| Container(val)); + + move |input| parser.parse(input) +} + +#[allow(dead_code)] +fn parse_number_a<'a, E: ParseError<&'a str>>() -> impl FnMut(&'a str) -> IResult<&'a str, i32, E> { + parse_number +} + +#[allow(dead_code)] +fn parse_number_b<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, i32, E> { + parse_number +} + +#[allow(dead_code)] +fn parse_number<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, i32, E> { + let (input, val) = digit1(input)?; + Ok((input, val.parse::().unwrap())) +} + +#[cfg(test)] +mod tests { + use super::*; + use cool_asserts::assert_matches; + + const DATA: &'static str = "15"; + + #[test] + fn function() { + let resp = parse_number_a::>() + .map(|val| Container(val)) + .parse(DATA); + assert_matches!(resp, Ok((_, content)) => + assert_eq!(content, Container(15)) + ); + } + + #[test] + fn parser() { + let resp = parse_number_b::>() + .map(|val| Container(val)) + .parse(DATA); + assert_matches!(resp, Ok((_, content)) => + assert_eq!(content, Container(15)) + ); + } + + #[test] + fn parser_composition_a() { + let resp = + parse_container_a::>(parse_number_a()).parse(DATA); + assert_matches!(resp, Ok((_, content)) => + assert_eq!(content, Container(15)) + ); + } + + #[test] + fn parser_composition_c() { + let resp = + parse_container_c::>(parse_number_b()).parse(DATA); + assert_matches!(resp, Ok((_, content)) => + assert_eq!(content, Container(15)) + ); + } +}