home ~ projects ~ socials

Using Multiple Levels Of "many" In Rust's nom Parser

I kept running into stuff with many0, many1, and many_till in nom that I thought should have worked. Specifically when I was having one looping over another one by nesting them

I finally broke things out to it's own file and got things working by using many1 in both cases. Adding an opt to the first one makes sure that things pass.

Actually this may not always work. I'm still having problems with it and have ended up going to many_till

use nom::bytes::complete::tag;
use nom::combinator::opt;
use nom::multi::many1;
use nom::IResult;

fn main() {
    dbg!(parse("aaaabbbb")).unwrap();
    dbg!(parse("wwwwxxxx")).unwrap();
    dbg!(parse("xxxxyyyy")).unwrap();
}

fn parse(source: &str) -> IResult<&str, Option<Vec<Vec<&str>>>> {
    let (source, response) = opt(many1(level2))(source)?;
    Ok((source, response))
}
fn level2(source: &str) -> IResult<&str, Vec<&str>> {
    dbg!(&source);
    let (source, response) = many1(tag("x"))(source)?;
    Ok((source, response))
}

Things That Didn't Work

// // this doesn't work either
// fn parse(source: &str) -> IResult<&str, Vec<Vec<&str>>> {
//     let (source, response) = many_till(level2, eof)(source)?;
//     Ok((source, response.0))
// }
// fn level2(source: &str) -> IResult<&str, Vec<&str>> {
//     dbg!(&source);
//     let (source, response) = many0(tag("a"))(source)?;
//     Ok((source, response))
// }

// // these don't work. it throws an error because
// it looks like its sending an empty string to
// many0 on the second time thru
// fn parse(source: &str) -> IResult<&str, Vec<String>> {
//     let (source, response) = many0(level2)(source)?;
//     Ok((source, response))
// }
// fn level2(source: &str) -> IResult<&str, String> {
//     dbg!(&source);
//     let (source, response) = many0(is_not("x"))(source)?;
//     Ok((source, response.join("")))
// }
-- end of line --