Examples of composability with nom parsers #71
|
@ -1625,6 +1625,14 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom-training"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cool_asserts",
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
|
|
|
@ -18,4 +18,5 @@ members = [
|
||||||
"memorycache",
|
"memorycache",
|
||||||
"screenplay",
|
"screenplay",
|
||||||
"sgf",
|
"sgf",
|
||||||
|
"nom-training",
|
||||||
]
|
]
|
||||||
|
|
|
@ -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 = "*" }
|
|
@ -0,0 +1,122 @@
|
||||||
|
// Write two separate parser functions
|
||||||
|
// One function returns `impl Parser<>`
|
||||||
|
// The other function returns `FnMut(I) -> IResult<I, ...`
|
||||||
|
// Test each with the `map` function and the `parse` function
|
||||||
|
use nom::{character::complete::digit1, error::ParseError, IResult, Parser};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
struct Container(i32);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn parse_container_a<'a, E: ParseError<&'a str>>(
|
||||||
|
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::<i32>().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::<nom::error::VerboseError<&str>>()
|
||||||
|
.map(|val| Container(val))
|
||||||
|
.parse(DATA);
|
||||||
|
assert_matches!(resp, Ok((_, content)) =>
|
||||||
|
assert_eq!(content, Container(15))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parser() {
|
||||||
|
let resp = parse_number_b::<nom::error::VerboseError<&str>>()
|
||||||
|
.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::<nom::error::VerboseError<&str>>(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::<nom::error::VerboseError<&str>>(parse_number_b()).parse(DATA);
|
||||||
|
assert_matches!(resp, Ok((_, content)) =>
|
||||||
|
assert_eq!(content, Container(15))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue