[poincare] childNeedsUserParentheses takes childIndex param

Scenario:
0+exp^0 i->b
0+exp b^0 i->b
Go to VariableBox/expression -> Parentheses were not properly added when
b was replaced
This commit is contained in:
Léa Saviot
2019-09-19 14:13:19 +02:00
committed by EmilieNumworks
parent 1cbc40815b
commit 93832549f1
16 changed files with 38 additions and 41 deletions

View File

@@ -145,11 +145,11 @@ public:
virtual bool isNumber() const { return false; }
virtual bool isRandom() const { return false; }
virtual bool isParameteredExpression() const { return false; }
/* childNeedsUserParentheses checks if parentheses are required by mathematical rules:
/* childAtIndexNeedsUserParentheses checks if parentheses are required by mathematical rules:
* +(2,-1) --> 2+(-1)
* *(+(2,1),3) --> (2+1)*3
*/
virtual bool childNeedsUserParentheses(const Expression & child) const { return false; }
virtual bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const { return false; }
/*!*/ virtual Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
/*!*/ virtual Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
/*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext);

View File

@@ -22,7 +22,7 @@ public:
Type type() const override { return Type::Factorial; }
Sign sign(Context * context) const override { return Sign::Positive; }
Expression setSign(Sign s, ReductionContext reductionContext) override;
bool childNeedsUserParentheses(const Expression & child) const override;
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
private:
// Layout

View File

@@ -24,7 +24,7 @@ public:
Sign sign(Context * context) const override;
int polynomialDegree(Context * context, const char * symbolName) const override;
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override;
bool childNeedsUserParentheses(const Expression & child) const override;
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
// Approximation
template<typename T> static Complex<T> compute(const std::complex<T> c, const std::complex<T> d, Preferences::ComplexFormat complexFormat) { return Complex<T>::Builder(c*d); }

View File

@@ -21,7 +21,7 @@ public:
void eraseNumberOfChildren() override { m_numberOfChildren = 0; }
// Properties
bool childNeedsUserParentheses(const Expression & child) const override;
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
// Comparison
typedef int (*ExpressionOrder)(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted);

View File

@@ -26,7 +26,7 @@ public:
Type type() const override { return Type::Opposite; }
int polynomialDegree(Context * context, const char * symbolName) const override;
Sign sign(Context * context) const override;
bool childNeedsUserParentheses(const Expression & child) const override;
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
// Approximation
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override {

View File

@@ -28,7 +28,7 @@ public:
Type type() const override { return Type::Power; }
Sign sign(Context * context) const override;
Expression setSign(Sign s, ReductionContext reductionContext) override;
bool childNeedsUserParentheses(const Expression & child) const override;
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
int polynomialDegree(Context * context, const char * symbolName) const override;
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override;

View File

@@ -23,7 +23,7 @@ public:
// Properties
Type type() const override { return Type::Subtraction; }
int polynomialDegree(Context * context, const char * symbolName) const override;
bool childNeedsUserParentheses(const Expression & child) const override;
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
// Approximation
template<typename T> static Complex<T> compute(const std::complex<T> c, const std::complex<T> d, Preferences::ComplexFormat complexFormat) { return Complex<T>::Builder(c - d); }

View File

@@ -250,7 +250,7 @@ void Expression::shallowAddMissingParenthesis() {
}
for (int i = 0; i < numberOfChildren(); i++) {
Expression child = childAtIndex(0);
if (node()->childNeedsUserParentheses(child)) {
if (node()->childAtIndexNeedsUserParentheses(child, i)) {
replaceChildAtIndexInPlace(i, Parenthesis::Builder(child));
}
}
@@ -259,7 +259,7 @@ void Expression::shallowAddMissingParenthesis() {
Expression Expression::addMissingParentheses() {
for (int i = 0; i < numberOfChildren(); i++) {
Expression child = childAtIndex(i).addMissingParentheses();
if (node()->childNeedsUserParentheses(child)) {
if (node()->childAtIndexNeedsUserParentheses(child, i)) {
child = Parenthesis::Builder(child);
}
replaceChildAtIndexInPlace(i, child);
@@ -748,7 +748,7 @@ Expression Expression::deepBeautify(ExpressionNode::ReductionContext reductionCo
Expression child = e.childAtIndex(i);
child = child.deepBeautify(reductionContext);
// We add missing Parentheses after beautifying the parent and child
if (e.node()->childNeedsUserParentheses(child)) {
if (e.node()->childAtIndexNeedsUserParentheses(child, i)) {
e.replaceChildAtIndexInPlace(i, Parenthesis::Builder(child));
}
}

View File

@@ -19,12 +19,12 @@ Expression FactorialNode::setSign(Sign s, ReductionContext reductionContext) {
return Factorial(this);
}
bool FactorialNode::childNeedsUserParentheses(const Expression & child) const {
bool FactorialNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
return true;
}
if (child.type() == Type::Conjugate) {
return childNeedsUserParentheses(child.childAtIndex(0));
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
}
Type types[] = {Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Addition};
return child.isOfType(types, 4);

View File

@@ -106,7 +106,7 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol,
Expression xValue = childAtIndex(0);
value = value.replaceSymbolWithExpression(xSymbol, xValue);
Expression p = parent();
if (!p.isUninitialized() && p.node()->childNeedsUserParentheses(value)) {
if (!p.isUninitialized() && p.node()->childAtIndexNeedsUserParentheses(value, p.indexOfChild(*this))) {
value = Parenthesis::Builder(value);
}
replaceWithInPlace(value);

View File

@@ -50,8 +50,8 @@ int MultiplicationNode::getPolynomialCoefficients(Context * context, const char
return Multiplication(this).getPolynomialCoefficients(context, symbolName, coefficients);
}
bool MultiplicationNode::childNeedsUserParentheses(const Expression & child) const {
if (NAryExpressionNode::childNeedsUserParentheses(child)) {
bool MultiplicationNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
if (NAryExpressionNode::childAtIndexNeedsUserParentheses(child, childIndex)) {
return true;
}
Type types[] = {Type::Subtraction, Type::Addition};

View File

@@ -7,18 +7,17 @@ extern "C" {
namespace Poincare {
bool NAryExpressionNode::childNeedsUserParentheses(const Expression & child) const {
bool NAryExpressionNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
/* Expressions like "-2" require parentheses in Addition/Multiplication except
* when they are the first operand. */
if (((child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative)
|| child.type() == Type::Opposite)
/* We use "hasAncestor" instead of "==" because child might not be the
* direct child of the addition/multiplication [e.g. +(conj(-2), 3)] */
&& !child.node()->hasAncestor(childAtIndex(0), true)) {
if (childIndex != 0
&& ((child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative)
|| child.type() == Type::Opposite))
{
return true;
}
if (child.type() == Type::Conjugate) {
return childNeedsUserParentheses(child.childAtIndex(0));
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
}
return false;
}

