diff --git a/src/bindings/expression.rs b/src/bindings/expression.rs index 4067f47..d70c67d 100644 --- a/src/bindings/expression.rs +++ b/src/bindings/expression.rs @@ -5,7 +5,7 @@ use pyo3::Bound; use crate::bindings::error::PythonExpressionError; use crate::bindings::error::PythonExpressionError::UnknownVariableWhileEvaluating; -use crate::expressions::Expression as RustExpression; +use crate::expressions::{Expression as RustExpression, ExpressionNode}; use crate::traits::{Evaluate, GatherLiterals, Parse, SemanticEq}; #[pyclass(frozen)] @@ -14,6 +14,20 @@ pub struct PythonExpression { root: RustExpression, } +impl From> for PythonExpression { + fn from(value: RustExpression) -> Self { + PythonExpression::new(value) + } +} + +impl From for RustExpression { + fn from(value: PythonExpression) -> Self { + // We can safely clone here because this only increases + // the reference count of the root expression. + value.root.clone() + } +} + #[pymethods] impl PythonExpression { #[new] @@ -89,47 +103,41 @@ impl PythonExpression { // TODO maybe allow numeric booleans? #[staticmethod] pub fn mk_constant(value: bool) -> PythonExpression { - Self::new(RustExpression::Constant(value)) + Self::new(ExpressionNode::Constant(value).into()) } #[staticmethod] pub fn mk_literal(name: String) -> PythonExpression { - Self::new(RustExpression::Literal(name)) + Self::new(ExpressionNode::Literal(name).into()) } #[staticmethod] pub fn mk_not(expression: &PythonExpression) -> PythonExpression { - Self::new(RustExpression::negate(expression.root.clone())) + Self::new(RustExpression::negate(&expression.root)) } #[staticmethod] pub fn mk_and_binary(left: &PythonExpression, right: &PythonExpression) -> PythonExpression { - Self::new(RustExpression::binary_and( - left.root.clone(), - right.root.clone(), - )) + Self::new(RustExpression::binary_and(&left.root, &right.root)) } #[staticmethod] pub fn mk_and_n_ary(expressions: Vec) -> PythonExpression { - Self::new(RustExpression::n_ary_and( - expressions.into_iter().map(|e| e.root).collect(), - )) + Self::new(RustExpression::n_ary_and(&Vec::from_iter( + expressions.into_iter().map(Into::into), + ))) } #[staticmethod] pub fn mk_or_binary(left: &PythonExpression, right: &PythonExpression) -> PythonExpression { - Self::new(RustExpression::binary_or( - left.root.clone(), - right.root.clone(), - )) + Self::new(RustExpression::binary_or(&left.root, &right.root)) } #[staticmethod] pub fn mk_or_n_ary(expressions: Vec) -> PythonExpression { - Self::new(RustExpression::n_ary_or( - expressions.into_iter().map(|e| e.root).collect(), - )) + Self::new(RustExpression::n_ary_or(&Vec::from_iter( + expressions.into_iter().map(Into::into), + ))) } pub fn __str__(&self) -> String { diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index 80a2639..b30bb79 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -1,69 +1,84 @@ use std::collections::HashMap; use std::fmt::Debug; use std::hash::Hash; -use std::ops::Deref; use std::sync::Arc; -use Expression::{And, Constant, Literal, Not, Or}; +use ExpressionNode::{And, Constant, Literal, Not, Or}; pub mod traits; -/// Immutable struct representing a boolean expression. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum Expression +pub enum ExpressionNode where T: Debug + Clone + Eq + Hash, { Literal(T), Constant(bool), - Not(Arc>), - And(Vec>>), - Or(Vec>>), + Not(Expression), + And(Vec>), + Or(Vec>), +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Expression(Arc>) +where + T: Debug + Clone + Eq + Hash; + +impl From> for Expression { + fn from(value: ExpressionNode) -> Self { + Expression(Arc::new(value)) + } } impl Expression { + pub fn node(&self) -> &ExpressionNode { + self.0.as_ref() + } + pub fn is_literal(&self) -> bool { - match self { - &Literal(_) => true, - Not(maybe_literal) => maybe_literal.is_literal(), + match self.node() { + Literal(_) => true, + Not(maybe_literal) => { + matches!(maybe_literal.node(), Literal(..)) + } _ => false, } } pub fn is_constant(&self) -> bool { - matches!(self, Constant(_)) + matches!(self.node(), Constant(_)) } pub fn is_not(&self) -> bool { - matches!(self, Not(_)) + matches!(self.node(), Not(_)) } pub fn is_and(&self) -> bool { - matches!(self, And(_)) + matches!(self.node(), And(_)) } pub fn is_or(&self) -> bool { - matches!(self, Or(_)) + matches!(self.node(), Or(_)) } - pub fn negate(e: Expression) -> Expression { - Not(Arc::new(e)) + pub fn negate(e: &Expression) -> Expression { + Not(e.clone()).into() } - pub fn binary_and(e1: Expression, e2: Expression) -> Expression { - And(vec![Arc::new(e1), Arc::new(e2)]) + pub fn binary_and(e1: &Expression, e2: &Expression) -> Expression { + And(vec![e1.clone(), e2.clone()]).into() } - pub fn n_ary_and(es: Vec>) -> Expression { - And(es.into_iter().map(Arc::new).collect()) + pub fn n_ary_and(es: &[Expression]) -> Expression { + And(es.to_vec()).into() } - pub fn binary_or(e1: Expression, e2: Expression) -> Expression { - Or(vec![Arc::new(e1), Arc::new(e2)]) + pub fn binary_or(e1: &Expression, e2: &Expression) -> Expression { + Or(vec![e1.clone(), e2.clone()]).into() } - pub fn n_ary_or(es: Vec>) -> Expression { - Or(es.into_iter().map(Arc::new).collect()) + pub fn n_ary_or(es: &[Expression]) -> Expression { + Or(es.to_vec()).into() } // toNNF (Not (Bin And l r)) = Bin Or (toNNF (Not l)) (toNNF (Not r)) -- ¬(ϕ ∧ ψ) = ¬ϕ ∨ ¬ψ @@ -73,22 +88,16 @@ impl Expression { // toNNF (Not exp) = Not (toNNF exp) // toNNF leaf = leaf pub fn to_nnf(&self) -> Self { - match self { - Not(inner) => match inner.as_ref() { - And(expressions) => Or(expressions - .iter() - .map(|e| Arc::new(Not(e.clone()).to_nnf())) - .collect()), - Or(expressions) => And(expressions - .iter() - .map(|e| Arc::new(Not(e.clone()).to_nnf())) - .collect()), - Not(expression) => expression.to_nnf(), - expression => Expression::negate(expression.to_nnf()), + match self.node() { + Not(inner) => match inner.node() { + And(es) => Or(es.iter().map(|e| Expression::negate(e).to_nnf()).collect()).into(), + Or(es) => And(es.iter().map(|e| Expression::negate(e).to_nnf()).collect()).into(), + Not(e) => e.to_nnf(), + _leaf => self.clone(), // TODO: Should we propagate negation to constants? }, - And(expressions) => And(expressions.iter().map(|e| Arc::new(e.to_nnf())).collect()), - Or(expressions) => Or(expressions.iter().map(|e| Arc::new(e.to_nnf())).collect()), - leaf => leaf.clone(), + And(es) => And(es.iter().map(|e| e.to_nnf()).collect()).into(), + Or(es) => Or(es.iter().map(|e| e.to_nnf()).collect()).into(), + _leaf => self.clone(), } } @@ -101,17 +110,14 @@ impl Expression { pub fn to_cnf(&self) -> Self { let nnf = self.to_nnf(); - match nnf { - Or(expressions) => expressions - .into_iter() + match nnf.node() { + Or(es) => es + .iter() .map(|e| e.to_cnf()) - .reduce(|acc, e| Expression::distribute(acc, e)) + .reduce(|acc, e| Expression::distribute(&acc, &e)) .unwrap(), - And(expressions) => And(expressions - .into_iter() - .map(|e| Arc::new(e.to_cnf())) - .collect()), - expression => expression, + And(es) => And(es.iter().map(|e| e.to_cnf()).collect()).into(), + _other => nnf, } } @@ -121,74 +127,93 @@ impl Expression { // | phi1, FAnd_wi and1 and2 → FAnd_wi (distr phi1 and1) (distr phi1 and2) // | phi1,phi2 → FOr_wi phi1 phi2 // end - fn distribute(first: Self, other: Self) -> Self { - match (first, other) { - (And(expressions), other) => And(expressions - .into_iter() - .map(|e| Arc::new(Expression::distribute(e.as_ref().clone(), other.clone()))) - .collect()), - (other, And(expressions)) => And(expressions - .into_iter() - .map(|e| Arc::new(Expression::distribute(other.clone(), e.as_ref().clone()))) - .collect()), - (expression1, expression2) => Expression::binary_or(expression1, expression2), + fn distribute(first: &Self, second: &Self) -> Self { + match (first.node(), second.node()) { + (And(es), _) => { + let es = es + .iter() + .map(|e| Expression::distribute(e, second)) + .collect(); + And(es).into() + } + (_, And(es)) => { + let es = es + .iter() + .map(|e| Expression::distribute(first, e)) + .collect(); + And(es).into() + } + (_e1, _e2) => Expression::binary_or(first, second), } } pub fn is_cnf(&self) -> bool { - match self { + match self.node() { Literal(_) => true, Constant(_) => false, - Not(ref inner) => matches!(inner.deref(), Literal(_)), + Not(inner) => matches!(inner.node(), Literal(_)), And(es) => es.iter().all(|e| e.is_cnf()), Or(es) => !es.iter().any(|e| e.is_and()) && es.iter().all(|e| e.is_cnf()), } } pub fn rename_literals(&self, mapping: &HashMap) -> Self { - match self { - Literal(name) => { - let new = mapping.get(name).unwrap_or(name); - Literal(new.clone()) - } + match self.node() { + Literal(name) => Literal(mapping.get(name).unwrap_or(name).clone()), Constant(value) => Constant(*value), - Not(inner) => Expression::negate(inner.as_ref().rename_literals(mapping)), + Not(inner) => Not(inner.rename_literals(mapping)), And(expressions) => And(expressions .iter() - .map(|e| Arc::new(e.as_ref().rename_literals(mapping))) + .map(|e| e.rename_literals(mapping)) .collect()), Or(expressions) => Or(expressions .iter() - .map(|e| Arc::new(e.as_ref().rename_literals(mapping))) + .map(|e| e.rename_literals(mapping)) .collect()), } + .into() } } #[cfg(test)] -mod tests { +pub mod tests { use std::collections::HashMap; - #[allow(unused_imports)] // false positive, no idea why - use crate::expressions::Expression::{self, Constant, Literal}; - #[allow(unused_imports)] // false positive, probably because of usage in macros? use crate::traits::SemanticEq; + use super::Expression; + use super::ExpressionNode; + + /// A utiltiy function to quickly create a list of literal expressions. + pub fn vars(names: [&str; K]) -> [Expression; K] { + std::array::from_fn(|i| ExpressionNode::Literal(names[i].to_string()).into()) + } + + /// A utility function to quickly create a single literal expression. + pub fn var(name: T) -> Expression { + ExpressionNode::Literal(name.to_string()).into() + } + + /// A utility function to quickly create a constant expression. + pub fn bool(value: bool) -> Expression { + ExpressionNode::Constant(value).into() + } + + #[test] + fn test_literals() { + let x = var("a"); + let y = Expression::negate(&x); + let z = Expression::negate(&y); + assert!(x.is_literal()); + assert!(y.is_literal()); + assert!(!z.is_literal()); + } + #[test] fn test_to_nnf_1() { // (Not notA) ∨ (Not (notB ∨ vC)), vA ∨ (vB ∧ notC) - let input = Expression::binary_or( - Expression::negate(Expression::negate(Literal("a"))), - Expression::negate(Expression::binary_or( - Expression::negate(Literal("b")), - Literal("c"), - )), - ); - - let expected = Expression::binary_or( - Literal("a"), - Expression::binary_and(Literal("b"), Expression::negate(Literal("c"))), - ); + let input = !!var("a") | !(!var("b") | var("c")); + let expected = var("a") | (var("b") & !var("c")); let actual = input.to_nnf(); assert!(expected.semantic_eq(&actual)); @@ -197,24 +222,8 @@ mod tests { #[test] fn test_to_nnf_2() { // Not (vA ∨ (notD ∨ Not (notA ∨ Not notB))), notA ∧ (vD ∧ (notA ∨ vB)) - let input = Expression::negate(Expression::binary_or( - Literal("a"), - Expression::binary_or( - Expression::negate(Literal("d")), - Expression::negate(Expression::binary_or( - Expression::negate(Literal("a")), - Expression::negate(Expression::negate(Literal("b"))), - )), - ), - )); - - let expected = Expression::binary_and( - Expression::negate(Literal("a")), - Expression::binary_and( - Literal("d"), - Expression::binary_or(Expression::negate(Literal("a")), Literal("b")), - ), - ); + let input = !(var("a") | !var("d") | !(!var("a") | !!var("b"))); + let expected = !var("a") & var("d") & (!var("a") | var("b")); let actual = input.to_nnf(); assert!(expected.semantic_eq(&actual)); @@ -223,21 +232,8 @@ mod tests { #[test] fn test_to_nnn_3() { // Not (notA ∨ vB) ∨ Not (vB ∧ notC), (vA ∧ notB) ∨ (notB ∨ vC) - let input = Expression::binary_or( - Expression::negate(Expression::binary_or( - Expression::negate(Literal("a")), - Literal("b"), - )), - Expression::negate(Expression::binary_and( - Literal("b"), - Expression::negate(Literal("c")), - )), - ); - - let expected = Expression::binary_or( - Expression::binary_and(Literal("a"), Expression::negate(Literal("b"))), - Expression::binary_or(Expression::negate(Literal("b")), Literal("c")), - ); + let input = !(!var("a") | var("b")) | !(var("b") & !var("c")); + let expected = (var("a") & !var("b")) | !var("b") | var("c"); let actual = input.to_nnf(); assert!(expected.semantic_eq(&actual)); @@ -245,29 +241,19 @@ mod tests { #[test] fn distribute_basic() { - let input_left = Literal("a"); - let input_right = Expression::binary_and(Literal("b"), Literal("c")); + let input_left = var("a"); + let input_right = var("b") & var("c"); - let expected = Expression::binary_and( - Expression::binary_or(Literal("a"), Literal("b")), - Expression::binary_or(Literal("a"), Literal("c")), - ); - let actual = Expression::distribute(input_left, input_right); + let expected = (var("a") | var("b")) & (var("a") | var("c")); + let actual = Expression::distribute(&input_left, &input_right); assert!(expected.semantic_eq(&actual)); } #[test] fn to_cnf_basic() { - let input = Expression::binary_or( - Literal("a"), - Expression::binary_and(Literal("b"), Literal("c")), - ); - - let expected = Expression::binary_and( - Expression::binary_or(Literal("a"), Literal("b")), - Expression::binary_or(Literal("a"), Literal("c")), - ); + let input = var("a") | (var("b") & var("c")); + let expected = (var("a") | var("b")) & (var("a") | var("c")); let actual = input.to_cnf(); assert!(expected.semantic_eq(&actual)); @@ -276,16 +262,8 @@ mod tests { #[test] fn to_cnf_n_ary() { - let input = Expression::n_ary_or(vec![ - Literal("a"), - Literal("b"), - Expression::binary_and(Literal("c"), Literal("d")), - ]); - - let expected = Expression::binary_and( - Expression::n_ary_or(vec![Literal("a"), Literal("b"), Literal("c")]), - Expression::n_ary_or(vec![Literal("a"), Literal("b"), Literal("d")]), - ); + let input = var("a") | var("b") | (var("c") & var("d")); + let expected = (var("a") | var("b") | var("c")) & (var("a") | var("b") | var("d")); let actual = input.to_cnf(); assert!(expected.semantic_eq(&actual)); @@ -294,62 +272,15 @@ mod tests { #[test] fn to_cnf_n_ary_2() { - let input = Expression::n_ary_or(vec![ - Literal("e1"), - Literal("e2"), - Literal("e3"), - Literal("e4"), - Literal("e5"), - Expression::n_ary_and(vec![ - Literal("c1"), - Literal("c2"), - Literal("c3"), - Literal("c4"), - Literal("c5"), - ]), - ]); - - let expected = Expression::n_ary_and(vec![ - Expression::n_ary_or(vec![ - Literal("e1"), - Literal("e2"), - Literal("e3"), - Literal("e4"), - Literal("e5"), - Literal("c1"), - ]), - Expression::n_ary_or(vec![ - Literal("e1"), - Literal("e2"), - Literal("e3"), - Literal("e4"), - Literal("e5"), - Literal("c2"), - ]), - Expression::n_ary_or(vec![ - Literal("e1"), - Literal("e2"), - Literal("e3"), - Literal("e4"), - Literal("e5"), - Literal("c3"), - ]), - Expression::n_ary_or(vec![ - Literal("e1"), - Literal("e2"), - Literal("e3"), - Literal("e4"), - Literal("e5"), - Literal("c4"), - ]), - Expression::n_ary_or(vec![ - Literal("e1"), - Literal("e2"), - Literal("e3"), - Literal("e4"), - Literal("e5"), - Literal("c5"), - ]), + let c = Expression::n_ary_and(&vars(["c1", "c2", "c3", "c4", "c5"])); + let input = var("e1") | var("e2") | var("e3") | var("e4") | var("e5") | c; + + let expected = Expression::n_ary_and(&[ + Expression::n_ary_or(&vars(["e1", "e2", "e3", "e4", "e5", "c1"])), + Expression::n_ary_or(&vars(["e1", "e2", "e3", "e4", "e5", "c2"])), + Expression::n_ary_or(&vars(["e1", "e2", "e3", "e4", "e5", "c3"])), + Expression::n_ary_or(&vars(["e1", "e2", "e3", "e4", "e5", "c4"])), + Expression::n_ary_or(&vars(["e1", "e2", "e3", "e4", "e5", "c5"])), ]); let actual = input.to_cnf(); @@ -359,18 +290,21 @@ mod tests { #[test] fn is_cnf_levels() { + // We intentionally don't use the built-in operators because they would "level" the expression. + let x = var("x"); + let y = var("y"); let nested = Expression::binary_and( - Expression::binary_and( - Expression::binary_or(Literal("x"), Literal("y")), - Expression::binary_or(Literal("x"), Literal("y")), + &Expression::binary_and( + &Expression::binary_or(&x, &y), + &Expression::binary_or(&x, &y), ), - Expression::binary_or(Literal("x"), Literal("y")), + &Expression::binary_or(&x, &y), ); - let leveled = Expression::n_ary_and(vec![ - Expression::binary_or(Literal("x"), Literal("y")), - Expression::binary_or(Literal("x"), Literal("y")), - Expression::binary_or(Literal("x"), Literal("y")), + let leveled = Expression::n_ary_and(&[ + Expression::binary_or(&x, &y), + Expression::binary_or(&x, &y), + Expression::binary_or(&x, &y), ]); assert!(nested.semantic_eq(&leveled)); @@ -381,29 +315,12 @@ mod tests { #[test] fn test_rename_literals_ok() { - let mut mapping = HashMap::new(); - mapping.insert("a", "1"); - mapping.insert("b", "2"); - mapping.insert("c", "3"); - mapping.insert("d", "4"); - mapping.insert("e", "5"); - - let input = Expression::n_ary_or(vec![ - Literal("a"), - Literal("b"), - Expression::binary_and(Literal("c"), Literal("d")), - Constant(true), - Expression::negate(Literal("a")), - ]); + let pairs = [("a", "1"), ("b", "2"), ("c", "3"), ("d", "4"), ("e", "5")]; + let mapping = HashMap::from_iter(pairs.iter().map(|(x, y)| (x.to_string(), y.to_string()))); + let input = var("a") | var("b") | (var("c") & var("d")) | bool(true) | !var("a"); + let expected = var("1") | var("2") | (var("3") & var("4")) | bool(true) | !var("1"); let actual = input.rename_literals(&mapping); - let expected = Expression::n_ary_or(vec![ - Literal("1"), - Literal("2"), - Expression::binary_and(Literal("3"), Literal("4")), - Constant(true), - Expression::negate(Literal("1")), - ]); assert_eq!(actual, expected) } diff --git a/src/expressions/traits.rs b/src/expressions/traits.rs index a4892e7..2eba4d8 100644 --- a/src/expressions/traits.rs +++ b/src/expressions/traits.rs @@ -5,10 +5,12 @@ use std::ops::{BitAnd, BitOr}; use itertools::Itertools; -use crate::expressions::Expression::{self, And, Constant, Literal, Not, Or}; use crate::parser::{parse_tokens, tokenize, ParseError}; use crate::traits::{Evaluate, GatherLiterals, Parse, PowerSet, SemanticEq}; +use super::Expression; +use super::ExpressionNode::{And, Constant, Literal, Not, Or}; + impl SemanticEq for Expression { fn semantic_eq(&self, other: &Self) -> bool { let self_literals = self.gather_literals(); @@ -25,7 +27,7 @@ impl SemanticEq for Expression GatherLiterals for Expression { fn gather_literals_rec(&self, current: &mut HashSet) { - match self { + match self.node() { Literal(l) => { current.insert(l.clone()); } @@ -60,7 +62,7 @@ impl PowerSet for Expression Evaluate for Expression { fn evaluate(&self, literal_values: &HashMap) -> bool { - match self { + match self.node() { Literal(t) => *literal_values.get(t).unwrap_or(&false), Constant(value) => *value, And(values) => values.iter().all(|e| e.evaluate(literal_values)), @@ -73,7 +75,7 @@ impl Evaluate for Expression, ) -> Result { - match self { + match self.node() { Literal(t) => match literal_values.get(t) { None => Err(t.clone()), Some(valuation) => Ok(*valuation), @@ -103,7 +105,7 @@ impl Parse for Expression { impl Display for Expression { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { - match self { + match self.node() { Constant(value) => write!(f, "{}", value), Literal(name) => write!(f, "{}", name), Not(inner) => write!(f, "!{}", inner), @@ -117,3 +119,83 @@ impl Display for Expression std::ops::BitAnd> for Expression { + type Output = Expression; + + fn bitand(self, rhs: Expression) -> Self::Output { + let mut es = Vec::new(); + match (self.node(), rhs.node()) { + (And(es1), And(es2)) => { + es.extend(es1.iter().cloned()); + es.extend(es2.iter().cloned()); + } + (And(es1), _other) => { + es.extend(es1.iter().cloned()); + es.push(rhs); + } + (_other, And(es2)) => { + es.push(self); + es.extend(es2.iter().cloned()); + } + _ => { + es.push(self); + es.push(rhs); + } + } + + And(es).into() + } + } + + impl std::ops::BitOr> for Expression { + type Output = Expression; + + fn bitor(self, rhs: Expression) -> Self::Output { + let mut es = Vec::new(); + match (self.node(), rhs.node()) { + (Or(es1), Or(es2)) => { + es.extend(es1.iter().cloned()); + es.extend(es2.iter().cloned()); + } + (Or(es1), _other) => { + es.extend(es1.iter().cloned()); + es.push(rhs); + } + (_other, Or(es2)) => { + es.push(self); + es.extend(es2.iter().cloned()); + } + _ => { + es.push(self); + es.push(rhs); + } + } + + Or(es).into() + } + } + + impl std::ops::Not for Expression { + type Output = Expression; + + fn not(self) -> Self::Output { + Not(self).into() + } + } +} diff --git a/src/parser/parse.rs b/src/parser/parse.rs index 79b5778..330487f 100644 --- a/src/parser/parse.rs +++ b/src/parser/parse.rs @@ -1,7 +1,5 @@ -use itertools::Itertools; -use std::sync::Arc; - use crate::expressions::Expression; +use crate::expressions::ExpressionNode::{And, Constant, Literal, Not, Or}; use crate::parser::error::ParseTokensError; use crate::parser::structs::FinalToken; @@ -10,45 +8,44 @@ pub fn parse_tokens(input: &[FinalToken]) -> Result, ParseTok } fn priority_0_parse_or(data: &[FinalToken]) -> Result, ParseTokensError> { - data.split(|t| t == &FinalToken::Or) - .map(priority_1_parse_and) - .fold_ok(None::>, |acc, item| match acc { - None => Some(item), - Some(Expression::Or(mut es)) => { - es.push(Arc::new(item)); - Some(Expression::Or(es)) - } - Some(previous) => Some(Expression::n_ary_or(vec![previous, item])), - })? - .ok_or(ParseTokensError::EmptySideOfOperator) + let mut es = Vec::new(); + for group in data.split(|t| t == &FinalToken::Or) { + es.push(priority_1_parse_and(group)?); + } + + match es.len() { + 0 => Err(ParseTokensError::EmptySideOfOperator), + 1 => Ok(es.remove(0)), + _ => Ok(Or(es).into()), + } } fn priority_1_parse_and(data: &[FinalToken]) -> Result, ParseTokensError> { - data.split(|t| t == &FinalToken::And) - .map(priority_2_terminal) - .fold_ok(None::>, |acc, item| match acc { - None => Some(item), - Some(Expression::And(mut es)) => { - es.push(Arc::new(item)); - Some(Expression::And(es)) - } - Some(previous) => Some(Expression::n_ary_and(vec![previous, item])), - })? - .ok_or(ParseTokensError::EmptySideOfOperator) + let mut es = Vec::new(); + for group in data.split(|t| t == &FinalToken::And) { + es.push(priority_2_terminal(group)?); + } + + match es.len() { + 0 => Err(ParseTokensError::EmptySideOfOperator), + 1 => Ok(es.remove(0)), + _ => Ok(And(es).into()), + } } fn priority_2_terminal(data: &[FinalToken]) -> Result, ParseTokensError> { if data.is_empty() { Err(ParseTokensError::EmptySideOfOperator) } else if data[0] == FinalToken::Not { - Ok(Expression::negate(priority_2_terminal(&data[1..])?)) + Ok(Not(priority_2_terminal(&data[1..])?).into()) } else if data.len() > 1 { Err(ParseTokensError::UnexpectedLiteralsGroup) } else { + // data.len() == 1 match &data[0] { - FinalToken::ConstantTrue => Ok(Expression::Constant(true)), - FinalToken::ConstantFalse => Ok(Expression::Constant(false)), - FinalToken::Literal(name) => Ok(Expression::Literal(name.clone())), + FinalToken::ConstantTrue => Ok(Constant(true).into()), + FinalToken::ConstantFalse => Ok(Constant(false).into()), + FinalToken::Literal(name) => Ok(Literal(name.clone()).into()), FinalToken::Parentheses(inner) => Ok(parse_tokens(inner)?), _ => unreachable!( "Other tokens are matched by remaining functions, nothing else should remain." @@ -59,7 +56,7 @@ fn priority_2_terminal(data: &[FinalToken]) -> Result, ParseT #[cfg(test)] mod tests { - use crate::expressions::Expression::{Constant, Literal}; + use crate::expressions::tests::{bool, var}; use crate::parser::error::ParseTokensError::EmptySideOfOperator; use crate::parser::{tokenize, ParseError}; use crate::traits::SemanticEq; @@ -81,7 +78,7 @@ mod tests { fn test_binaryand_ok() -> Result<(), ParseError> { let input = tokenize("a & b")?; let actual = parse_tokens(&input)?; - let expected = Expression::binary_and(Literal("a".to_string()), Literal("b".to_string())); + let expected = var("a") & var("b"); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -93,11 +90,7 @@ mod tests { fn test_naryand_ok() -> Result<(), ParseError> { let input = tokenize("a & b & c")?; let actual = parse_tokens(&input)?; - let expected = Expression::n_ary_and(vec![ - Literal("a".to_string()), - Literal("b".to_string()), - Literal("c".to_string()), - ]); + let expected = var("a") & var("b") & var("c"); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -109,7 +102,7 @@ mod tests { fn test_binaryor_ok() -> Result<(), ParseError> { let input = tokenize("a | b")?; let actual = parse_tokens(&input)?; - let expected = Expression::binary_or(Literal("a".to_string()), Literal("b".to_string())); + let expected = var("a") | var("b"); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -121,11 +114,7 @@ mod tests { fn test_naryor_ok() -> Result<(), ParseError> { let input = tokenize("a | b | c")?; let actual = parse_tokens(&input)?; - let expected = Expression::n_ary_or(vec![ - Literal("a".to_string()), - Literal("b".to_string()), - Literal("c".to_string()), - ]); + let expected = var("a") | var("b") | var("c"); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -137,7 +126,7 @@ mod tests { fn test_parentheses_toplevel_ok() -> Result<(), ParseError> { let input = tokenize("(a)")?; let actual = parse_tokens(&input)?; - let expected = Literal("a".to_string()); + let expected = var("a"); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -149,15 +138,7 @@ mod tests { fn test_parentheses_naryor_naryand_ok() -> Result<(), ParseError> { let input = tokenize("a | b | (a & b & !c)")?; let actual = parse_tokens(&input)?; - let expected = Expression::n_ary_or(vec![ - Literal("a".to_string()), - Literal("b".to_string()), - Expression::n_ary_and(vec![ - Literal("a".to_string()), - Literal("b".to_string()), - Expression::negate(Literal("c".to_string())), - ]), - ]); + let expected = var("a") | var("b") | (var("a") & var("b") & !var("c")); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -169,12 +150,8 @@ mod tests { fn test_parentheses_naryor_naryand_constants_ok() -> Result<(), ParseError> { let input = tokenize("F | 0 | False | (T & 1 & True)")?; let actual = parse_tokens(&input)?; - let expected = Expression::n_ary_or(vec![ - Constant(false), - Constant(false), - Constant(false), - Expression::n_ary_and(vec![Constant(true), Constant(true), Constant(true)]), - ]); + let expected = + bool(false) | bool(false) | bool(false) | (bool(true) & bool(true) & bool(true)); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected); @@ -186,15 +163,7 @@ mod tests { fn test_priorities_naryor_naryand_ok() -> Result<(), ParseError> { let input = tokenize("a | b | a & b & !c")?; let actual = parse_tokens(&input)?; - let expected = Expression::n_ary_or(vec![ - Literal("a".to_string()), - Literal("b".to_string()), - Expression::n_ary_and(vec![ - Literal("a".to_string()), - Literal("b".to_string()), - Expression::negate(Literal("c".to_string())), - ]), - ]); + let expected = var("a") | var("b") | (var("a") & var("b") & !var("c")); assert!(actual.semantic_eq(&expected)); assert_eq!(actual, expected);