use nom:: { IResult, sequence::{delimited, pair, preceded, terminated, tuple}, combinator::{map, recognize}, branch::alt, bytes::complete::tag, }; use foliage::parse::whitespace0; pub fn recognize_and_keep>, O, E: nom::error::ParseError, F>(parser: F) -> impl Fn(I) -> IResult where F: Fn(I) -> IResult, { move |input: I| { let i = input.clone(); match parser(i) { Ok((i, result)) => { let index = input.offset(&i); Ok((i, (input.slice(..index), result))) }, Err(e) => Err(e), } } } fn statement_kind(i: &str) -> IResult<&str, crate::project::StatementKind> { let foo = delimited ( whitespace0, alt (( map ( tag("axiom:"), |_| crate::project::StatementKind::Axiom, ), map ( tag("lemma:"), |_| crate::project::StatementKind::Lemma, ), map ( tag("conjecture:"), |_| crate::project::StatementKind::Conjecture, ), )), whitespace0, )(i); foo } fn statement(i: &str) -> IResult<&str, (crate::project::StatementKind, foliage::Formula)> { terminated ( pair ( statement_kind, foliage::formula, ), preceded ( whitespace0, tag("."), ), )(i) } fn statement_enclosed_by_whitespace(i: &str) -> IResult<&str, (&str, (&str, (crate::project::StatementKind, foliage::Formula)), &str)> { tuple (( recognize(whitespace0), recognize_and_keep(statement), recognize(whitespace0), ))(i) } pub fn project(i: &str) -> IResult<&str, crate::Project> { let mut statement_input = i.clone(); let mut blocks = Vec::new(); loop { let i_ = statement_input.clone(); match statement_enclosed_by_whitespace(i_) { Ok((i, (whitespace_before, (statement_original_text, (statement_kind, formula)), whitespace_after))) => { // Iteration must always consume input (to prevent infinite loops) if i == statement_input { return Err(nom::Err::Error(nom::error::ParseError::from_error_kind(statement_input, nom::error::ErrorKind::Many0))); } if !whitespace_before.is_empty() { blocks.push(crate::project::Block::Whitespace(whitespace_before)); } let statement = crate::project::Statement { kind: statement_kind, original_text: statement_original_text, formula, }; blocks.push(crate::project::Block::Statement(statement)); if !whitespace_after.is_empty() { blocks.push(crate::project::Block::Whitespace(whitespace_after)); } statement_input = i; }, Err(nom::Err::Error(_)) => break, Err(e) => return Err(e), } } let i = statement_input; // Verify that the whole file has been parsed if i != "" { return Err(nom::Err::Error(nom::error::ParseError::from_error_kind(statement_input, nom::error::ErrorKind::Many0))); } let project = crate::Project { blocks, }; Ok((i, project)) }