View File

@@ -33,12 +33,13 @@ ExpressionNode::Sign OppositeNode::sign(Context * context) const {
/* Layout */
bool OppositeNode::childNeedsUserParentheses(const Expression & child) const {
bool OppositeNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
assert(childIndex == 0);
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
return true;
}
if (child.type() == Type::Conjugate) {
return childNeedsUserParentheses(child.childAtIndex(0));
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), 0);
}
Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite};
return child.isOfType(types, 3);

View File

@@ -99,19 +99,18 @@ bool PowerNode::isReal(Context * context) const {
return false;
}
bool PowerNode::childNeedsUserParentheses(const Expression & child) const {
/* We use "hasAncestor" instead of "==" because child might not be the direct
* child of thepower [e.g. ^(conj(+(A,B), C)] */
if (child.node()->hasAncestor(childAtIndex(0), true)) {
/* ^(-2.3, 4) --> (-2.3)^{4}
* ^(2/3, 4) --> (2/3)^{4}
*/
bool PowerNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
if (childIndex == 0) {
if ((child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative)
|| (child.type() == Type::Rational && !static_cast<const Rational &>(child).isInteger())) {
|| (child.type() == Type::Rational && !static_cast<const Rational &>(child).isInteger()))
{
/* ^(-2.3, 4) --> (-2.3)^{4}
* ^(2/3, 4) --> (2/3)^{4} */
return true;
}
if (child.type() == Type::Conjugate) {
return childNeedsUserParentheses(child.childAtIndex(0));
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
}
// ^(2+3,4) --> (2+3)^{4}
Type types[] = {Type::Power, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Addition};

View File

@@ -23,18 +23,16 @@ int SubtractionNode::polynomialDegree(Context * context, const char * symbolName
// Private
bool SubtractionNode::childNeedsUserParentheses(const Expression & child) const {
/* First operand of a subtraction never requires parentheses.
* We use "hasAncestor" instead of "==" because child might not be the direct
* child of the subtraction [e.g. 'conj(-2) - 3' ] */
if (child.node()->hasAncestor(childAtIndex(0), true)) {
bool SubtractionNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
if (childIndex == 0) {
// First operand of a subtraction never requires parentheses
return false;
}
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
return true;
}
if (child.type() == Type::Conjugate) {
return childNeedsUserParentheses(child.childAtIndex(0));
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
}
Type types[] = {Type::Subtraction, Type::Opposite, Type::Addition};
return child.isOfType(types, 3);

View File

@@ -200,7 +200,7 @@ Expression Symbol::replaceSymbolWithExpression(const SymbolAbstract & symbol, co
if (symbol.type() == ExpressionNode::Type::Symbol && strcmp(name(), symbol.name()) == 0) {
Expression value = expression.clone();
Expression p = parent();
if (!p.isUninitialized() && p.node()->childNeedsUserParentheses(value)) {
if (!p.isUninitialized() && p.node()->childAtIndexNeedsUserParentheses(value, p.indexOfChild(*this))) {
value = Parenthesis::Builder(value);
}
replaceWithInPlace(value);