home ~ projects ~ socials

Pass Extra Arguments To Child Parsers In Rust's nom

This is how I'm passing supplemental arguments/parameters to nom parsers inside other parsers (e.g. inside many1). The key is on lines 21-22 between the comments. More notes below the code.

//! ```cargo
//! [dependencies]
//! nom = "7.1.3"
//! ```

use nom::bytes::complete::tag;
use nom::error::ParseError;
use nom::multi::many1;
use nom::IResult;
use nom::{ Compare, InputLength, InputTake };

fn main() {
  let left = Ok((" bravo", vec!["alfa"]));
  let right = parse("alfa bravo");
  assert_eq!(left, right);
  println!("test past");
}

fn parse(source: &str) -> IResult<&str, Vec<&str>> {
  let extra_arg = "alfa";

  /////////////////////////////////////////////
  // let (source, result) = many1(|src| 
  // grabber(src, extra_arg))(source)?; 
  // TODO: Write up this version above ^ too//
  /////////////////////////////////////////////
  let (source, result) = many1(grabber(extra_arg))(source)?; 
  /////////////////////////////////////////////

  Ok((source, result))
}

fn grabber<T, Input, Error: ParseError<Input>>(
    extra: T,
) -> impl Fn(Input) -> IResult<Input, Input, Error>
where
    Input: InputTake + Compare<T>,
    T: InputLength + Clone,
{
    tag(extra)
}

//fn grabber<'a>(source: &'a str, extra: &'a str) -> 
 // IResult<&'a str, &'a str> {
  //  let (source, result) = tag(extra)(source)?;
   // Ok((source, result))
//}
Output:
test past

Notes

  • The standard way to use many1 without passing extra arguments looks like this:

    many1(grabber)(source)?

  • This is what I'm using instead to pass the arguments:

    many1(PIPEHEREsrcPIPEHERE grabber(src, extra_arg))(source)?

    (NOTE: PIPEHERE is for a |, but they have trouble parsing right now.)

  • The methodology is to pass a closure to many1 with the original source as src and then add the extra argument via the extra_arg variable
  • This method require adding explict lifetimes to the method that's getting the extra arguments (grabber in this case)
  • This looks to be the way to do it with alt, but I need to test it more:
alt ((
        |src| block_section_name(src, config),
        |src| block_section_name(src, config),
    ))(source)

TODO

    Get other examples of parsers this works with besides many1. Look at alt, opt, tuple, pair, etc...)

-- end of line --