From 1b89d8900e588a04acb0305fd228fc0958e8310c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Fri, 13 Mar 2020 22:58:53 +0100 Subject: [PATCH] Start parsing formulas --- src/parse.rs | 5 +- src/parse/formulas.rs | 260 ++++++++++++++++++++++++++++++++++++++++++ src/parse/terms.rs | 54 ++++----- 3 files changed, 290 insertions(+), 29 deletions(-) create mode 100644 src/parse/formulas.rs diff --git a/src/parse.rs b/src/parse.rs index d7695a6..c1b8333 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,11 +1,12 @@ +mod formulas; mod helpers; mod names; mod terms; pub(crate) use helpers::word_boundary; pub use names::{function_or_predicate_name, variable_name}; -pub use terms::{boolean, function, integer, predicate, special_integer, string, term, variable, - variable_declaration}; +pub use terms::term; +//pub use formulas::formula; pub struct Declarations { diff --git a/src/parse/formulas.rs b/src/parse/formulas.rs new file mode 100644 index 0000000..bf1ba7a --- /dev/null +++ b/src/parse/formulas.rs @@ -0,0 +1,260 @@ +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) +} + +/*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 term_precedence_0<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term> +{ + alt + (( + boolean, + special_integer, + integer, + map + ( + |i| function(i, d), + crate::Term::Function, + ), + string, + map + ( + |i| variable(i, d), + crate::Term::Variable, + ), + |i| absolute_value(i, d), + |i| term_parenthesized(i, d), + ))(i) +} + +fn term_precedence_1<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term> +{ + alt + (( + |i| negative(i, d), + |i| term_precedence_0(i, d), + ))(i) +} + +fn term_precedence_2<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term> +{ + alt + (( + map + ( + pair + ( + many1 + ( + terminated + ( + |i| term_precedence_1(i, d), + delimited + ( + multispace0, + tag("**"), + multispace0, + ), + ) + ), + |i| term_precedence_1(i, d), + ), + |(arguments, last_argument)| arguments.into_iter().rev().fold(last_argument, + |accumulator, argument| + crate::Term::exponentiate(Box::new(argument), Box::new(accumulator))), + ), + |i| term_precedence_1(i, d), + ))(i) +} + +fn term_precedence_3<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term> +{ + alt + (( + map + ( + pair + ( + |i| term_precedence_2(i, d), + many1 + ( + pair + ( + delimited + ( + multispace0, + alt + (( + tag("*"), + tag("/"), + tag("%"), + )), + multispace0, + ), + |i| term_precedence_2(i, d), + ) + ), + ), + |(first_argument, arguments)| arguments.into_iter().fold(first_argument, + |accumulator, (operator, argument)| + match operator + { + "*" => crate::Term::multiply(Box::new(accumulator), Box::new(argument)), + "/" => crate::Term::divide(Box::new(accumulator), Box::new(argument)), + "%" => crate::Term::modulo(Box::new(accumulator), Box::new(argument)), + // TODO: handle appropriately + _ => panic!("test"), + }) + ), + |i| term_precedence_2(i, d), + ))(i) +} + +fn term_precedence_4<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term> +{ + alt + (( + map + ( + pair + ( + |i| term_precedence_3(i, d), + many1 + ( + pair + ( + delimited + ( + multispace0, + alt + (( + tag("+"), + tag("-"), + )), + multispace0, + ), + |i| term_precedence_3(i, d), + ) + ), + ), + |(first_argument, arguments)| arguments.into_iter().fold(first_argument, + |accumulator, (operator, argument)| + match operator + { + "+" => crate::Term::add(Box::new(accumulator), Box::new(argument)), + "-" => crate::Term::subtract(Box::new(accumulator), Box::new(argument)), + // TODO: handle appropriately + _ => panic!("test"), + }) + ), + |i| term_precedence_3(i, d), + ))(i) +} + +pub fn formula<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Formula> +{ + formula_precedence_4(i, d) +}*/ + +#[cfg(test)] +mod tests +{ + use crate::parse::formulas::*; + use crate::{Formula, 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()); + } +} diff --git a/src/parse/terms.rs b/src/parse/terms.rs index 84ab2e3..a4ab1f3 100644 --- a/src/parse/terms.rs +++ b/src/parse/terms.rs @@ -11,32 +11,6 @@ use nom:: use super::{Declarations, function_or_predicate_name, word_boundary, variable_name}; -fn true_(i: &str) -> IResult<&str, crate::Term> -{ - map - ( - terminated - ( - tag("true"), - word_boundary, - ), - |_| crate::Term::true_(), - )(i) -} - -fn false_(i: &str) -> IResult<&str, crate::Term> -{ - map - ( - terminated - ( - tag("false"), - word_boundary, - ), - |_| crate::Term::false_(), - )(i) -} - fn negative<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::Term> { map @@ -83,6 +57,32 @@ fn absolute_value<'i>(i: &'i str, d: &Declarations) -> IResult<&'i str, crate::T )(i) } +fn true_(i: &str) -> IResult<&str, crate::Term> +{ + map + ( + terminated + ( + tag("true"), + word_boundary, + ), + |_| crate::Term::true_(), + )(i) +} + +fn false_(i: &str) -> IResult<&str, crate::Term> +{ + map + ( + terminated + ( + tag("false"), + word_boundary, + ), + |_| crate::Term::false_(), + )(i) +} + pub fn boolean(i: &str) -> IResult<&str, crate::Term> { alt @@ -511,7 +511,7 @@ pub fn term<'a>(i: &'a str, d: &Declarations) -> IResult<&'a str, crate::Term> #[cfg(test)] mod tests { - use crate::parse::*; + use crate::parse::terms::*; use crate::{Term, VariableDeclaration, VariableDeclarationStack}; fn term(i: &str) -> Term