I tried winnow as suggested elsewhere in this thread, this is what it may look like:
use winnow::combinator::{ repeat };
use winnow::token::take_while;
use winnow::prelude::*;
pub fn csg_parse(input: &mut &str) -> PResult<usize> {
let a: &str = take_while(0.., 'a').parse_next(input)?;
let n: usize = a.len();
repeat(n, "b").parse_next(input)?;
repeat(n, "c").parse_next(input)?;
'\n'.parse_next(input)?;
return Ok(n);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parses_examples() {
assert_eq!(Ok(0), csg_parse(&mut "\n"));
assert_eq!(Ok(3), csg_parse(&mut "aaabbbccc\n"));
assert!(csg_parse(&mut "abcc\n").is_err());
assert!(csg_parse(&mut "abbcc\n").is_err());
assert!(csg_parse(&mut "aabc\n").is_err());
assert!(csg_parse(&mut "aabbc\n").is_err());
assert!(csg_parse(&mut "def\n").is_err());
}
}
So you are directly express context-sensitivity instead of approximating it with infinite context-free grammar.
Okay, good enough.