Refactor precedence rules

This commit is contained in:
Patrick Lühne 2020-03-30 08:04:09 +02:00
parent 8bf9d4bd45
commit 600a6a1b4b
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
4 changed files with 86 additions and 110 deletions

View File

@ -5,5 +5,13 @@ pub(crate) use terms::*;
trait Precedence trait Precedence
{ {
fn precedence(&self) -> i32; fn precedence_level(&self) -> i32;
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum Parentheses
{
None,
PrecedenceBased(i32),
Required,
} }

View File

@ -2,7 +2,7 @@ use super::*;
impl super::Precedence for crate::Formula impl super::Precedence for crate::Formula
{ {
fn precedence(&self) -> i32 fn precedence_level(&self) -> i32
{ {
match &self match &self
{ {
@ -57,15 +57,15 @@ impl std::fmt::Display for crate::PredicateDeclaration
struct FormulaDisplay<'formula> struct FormulaDisplay<'formula>
{ {
parent_precedence: Option<i32>, parentheses: Parentheses,
formula: &'formula crate::Formula, formula: &'formula crate::Formula,
} }
fn display_formula(formula: &crate::Formula, parent_precedence: Option<i32>) -> FormulaDisplay fn display_formula(formula: &crate::Formula, parentheses: Parentheses) -> FormulaDisplay
{ {
FormulaDisplay FormulaDisplay
{ {
parent_precedence, parentheses,
formula, formula,
} }
} }
@ -74,13 +74,15 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
let precedence = self.formula.precedence(); let precedence_level = self.formula.precedence_level();
let requires_parentheses = match self.parent_precedence let requires_parentheses = match self.parentheses
{ {
Some(parent_precedence) => precedence > parent_precedence, Parentheses::None => false,
None => false, Parentheses::PrecedenceBased(parent_precedence_level)
=> precedence_level > parent_precedence_level,
Parentheses::Required => true,
}; };
let precedence = Some(precedence); let parentheses = Parentheses::PrecedenceBased(precedence_level);
if requires_parentheses if requires_parentheses
{ {
@ -104,7 +106,7 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
separator = ", " separator = ", "
} }
write!(format, " {:?}", display_formula(&exists.argument, precedence))?; write!(format, " {:?}", display_formula(&exists.argument, parentheses))?;
}, },
crate::Formula::ForAll(for_all) => crate::Formula::ForAll(for_all) =>
{ {
@ -121,10 +123,10 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
separator = ", " separator = ", "
} }
write!(format, " {:?}", display_formula(&for_all.argument, precedence))?; write!(format, " {:?}", display_formula(&for_all.argument, parentheses))?;
}, },
crate::Formula::Not(argument) => write!(format, "not {:?}", crate::Formula::Not(argument) => write!(format, "not {:?}",
display_formula(argument, precedence))?, display_formula(argument, parentheses))?,
crate::Formula::And(arguments) => crate::Formula::And(arguments) =>
{ {
let mut separator = ""; let mut separator = "";
@ -133,7 +135,7 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
for argument in arguments for argument in arguments
{ {
write!(format, "{}{:?}", separator, display_formula(argument, precedence))?; write!(format, "{}{:?}", separator, display_formula(argument, parentheses))?;
separator = " and " separator = " and "
} }
@ -146,64 +148,40 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
for argument in arguments for argument in arguments
{ {
write!(format, "{}{:?}", separator, display_formula(argument, precedence))?; write!(format, "{}{:?}", separator, display_formula(argument, parentheses))?;
separator = " or " separator = " or "
} }
}, },
crate::Formula::Implies(crate::Implies{direction, antecedent, implication}) => crate::Formula::Implies(crate::Implies{direction, antecedent, implication}) =>
{ {
let antecedent_requires_parentheses = match **antecedent let antecedent_parentheses = match **antecedent
{ {
// Implication is right-associative and thus requires parentheses when nested on // Implication is right-associative and thus requires parentheses when nested on
// the antecedent side // the antecedent side
crate::Formula::Implies(_) => true, crate::Formula::Implies(_) => Parentheses::Required,
_ => false, _ => parentheses,
}; };
let implication_requires_parentheses = match **antecedent let implication_parentheses = match **antecedent
{ {
// Implication is right-associative and thus doesnt require parentheses when // Implication is right-associative and thus doesnt require parentheses when
// nested on the implication side with the same implication direction // nested on the implication side with the same implication direction
crate::Formula::Implies(crate::Implies{direction: nested_direction, ..}) crate::Formula::Implies(crate::Implies{direction: nested_direction, ..})
if nested_direction == *direction => false, if nested_direction == *direction => Parentheses::None,
// If the nested implication is in the other direction, parentheses are needed // If the nested implication is in the other direction, parentheses are needed
crate::Formula::Implies(_) => true, crate::Formula::Implies(_) => Parentheses::Required,
_ => false, _ => parentheses,
}; };
let format_antecedent = |format: &mut std::fmt::Formatter| -> Result<_, _> let format_antecedent = |format: &mut std::fmt::Formatter| -> Result<_, _>
{ {
if antecedent_requires_parentheses write!(format, "{:?}", display_formula(antecedent, antecedent_parentheses))
{
write!(format, "(")?;
}
write!(format, "{:?}", display_formula(antecedent, precedence))?;
if antecedent_requires_parentheses
{
write!(format, ")")?;
}
Ok(())
}; };
let format_implication = |format: &mut std::fmt::Formatter| -> Result<_, _> let format_implication = |format: &mut std::fmt::Formatter| -> Result<_, _>
{ {
if implication_requires_parentheses write!(format, "{:?}", display_formula(implication, implication_parentheses))
{
write!(format, "(")?;
}
write!(format, "{:?}", display_formula(implication, precedence))?;
if implication_requires_parentheses
{
write!(format, ")")?;
}
Ok(())
}; };
match direction match direction
@ -228,35 +206,35 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
for argument in arguments for argument in arguments
{ {
write!(format, "{}{:?}", separator, display_formula(argument, precedence))?; write!(format, "{}{:?}", separator, display_formula(argument, parentheses))?;
separator = " <-> "; separator = " <-> ";
} }
}, },
crate::Formula::Compare( crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::Less, left, right}) crate::Compare{operator: crate::ComparisonOperator::Less, left, right})
=> write!(format, "{:?} < {:?}", display_term(left, None), => write!(format, "{:?} < {:?}", display_term(left, Parentheses::None),
display_term(right, None))?, display_term(right, Parentheses::None))?,
crate::Formula::Compare( crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::LessOrEqual, left, right}) crate::Compare{operator: crate::ComparisonOperator::LessOrEqual, left, right})
=> write!(format, "{:?} <= {:?}", display_term(left, None), => write!(format, "{:?} <= {:?}", display_term(left, Parentheses::None),
display_term(right, None))?, display_term(right, Parentheses::None))?,
crate::Formula::Compare( crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::Greater, left, right}) crate::Compare{operator: crate::ComparisonOperator::Greater, left, right})
=> write!(format, "{:?} > {:?}", display_term(left, None), => write!(format, "{:?} > {:?}", display_term(left, Parentheses::None),
display_term(right, None))?, display_term(right, Parentheses::None))?,
crate::Formula::Compare( crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::GreaterOrEqual, left, right}) crate::Compare{operator: crate::ComparisonOperator::GreaterOrEqual, left, right})
=> write!(format, "{:?} >= {:?}", display_term(left, None), => write!(format, "{:?} >= {:?}", display_term(left, Parentheses::None),
display_term(right, None))?, display_term(right, Parentheses::None))?,
crate::Formula::Compare( crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::Equal, left, right}) crate::Compare{operator: crate::ComparisonOperator::Equal, left, right})
=> write!(format, "{:?} = {:?}", display_term(left, None), => write!(format, "{:?} = {:?}", display_term(left, Parentheses::None),
display_term(right, None))?, display_term(right, Parentheses::None))?,
crate::Formula::Compare( crate::Formula::Compare(
crate::Compare{operator: crate::ComparisonOperator::NotEqual, left, right}) crate::Compare{operator: crate::ComparisonOperator::NotEqual, left, right})
=> write!(format, "{:?} != {:?}", display_term(left, None), => write!(format, "{:?} != {:?}", display_term(left, Parentheses::None),
display_term(right, None))?, display_term(right, Parentheses::None))?,
crate::Formula::Boolean(true) => write!(format, "true")?, crate::Formula::Boolean(true) => write!(format, "true")?,
crate::Formula::Boolean(false) => write!(format, "false")?, crate::Formula::Boolean(false) => write!(format, "false")?,
crate::Formula::Predicate(predicate) => crate::Formula::Predicate(predicate) =>
@ -271,7 +249,8 @@ impl<'formula> std::fmt::Debug for FormulaDisplay<'formula>
for argument in &predicate.arguments for argument in &predicate.arguments
{ {
write!(format, "{}{:?}", separator, display_term(argument, None))?; write!(format, "{}{:?}", separator,
display_term(argument, Parentheses::None))?;
separator = ", " separator = ", "
} }
@ -302,7 +281,7 @@ impl std::fmt::Debug for crate::Formula
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
write!(format, "{:?}", display_formula(&self, None)) write!(format, "{:?}", display_formula(&self, Parentheses::None))
} }
} }
@ -310,7 +289,7 @@ impl std::fmt::Display for crate::Formula
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
write!(format, "{}", display_formula(&self, None)) write!(format, "{}", display_formula(&self, Parentheses::None))
} }
} }

