diff --git a/poincare/Makefile b/poincare/Makefile index cc77414fa..0bfce6660 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -16,6 +16,7 @@ objs += $(addprefix poincare/src/,\ opposite.o\ decimal.o\ rational.o\ + symbol.o\ ) objsExpected += $(addprefix poincare/src/,\ diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index fc94cfcca..f477a44ac 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -17,7 +17,6 @@ class Expression : public TreeByValue { friend class ExpressionNode; friend class NAryExpressionNode; friend class SubtractionNode; - friend class SymbolNode; public: /* Constructor & Destructor */ Expression() : Expression(nullptr) {} @@ -32,6 +31,9 @@ public: } /* Hierarchy */ + Expression parent() const { + return Expression(static_cast(TreeByReference::parent().node())); + } Expression childAtIndex(int i) const { return Expression(static_cast(TreeByValue::childAtIndex(i).node())); } @@ -102,7 +104,8 @@ public: /* Simplification */ static Expression ParseAndSimplify(const char * text, Context & context, Preferences::AngleUnit angleUnit); - void simplify(Context & context, Preferences::AngleUnit angleUnit); + Expression simplify(Context & context, Preferences::AngleUnit angleUnit); + Expression deepReduce(Context & context, Preferences::AngleUnit angleUnit) const; /* Approximation Helper */ template Expression approximate(Context& context, Preferences::AngleUnit angleUnit, Preferences::Preferences::ComplexFormat complexFormat) const; @@ -130,9 +133,8 @@ private: int getPolynomialCoefficients(char symbolName, Expression coefficients[], Context & context, Preferences::AngleUnit angleUnit) const; /* Simplification */ - Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit); - Expression deepBeautify(Context & context, Preferences::AngleUnit angleUnit); - Expression deepReduce(Context & context, Preferences::AngleUnit angleUnit); + Expression shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) const; + Expression deepBeautify(Context & context, Preferences::AngleUnit angleUnit) const; /* Approximation */ template static U epsilon(); diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index dca89239c..aad16dd38 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -8,6 +8,8 @@ namespace Poincare { class SymbolNode : public ExpressionNode { friend class Store; public: + SymbolNode() : m_name(0) {} + static SymbolNode * FailedAllocationStaticNode(); SymbolNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } @@ -38,20 +40,20 @@ public: int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; /* Simplification */ - Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + bool hasAnExactRepresentation(Context & context) const; + Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const override; /* Approximation */ Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } Evaluation approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } private: - bool hasAnExactRepresentation(Context & context) const; template Evaluation templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; char m_name; }; -class SymbolReference : public Expression { +class Symbol : public Expression { public: enum SpecialSymbols : char { /* We can use characters from 1 to 31 as they do not correspond to usual @@ -86,11 +88,10 @@ public: X3, Y3 = 29 }; - SymbolReference(const char name) : Expression(TreePool::sharedPool()->createTreeNode()) { - if (!node->isAllocationFailure()) { - static_cast(node)->setName(name); - } + Symbol(const char name) : Expression(TreePool::sharedPool()->createTreeNode()) { + node()->setName(name); } + Symbol(const SymbolNode * node) : Expression(node) {} // Symbol properties static const char * textForSpecialSymbols(char name); @@ -104,11 +105,11 @@ public: // Expression Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const; - Expression replaceSymbolWithExpression(char symbol, Expression expression); + Expression replaceSymbolWithExpression(char symbol, Expression expression) const; int getPolynomialCoefficients(char symbolName, Expression coefficients[]) const; private: - SymbolNode * node() { return static_cast(Expression::node()); } - char name() { return node()->name(); } + SymbolNode * node() const override { return static_cast(Expression::node()); } + char name() const { return node()->name(); } }; } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 7fb91cbcb..e07584f2a 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -33,14 +33,7 @@ ExpressionNode::Sign SymbolNode::sign() const { } Expression SymbolNode::replaceSymbolWithExpression(char symbol, Expression expression) const { - if (m_name == symbol) { - Expression value = expression.clone(); - if (parent() && value.needsParenthesesWithParent(parent())) { - value = ParenthesisReference(value); - } - return value; - } - return Expression(this); + return Symbol(this).replaceSymbolWithExpression(symbol, expression); } int SymbolNode::polynomialDegree(char symbol) const { @@ -51,13 +44,7 @@ int SymbolNode::polynomialDegree(char symbol) const { } int SymbolNode::getPolynomialCoefficients(char symbolName, Expression coefficients[]) const { - if (m_name == symbolName) { - coefficients[0] = RationalReference(0); - coefficients[1] = RationalReference(1); - return 1; - } - coefficients[0] = SymbolReference(m_name); - return 0; + return Symbol(this).getPolynomialCoefficients(symbolName, coefficients); } int SymbolNode::getVariables(isVariableTest isVariable, char * variables) const { @@ -131,7 +118,7 @@ LayoutRef SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, VerticalOffsetLayoutNode::Type::Subscript)); } if (Symbol::isMatrixSymbol(m_name) || Symbol::isSeriesSymbol(m_name) || Symbol::isRegressionSymbol(m_name)) { - return LayoutHelper::String(SymbolReference::textForSpecialSymbols(m_name), 2); + return LayoutHelper::String(Symbol::textForSpecialSymbols(m_name), 2); } return LayoutHelper::String(&m_name, 1); } @@ -153,17 +140,8 @@ int SymbolNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloat return 1; } -Expression SymbolNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - // Do not replace symbols in expression of type: 3->A - if (parent() && parent()->type() == Type::Store && parent()->childAtIndex(1) == this) { - return this; - } - const Expression e = context.expressionForSymbol(SymbolReference(m_name)); - if (e.isDefined() && hasAnExactRepresentation(context)) { // TODO: later AZ should be replaced. - /* The stored expression had been beautified which forces to call deepReduce. */ - return e.clone().deepReduce(context, angleUnit); - } - return Expression(this); +Expression SymbolNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + return Symbol(this).shallowReduce(context, angleUnit); } bool SymbolNode::hasAnExactRepresentation(Context & context) const { @@ -176,7 +154,7 @@ Evaluation SymbolNode::templatedApproximate(Context& context, Preferences::An if (m_name == Ion::Charset::IComplex) { return Complex(0.0, 1.0); } - const Expression e = context.expressionForSymbol(SymbolReference(m_name)); + const Expression e = context.expressionForSymbol(Symbol(m_name)); if (e.isDefined()) { return e.node()->approximate(T(), context, angleUnit); } @@ -316,26 +294,31 @@ bool Symbol::isApproximate(char c, Context & context) { return false; } -Expression Symbol::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { +Expression Symbol::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { +// TODO: avoid ExpressionRef comparison ? 2 solutions: +// - Compare identifiant +// - virtualize deepReduce to do nothing on the second child of Store? +#if 0 // Do not replace symbols in expression of type: 3->A Expression p = parent(); - if (p.isDefined() && p.type() == Type::Store && p.childAtIndex(1) == *this) { + if (p.isDefined() && p.type() == ExpressionNode::Type::Store && p.childAtIndex(1) == *this) { return *this; } +#endif const Expression e = context.expressionForSymbol(*this); - if (e.isDefined() && hasAnExactRepresentation(context)) { + if (e.isDefined() && node()->hasAnExactRepresentation(context)) { // TODO: later AZ should be replaced. /* The stored expression had been beautified which forces to call deepReduce. */ - return e.clone().deepReduce(context, angleUnit); + return e.deepReduce(context, angleUnit); } return *this; } -Expression Symbol::replaceSymbolWithExpression(char symbol, Expression expression) { +Expression Symbol::replaceSymbolWithExpression(char symbol, Expression expression) const { if (name() == symbol) { - Expression value = expression.clone(); + Expression value = expression; Expression p = parent(); - if (p.isDefined() && value.needsParenthesesWithParent(p)) { + if (p.isDefined() && value.node()->needsParenthesesWithParent(p.node())) { value = Parenthesis(value); } return value;