Refactor parenthesis rules for terms

This commit is contained in:
Patrick Lühne 2020-04-09 15:01:51 +02:00
parent 9754f933ef
commit 6c326ddb70
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
2 changed files with 120 additions and 69 deletions

View File

@ -295,28 +295,28 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
},
crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::Less, left, right})
=> write!(format, "{:?} < {:?}", display_term(left, Parentheses::None),
display_term(right, Parentheses::None))?,
=> write!(format, "{:?} < {:?}", display_term(left, Parentheses::None, None, crate::format::terms::ChildPosition::Any),
display_term(right, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?,
crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::LessOrEqual, left, right})
=> write!(format, "{:?} <= {:?}", display_term(left, Parentheses::None),
display_term(right, Parentheses::None))?,
=> write!(format, "{:?} <= {:?}", display_term(left, Parentheses::None, None, crate::format::terms::ChildPosition::Any),
display_term(right, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?,
crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::Greater, left, right})
=> write!(format, "{:?} > {:?}", display_term(left, Parentheses::None),
display_term(right, Parentheses::None))?,
=> write!(format, "{:?} > {:?}", display_term(left, Parentheses::None, None, crate::format::terms::ChildPosition::Any),
display_term(right, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?,
crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::GreaterOrEqual, left, right})
=> write!(format, "{:?} >= {:?}", display_term(left, Parentheses::None),
display_term(right, Parentheses::None))?,
=> write!(format, "{:?} >= {:?}", display_term(left, Parentheses::None, None, crate::format::terms::ChildPosition::Any),
display_term(right, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?,
crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::Equal, left, right})
=> write!(format, "{:?} = {:?}", display_term(left, Parentheses::None),
display_term(right, Parentheses::None))?,
=> write!(format, "{:?} = {:?}", display_term(left, Parentheses::None, None, crate::format::terms::ChildPosition::Any),
display_term(right, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?,
crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::NotEqual, left, right})
=> write!(format, "{:?} != {:?}", display_term(left, Parentheses::None),
display_term(right, Parentheses::None))?,
=> write!(format, "{:?} != {:?}", display_term(left, Parentheses::None, None, crate::format::terms::ChildPosition::Any),
display_term(right, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?,
crate::Formula::Boolean(true) => write!(format, "true")?,
crate::Formula::Boolean(false) => write!(format, "false")?,
crate::Formula::Predicate(predicate) =>
@ -332,7 +332,7 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
for argument in &predicate.arguments
{
write!(format, "{}{:?}", separator,
display_term(argument, Parentheses::None))?;
display_term(argument, Parentheses::None, None, crate::format::terms::ChildPosition::Any))?;
separator = ", "
}

View File

@ -1,5 +1,13 @@
use super::*;
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum ChildPosition
{
Any,
Left,
Right,
}
impl super::Precedence for crate::Term
{
fn precedence_level(&self) -> i32
@ -92,14 +100,103 @@ pub(crate) struct TermDisplay<'term>
{
parentheses: Parentheses,
term: &'term crate::Term,
parent_term: Option<&'term crate::Term>,
position: ChildPosition,
}
pub(crate) fn display_term(term: &crate::Term, parentheses: Parentheses) -> TermDisplay
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 == ChildPosition::Left,
crate::BinaryOperator::Multiply
| crate::BinaryOperator::Divide
=> match parent_binary_operation.operator
{
crate::BinaryOperator::Exponentiate => true,
crate::BinaryOperator::Divide
| crate::BinaryOperator::Modulo
=> self.position == ChildPosition::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 == ChildPosition::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 == ChildPosition::Right,
_ => false,
},
}
},
}
}
}
pub(crate) fn display_term<'term>(term: &'term crate::Term, parentheses: Parentheses,
parent_term: Option<&'term crate::Term>, position: ChildPosition) -> TermDisplay<'term>
{
TermDisplay
{
parentheses,
term,
parent_term,
position,
}
}
@ -107,15 +204,7 @@ 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);
let requires_parentheses = self.requires_parentheses();
if requires_parentheses
{
@ -148,7 +237,7 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
for argument in &function.arguments
{
write!(format, "{}{:?}", separator,
display_term(&argument, Parentheses::None))?;
display_term(&argument, Parentheses::None, Some(self.term), ChildPosition::Any))?;
separator = ", ";
}
@ -170,55 +259,17 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
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))
display_term(&binary_operation.left, Parentheses::None, Some(self.term), ChildPosition::Left),
operator_string,
display_term(&binary_operation.right, Parentheses::None, Some(self.term), ChildPosition::Right))
},
crate::Term::UnaryOperation(
crate::UnaryOperation{operator: crate::UnaryOperator::Negative, argument})
=> write!(format, "-{:?}", display_term(argument, parentheses)),
=> write!(format, "-{:?}", display_term(argument, Parentheses::None, Some(self.term), ChildPosition::Any)),
crate::Term::UnaryOperation(
crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, argument})
=> write!(format, "|{:?}|", display_term(argument, Parentheses::None)),
=> write!(format, "|{:?}|", display_term(argument, Parentheses::None, Some(self.term), ChildPosition::Any)),
}?;
if requires_parentheses
@ -242,7 +293,7 @@ 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))
write!(format, "{:?}", display_term(&self, Parentheses::None, None, ChildPosition::Any))
}
}
@ -250,7 +301,7 @@ 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))
write!(format, "{}", display_term(&self, Parentheses::None, None, ChildPosition::Any))
}
}