use super::*; impl super::Precedence for crate::Term { fn precedence_level(&self) -> i32 { match &self { Self::Boolean(_) | Self::SpecialInteger(_) | Self::Integer(_) | Self::String(_) | Self::Variable(_) | Self::Function(_) | Self::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, ..}) => 0, Self::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::Negative, ..}) => 1, Self::BinaryOperation( crate::BinaryOperation{operator: crate::BinaryOperator::Exponentiate, ..}) => 2, Self::BinaryOperation( crate::BinaryOperation{operator: crate::BinaryOperator::Multiply, ..}) | Self::BinaryOperation( crate::BinaryOperation{operator: crate::BinaryOperator::Divide, ..}) | Self::BinaryOperation( crate::BinaryOperation{operator: crate::BinaryOperator::Modulo, ..}) => 3, Self::BinaryOperation(crate::BinaryOperation{operator: crate::BinaryOperator::Add, ..}) | Self::BinaryOperation( crate::BinaryOperation{operator: crate::BinaryOperator::Subtract, ..}) => 4, } } } impl std::fmt::Debug for crate::SpecialInteger { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { match &self { Self::Infimum => write!(format, "#inf"), Self::Supremum => write!(format, "#sup"), } } } impl std::fmt::Display for crate::SpecialInteger { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } } impl std::fmt::Debug for crate::FunctionDeclaration { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{}/{}", &self.name, self.arity) } } impl std::fmt::Display for crate::FunctionDeclaration { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } } impl std::fmt::Debug for crate::VariableDeclaration { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{}", &self.name) } } impl std::fmt::Display for crate::VariableDeclaration { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } } pub(crate) struct TermDisplay<'term> { parentheses: Parentheses, term: &'term crate::Term, } pub(crate) fn display_term(term: &crate::Term, parentheses: Parentheses) -> TermDisplay { TermDisplay { parentheses, term, } } impl<'term> std::fmt::Debug for TermDisplay<'term> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { let precedence_level = self.term.precedence_level(); let requires_parentheses = match self.parentheses { Parentheses::Required => true, Parentheses::PrecedenceBased(parent_precedence_level) => precedence_level > parent_precedence_level, Parentheses::None => false, }; let parentheses = Parentheses::PrecedenceBased(precedence_level); if requires_parentheses { write!(format, "(")?; } match &self.term { crate::Term::Boolean(true) => write!(format, "true"), crate::Term::Boolean(false) => write!(format, "false"), crate::Term::SpecialInteger(value) => write!(format, "{:?}", value), crate::Term::Integer(value) => write!(format, "{}", value), crate::Term::String(value) => write!(format, "\"{}\"", value.replace("\\", "\\\\").replace("\n", "\\n").replace("\t", "\\t")), crate::Term::Variable(variable) => write!(format, "{:?}", variable.declaration), crate::Term::Function(function) => { write!(format, "{}", function.declaration.name)?; assert!(function.declaration.arity == function.arguments.len(), "number of function arguments differs from declaration (expected {}, got {})", function.declaration.arity, function.arguments.len()); if !function.arguments.is_empty() { write!(format, "(")?; let mut separator = ""; for argument in &function.arguments { write!(format, "{}{:?}", separator, display_term(&argument, Parentheses::None))?; separator = ", "; } write!(format, ")")?; } Ok(()) }, crate::Term::BinaryOperation(binary_operation) => { let operator_string = match binary_operation.operator { crate::BinaryOperator::Add => "+", crate::BinaryOperator::Subtract => "-", crate::BinaryOperator::Multiply => "*", crate::BinaryOperator::Divide => "/", crate::BinaryOperator::Modulo => "%", crate::BinaryOperator::Exponentiate => "**", }; let left_parentheses = match binary_operation.left.precedence_level() == precedence_level // Exponentiation is right-associative and thus requires parentheses when // nested on the left side && binary_operation.operator == crate::BinaryOperator::Exponentiate { true => Parentheses::Required, false => parentheses, }; // The subtraction, division, and modulo operators require parentheses around the // right argument even if it has the same precedence let operator_requires_right_priority = match binary_operation.operator { crate::BinaryOperator::Subtract | crate::BinaryOperator::Divide | crate::BinaryOperator::Modulo => true, _ => false, }; // Additionally, modulo operations nested to the right of another multiplicative // operation always require parentheses let right_requires_priority = match *binary_operation.right { crate::Term::BinaryOperation( crate::BinaryOperation{operator: crate::BinaryOperator::Modulo, ..}) => true, _ => false, }; let right_parentheses = match binary_operation.right.precedence_level() == precedence_level && (operator_requires_right_priority || right_requires_priority) { true => Parentheses::Required, false => parentheses, }; write!(format, "{:?} {} {:?}", display_term(&binary_operation.left, left_parentheses), operator_string, display_term(&binary_operation.right, right_parentheses)) }, crate::Term::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::Negative, argument}) => write!(format, "-{:?}", display_term(argument, parentheses)), crate::Term::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, argument}) => write!(format, "|{:?}|", display_term(argument, Parentheses::None)), }?; if requires_parentheses { write!(format, ")")?; } Ok(()) } } impl<'term> std::fmt::Display for TermDisplay<'term> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", self) } } impl std::fmt::Debug for crate::Term { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", display_term(&self, Parentheses::None)) } } impl std::fmt::Display for crate::Term { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{}", display_term(&self, Parentheses::None)) } } #[cfg(test)] pub(crate) mod tests { use crate::*; fn format(term: Box) -> String { format!("{}", term) } pub(crate) fn absolute_value(argument: Box) -> Box { Box::new(Term::absolute_value(argument)) } pub(crate) fn add(left: Box, right: Box) -> Box { Box::new(Term::add(left, right)) } pub(crate) fn constant(name: &str) -> Box { Box::new(Term::function(function_declaration(name, 0), vec![])) } pub(crate) fn divide(left: Box, right: Box) -> Box { Box::new(Term::divide(left, right)) } pub(crate) fn exponentiate(left: Box, right: Box) -> Box { Box::new(Term::exponentiate(left, right)) } pub(crate) fn false_() -> Box { Box::new(Term::false_()) } pub(crate) fn function(name: &str, arguments: Vec>) -> Box { Box::new(Term::function(function_declaration(name, arguments.len()), arguments)) } pub(crate) fn function_declaration(name: &str, arity: usize) -> std::rc::Rc { std::rc::Rc::new(FunctionDeclaration::new(name.to_string(), arity)) } pub(crate) fn infimum() -> Box { Box::new(Term::infimum()) } pub(crate) fn integer(value: i32) -> Box { Box::new(Term::integer(value)) } pub(crate) fn modulo(left: Box, right: Box) -> Box { Box::new(Term::modulo(left, right)) } pub(crate) fn multiply(left: Box, right: Box) -> Box { Box::new(Term::multiply(left, right)) } pub(crate) fn negative(argument: Box) -> Box { Box::new(Term::negative(argument)) } pub(crate) fn subtract(left: Box, right: Box) -> Box { Box::new(Term::subtract(left, right)) } pub(crate) fn supremum() -> Box { Box::new(Term::supremum()) } pub(crate) fn string(value: &str) -> Box { Box::new(Term::string(value.to_string())) } pub(crate) fn true_() -> Box { Box::new(Term::true_()) } pub(crate) fn variable(name: &str) -> Box { Box::new(Term::variable(variable_declaration(name))) } pub(crate) fn variable_declaration(name: &str) -> std::rc::Rc { std::rc::Rc::new(VariableDeclaration::new(name.to_string())) } #[test] fn format_binary_operation() { assert_eq!(format(add(constant("a"), constant("b"))), "a + b"); assert_eq!(format(subtract(constant("a"), constant("b"))), "a - b"); assert_eq!(format(multiply(constant("a"), constant("b"))), "a * b"); assert_eq!(format(divide(constant("a"), constant("b"))), "a / b"); assert_eq!(format(modulo(constant("a"), constant("b"))), "a % b"); assert_eq!(format(exponentiate(constant("a"), constant("b"))), "a ** b"); } #[test] fn format_boolean() { assert_eq!(format(true_()), "true"); assert_eq!(format(false_()), "false"); } #[test] fn format_special_integer() { assert_eq!(format(infimum()), "#inf"); assert_eq!(format(supremum()), "#sup"); } #[test] fn format_integer() { assert_eq!(format(integer(0)), "0"); assert_eq!(format(integer(1)), "1"); assert_eq!(format(integer(10000)), "10000"); assert_eq!(format(integer(-1)), "-1"); assert_eq!(format(integer(-10000)), "-10000"); } #[test] fn format_string() { assert_eq!(format(string("")), "\"\""); assert_eq!(format(string(" ")), "\" \""); assert_eq!(format(string(" ")), "\" \""); assert_eq!(format(string("a")), "\"a\""); assert_eq!(format(string("test test")), "\"test test\""); assert_eq!(format(string("123 123")), "\"123 123\""); assert_eq!(format(string("\ntest\n123\n")), "\"\\ntest\\n123\\n\""); assert_eq!(format(string("\ttest\t123\t")), "\"\\ttest\\t123\\t\""); assert_eq!(format(string("\\test\\123\\")), "\"\\\\test\\\\123\\\\\""); assert_eq!(format(string("๐Ÿ™‚test๐Ÿ™‚123๐Ÿ™‚")), "\"๐Ÿ™‚test๐Ÿ™‚123๐Ÿ™‚\""); } #[test] fn format_function() { assert_eq!(format(constant("a")), "a"); assert_eq!(format(constant("constant")), "constant"); assert_eq!(format(function("f", vec![constant("a")])), "f(a)"); assert_eq!(format( function("f", vec![constant("a"), constant("b"), constant("c")])), "f(a, b, c)"); assert_eq!(format(function("function", vec![constant("a"), constant("b"), constant("c")])), "function(a, b, c)"); assert_eq!(format( function("function", vec![ exponentiate(absolute_value(multiply(constant("a"), integer(-20))), integer(2)), string("test"), function("f", vec![multiply(add(constant("b"), constant("c")), subtract(constant("b"), constant("c"))), infimum(), variable("X")])])), "function(|a * -20| ** 2, \"test\", f((b + c) * (b - c), #inf, X))"); // TODO: escape functions that start with capital letters or that conflict with keywords } #[test] fn format_function_declaration() { assert_eq!(format!("{}", function_declaration("a", 0)), "a/0"); assert_eq!(format!("{}", function_declaration("constant", 0)), "constant/0"); assert_eq!(format!("{}", function_declaration("f", 1)), "f/1"); assert_eq!(format!("{}", function_declaration("f", 3)), "f/3"); assert_eq!(format!("{}", function_declaration("function", 3)), "function/3"); } #[test] fn format_variable() { assert_eq!(format(variable("X")), "X"); assert_eq!(format(variable("Variable")), "Variable"); } #[test] fn format_combination_boolean_and_lower() { assert_eq!(format(function("f", vec![true_(), true_(), true_()])), "f(true, true, true)"); assert_eq!(format( function("f", vec![false_(), false_(), false_()])), "f(false, false, false)"); assert_eq!(format(absolute_value(true_())), "|true|"); assert_eq!(format(absolute_value(false_())), "|false|"); assert_eq!(format(negative(true_())), "-true"); assert_eq!(format(negative(false_())), "-false"); assert_eq!(format(exponentiate(true_(), true_())), "true ** true"); assert_eq!(format(exponentiate(false_(), false_())), "false ** false"); assert_eq!(format(multiply(true_(), true_())), "true * true"); assert_eq!(format(multiply(false_(), false_())), "false * false"); assert_eq!(format(divide(true_(), true_())), "true / true"); assert_eq!(format(divide(false_(), false_())), "false / false"); assert_eq!(format(modulo(true_(), true_())), "true % true"); assert_eq!(format(modulo(false_(), false_())), "false % false"); assert_eq!(format(add(true_(), true_())), "true + true"); assert_eq!(format(add(false_(), false_())), "false + false"); assert_eq!(format(subtract(true_(), true_())), "true - true"); assert_eq!(format(subtract(false_(), false_())), "false - false"); } #[test] fn format_combination_special_integer_and_lower() { assert_eq!(format( function("f", vec![infimum(), infimum(), infimum()])), "f(#inf, #inf, #inf)"); assert_eq!(format( function("f", vec![supremum(), supremum(), supremum()])), "f(#sup, #sup, #sup)"); assert_eq!(format(absolute_value(infimum())), "|#inf|"); assert_eq!(format(absolute_value(supremum())), "|#sup|"); assert_eq!(format(negative(infimum())), "-#inf"); assert_eq!(format(negative(supremum())), "-#sup"); assert_eq!(format(exponentiate(infimum(), infimum())), "#inf ** #inf"); assert_eq!(format(exponentiate(supremum(), supremum())), "#sup ** #sup"); assert_eq!(format(multiply(infimum(), infimum())), "#inf * #inf"); assert_eq!(format(multiply(supremum(), supremum())), "#sup * #sup"); assert_eq!(format(divide(infimum(), infimum())), "#inf / #inf"); assert_eq!(format(divide(supremum(), supremum())), "#sup / #sup"); assert_eq!(format(modulo(infimum(), infimum())), "#inf % #inf"); assert_eq!(format(modulo(supremum(), supremum())), "#sup % #sup"); assert_eq!(format(add(infimum(), infimum())), "#inf + #inf"); assert_eq!(format(add(supremum(), supremum())), "#sup + #sup"); assert_eq!(format(subtract(infimum(), infimum())), "#inf - #inf"); assert_eq!(format(subtract(supremum(), supremum())), "#sup - #sup"); } #[test] fn format_combination_integer_and_lower() { assert_eq!(format( function("f", vec![integer(0), integer(0), integer(0)])), "f(0, 0, 0)"); assert_eq!(format( function("f", vec![integer(10000), integer(10000), integer(10000)])), "f(10000, 10000, 10000)"); assert_eq!(format( function("f", vec![integer(-10000), integer(-10000), integer(-10000)])), "f(-10000, -10000, -10000)"); assert_eq!(format(absolute_value(integer(0))), "|0|"); assert_eq!(format(absolute_value(integer(10000))), "|10000|"); assert_eq!(format(absolute_value(integer(-10000))), "|-10000|"); assert_eq!(format(negative(integer(0))), "-0"); assert_eq!(format(negative(integer(10000))), "-10000"); assert_eq!(format(negative(integer(-10000))), "--10000"); assert_eq!(format(exponentiate(integer(0), integer(0))), "0 ** 0"); assert_eq!(format(exponentiate(integer(10000), integer(10000))), "10000 ** 10000"); assert_eq!(format(exponentiate(integer(-10000), integer(-10000))), "-10000 ** -10000"); assert_eq!(format(multiply(integer(0), integer(0))), "0 * 0"); assert_eq!(format(multiply(integer(10000), integer(10000))), "10000 * 10000"); assert_eq!(format(multiply(integer(-10000), integer(-10000))), "-10000 * -10000"); assert_eq!(format(divide(integer(0), integer(0))), "0 / 0"); assert_eq!(format(divide(integer(10000), integer(10000))), "10000 / 10000"); assert_eq!(format(divide(integer(-10000), integer(-10000))), "-10000 / -10000"); assert_eq!(format(modulo(integer(0), integer(0))), "0 % 0"); assert_eq!(format(modulo(integer(10000), integer(10000))), "10000 % 10000"); assert_eq!(format(modulo(integer(-10000), integer(-10000))), "-10000 % -10000"); assert_eq!(format(add(integer(0), integer(0))), "0 + 0"); assert_eq!(format(add(integer(10000), integer(10000))), "10000 + 10000"); assert_eq!(format(add(integer(-10000), integer(-10000))), "-10000 + -10000"); assert_eq!(format(subtract(integer(0), integer(0))), "0 - 0"); assert_eq!(format(subtract(integer(10000), integer(10000))), "10000 - 10000"); assert_eq!(format(subtract(integer(-10000), integer(-10000))), "-10000 - -10000"); } #[test] fn format_combination_string_and_lower() { assert_eq!(format( function("f", vec![string(""), string(""), string("")])), "f(\"\", \"\", \"\")"); assert_eq!(format( function("f", vec![string("test 123"), string("test 123"), string("test 123")])), "f(\"test 123\", \"test 123\", \"test 123\")"); assert_eq!(format( function("f", vec![string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")])), "f(\"\\\\a\\nb๐Ÿ™‚c\\t\", \"\\\\a\\nb๐Ÿ™‚c\\t\", \"\\\\a\\nb๐Ÿ™‚c\\t\")"); assert_eq!(format(absolute_value(string(""))), "|\"\"|"); assert_eq!(format(absolute_value(string("test 123"))), "|\"test 123\"|"); assert_eq!(format(absolute_value(string("\\a\nb๐Ÿ™‚c\t"))), "|\"\\\\a\\nb๐Ÿ™‚c\\t\"|"); assert_eq!(format(negative(string(""))), "-\"\""); assert_eq!(format(negative(string("test 123"))), "-\"test 123\""); assert_eq!(format(negative(string("\\a\nb๐Ÿ™‚c\t"))), "-\"\\\\a\\nb๐Ÿ™‚c\\t\""); assert_eq!(format(exponentiate(string(""), string(""))), "\"\" ** \"\""); assert_eq!(format( exponentiate(string("test 123"), string("test 123"))), "\"test 123\" ** \"test 123\""); assert_eq!(format( exponentiate(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"))), "\"\\\\a\\nb๐Ÿ™‚c\\t\" ** \"\\\\a\\nb๐Ÿ™‚c\\t\""); assert_eq!(format(multiply(string(""), string(""))), "\"\" * \"\""); assert_eq!(format( multiply(string("test 123"), string("test 123"))), "\"test 123\" * \"test 123\""); assert_eq!(format( multiply(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"))), "\"\\\\a\\nb๐Ÿ™‚c\\t\" * \"\\\\a\\nb๐Ÿ™‚c\\t\""); assert_eq!(format(divide(string(""), string(""))), "\"\" / \"\""); assert_eq!(format( divide(string("test 123"), string("test 123"))), "\"test 123\" / \"test 123\""); assert_eq!(format( divide(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"))), "\"\\\\a\\nb๐Ÿ™‚c\\t\" / \"\\\\a\\nb๐Ÿ™‚c\\t\""); assert_eq!(format(modulo(string(""), string(""))), "\"\" % \"\""); assert_eq!(format( modulo(string("test 123"), string("test 123"))), "\"test 123\" % \"test 123\""); assert_eq!(format( modulo(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"))), "\"\\\\a\\nb๐Ÿ™‚c\\t\" % \"\\\\a\\nb๐Ÿ™‚c\\t\""); assert_eq!(format(add(string(""), string(""))), "\"\" + \"\""); assert_eq!(format( add(string("test 123"), string("test 123"))), "\"test 123\" + \"test 123\""); assert_eq!(format( add(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"))), "\"\\\\a\\nb๐Ÿ™‚c\\t\" + \"\\\\a\\nb๐Ÿ™‚c\\t\""); assert_eq!(format(subtract(string(""), string(""))), "\"\" - \"\""); assert_eq!(format( subtract(string("test 123"), string("test 123"))), "\"test 123\" - \"test 123\""); assert_eq!(format( subtract(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t"))), "\"\\\\a\\nb๐Ÿ™‚c\\t\" - \"\\\\a\\nb๐Ÿ™‚c\\t\""); } #[test] fn format_combination_variable_and_lower() { assert_eq!(format(variable("X")), "X"); assert_eq!(format(variable("Variable")), "Variable"); assert_eq!(format(absolute_value(variable("X"))), "|X|"); assert_eq!(format(absolute_value(variable("Variable"))), "|Variable|"); assert_eq!(format(negative(variable("X"))), "-X"); assert_eq!(format(negative(variable("Variable"))), "-Variable"); assert_eq!(format(exponentiate(variable("X"), variable("X"))), "X ** X"); assert_eq!(format( exponentiate(variable("Variable"), variable("Variable"))), "Variable ** Variable"); assert_eq!(format(multiply(variable("X"), variable("X"))), "X * X"); assert_eq!(format( multiply(variable("Variable"), variable("Variable"))), "Variable * Variable"); assert_eq!(format(divide(variable("X"), variable("X"))), "X / X"); assert_eq!(format( divide(variable("Variable"), variable("Variable"))), "Variable / Variable"); assert_eq!(format(modulo(variable("X"), variable("X"))), "X % X"); assert_eq!(format( modulo(variable("Variable"), variable("Variable"))), "Variable % Variable"); assert_eq!(format(add(variable("X"), variable("X"))), "X + X"); assert_eq!(format( add(variable("Variable"), variable("Variable"))), "Variable + Variable"); assert_eq!(format(subtract(variable("X"), variable("X"))), "X - X"); assert_eq!(format( subtract(variable("Variable"), variable("Variable"))), "Variable - Variable"); } #[test] fn format_combination_function_and_lower() { let f1 = || constant("a"); let f2 = || constant("constant"); let f3 = || function("f", vec![constant("a")]); let f4 = || function("function", vec![constant("a"), constant("b"), constant("c")]); assert_eq!(format(absolute_value(f1())), "|a|"); assert_eq!(format(absolute_value(f2())), "|constant|"); assert_eq!(format(absolute_value(f3())), "|f(a)|"); assert_eq!(format(absolute_value(f4())), "|function(a, b, c)|"); assert_eq!(format(function("f", vec![absolute_value(constant("a"))])), "f(|a|)"); assert_eq!(format( function("f", vec![absolute_value(constant("a")), absolute_value(constant("b")), absolute_value(constant("c"))])), "f(|a|, |b|, |c|)"); assert_eq!(format(negative(f1())), "-a"); assert_eq!(format(negative(f2())), "-constant"); assert_eq!(format(negative(f3())), "-f(a)"); assert_eq!(format(negative(f4())), "-function(a, b, c)"); assert_eq!(format(function("f", vec![negative(constant("a"))])), "f(-a)"); assert_eq!(format( function("f", vec![negative(constant("a")), negative(constant("b")), negative(constant("c"))])), "f(-a, -b, -c)"); assert_eq!(format(exponentiate(f1(), f1())), "a ** a"); assert_eq!(format(exponentiate(f2(), f2())), "constant ** constant"); assert_eq!(format(exponentiate(f3(), f3())), "f(a) ** f(a)"); assert_eq!(format(exponentiate(f4(), f4())), "function(a, b, c) ** function(a, b, c)"); assert_eq!(format( function("f", vec![exponentiate(constant("a"), constant("b"))])), "f(a ** b)"); assert_eq!(format( function("f", vec![exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")), exponentiate(constant("e"), constant("f"))])), "f(a ** b, c ** d, e ** f)"); assert_eq!(format(multiply(f1(), f1())), "a * a"); assert_eq!(format(multiply(f2(), f2())), "constant * constant"); assert_eq!(format(multiply(f3(), f3())), "f(a) * f(a)"); assert_eq!(format(multiply(f4(), f4())), "function(a, b, c) * function(a, b, c)"); assert_eq!(format(function("f", vec![multiply(constant("a"), constant("b"))])), "f(a * b)"); assert_eq!(format( function("f", vec![multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")), multiply(constant("e"), constant("f"))])), "f(a * b, c * d, e * f)"); assert_eq!(format(divide(f1(), f1())), "a / a"); assert_eq!(format(divide(f2(), f2())), "constant / constant"); assert_eq!(format(divide(f3(), f3())), "f(a) / f(a)"); assert_eq!(format(divide(f4(), f4())), "function(a, b, c) / function(a, b, c)"); assert_eq!(format(function("f", vec![divide(constant("a"), constant("b"))])), "f(a / b)"); assert_eq!(format( function("f", vec![divide(constant("a"), constant("b")), divide(constant("c"), constant("d")), divide(constant("e"), constant("f"))])), "f(a / b, c / d, e / f)"); assert_eq!(format(modulo(f1(), f1())), "a % a"); assert_eq!(format(modulo(f2(), f2())), "constant % constant"); assert_eq!(format(modulo(f3(), f3())), "f(a) % f(a)"); assert_eq!(format(modulo(f4(), f4())), "function(a, b, c) % function(a, b, c)"); assert_eq!(format(function("f", vec![modulo(constant("a"), constant("b"))])), "f(a % b)"); assert_eq!(format( function("f", vec![modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")), modulo(constant("e"), constant("f"))])), "f(a % b, c % d, e % f)"); assert_eq!(format(add(f1(), f1())), "a + a"); assert_eq!(format(add(f2(), f2())), "constant + constant"); assert_eq!(format(add(f3(), f3())), "f(a) + f(a)"); assert_eq!(format(add(f4(), f4())), "function(a, b, c) + function(a, b, c)"); assert_eq!(format(function("f", vec![add(constant("a"), constant("b"))])), "f(a + b)"); assert_eq!(format( function("f", vec![add(constant("a"), constant("b")), add(constant("c"), constant("d")), add(constant("e"), constant("f"))])), "f(a + b, c + d, e + f)"); assert_eq!(format(subtract(f1(), f1())), "a - a"); assert_eq!(format(subtract(f2(), f2())), "constant - constant"); assert_eq!(format(subtract(f3(), f3())), "f(a) - f(a)"); assert_eq!(format(subtract(f4(), f4())), "function(a, b, c) - function(a, b, c)"); assert_eq!(format(function("f", vec![subtract(constant("a"), constant("b"))])), "f(a - b)"); assert_eq!(format( function("f", vec![subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")), subtract(constant("e"), constant("f"))])), "f(a - b, c - d, e - f)"); } #[test] fn format_combination_absolute_value_and_lower() { assert_eq!(format(absolute_value(absolute_value(constant("a")))), "||a||"); assert_eq!(format(absolute_value(negative(constant("a")))), "|-a|"); assert_eq!(format(negative(absolute_value(constant("a")))), "-|a|"); assert_eq!(format(absolute_value(add(constant("a"), constant("b")))), "|a + b|"); assert_eq!(format( add(absolute_value(constant("a")), absolute_value(constant("b")))), "|a| + |b|"); assert_eq!(format(absolute_value(subtract(constant("a"), constant("b")))), "|a - b|"); assert_eq!(format( subtract(absolute_value(constant("a")), absolute_value(constant("b")))), "|a| - |b|"); assert_eq!(format(absolute_value(multiply(constant("a"), constant("b")))), "|a * b|"); assert_eq!(format( multiply(absolute_value(constant("a")), absolute_value(constant("b")))), "|a| * |b|"); assert_eq!(format(absolute_value(divide(constant("a"), constant("b")))), "|a / b|"); assert_eq!(format( divide(absolute_value(constant("a")), absolute_value(constant("b")))), "|a| / |b|"); assert_eq!(format(absolute_value(modulo(constant("a"), constant("b")))), "|a % b|"); assert_eq!(format( modulo(absolute_value(constant("a")), absolute_value(constant("b")))), "|a| % |b|"); assert_eq!(format(absolute_value(exponentiate(constant("a"), constant("b")))), "|a ** b|"); assert_eq!(format( exponentiate(absolute_value(constant("a")), absolute_value(constant("b")))), "|a| ** |b|"); } #[test] fn format_combination_negative_and_lower() { assert_eq!(format(negative(negative(constant("a")))), "--a"); assert_eq!(format(add(negative(constant("a")), negative(constant("b")))), "-a + -b"); assert_eq!(format(negative(add(constant("a"), constant("b")))), "-(a + b)"); assert_eq!(format(subtract(negative(constant("a")), negative(constant("b")))), "-a - -b"); assert_eq!(format(negative(subtract(constant("a"), constant("b")))), "-(a - b)"); assert_eq!(format(multiply(negative(constant("a")), negative(constant("b")))), "-a * -b"); assert_eq!(format(negative(multiply(constant("a"), constant("b")))), "-(a * b)"); assert_eq!(format(divide(negative(constant("a")), negative(constant("b")))), "-a / -b"); assert_eq!(format(negative(divide(constant("a"), constant("b")))), "-(a / b)"); assert_eq!(format(modulo(negative(constant("a")), negative(constant("b")))), "-a % -b"); assert_eq!(format(negative(modulo(constant("a"), constant("b")))), "-(a % b)"); assert_eq!(format(exponentiate(negative(constant("a")), negative(constant("b")))), "-a ** -b"); assert_eq!(format(negative(exponentiate(constant("a"), constant("b")))), "-(a ** b)"); } #[test] fn format_combination_exponentiate_and_lower() { assert_eq!(format( exponentiate( exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")))), "(a ** b) ** c ** d"); assert_eq!(format( exponentiate( multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")))), "(a * b) ** (c * d)"); assert_eq!(format( multiply( exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")))), "a ** b * c ** d"); assert_eq!(format( exponentiate( divide(constant("a"), constant("b")), divide(constant("c"), constant("d")))), "(a / b) ** (c / d)"); assert_eq!(format( divide( exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")))), "a ** b / c ** d"); assert_eq!(format( exponentiate( modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")))), "(a % b) ** (c % d)"); assert_eq!(format( modulo( exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")))), "a ** b % c ** d"); assert_eq!(format( exponentiate( add(constant("a"), constant("b")), add(constant("c"), constant("d")))), "(a + b) ** (c + d)"); assert_eq!(format( add( exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")))), "a ** b + c ** d"); assert_eq!(format( exponentiate( subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")))), "(a - b) ** (c - d)"); assert_eq!(format( subtract( exponentiate(constant("a"), constant("b")), exponentiate(constant("c"), constant("d")))), "a ** b - c ** d"); } #[test] fn format_combination_multiplicative_binary_operations_and_lower() { assert_eq!(format( multiply( multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")))), "a * b * c * d"); assert_eq!(format( multiply( divide(constant("a"), constant("b")), divide(constant("c"), constant("d")))), "a / b * c / d"); assert_eq!(format( multiply( modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")))), "a % b * (c % d)"); assert_eq!(format( divide( multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")))), "a * b / (c * d)"); assert_eq!(format( divide( divide(constant("a"), constant("b")), divide(constant("c"), constant("d")))), "a / b / (c / d)"); assert_eq!(format( divide( modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")))), "a % b / (c % d)"); assert_eq!(format( modulo( multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")))), "a * b % (c * d)"); assert_eq!(format( modulo( divide(constant("a"), constant("b")), divide(constant("c"), constant("d")))), "a / b % (c / d)"); assert_eq!(format( modulo( modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")))), "a % b % (c % d)"); assert_eq!(format( multiply( add(constant("a"), constant("b")), add(constant("c"), constant("d")))), "(a + b) * (c + d)"); assert_eq!(format( add( multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")))), "a * b + c * d"); assert_eq!(format( multiply( subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")))), "(a - b) * (c - d)"); assert_eq!(format( subtract( multiply(constant("a"), constant("b")), multiply(constant("c"), constant("d")))), "a * b - c * d"); assert_eq!(format( divide( add(constant("a"), constant("b")), add(constant("c"), constant("d")))), "(a + b) / (c + d)"); assert_eq!(format( add( divide(constant("a"), constant("b")), divide(constant("c"), constant("d")))), "a / b + c / d"); assert_eq!(format( divide( subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")))), "(a - b) / (c - d)"); assert_eq!(format( subtract( divide(constant("a"), constant("b")), divide(constant("c"), constant("d")))), "a / b - c / d"); assert_eq!(format( modulo( add(constant("a"), constant("b")), add(constant("c"), constant("d")))), "(a + b) % (c + d)"); assert_eq!(format( add( modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")))), "a % b + c % d"); assert_eq!(format( modulo( subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")))), "(a - b) % (c - d)"); assert_eq!(format( subtract( modulo(constant("a"), constant("b")), modulo(constant("c"), constant("d")))), "a % b - c % d"); } #[test] fn format_combination_additive_binary_operations_and_lower() { assert_eq!(format( add( add(constant("a"), constant("b")), add(constant("c"), constant("d")))), "a + b + c + d"); assert_eq!(format( add( subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")))), "a - b + c - d"); assert_eq!(format( subtract( add(constant("a"), constant("b")), add(constant("c"), constant("d")))), "a + b - (c + d)"); assert_eq!(format( subtract( subtract(constant("a"), constant("b")), subtract(constant("c"), constant("d")))), "a - b - (c - d)"); } }