Don't Use "rest" With "many1" In Rust's nom Parsing Crate
I'm still working to figure this out...
This one works.
#![allow(unused_imports)]
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::character::complete::multispace0;
use nom::combinator::rest;
use nom::multi::many1;
use nom::sequence::terminated;
use nom::IResult;
#[derive(Debug)]
enum Section {
Alfa,
Bravo,
}
fn main() {
let source = "-- alfa\n\n-- bravo";
dbg!(sections(source).unwrap());
}
fn sections(source: &str) -> IResult<&str, Vec<Section>> {
let (source, sections) = many1(alt((alfa, bravo)))(source)?;
Ok((source, sections))
}
fn alfa(source: &str) -> IResult<&str, Section> {
let (source, _section) = tag("-- alfa")(source)?;
let (source, data) = terminated(take_until("\n\n"), tag("\n\n"))(source)?;
Ok((source, Section::Alfa))
}
fn bravo(source: &str) -> IResult<&str, Section> {
let (source, _section) = tag("-- bravo")(source)?;
let (source, data) = alt((terminated(take_until("\n\n"), tag("\n\n")), rest))(source)?;
Ok((source, Section::Bravo))
}
Earlier notes about what wasn't working
Need to do a little more verification, but I think part of the problems I've been running into with nom and the many
functions is because I was pulling in content below them with rest
. The way many1
and many0
work is that the stop processing when they hit an error. By using rest
to slurp the rest of the content that wasn't happening.
This is some code where I figured that out
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::character::complete::multispace0;
use nom::combinator::rest;
use nom::multi::many1;
use nom::sequence::terminated;
use nom::IResult;
fn main() {
let source = "alfa bravo\n\ncharlie delta\n\necho foxtrot";
dbg!(this_works(&source).unwrap());
dbg!(this_fails(&source).unwrap());
}
fn this_works(source: &str) -> IResult<&str, Vec<&str>> {
let (source, x) = many1(this_works_part_2)(source)?;
Ok((source, x))
}
fn this_works_part_2(source: &str) -> IResult<&str, &str> {
let (source, _) = multispace0(source)?;
let (source, captured) = terminated(take_until("\n\n"), tag("\n\n"))(source)?;
Ok((source, captured))
}
fn this_fails(source: &str) -> IResult<&str, Vec<&str>> {
let (source, x) = many1(this_fails_part_2)(source)?;
Ok((source, x))
}
fn this_fails_part_2(source: &str) -> IResult<&str, &str> {
let (source, _) = multispace0(source)?;
let (source, captured) = alt((terminated(take_until("\n\n"), tag("\n\n")), rest))(source)?;
Ok((source, captured))
}
Notes
-
I don't know if
rest
always returns true or not, but it certinaly seems like it might.