use pom::parser::*; #[derive(Clone, Debug, PartialEq)] struct Container { containers: Vec, contents: Vec, } enum TmpContainerOrContent { Container(Container), Content(String), } fn whitespace<'a>() -> Parser<'a, u8, ()> { one_of(b" \t\r\n").repeat(0..).discard() } fn linebreak<'a>() -> Parser<'a, u8, ()> { sym(b'\r').opt() * sym(b'\n').discard() } fn indented<'a>() -> Parser<'a, u8, Vec> { sym(b'\t') * none_of(b"\n\r").repeat(1..) - linebreak() } fn empty<'a>() -> Parser<'a, u8, ()> { one_of(b" \t").repeat(0..).discard() - linebreak() } fn content<'a>() -> Parser<'a, u8, String> { none_of(b" \t\r\n").repeat(1..).convert(String::from_utf8) - linebreak() } fn subcontainer<'a>() -> Parser<'a, u8, (Vec, Vec)> { ( call(container).map(|ctr| TmpContainerOrContent::Container(ctr)) | content().map(|ctn| TmpContainerOrContent::Content(ctn)) ).repeat(1..).map( |tmp| { tmp.into_iter().fold( (vec![], vec![]), |acc, x| match x { TmpContainerOrContent::Container(ct) => ( acc.0.into_iter().chain(vec![ct].into_iter()).collect(), acc.1, ), TmpContainerOrContent::Content(cn) => ( acc.0, acc.1.into_iter().chain(vec![cn].into_iter()).collect(), ), } ) } ) } fn container<'a>() -> Parser<'a, u8, Container> { seq(b"Container\n") * ( indented() | empty().map(|()| vec![]) ).repeat(1..).map( |lines| lines.into_iter().filter( |line| line.len() > 0 ).fold( vec![], |accum, line| accum.into_iter().chain( line.into_iter().chain(vec![b'\n'].into_iter()) ).collect() ) ).map(|deden| { subcontainer().parse(&deden).expect("subcont") }).map(|(containers, contents)| Container { containers, contents }) } fn mylang<'a>() -> Parser<'a, u8, Vec> { ( whitespace() * list( call(container), whitespace() ) ) } fn main() -> Result<(), ()> { let input = br#" Container Container a b c 1 2 3 Container q Container foo bar Container baz quux "#; assert_eq!( mylang().parse(input), Ok( vec![ Container { containers: vec![ Container { containers: vec![], contents: vec![ "a".into(), "b".into(), "c".into(), ] }, Container { containers: vec![], contents: vec![ "q".into(), ] } ], contents: vec![ "1".into(), "2".into(), "3".into(), ] }, Container { containers: vec![ Container { contents: vec![ "baz".into(), "quux".into(), ], containers: vec![], }, ], contents: vec![ "foo".into(), "bar".into(), ] }, ] ) ); Ok(()) }