From a7a719df4a23e90f529436a23d98e88439cfdb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 1 Oct 2018 14:38:38 +0200 Subject: [PATCH] [poincare] Handle functions in replaceSymbolWithExp and similar methods --- apps/calculation/app.cpp | 5 +++- apps/calculation/calculation.cpp | 11 +++++--- apps/sequence/sequence_context.h | 4 +-- apps/shared/store_context.cpp | 4 +-- apps/shared/store_context.h | 2 +- apps/variable_box_controller.cpp | 5 ++-- poincare/include/poincare/context.h | 2 +- poincare/include/poincare/expression.h | 5 ++-- poincare/include/poincare/expression_node.h | 4 ++- poincare/include/poincare/function.h | 2 ++ poincare/include/poincare/global_context.h | 2 +- poincare/include/poincare/symbol.h | 4 +-- poincare/include/poincare/variable_context.h | 2 +- poincare/src/expression.cpp | 2 +- poincare/src/expression_node.cpp | 5 ++-- poincare/src/function.cpp | 29 ++++++++++++++++++-- poincare/src/global_context.cpp | 8 +++--- poincare/src/store.cpp | 6 ++-- poincare/src/symbol.cpp | 6 ++-- poincare/src/variable_context.cpp | 6 ++-- 20 files changed, 76 insertions(+), 38 deletions(-) diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index c571db138..f08dc917c 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -96,7 +96,10 @@ bool App::textInputIsCorrect(const char * text) { return false; } Expression ansExpression = static_cast(snapshot())->calculationStore()->ansExpression(localContext()); - exp = exp.replaceSymbolWithExpression(Symbol::k_ans, ansExpression); + { + Symbol ansSymbol = Symbol(Symbol::k_ans, 3); + exp = exp.replaceSymbolWithExpression(ansSymbol, ansExpression); + } char buffer[Calculation::k_printedExpressionSize]; int length = PoincareHelpers::Serialize(exp, buffer, sizeof(buffer)); /* if the buffer is totally full, it is VERY likely that writeTextInBuffer diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 38c0e2e84..d4c5a9e6c 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -35,10 +35,13 @@ void Calculation::reset() { void Calculation::setContent(const char * c, Context * context, Expression ansExpression) { reset(); - Expression input = Expression::parse(c).replaceSymbolWithExpression(Symbol::k_ans, ansExpression); - /* We do not store directly the text enter by the user because we do not want - * to keep Ans symbol in the calculation store. */ - PoincareHelpers::Serialize(input, m_inputText, sizeof(m_inputText)); + { + Symbol ansSymbol = Symbol(Symbol::k_ans, 3); + Expression input = Expression::parse(c).replaceSymbolWithExpression(ansSymbol, ansExpression); + /* We do not store directly the text enter by the user because we do not want + * to keep Ans symbol in the calculation store. */ + PoincareHelpers::Serialize(input, m_inputText, sizeof(m_inputText)); + } Expression exactOutput = PoincareHelpers::ParseAndSimplify(m_inputText, *context); PoincareHelpers::Serialize(exactOutput, m_exactOutputText, sizeof(m_exactOutputText)); Expression approximateOutput = PoincareHelpers::Approximate(exactOutput, *context); diff --git a/apps/sequence/sequence_context.h b/apps/sequence/sequence_context.h index 7ce0afd4c..94ae593cf 100644 --- a/apps/sequence/sequence_context.h +++ b/apps/sequence/sequence_context.h @@ -48,8 +48,8 @@ public: const Poincare::Expression expressionForSymbol(const Poincare::Symbol & symbol) override { return m_parentContext->expressionForSymbol(symbol); } - void setExpressionForSymbolName(const Poincare::Expression & expression, const char * symbolName, Poincare::Context & context) override { - m_parentContext->setExpressionForSymbolName(expression, symbolName, context); + void setExpressionForSymbol(const Poincare::Expression & expression, const Poincare::Symbol & symbol, Poincare::Context & context) override { + m_parentContext->setExpressionForSymbol(expression, symbol, context); } template T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const { if (sizeof(T) == sizeof(float)) { diff --git a/apps/shared/store_context.cpp b/apps/shared/store_context.cpp index 8ec49e6cb..533a7a3e9 100644 --- a/apps/shared/store_context.cpp +++ b/apps/shared/store_context.cpp @@ -7,8 +7,8 @@ using namespace Poincare; namespace Shared { -void StoreContext::setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) { - m_parentContext->setExpressionForSymbolName(expression, symbolName, context); +void StoreContext::setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) { + m_parentContext->setExpressionForSymbol(expression, symbol, context); } } diff --git a/apps/shared/store_context.h b/apps/shared/store_context.h index f29471e7d..9c1eaeb7e 100644 --- a/apps/shared/store_context.h +++ b/apps/shared/store_context.h @@ -19,7 +19,7 @@ public: {} void setParentContext(Poincare::Context * parentContext) { m_parentContext = parentContext; } void setSeriesPairIndex(int j) { m_seriesPairIndex = j; } - void setExpressionForSymbolName(const Poincare::Expression & expression, const char * symbolName, Poincare::Context & context) override; + void setExpressionForSymbol(const Poincare::Expression & expression, const Poincare::Symbol & symbol, Poincare::Context & context) override; protected: Shared::DoublePairStore * m_store; int m_seriesPairIndex; diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 67787db39..2f4758032 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -80,11 +80,12 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even if (event == Ion::Events::Backspace && m_currentPage != Page::RootMenu) { if (m_currentPage == Page::Scalar) { const char symbolName[2] = {static_cast('A'+selectedRow()), 0}; - m_context->setExpressionForSymbolName(Expression(), symbolName, *m_context); + Symbol symbol = Symbol(symbolName, 2); + m_context->setExpressionForSymbol(Expression(), symbol, *m_context); } if (m_currentPage == Page::Matrix) { const Symbol symbol("M0", 2); // FIXME: dummy variable box controller - m_context->setExpressionForSymbolName(Expression(), symbol.name(), *m_context); + m_context->setExpressionForSymbol(Expression(), symbol, *m_context); m_matrixLayouts[selectedRow()] = Layout(); } m_selectableTableView.reloadData(); diff --git a/poincare/include/poincare/context.h b/poincare/include/poincare/context.h index bc84a0ecd..c53b34de9 100644 --- a/poincare/include/poincare/context.h +++ b/poincare/include/poincare/context.h @@ -9,7 +9,7 @@ class Symbol; class Context { public: virtual const Expression expressionForSymbol(const Symbol & symbol) = 0; - virtual void setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) = 0; + virtual void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) = 0; }; } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index cc1d85f9c..c579a5a5b 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -12,6 +12,7 @@ namespace Poincare { class Context; +class Symbol; class Expression : public TreeHandle { friend class AbsoluteValue; @@ -145,7 +146,7 @@ public: static constexpr int k_maxPolynomialDegree = 2; static constexpr int k_maxNumberOfPolynomialCoefficients = k_maxPolynomialDegree+1; int getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context & context, Preferences::AngleUnit angleUnit) const; - Expression replaceSymbolWithExpression(const char * symbol, Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); } + Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); } /* Comparison */ /* isIdenticalTo is the "easy" equality, it returns true if both trees have @@ -233,7 +234,7 @@ private: template Evaluation approximateToEvaluation(Context& context, Preferences::AngleUnit angleUnit) const; /* Properties */ - Expression defaultReplaceSymbolWithExpression(const char * symbol, Expression expression); + Expression defaultReplaceSymbolWithExpression(const Symbol & symbol, const Expression expression); int defaultGetPolynomialCoefficients(Context & context, const char * symbol, Expression expression[]) const; /* Expression roots/extrema solver*/ diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 7cb68ddc0..af13821d9 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -12,6 +12,8 @@ namespace Poincare { /* Methods preceded by '*!*' interfere with the expression pool, which can make * 'this' outdated. They should only be called in a wrapper on Expression. */ +class Symbol; + class ExpressionNode : public TreeNode { friend class AdditionNode; friend class DivisionNode; @@ -99,7 +101,7 @@ public: }; virtual Sign sign() const { return Sign::Unknown; } virtual bool isNumber() const { return false; } - /*!*/ virtual Expression replaceSymbolWithExpression(const char * symbol, Expression & expression); + /*!*/ virtual Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression); /*!*/ virtual Expression setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit); virtual int polynomialDegree(Context & context, const char * symbolName) const; /*!*/ virtual int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const; diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h index 9fad2a11d..2cdeb926b 100644 --- a/poincare/include/poincare/function.h +++ b/poincare/include/poincare/function.h @@ -19,6 +19,7 @@ public: // Properties Type type() const override { return Type::Function; } + Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) override; int polynomialDegree(Context & context, const char * symbolName) const override; int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const override; int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override; @@ -45,6 +46,7 @@ public: } Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit); + Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression); }; } diff --git a/poincare/include/poincare/global_context.h b/poincare/include/poincare/global_context.h index 00d830e7c..27f3781d3 100644 --- a/poincare/include/poincare/global_context.h +++ b/poincare/include/poincare/global_context.h @@ -17,7 +17,7 @@ public: /* The expression recorded in global context is already a expression. * Otherwise, we would need the context and the angle unit to evaluate it */ const Expression expressionForSymbol(const Symbol & symbol) override; - void setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) override; + void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) override; static bool storageMemoryFull(); //TODO static constexpr uint16_t k_maxNumberOfSequences = 10; private: diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index b90b833c0..3a7c49079 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -29,7 +29,7 @@ public: // Expression Properties Type type() const override { return Type::Symbol; } Sign sign() const override; - Expression replaceSymbolWithExpression(const char * symbol, Expression & expression) override; + Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) override; int polynomialDegree(Context & context, const char * symbolName) const override; int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const override; int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override; @@ -85,7 +85,7 @@ public: // Expression Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit); - Expression replaceSymbolWithExpression(const char * symbol, Expression & expression); + Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression); int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const; // Symbol diff --git a/poincare/include/poincare/variable_context.h b/poincare/include/poincare/variable_context.h index 36d0694e1..435928ab7 100644 --- a/poincare/include/poincare/variable_context.h +++ b/poincare/include/poincare/variable_context.h @@ -13,7 +13,7 @@ public: void setApproximationForVariable(T value); // Context - void setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) override; + void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) override; const Expression expressionForSymbol(const Symbol & symbol) override; private: diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index ae31832ff..96286ad35 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -200,7 +200,7 @@ Evaluation Expression::approximateToEvaluation(Context& context, Preferences: return node()->approximate(U(), context, angleUnit); } -Expression Expression::defaultReplaceSymbolWithExpression(const char * symbol, Expression expression) { +Expression Expression::defaultReplaceSymbolWithExpression(const Symbol & symbol, const Expression expression) { for (int i = 0; i < numberOfChildren(); i++) { childAtIndex(i).replaceSymbolWithExpression(symbol, expression); } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index 862d4e227..7e4c53554 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -1,10 +1,11 @@ #include -#include #include +#include +#include namespace Poincare { -Expression ExpressionNode::replaceSymbolWithExpression(const char * symbol, Expression & expression) { +Expression ExpressionNode::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { return Expression(this).defaultReplaceSymbolWithExpression(symbol, expression); } diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index f11f7b421..c09c2a62b 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -1,12 +1,17 @@ #include #include +#include +#include #include #include -#include #include namespace Poincare { +Expression FunctionNode::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { + return Function(this).replaceSymbolWithExpression(symbol, expression); +} + int FunctionNode::polynomialDegree(Context & context, const char * symbolName) const { Expression e = context.expressionForSymbol(Function(this)); if (e.isUninitialized()) { @@ -47,7 +52,7 @@ float FunctionNode::characteristicXRange(Context & context, Preferences::AngleUn VariableContext FunctionNode::xContext(Context & parentContext) const { const char x[] = {Symbol::SpecialSymbols::UnknownX, 0}; VariableContext xContext = VariableContext(x, &parentContext); - xContext.setExpressionForSymbolName(Expression(childAtIndex(0)), x, xContext); + xContext.setExpressionForSymbol(Expression(childAtIndex(0)), Symbol(x, 1), xContext); return xContext; } @@ -91,4 +96,24 @@ Expression Function::shallowReduce(Context & context, Preferences::AngleUnit ang return Expression::defaultShallowReduce(context, angleUnit); } +Expression Function::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { + // Replace the symbol in the child + childAtIndex(0).replaceSymbolWithExpression(symbol, expression); + if (symbol.type() == ExpressionNode::Type::Function && strcmp(name(), symbol.name()) == 0) { + Expression value = expression.clone(); + // Replace the unknown in the new expression by the function's child + const char x[2] = {SpecialSymbols::UnknownX, 0}; + Symbol xSymbol = Symbol(x, 1); + Expression xValue = childAtIndex(0); + value.replaceSymbolWithExpression(xSymbol, xValue); + Expression p = parent(); + if (!p.isUninitialized() && p.node()->childNeedsParenthesis(value.node())) { + value = Parenthesis(value); + } + replaceWithInPlace(value); + return value; + } + return *this; +} + } diff --git a/poincare/src/global_context.cpp b/poincare/src/global_context.cpp index 3bb5fa62b..368eb40d1 100644 --- a/poincare/src/global_context.cpp +++ b/poincare/src/global_context.cpp @@ -33,17 +33,17 @@ const Expression GlobalContext::expressionForSymbol(const Symbol & symbol) { return ExpressionForRecord(RecordWithName(symbol.name())); } -void GlobalContext::setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) { +void GlobalContext::setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) { sStorageMemoryFull = false; /* If the new expression contains the symbol, replace it because it will be * destroyed afterwards (to be able to do A+2->A) */ - Ion::Storage::Record record = RecordWithName(symbolName); + Ion::Storage::Record record = RecordWithName(symbol.name()); Expression e = ExpressionForRecord(record); - Expression finalExpression = expression.clone().replaceSymbolWithExpression(symbolName, e); + Expression finalExpression = expression.clone().replaceSymbolWithExpression(symbol, e); // Delete any record with same name (as it is going to be overriden) record.destroy(); - Ion::Storage::Record::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithExtension(symbolName, ExtensionForExpression(finalExpression), finalExpression.addressInPool(), finalExpression.size()); + Ion::Storage::Record::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithExtension(symbol.name(), ExtensionForExpression(symbol), finalExpression.addressInPool(), finalExpression.size()); if (err != Ion::Storage::Record::ErrorStatus::None) { assert(err == Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable); sStorageMemoryFull = true; diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 7ff3e3d4e..5b01586c8 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -34,9 +34,9 @@ template Evaluation StoreNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { /* If we are here, it means that the store node was not shallowReduced. * Otherwise, it would have been replaced by its symbol. We thus have to - * setExpressionForSymbolName. */ + * setExpressionForSymbol. */ Store s(this); - context.setExpressionForSymbolName(s.value(), s.symbol().name(), context); + context.setExpressionForSymbol(s.value(), s.symbol(), context); Expression e = context.expressionForSymbol(s.symbol()); if (e.isUninitialized()) { return Complex::Undefined(); @@ -45,7 +45,7 @@ Evaluation StoreNode::templatedApproximate(Context& context, Preferences::Ang } Expression Store::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { - context.setExpressionForSymbolName(value(), symbol().name(), context); + context.setExpressionForSymbol(value(), symbol(), context); Expression c1 = childAtIndex(1); replaceWithInPlace(c1); return c1.shallowReduce(context, angleUnit); diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 19d50f884..fce416c30 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -43,7 +43,7 @@ ExpressionNode::Sign SymbolNode::sign() const { return Sign::Unknown; } -Expression SymbolNode::replaceSymbolWithExpression(const char * symbol, Expression & expression) { +Expression SymbolNode::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { return Symbol(this).replaceSymbolWithExpression(symbol, expression); } @@ -205,8 +205,8 @@ Expression Symbol::shallowReduce(Context & context, Preferences::AngleUnit angle return *this; } -Expression Symbol::replaceSymbolWithExpression(const char * symbol, Expression & expression) { - if (strcmp(name(), symbol) == 0) { +Expression Symbol::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { + if (symbol.type() == ExpressionNode::Type::Symbol && strcmp(name(), symbol.name()) == 0) { Expression value = expression.clone(); Expression p = parent(); if (!p.isUninitialized() && p.node()->childNeedsParenthesis(value.node())) { diff --git a/poincare/src/variable_context.cpp b/poincare/src/variable_context.cpp index 672483373..ab364d15d 100644 --- a/poincare/src/variable_context.cpp +++ b/poincare/src/variable_context.cpp @@ -18,14 +18,14 @@ void VariableContext::setApproximationForVariable(T value) { m_value = Float(value); } -void VariableContext::setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) { - if (strcmp(symbolName, m_name) == 0) { +void VariableContext::setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) { + if (strcmp(symbol.name(), m_name) == 0) { if (expression.isUninitialized()) { return; } m_value = expression.clone(); } else { - m_parentContext->setExpressionForSymbolName(expression, symbolName, context); + m_parentContext->setExpressionForSymbol(expression, symbol, context); } }