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) } } #[derive(Clone, Copy, Eq, PartialEq)] pub(crate) enum TermPosition { Any, Left, Right, } pub(crate) struct TermDisplay<'term> { term: &'term crate::Term, parent_term: Option<&'term crate::Term>, position: TermPosition, } impl<'term> TermDisplay<'term> { fn requires_parentheses(&self) -> bool { use crate::Term; let parent_term = match self.parent_term { Some(parent_term) => parent_term, None => return false, }; // The absolute value operation never requires parentheses, as it has its own parentheses if let Term::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, ..}) = parent_term { return false; } match self.term { Term::Boolean(_) | Term::SpecialInteger(_) | Term::Integer(_) | Term::String(_) | Term::Variable(_) | Term::Function(_) | Term::UnaryOperation(_) => false, Term::BinaryOperation(binary_operation) => { let parent_binary_operation = match parent_term { Term::BinaryOperation(parent_binary_operation) => parent_binary_operation, // Binary operations nested in the negative operation always require parentheses Term::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::Negative, ..}) => return true, _ => return false, }; match binary_operation.operator { crate::BinaryOperator::Exponentiate => parent_binary_operation.operator == crate::BinaryOperator::Exponentiate && self.position == TermPosition::Left, crate::BinaryOperator::Multiply | crate::BinaryOperator::Divide => match parent_binary_operation.operator { crate::BinaryOperator::Exponentiate => true, crate::BinaryOperator::Divide | crate::BinaryOperator::Modulo => self.position == TermPosition::Right, _ => false, }, crate::BinaryOperator::Modulo => match parent_binary_operation.operator { crate::BinaryOperator::Exponentiate => true, crate::BinaryOperator::Multiply | crate::BinaryOperator::Divide | crate::BinaryOperator::Modulo => self.position == TermPosition::Right, _ => false, }, crate::BinaryOperator::Add | crate::BinaryOperator::Subtract => match parent_binary_operation.operator { crate::BinaryOperator::Exponentiate | crate::BinaryOperator::Multiply | crate::BinaryOperator::Divide | crate::BinaryOperator::Modulo => true, crate::BinaryOperator::Subtract => self.position == TermPosition::Right, _ => false, }, } }, } } } pub(crate) fn display_term<'term>(term: &'term crate::Term, parent_term: Option<&'term crate::Term>, position: TermPosition) -> TermDisplay<'term> { TermDisplay { term, parent_term, position, } } impl<'term> std::fmt::Debug for TermDisplay<'term> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { let requires_parentheses = self.requires_parentheses(); 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, Some(self.term), TermPosition::Any))?; separator = ", "; } write!(format, ")")?; } }, 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 => "**", }; write!(format, "{:?} {} {:?}", display_term(&binary_operation.left, Some(self.term), TermPosition::Left), operator_string, display_term(&binary_operation.right, Some(self.term), TermPosition::Right))?; }, crate::Term::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::Negative, argument}) => write!(format, "-{:?}", display_term(argument, Some(self.term), TermPosition::Any))?, crate::Term::UnaryOperation( crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, argument}) => write!(format, "|{:?}|", display_term(argument, Some(self.term), TermPosition::Any))?, } 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, None, TermPosition::Any)) } } impl std::fmt::Display for crate::Term { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{}", display_term(&self, None, TermPosition::Any)) } } #[cfg(test)] pub(crate) mod tests { use crate::*; macro_rules! assert { ($term:expr, $output:expr) => { assert_eq!(format($term), $output); }; } 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.into_iter().map(|x| *x).collect())) } 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())) } pub(crate) fn a() -> Box { constant("a") } pub(crate) fn b() -> Box { constant("b") } pub(crate) fn c() -> Box { constant("c") } pub(crate) fn d() -> Box { constant("d") } pub(crate) fn e() -> Box { constant("e") } pub(crate) fn abc() -> Vec> { vec![a(), b(), c()] } pub(crate) fn a1b1c1() -> Vec> { vec![constant("a1"), constant("b1"), constant("c1")] } pub(crate) fn a2b2c2() -> Vec> { vec![constant("a2"), constant("b2"), constant("c2")] } pub(crate) fn x() -> Box { variable("X") } pub(crate) fn y() -> Box { variable("Y") } pub(crate) fn z() -> Box { variable("Z") } pub(crate) fn xyz() -> Vec> { vec![x(), y(), z()] } #[test] fn format_binary_operation() { assert!(add(a(), constant("b")), "a + b"); assert!(subtract(a(), constant("b")), "a - b"); assert!(multiply(a(), constant("b")), "a * b"); assert!(divide(a(), constant("b")), "a / b"); assert!(modulo(a(), constant("b")), "a % b"); assert!(exponentiate(a(), constant("b")), "a ** b"); } #[test] fn format_boolean() { assert!(true_(), "true"); assert!(false_(), "false"); } #[test] fn format_special_integer() { assert!(infimum(), "#inf"); assert!(supremum(), "#sup"); } #[test] fn format_integer() { assert!(integer(0), "0"); assert!(integer(1), "1"); assert!(integer(10000), "10000"); assert!(integer(-1), "-1"); assert!(integer(-10000), "-10000"); } #[test] fn format_string() { assert!(string(""), "\"\""); assert!(string(" "), "\" \""); assert!(string(" "), "\" \""); assert!(string("a"), "\"a\""); assert!(string("test test"), "\"test test\""); assert!(string("123 123"), "\"123 123\""); assert!(string("\ntest\n123\n"), "\"\\ntest\\n123\\n\""); assert!(string("\ttest\t123\t"), "\"\\ttest\\t123\\t\""); assert!(string("\\test\\123\\"), "\"\\\\test\\\\123\\\\\""); assert!(string("๐Ÿ™‚test๐Ÿ™‚123๐Ÿ™‚"), "\"๐Ÿ™‚test๐Ÿ™‚123๐Ÿ™‚\""); } #[test] fn format_function() { assert!(a(), "a"); assert!(constant("constant"), "constant"); assert!(function("f", vec![a()]), "f(a)"); assert!(function("f", abc()), "f(a, b, c)"); assert!(function("function", abc()), "function(a, b, c)"); assert!(function("function", vec![ exponentiate(absolute_value(multiply(a(), integer(-20))), integer(2)), string("test"), function("f", vec![multiply(add(b(), c()), subtract(b(), c())), infimum(), 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!(variable("X"), "X"); assert!(variable("Variable"), "Variable"); } #[test] fn format_combinations_boolean() { // Function + Boolean assert!(function("f", vec![true_()]), "f(true)"); assert!(function("f", vec![false_()]), "f(false)"); assert!(function("f", vec![true_(), true_(), true_()]), "f(true, true, true)"); assert!(function("f", vec![false_(), false_(), false_()]), "f(false, false, false)"); // Absolute value + Boolean assert!(absolute_value(true_()), "|true|"); assert!(absolute_value(false_()), "|false|"); // Negative + Boolean assert!(negative(true_()), "-true"); assert!(negative(false_()), "-false"); // Exponentiate + Boolean assert!(exponentiate(true_(), true_()), "true ** true"); assert!(exponentiate(false_(), false_()), "false ** false"); // Multiply + Boolean assert!(multiply(true_(), true_()), "true * true"); assert!(multiply(false_(), false_()), "false * false"); // Divide + Boolean assert!(divide(true_(), true_()), "true / true"); assert!(divide(false_(), false_()), "false / false"); // Modulo + Boolean assert!(modulo(true_(), true_()), "true % true"); assert!(modulo(false_(), false_()), "false % false"); // Add + Boolean assert!(add(true_(), true_()), "true + true"); assert!(add(false_(), false_()), "false + false"); // Subtract + Boolean assert!(subtract(true_(), true_()), "true - true"); assert!(subtract(false_(), false_()), "false - false"); } #[test] fn format_combinations_special_integer() { // Function + special integer assert!(function("f", vec![infimum()]), "f(#inf)"); assert!(function("f", vec![supremum()]), "f(#sup)"); assert!(function("f", vec![infimum(), infimum(), infimum()]), "f(#inf, #inf, #inf)"); assert!(function("f", vec![supremum(), supremum(), supremum()]), "f(#sup, #sup, #sup)"); // Absolute value + special integer assert!(absolute_value(infimum()), "|#inf|"); assert!(absolute_value(supremum()), "|#sup|"); // Negative + special integer assert!(negative(infimum()), "-#inf"); assert!(negative(supremum()), "-#sup"); // Exponentiate + special integer assert!(exponentiate(infimum(), infimum()), "#inf ** #inf"); assert!(exponentiate(supremum(), supremum()), "#sup ** #sup"); // Multiply + special integer assert!(multiply(infimum(), infimum()), "#inf * #inf"); assert!(multiply(supremum(), supremum()), "#sup * #sup"); // Divide + special integer assert!(divide(infimum(), infimum()), "#inf / #inf"); assert!(divide(supremum(), supremum()), "#sup / #sup"); // Modulo + special integer assert!(modulo(infimum(), infimum()), "#inf % #inf"); assert!(modulo(supremum(), supremum()), "#sup % #sup"); // Add + special integer assert!(add(infimum(), infimum()), "#inf + #inf"); assert!(add(supremum(), supremum()), "#sup + #sup"); // Subtract + special integer assert!(subtract(infimum(), infimum()), "#inf - #inf"); assert!(subtract(supremum(), supremum()), "#sup - #sup"); } #[test] fn format_combinations_integer() { // Function + integer assert!(function("f", vec![integer(0)]), "f(0)"); assert!(function("f", vec![integer(10000)]), "f(10000)"); assert!(function("f", vec![integer(-10000)]), "f(-10000)"); assert!(function("f", vec![integer(0), integer(0), integer(0)]), "f(0, 0, 0)"); assert!(function("f", vec![integer(10000), integer(10000), integer(10000)]), "f(10000, 10000, 10000)"); assert!(function("f", vec![integer(-10000), integer(-10000), integer(-10000)]), "f(-10000, -10000, -10000)"); // Absolute value + integer assert!(absolute_value(integer(0)), "|0|"); assert!(absolute_value(integer(10000)), "|10000|"); assert!(absolute_value(integer(-10000)), "|-10000|"); // Negative + integer assert!(negative(integer(0)), "-0"); assert!(negative(integer(10000)), "-10000"); assert!(negative(integer(-10000)), "--10000"); // Exponentiate + integer assert!(exponentiate(integer(0), integer(0)), "0 ** 0"); assert!(exponentiate(integer(10000), integer(10000)), "10000 ** 10000"); assert!(exponentiate(integer(-10000), integer(-10000)), "-10000 ** -10000"); // Multiply + integer assert!(multiply(integer(0), integer(0)), "0 * 0"); assert!(multiply(integer(10000), integer(10000)), "10000 * 10000"); assert!(multiply(integer(-10000), integer(-10000)), "-10000 * -10000"); // Divide + integer assert!(divide(integer(0), integer(0)), "0 / 0"); assert!(divide(integer(10000), integer(10000)), "10000 / 10000"); assert!(divide(integer(-10000), integer(-10000)), "-10000 / -10000"); // Modulo + integer assert!(modulo(integer(0), integer(0)), "0 % 0"); assert!(modulo(integer(10000), integer(10000)), "10000 % 10000"); assert!(modulo(integer(-10000), integer(-10000)), "-10000 % -10000"); // Add + integer assert!(add(integer(0), integer(0)), "0 + 0"); assert!(add(integer(10000), integer(10000)), "10000 + 10000"); assert!(add(integer(-10000), integer(-10000)), "-10000 + -10000"); // Subtract + integer assert!(subtract(integer(0), integer(0)), "0 - 0"); assert!(subtract(integer(10000), integer(10000)), "10000 - 10000"); assert!(subtract(integer(-10000), integer(-10000)), "-10000 - -10000"); } #[test] fn format_combinations_string() { // Function + string assert!(function("f", vec![string("")]), "f(\"\")"); assert!(function("f", vec![string("test 123")]), "f(\"test 123\")"); assert!(function("f", vec![string("\\a\nb๐Ÿ™‚c\t")]), "f(\"\\\\a\\nb๐Ÿ™‚c\\t\")"); assert!(function("f", vec![string(""), string(""), string("")]), "f(\"\", \"\", \"\")"); assert!(function("f", vec![string("test 123"), string("test 123"), string("test 123")]), "f(\"test 123\", \"test 123\", \"test 123\")"); assert!(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\")"); // Absolute value + string assert!(absolute_value(string("")), "|\"\"|"); assert!(absolute_value(string("test 123")), "|\"test 123\"|"); assert!(absolute_value(string("\\a\nb๐Ÿ™‚c\t")), "|\"\\\\a\\nb๐Ÿ™‚c\\t\"|"); // Negative + string assert!(negative(string("")), "-\"\""); assert!(negative(string("test 123")), "-\"test 123\""); assert!(negative(string("\\a\nb๐Ÿ™‚c\t")), "-\"\\\\a\\nb๐Ÿ™‚c\\t\""); // Exponentiate + string assert!(exponentiate(string(""), string("")), "\"\" ** \"\""); assert!(exponentiate(string("test 123"), string("test 123")), "\"test 123\" ** \"test 123\""); assert!(exponentiate(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")), "\"\\\\a\\nb๐Ÿ™‚c\\t\" ** \"\\\\a\\nb๐Ÿ™‚c\\t\""); // Multiply + string assert!(multiply(string(""), string("")), "\"\" * \"\""); assert!(multiply(string("test 123"), string("test 123")), "\"test 123\" * \"test 123\""); assert!(multiply(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")), "\"\\\\a\\nb๐Ÿ™‚c\\t\" * \"\\\\a\\nb๐Ÿ™‚c\\t\""); // Divide + string assert!(divide(string(""), string("")), "\"\" / \"\""); assert!(divide(string("test 123"), string("test 123")), "\"test 123\" / \"test 123\""); assert!(divide(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")), "\"\\\\a\\nb๐Ÿ™‚c\\t\" / \"\\\\a\\nb๐Ÿ™‚c\\t\""); // Modulo + string assert!(modulo(string(""), string("")), "\"\" % \"\""); assert!(modulo(string("test 123"), string("test 123")), "\"test 123\" % \"test 123\""); assert!(modulo(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")), "\"\\\\a\\nb๐Ÿ™‚c\\t\" % \"\\\\a\\nb๐Ÿ™‚c\\t\""); // Add + string assert!(add(string(""), string("")), "\"\" + \"\""); assert!(add(string("test 123"), string("test 123")), "\"test 123\" + \"test 123\""); assert!(add(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")), "\"\\\\a\\nb๐Ÿ™‚c\\t\" + \"\\\\a\\nb๐Ÿ™‚c\\t\""); // Subtract + string assert!(subtract(string(""), string("")), "\"\" - \"\""); assert!(subtract(string("test 123"), string("test 123")), "\"test 123\" - \"test 123\""); assert!(subtract(string("\\a\nb๐Ÿ™‚c\t"), string("\\a\nb๐Ÿ™‚c\t")), "\"\\\\a\\nb๐Ÿ™‚c\\t\" - \"\\\\a\\nb๐Ÿ™‚c\\t\""); } #[test] fn format_combinations_variable() { let variable = || variable("Variable"); // Function + variable assert!(function("f", vec![x()]), "f(X)"); assert!(function("f", vec![variable()]), "f(Variable)"); assert!(function("f", xyz()), "f(X, Y, Z)"); assert!(function("f", vec![variable(), variable(), variable()]), "f(Variable, Variable, Variable)"); // Absolute value + variable assert!(absolute_value(x()), "|X|"); assert!(absolute_value(variable()), "|Variable|"); // Negative + variable assert!(negative(x()), "-X"); assert!(negative(variable()), "-Variable"); // Exponentiate + variable assert!(exponentiate(x(), y()), "X ** Y"); assert!(exponentiate(variable(), variable()), "Variable ** Variable"); // Multiply + variable assert!(multiply(x(), y()), "X * Y"); assert!(multiply(variable(), variable()), "Variable * Variable"); // Divide + variable assert!(divide(x(), y()), "X / Y"); assert!(divide(variable(), variable()), "Variable / Variable"); // Modulo + variable assert!(modulo(x(), y()), "X % Y"); assert!(modulo(variable(), variable()), "Variable % Variable"); // Add + variable assert!(add(x(), y()), "X + Y"); assert!(add(variable(), variable()), "Variable + Variable"); // Subtract + variable assert!(subtract(x(), y()), "X - Y"); assert!(subtract(variable(), variable()), "Variable - Variable"); } #[test] fn format_combinations_function() { let f_a = || function("f", vec![a()]); let g_b = || function("g", vec![b()]); let f_abc = || function("f", abc()); let f_a1b1c1 = || function("f", a1b1c1()); let g_a2b2c2 = || function("g", a2b2c2()); // Function + function // TODO // Absolute value + function assert!(absolute_value(a()), "|a|"); assert!(absolute_value(f_a()), "|f(a)|"); assert!(absolute_value(f_abc()), "|f(a, b, c)|"); // Negative + function assert!(negative(a()), "-a"); assert!(negative(f_a()), "-f(a)"); assert!(negative(f_abc()), "-f(a, b, c)"); // Exponentiate + function assert!(exponentiate(a(), b()), "a ** b"); assert!(exponentiate(f_a(), g_b()), "f(a) ** g(b)"); assert!(exponentiate(f_a1b1c1(), g_a2b2c2()), "f(a1, b1, c1) ** g(a2, b2, c2)"); // Multiply + function assert!(multiply(a(), b()), "a * b"); assert!(multiply(f_a(), g_b()), "f(a) * g(b)"); assert!(multiply(f_a1b1c1(), g_a2b2c2()), "f(a1, b1, c1) * g(a2, b2, c2)"); // Divide + function assert!(divide(a(), b()), "a / b"); assert!(divide(f_a(), g_b()), "f(a) / g(b)"); assert!(divide(f_a1b1c1(), g_a2b2c2()), "f(a1, b1, c1) / g(a2, b2, c2)"); // Modulo + function assert!(modulo(a(), b()), "a % b"); assert!(modulo(f_a(), g_b()), "f(a) % g(b)"); assert!(modulo(f_a1b1c1(), g_a2b2c2()), "f(a1, b1, c1) % g(a2, b2, c2)"); // Add + function assert!(add(a(), b()), "a + b"); assert!(add(f_a(), g_b()), "f(a) + g(b)"); assert!(add(f_a1b1c1(), g_a2b2c2()), "f(a1, b1, c1) + g(a2, b2, c2)"); // Subtract + function assert!(subtract(a(), b()), "a - b"); assert!(subtract(f_a(), g_b()), "f(a) - g(b)"); assert!(subtract(f_a1b1c1(), g_a2b2c2()), "f(a1, b1, c1) - g(a2, b2, c2)"); } #[test] fn format_combinations_absolute_value() { // Function + absolute value assert!(function("f", vec![absolute_value(a())]), "f(|a|)"); assert!(function("f", vec![absolute_value(a()), absolute_value(b()), absolute_value(c())]), "f(|a|, |b|, |c|)"); // Absolute value + absolute value assert!(absolute_value(absolute_value(a())), "||a||"); // Negative + absolute value assert!(negative(absolute_value(a())), "-|a|"); // Exponentiate + absolute value assert!(exponentiate(absolute_value(a()), absolute_value(b())), "|a| ** |b|"); // Multiply + absolute value assert!(multiply(absolute_value(a()), absolute_value(b())), "|a| * |b|"); // Divide + absolute value assert!(divide(absolute_value(a()), absolute_value(b())), "|a| / |b|"); // Modulo + absolute value assert!(modulo(absolute_value(a()), absolute_value(b())), "|a| % |b|"); // Add + absolute value assert!(add(absolute_value(a()), absolute_value(b())), "|a| + |b|"); // Subtract + absolute value assert!(subtract(absolute_value(a()), absolute_value(b())), "|a| - |b|"); } #[test] fn format_combinations_negative() { // Function + negative assert!(function("f", vec![negative(a())]), "f(-a)"); assert!(function("f", vec![negative(a()), negative(b()), negative(c())]), "f(-a, -b, -c)"); // Absolute value + negative assert!(absolute_value(negative(a())), "|-a|"); // Negative + negative assert!(negative(negative(a())), "--a"); // Exponentiate + negative assert!(exponentiate(negative(a()), negative(b())), "-a ** -b"); // Multiply + negative assert!(multiply(negative(a()), negative(b())), "-a * -b"); // Divide + negative assert!(divide(negative(a()), negative(b())), "-a / -b"); // Modulo + negative assert!(modulo(negative(a()), negative(b())), "-a % -b"); // Add + negative assert!(add(negative(a()), negative(b())), "-a + -b"); // Subtract + negative assert!(subtract(negative(a()), negative(b())), "-a - -b"); } #[test] fn format_combinations_exponentiate() { // Function + exponentiate assert!(function("f", vec![exponentiate(a(), b())]), "f(a ** b)"); assert!(function("f", vec![exponentiate(a(), b()), exponentiate(c(), d()), exponentiate(e(), a())]), "f(a ** b, c ** d, e ** a)"); // Absolute value + exponentiate assert!(absolute_value(exponentiate(a(), b())), "|a ** b|"); // Negative + exponentiate assert!(negative(exponentiate(a(), b())), "-(a ** b)"); // Exponentiate + exponentiate assert!(exponentiate(exponentiate(a(), b()), exponentiate(c(), d())), "(a ** b) ** c ** d"); // Multiply + exponentiate assert!(multiply(exponentiate(a(), b()), exponentiate(c(), d())), "a ** b * c ** d"); // Divide + exponentiate assert!(divide(exponentiate(a(), b()), exponentiate(c(), d())), "a ** b / c ** d"); // Modulo + exponentiate assert!(modulo(exponentiate(a(), b()), exponentiate(c(), d())), "a ** b % c ** d"); // Add + exponentiate assert!(add(exponentiate(a(), b()), exponentiate(c(), d())), "a ** b + c ** d"); // Subtract + exponentiate assert!(subtract(exponentiate(a(), b()), exponentiate(c(), d())), "a ** b - c ** d"); } #[test] fn format_combinations_multiply() { // Function + multiply assert!(function("f", vec![multiply(a(), b())]), "f(a * b)"); assert!(function("f", vec![multiply(a(), b()), multiply(c(), d()), multiply(e(), a())]), "f(a * b, c * d, e * a)"); // Absolute value + multiply assert!(absolute_value(multiply(a(), b())), "|a * b|"); // Negative + multiply assert!(negative(multiply(a(), b())), "-(a * b)"); // Exponentiate + multiply assert!(exponentiate(multiply(a(), b()), multiply(c(), d())), "(a * b) ** (c * d)"); // Multiply + multiply assert!(multiply(multiply(a(), b()), multiply(c(), d())), "a * b * c * d"); // Divide + multiply assert!(divide(multiply(a(), b()), multiply(c(), d())), "a * b / (c * d)"); // Modulo + multiply assert!(modulo(multiply(a(), b()), multiply(c(), d())), "a * b % (c * d)"); // Add + multiply assert!(add(multiply(a(), b()), multiply(c(), d())), "a * b + c * d"); // Subtract + multiply assert!(subtract(multiply(a(), b()), multiply(c(), d())), "a * b - c * d"); } #[test] fn format_combinations_divide() { // Function + divide assert!(function("f", vec![divide(a(), b())]), "f(a / b)"); assert!(function("f", vec![divide(a(), b()), divide(c(), d()), divide(e(), a())]), "f(a / b, c / d, e / a)"); // Absolute value + divide assert!(absolute_value(divide(a(), b())), "|a / b|"); // Negative + divide assert!(negative(divide(a(), b())), "-(a / b)"); // Exponentiate + divide assert!(exponentiate(divide(a(), b()), divide(c(), d())), "(a / b) ** (c / d)"); // Multiply + divide assert!(multiply(divide(a(), b()), divide(c(), d())), "a / b * c / d"); // Divide + divide assert!(divide(divide(a(), b()), divide(c(), d())), "a / b / (c / d)"); // Modulo + divide assert!(modulo(divide(a(), b()), divide(c(), d())), "a / b % (c / d)"); // Add + divide assert!(add(divide(a(), b()), divide(c(), d())), "a / b + c / d"); // Subtract + divide assert!(subtract(divide(a(), b()), divide(c(), d())), "a / b - c / d"); } #[test] fn format_combinations_modulo() { // Function + modulo assert!(function("f", vec![modulo(a(), b())]), "f(a % b)"); assert!(function("f", vec![modulo(a(), b()), modulo(c(), d()), modulo(e(), a())]), "f(a % b, c % d, e % a)"); // Absolute value + modulo assert!(absolute_value(modulo(a(), b())), "|a % b|"); // Negative + modulo assert!(negative(modulo(a(), b())), "-(a % b)"); // Exponentiate + modulo assert!(exponentiate(modulo(a(), b()), modulo(c(), d())), "(a % b) ** (c % d)"); // Multiply + modulo assert!(multiply(modulo(a(), b()), modulo(c(), d())), "a % b * (c % d)"); // Divide + modulo assert!(divide(modulo(a(), b()), modulo(c(), d())), "a % b / (c % d)"); // Modulo + modulo assert!(modulo(modulo(a(), b()), modulo(c(), d())), "a % b % (c % d)"); // Add + modulo assert!(add(modulo(a(), b()), modulo(c(), d())), "a % b + c % d"); // Subtract + modulo assert!(subtract(modulo(a(), b()), modulo(c(), d())), "a % b - c % d"); } #[test] fn format_combinations_add() { // Function + add assert!(function("f", vec![add(a(), b())]), "f(a + b)"); assert!(function("f", vec![add(a(), b()), add(c(), d()), add(e(), a())]), "f(a + b, c + d, e + a)"); // Absolute value + add assert!(absolute_value(add(a(), b())), "|a + b|"); // Negative + add assert!(negative(add(a(), b())), "-(a + b)"); // Exponentiate + add assert!(exponentiate(add(a(), b()), add(c(), d())), "(a + b) ** (c + d)"); // Multiply + add assert!(multiply(add(a(), b()), add(c(), d())), "(a + b) * (c + d)"); // Divide + add assert!(divide(add(a(), b()), add(c(), d())), "(a + b) / (c + d)"); // Modulo + add assert!(modulo(add(a(), b()), add(c(), d())), "(a + b) % (c + d)"); // Add + add assert!(add(add(a(), b()), add(c(), d())), "a + b + c + d"); // Subtract + add assert!(subtract(add(a(), b()), add(c(), d())), "a + b - (c + d)"); } #[test] fn format_combinations_subtract() { // Function + subtract assert!(function("f", vec![subtract(a(), b())]), "f(a - b)"); assert!(function("f", vec![subtract(a(), b()), subtract(c(), d()), subtract(e(), a())]), "f(a - b, c - d, e - a)"); // Absolute value + subtract assert!(absolute_value(subtract(a(), b())), "|a - b|"); // Negative + subtract assert!(negative(subtract(a(), b())), "-(a - b)"); // Exponentiate + subtract assert!(exponentiate(subtract(a(), b()), subtract(c(), d())), "(a - b) ** (c - d)"); // Multiply + subtract assert!(multiply(subtract(a(), b()), subtract(c(), d())), "(a - b) * (c - d)"); // Divide + subtract assert!(divide(subtract(a(), b()), subtract(c(), d())), "(a - b) / (c - d)"); // Modulo + subtract assert!(modulo(subtract(a(), b()), subtract(c(), d())), "(a - b) % (c - d)"); // Add + subtract assert!(add(subtract(a(), b()), subtract(c(), d())), "a - b + c - d"); // Subtract + subtract assert!(subtract(subtract(a(), b()), subtract(c(), d())), "a - b - (c - d)"); } }