View File

@ -2,7 +2,7 @@ use super::*;
impl super::Precedence for crate::Term impl super::Precedence for crate::Term
{ {
fn precedence(&self) -> i32 fn precedence_level(&self) -> i32
{ {
match &self match &self
{ {
@ -90,15 +90,15 @@ impl std::fmt::Display for crate::VariableDeclaration
pub(crate) struct TermDisplay<'term> pub(crate) struct TermDisplay<'term>
{ {
parent_precedence: Option<i32>, parentheses: Parentheses,
term: &'term crate::Term, term: &'term crate::Term,
} }
pub(crate) fn display_term(term: &crate::Term, parent_precedence: Option<i32>) -> TermDisplay pub(crate) fn display_term(term: &crate::Term, parentheses: Parentheses) -> TermDisplay
{ {
TermDisplay TermDisplay
{ {
parent_precedence, parentheses,
term, term,
} }
} }
@ -107,12 +107,15 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
let precedence = self.term.precedence(); let precedence_level = self.term.precedence_level();
let requires_parentheses = match self.parent_precedence let requires_parentheses = match self.parentheses
{ {
Some(parent_precedence) => precedence > parent_precedence, Parentheses::Required => true,
None => false, Parentheses::PrecedenceBased(parent_precedence_level)
=> precedence_level > parent_precedence_level,
Parentheses::None => false,
}; };
let parentheses = Parentheses::PrecedenceBased(precedence_level);
if requires_parentheses if requires_parentheses
{ {
@ -144,7 +147,8 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
for argument in &function.arguments for argument in &function.arguments
{ {
write!(format, "{}{:?}", separator, display_term(&argument, None))?; write!(format, "{}{:?}", separator,
display_term(&argument, Parentheses::None))?;
separator = ", "; separator = ", ";
} }
@ -166,10 +170,15 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
crate::BinaryOperator::Exponentiate => "**", crate::BinaryOperator::Exponentiate => "**",
}; };
let left_requires_parentheses = binary_operation.left.precedence() == precedence let left_parentheses = match
binary_operation.left.precedence_level() == precedence_level
// Exponentiation is right-associative and thus requires parentheses when // Exponentiation is right-associative and thus requires parentheses when
// nested on the left side // nested on the left side
&& binary_operation.operator == crate::BinaryOperator::Exponentiate; && binary_operation.operator == crate::BinaryOperator::Exponentiate
{
true => Parentheses::Required,
false => parentheses,
};
// The subtraction, division, and modulo operators require parentheses around the // The subtraction, division, and modulo operators require parentheses around the
// right argument even if it has the same precedence // right argument even if it has the same precedence
@ -192,43 +201,24 @@ impl<'term> std::fmt::Debug for TermDisplay<'term>
_ => false, _ => false,
}; };
let right_requires_parentheses = binary_operation.right.precedence() == precedence let right_parentheses = match
&& (operator_requires_right_priority || right_requires_priority); binary_operation.right.precedence_level() == precedence_level
&& (operator_requires_right_priority || right_requires_priority)
if left_requires_parentheses
{ {
write!(format, "(")?; true => Parentheses::Required,
} false => parentheses,
};
write!(format, "{:?}", display_term(&binary_operation.left, Some(precedence)))?; write!(format, "{:?} {} {:?}",
display_term(&binary_operation.left, left_parentheses),
if left_requires_parentheses operator_string, display_term(&binary_operation.right, right_parentheses))
{
write!(format, ")")?;
}
write!(format, " {} ", operator_string)?;
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, Some(precedence))), => write!(format, "-{:?}", display_term(argument, parentheses)),
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, None)), => write!(format, "|{:?}|", display_term(argument, Parentheses::None)),
}?; }?;
if requires_parentheses if requires_parentheses
@ -252,7 +242,7 @@ impl std::fmt::Debug for crate::Term
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
write!(format, "{:?}", display_term(&self, None)) write!(format, "{:?}", display_term(&self, Parentheses::None))
} }
} }
@ -260,7 +250,7 @@ impl std::fmt::Display for crate::Term
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
write!(format, "{}", display_term(&self, None)) write!(format, "{}", display_term(&self, Parentheses::None))
} }
} }

View File

@ -627,9 +627,8 @@ mod tests
crate::ImplicationDirection::RightToLeft); crate::ImplicationDirection::RightToLeft);
assert_eq!(format_formula("(a -> b -> c)"), "a -> b -> c"); assert_eq!(format_formula("(a -> b -> c)"), "a -> b -> c");
// TODO: fix assert_eq!(format_formula("(a -> (b -> c))"), "a -> b -> c");
//assert_eq!(format_formula("(a -> (b -> c))"), "a -> b -> c"); assert_eq!(format_formula("((a -> b) -> c)"), "(a -> b) -> c");
//assert_eq!(format_formula("((a -> b) -> c)"), "(a -> b) -> c");
} }
#[test] #[test]