use nom:: { IResult, branch::alt, bytes::complete::{escaped_transform, tag}, character::complete::{digit1, multispace0, none_of}, combinator::{map, map_res, opt, recognize}, multi::{many1, separated_list}, sequence::{delimited, pair, preceded, terminated}, }; use super::{Declarations, function_or_predicate_name, word_boundary, variable_name}; // TODO: avoid code duplication fn true_(i: &str) -> IResult<&str, crate::Formula> { map ( terminated ( tag("true"), word_boundary, ), |_| crate::Formula::true_(), )(i) } fn false_(i: &str) -> IResult<&str, crate::Formula> { map ( terminated ( tag("false"), word_boundary, ), |_| crate::Formula::false_(), )(i) } pub fn boolean(i: &str) -> IResult<&str, crate::Formula> { alt (( true_, false_, ))(i) } pub fn predicate<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::Predicate> { map ( |i| crate::parse::terms::function_or_predicate(i, d), |(name, arguments)| { let arguments = match arguments { Some(arguments) => arguments, None => vec![], }; let mut predicate_declarations = d.predicate_declarations.borrow_mut(); let declaration = match predicate_declarations.iter() .find(|x| x.name == name && x.arity == arguments.len()) { Some(declaration) => std::rc::Rc::clone(&declaration), None => { let declaration = crate::PredicateDeclaration { name: name.to_string(), arity: arguments.len(), }; let declaration = std::rc::Rc::new(declaration); predicate_declarations.insert(std::rc::Rc::clone(&declaration)); declaration }, }; crate::Predicate::new(declaration, arguments) }, )(i) } fn formula_parenthesized<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { delimited ( terminated ( tag("("), multispace0, ), |i| formula(i, d), preceded ( multispace0, tag(")"), ), )(i) } fn formula_precedence_0<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( boolean, map ( |i| predicate(i, d), crate::Formula::Predicate, ), // TODO: comparisons // TODO: quantified expressions // TODO: negation |i| formula_parenthesized(i, d), ))(i) } fn formula_precedence_3<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( map_res ( separated_list ( delimited ( multispace0, terminated ( tag("and"), word_boundary, ), multispace0, ), // TODO: fix |i| formula_precedence_0(i, d), ), |arguments| -> Result<_, (_, _)> { if arguments.len() >= 2 { Ok(crate::Formula::and(arguments.into_iter().map(Box::new).collect())) } else { Err(nom::error::make_error(i, nom::error::ErrorKind::Many1)) } } ), // TODO: fix |i| formula_precedence_0(i, d), ))(i) } fn formula_precedence_4<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( map_res ( separated_list ( delimited ( multispace0, terminated ( tag("or"), word_boundary, ), multispace0, ), |i| formula_precedence_3(i, d), ), |arguments| -> Result<_, (_, _)> { if arguments.len() >= 2 { Ok(crate::Formula::or(arguments.into_iter().map(Box::new).collect())) } else { Err(nom::error::make_error(i, nom::error::ErrorKind::Many1)) } } ), |i| formula_precedence_3(i, d), ))(i) } fn implication_left_to_right<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( map ( pair ( many1 ( terminated ( |i| formula_precedence_4(i, d), delimited ( multispace0, tag("->"), multispace0, ), ) ), |i| formula_precedence_4(i, d), ), |(arguments, last_argument)| arguments.into_iter().rev().fold(last_argument, |accumulator, argument| crate::Formula::implies(crate::ImplicationDirection::LeftToRight, Box::new(accumulator), Box::new(argument))) ), |i| formula_precedence_4(i, d), ))(i) } fn implication_right_to_left<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( map ( pair ( |i| formula_precedence_4(i, d), many1 ( preceded ( delimited ( multispace0, tag("<-"), multispace0, ), |i| formula_precedence_4(i, d), ) ), ), |(first_argument, arguments)| arguments.into_iter().fold(first_argument, |accumulator, argument| crate::Formula::implies(crate::ImplicationDirection::RightToLeft, Box::new(accumulator), Box::new(argument))) ), |i| formula_precedence_4(i, d), ))(i) } fn formula_precedence_5<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( |i| implication_right_to_left(i, d), |i| implication_left_to_right(i, d), ))(i) } fn formula_precedence_6<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { alt (( map_res ( separated_list ( delimited ( multispace0, tag("<->"), multispace0, ), |i| formula_precedence_5(i, d), ), |arguments| -> Result<_, (_, _)> { if arguments.len() >= 2 { Ok(crate::Formula::if_and_only_if( arguments.into_iter().map(Box::new).collect())) } else { Err(nom::error::make_error(i, nom::error::ErrorKind::Many1)) } } ), |i| formula_precedence_5(i, d), ))(i) } pub fn formula<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> { formula_precedence_6(i, d) } #[cfg(test)] mod tests { use crate::parse::formulas::*; use crate::{Formula, Term, VariableDeclaration, VariableDeclarationStack}; /*fn formula(i: &str) -> Formula { crate::parse::formula(i, &Declarations::new()).unwrap().1 } fn format_formula(i: &str) -> String { format!("{}", formula(i)) } #[test] fn parse_formula_boolean() { assert_eq!(formula("true"), Formula::true_()); assert_eq!(formula("false"), Formula::false_()); }*/ #[test] fn parse_boolean() { assert_eq!(boolean("true"), Ok(("", Formula::true_()))); assert_eq!(boolean("false"), Ok(("", Formula::false_()))); assert_eq!(boolean("true false"), Ok((" false", Formula::true_()))); assert_eq!(boolean("false true"), Ok((" true", Formula::false_()))); assert_eq!(boolean("true,"), Ok((",", Formula::true_()))); assert_eq!(boolean("false,"), Ok((",", Formula::false_()))); assert!(boolean("truefalse").is_err()); assert!(boolean("falsetrue").is_err()); assert!(boolean("truea").is_err()); assert!(boolean("falsea").is_err()); assert!(boolean("a").is_err()); assert!(boolean("-").is_err()); assert!(boolean(" ").is_err()); } #[test] fn parse_predicate() { assert_eq!(predicate("s", &Declarations::new()) .map(|(i, x)| (i, x.declaration.name.clone())), Ok(("", "s".to_string()))); assert_eq!(predicate("s", &Declarations::new()) .map(|(i, x)| (i, x.declaration.arity)), Ok(("", 0))); assert_eq!(predicate("s ( )", &Declarations::new()) .map(|(i, x)| (i, x.declaration.name.clone())), Ok(("", "s".to_string()))); assert_eq!(predicate("s ( )", &Declarations::new()) .map(|(i, x)| (i, x.declaration.arity)), Ok(("", 0))); assert_eq!(predicate("s ( 1 , 2 , 3 )", &Declarations::new()) .map(|(i, x)| (i, x.declaration.name.clone())), Ok(("", "s".to_string()))); assert_eq!(predicate("s ( 1 , 2 , 3 )", &Declarations::new()) .map(|(i, x)| (i, x.declaration.arity)), Ok(("", 3))); assert_eq!(predicate("s ( 1 , 2 , 3 )", &Declarations::new()) .map(|(i, mut x)| (i, x.arguments.remove(0))), Ok(("", Box::new(Term::integer(1))))); assert_eq!(predicate("s ( 1 , 2 , 3 )", &Declarations::new()) .map(|(i, mut x)| (i, x.arguments.remove(2))), Ok(("", Box::new(Term::integer(3))))); assert_eq!(predicate("s ( ), rest", &Declarations::new()) .map(|(i, x)| (i, x.declaration.name.clone())), Ok((", rest", "s".to_string()))); assert_eq!(predicate("s ( ), rest", &Declarations::new()) .map(|(i, x)| (i, x.declaration.arity)), Ok((", rest", 0))); assert_eq!(predicate("s ( 1 , 2 , 3 ), rest", &Declarations::new()) .map(|(i, x)| (i, x.declaration.name.clone())), Ok((", rest", "s".to_string()))); assert_eq!(predicate("s ( 1 , 2 , 3 ), rest", &Declarations::new()) .map(|(i, x)| (i, x.declaration.arity)), Ok((", rest", 3))); } }