Fix formatting of binary operations
The precedence rules of binary operations are a bit trickier than expected. The fact that a parent and a child term have the same precedence level doesn’t automatically mean that parentheses can be omitted. This is the case, for example, with a - (b + c) While addition and subtraction have the same precedence level, the parenthesis cannot be omitted. In general, this happens on the right- hand side of the subtraction, division, and modulo operators if the right-hand side has the same precedence level. This patch fixes the output of binary operations accordingly.
This commit is contained in:
parent
549f127729
commit
551c35ed75
@ -160,7 +160,6 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
|
|||||||
Some(parent_precedence) => precedence > parent_precedence,
|
Some(parent_precedence) => precedence > parent_precedence,
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
let precedence = Some(precedence);
|
|
||||||
|
|
||||||
if requires_parentheses
|
if requires_parentheses
|
||||||
{
|
{
|
||||||
@ -201,36 +200,81 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
|
|||||||
|
|
||||||
Ok(())
|
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_requires_parentheses = binary_operation.left.precedence() == precedence
|
||||||
|
// Exponentiation is right-associative and thus requires parentheses when
|
||||||
|
// nested on the left side
|
||||||
|
&& binary_operation.operator == crate::BinaryOperator::Exponentiate;
|
||||||
|
|
||||||
|
// 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::Term::BinaryOperation(
|
||||||
crate::BinaryOperation{operator: crate::BinaryOperator::Add, left, right})
|
crate::BinaryOperation{operator: crate::BinaryOperator::Modulo, ..})
|
||||||
=> write!(format, "{:?} + {:?}", display_term(left, precedence),
|
=> true,
|
||||||
display_term(right, precedence)),
|
_ => false,
|
||||||
crate::Term::BinaryOperation(
|
};
|
||||||
crate::BinaryOperation{operator: crate::BinaryOperator::Subtract, left, right})
|
|
||||||
=> write!(format, "{:?} - {:?}", display_term(left, precedence),
|
let right_requires_parentheses = binary_operation.right.precedence() == precedence
|
||||||
display_term(right, precedence)),
|
&& (operator_requires_right_priority || right_requires_priority);
|
||||||
crate::Term::BinaryOperation(
|
|
||||||
crate::BinaryOperation{operator: crate::BinaryOperator::Multiply, left, right})
|
if left_requires_parentheses
|
||||||
=> write!(format, "{:?} * {:?}", display_term(left, precedence),
|
{
|
||||||
display_term(right, precedence)),
|
write!(format, "(")?;
|
||||||
crate::Term::BinaryOperation(
|
}
|
||||||
crate::BinaryOperation{operator: crate::BinaryOperator::Divide, left, right})
|
|
||||||
=> write!(format, "{:?} / {:?}", display_term(left, precedence),
|
write!(format, "{:?}", display_term(&binary_operation.left, Some(precedence)))?;
|
||||||
display_term(right, precedence)),
|
|
||||||
crate::Term::BinaryOperation(
|
if left_requires_parentheses
|
||||||
crate::BinaryOperation{operator: crate::BinaryOperator::Modulo, left, right})
|
{
|
||||||
=> write!(format, "{:?} % {:?}", display_term(left, precedence),
|
write!(format, ")")?;
|
||||||
display_term(right, precedence)),
|
}
|
||||||
crate::Term::BinaryOperation(
|
|
||||||
crate::BinaryOperation{operator: crate::BinaryOperator::Exponentiate, left, right})
|
write!(format, " {} ", operator_string)?;
|
||||||
=> write!(format, "{:?} ** {:?}", display_term(left, precedence),
|
|
||||||
display_term(right, precedence)),
|
if right_requires_parentheses
|
||||||
|
{
|
||||||
|
write!(format, "(")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(format, "{:?}", display_term(&binary_operation.right, Some(precedence)))?;
|
||||||
|
|
||||||
|
if right_requires_parentheses
|
||||||
|
{
|
||||||
|
write!(format, ")")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
crate::Term::UnaryOperation(
|
crate::Term::UnaryOperation(
|
||||||
crate::UnaryOperation{operator: crate::UnaryOperator::Negative, argument})
|
crate::UnaryOperation{operator: crate::UnaryOperator::Negative, argument})
|
||||||
=> write!(format, "-{:?}", display_term(argument, precedence)),
|
=> write!(format, "-{:?}", display_term(argument, Some(precedence))),
|
||||||
crate::Term::UnaryOperation(
|
crate::Term::UnaryOperation(
|
||||||
crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, argument})
|
crate::UnaryOperation{operator: crate::UnaryOperator::AbsoluteValue, argument})
|
||||||
=> write!(format, "|{:?}|", display_term(argument, precedence)),
|
=> write!(format, "|{:?}|", display_term(argument, None)),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if requires_parentheses
|
if requires_parentheses
|
||||||
|
Loading…
Reference in New Issue
Block a user