use nom:: { IResult, character::complete::multispace0, sequence::{delimited, pair, terminated}, combinator::map, branch::alt, bytes::complete::tag, }; fn statement_kind(i: &str) -> IResult<&str, crate::project::StatementKind> { let foo = delimited ( multispace0, alt (( map ( tag("axiom:"), |_| crate::project::StatementKind::Axiom, ), map ( tag("lemma:"), |_| crate::project::StatementKind::Lemma, ), map ( tag("conjecture:"), |_| crate::project::StatementKind::Conjecture, ), )), multispace0, )(i); foo } fn statement(i: &str) -> IResult<&str, (crate::project::StatementKind, foliage::Formula)> { terminated ( pair ( statement_kind, foliage::formula, ), delimited ( multispace0, tag("."), multispace0, ), )(i) } pub fn project(i: &str) -> IResult<&str, crate::Project> { let mut statement_input = i.clone(); let mut statements = std::collections::HashMap::new(); loop { let i_ = statement_input.clone(); match statement(i_) { Ok((i, (statement_kind, formula))) => { // 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))); } let statements = statements.entry(statement_kind).or_insert_with(Vec::new); statements.push(formula); 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 { statements, }; Ok((i, project)) }