diff --git a/apps/graph/storage_cartesian_function_store.h b/apps/graph/storage_cartesian_function_store.h index f81cd49b5..ee786cfcb 100644 --- a/apps/graph/storage_cartesian_function_store.h +++ b/apps/graph/storage_cartesian_function_store.h @@ -12,6 +12,7 @@ class StorageCartesianFunctionStore : public Shared::StorageFunctionStore { public: Shared::ExpiringPointer modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer(static_cast(privateModelForRecord(record))); } char symbol() const override { return Shared::StorageCartesianFunction::Symbol(); } + char unknownSymbol() const override { return Poincare::Symbol::SpecialSymbols::UnknownX; } private: Ion::Storage::Record::ErrorStatus addEmptyModel() override; const char * modelExtension() const override { return Shared::GlobalContext::funcExtension; } diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 80117dec1..61c52b8ff 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -104,6 +104,8 @@ void ListController::editExpression(int sequenceDefinition, Ion::Events::Event e break; } initialText = initialTextContent; + // Replace Poincare::Symbol::SpecialSymbols::UnknownN with 'n' + replaceUnknownSymbolWithReadableSymbol(initialText); } App * myApp = (App *)app(); InputViewController * inputController = myApp->inputViewController(); diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index 95f026c03..ba4ecb7cb 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -77,7 +77,7 @@ Poincare::Layout Sequence::nameLayout() { if (m_nameLayout.isUninitialized()) { m_nameLayout = HorizontalLayout::Builder( CodePointLayout::Builder(fullName()[0], KDFont::SmallFont), - VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Type::Subscript) + VerticalOffsetLayout::Builder(CodePointLayout::Builder(Symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Type::Subscript) ); } return m_nameLayout; @@ -122,7 +122,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { if (n < initialRank() || n < 0) { return NAN; } - char symb[] = {symbol(), 0}; + const char unknownN[2] = {Poincare::Symbol::SpecialSymbols::UnknownN, 0}; CacheContext ctx = CacheContext(sqctx); T un = sqctx->valueOfSequenceAtPreviousRank(0, 0); T unm1 = sqctx->valueOfSequenceAtPreviousRank(0, 1); @@ -139,7 +139,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { { ctx.setValueForSymbol(un, unSymbol); ctx.setValueForSymbol(vn, vnSymbol); - return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), symb, (T)n, ctx); + return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)n, ctx); } case Type::SingleRecurrence: { @@ -150,7 +150,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { ctx.setValueForSymbol(unm1, unSymbol); ctx.setValueForSymbol(vn, vn1Symbol); ctx.setValueForSymbol(vnm1, vnSymbol); - return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), symb, (T)(n-1), ctx); + return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)(n-1), ctx); } default: { @@ -164,7 +164,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { ctx.setValueForSymbol(unm2, unSymbol); ctx.setValueForSymbol(vnm1, vn1Symbol); ctx.setValueForSymbol(vnm2, vnSymbol); - return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), symb, (T)(n-2), ctx); + return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)(n-2), ctx); } } } diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index abaa8a59f..b6788ad6c 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -23,7 +23,6 @@ public: StorageFunction(record), m_nameLayout() {} static char Symbol() { return 'n'; } - char symbol() const override { return Symbol(); } void tidy() override; // MetaData getters Type type() const; @@ -33,6 +32,7 @@ public: void setInitialRank(int rank); // Definition Poincare::Layout definitionName() { return m_definitionHandle.name(this); } + Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableHandle()->setContent(this, c, Symbol(), Poincare::Symbol::SpecialSymbols::UnknownN); } // First initial condition Poincare::Layout firstInitialConditionName() { return m_firstInitialConditionHandle.name(this); } void firstInitialConditionText(char * buffer, size_t bufferSize) const { return m_firstInitialConditionHandle.text(this, buffer, bufferSize); } diff --git a/apps/sequence/sequence_store.h b/apps/sequence/sequence_store.h index 2b5143cd6..383499e6a 100644 --- a/apps/sequence/sequence_store.h +++ b/apps/sequence/sequence_store.h @@ -13,6 +13,7 @@ class SequenceStore : public Shared::StorageFunctionStore { public: using Shared::StorageFunctionStore::StorageFunctionStore; char symbol() const override { return Sequence::Symbol(); } + char unknownSymbol() const override { return Poincare::Symbol::SpecialSymbols::UnknownN; } /* Sequence Store hold all its Sequences in an array. The Sequence pointers * return by modelForRecord are therefore non-expirable. We choose to return * Sequence * instead of ExpiringPointer. */ diff --git a/apps/shared/expression_model_handle.cpp b/apps/shared/expression_model_handle.cpp index ae9697a99..c1c5674f6 100644 --- a/apps/shared/expression_model_handle.cpp +++ b/apps/shared/expression_model_handle.cpp @@ -65,8 +65,8 @@ Layout ExpressionModelHandle::layout(const Storage::Record * record) const { return m_layout; } -Ion::Storage::Record::ErrorStatus ExpressionModelHandle::setContent(Ion::Storage::Record * record, const char * c, char symbol) { - Expression e = ExpressionModelHandle::BuildExpressionFromText(c, symbol); +Ion::Storage::Record::ErrorStatus ExpressionModelHandle::setContent(Ion::Storage::Record * record, const char * c, char symbol, char unknownSymbol) { + Expression e = ExpressionModelHandle::BuildExpressionFromText(c, symbol, unknownSymbol); return setExpressionContent(record, e); } @@ -115,14 +115,14 @@ void ExpressionModelHandle::tidy() const { m_circular = 0; } -Poincare::Expression ExpressionModelHandle::BuildExpressionFromText(const char * c, char symbol) { +Poincare::Expression ExpressionModelHandle::BuildExpressionFromText(const char * c, char symbol, char unknownSymbol) { Expression expressionToStore; // if c = "", we want to reinit the Expression if (c && *c != 0) { // Compute the expression to store, without replacing symbols expressionToStore = Expression::Parse(c); if (!expressionToStore.isUninitialized() && symbol != 0) { - expressionToStore = expressionToStore.replaceUnknown(Symbol::Builder(symbol)); + expressionToStore = expressionToStore.replaceUnknown(Symbol::Builder(symbol), Symbol::Builder(unknownSymbol)); } } return expressionToStore; diff --git a/apps/shared/expression_model_handle.h b/apps/shared/expression_model_handle.h index 0f60adaf7..dbfb98781 100644 --- a/apps/shared/expression_model_handle.h +++ b/apps/shared/expression_model_handle.h @@ -20,7 +20,7 @@ public: Poincare::Layout layout(const Ion::Storage::Record * record) const; // Setters - virtual Ion::Storage::Record::ErrorStatus setContent(Ion::Storage::Record * record, const char * c, char symbol = 0); + virtual Ion::Storage::Record::ErrorStatus setContent(Ion::Storage::Record * record, const char * c, char symbol = 0, char unknownSymbol = 0); Ion::Storage::Record::ErrorStatus setExpressionContent(Ion::Storage::Record * record, Poincare::Expression & e); // Property @@ -30,7 +30,7 @@ public: virtual void tidy() const; protected: // Setters helper - static Poincare::Expression BuildExpressionFromText(const char * c, char symbol = 0); + static Poincare::Expression BuildExpressionFromText(const char * c, char symbol = 0, char unknownSymbol = 0); mutable Poincare::Expression m_expression; mutable Poincare::Layout m_layout; private: diff --git a/apps/shared/single_expression_model_handle.h b/apps/shared/single_expression_model_handle.h index 8590515ed..3700e0fd9 100644 --- a/apps/shared/single_expression_model_handle.h +++ b/apps/shared/single_expression_model_handle.h @@ -8,10 +8,9 @@ namespace Shared { class SingleExpressionModelHandle : public Ion::Storage::Record { public: - SingleExpressionModelHandle(Ion::Storage::Record record); + SingleExpressionModelHandle(Ion::Storage::Record record = Ion::Storage::Record()); // Property - virtual char symbol() const { return 0; }; void text(char * buffer, size_t bufferSize) const { return handle()->text(this, buffer, bufferSize); } Poincare::Expression expressionReduced(Poincare::Context * context) const { return handle()->expressionReduced(this, context); } Poincare::Expression expressionClone() const { return handle()->expressionClone(this); } @@ -30,7 +29,7 @@ public: * behaviour but it is not true for its child classes (for example, in * Sequence). */ virtual void tidy() { handle()->tidy(); } - virtual Ion::Storage::Record::ErrorStatus setContent(const char * c) { return editableHandle()->setContent(this, c, symbol()); } + virtual Ion::Storage::Record::ErrorStatus setContent(const char * c) { return editableHandle()->setContent(this, c); } Ion::Storage::Record::ErrorStatus setExpressionContent(Poincare::Expression & e) { return editableHandle()->setExpressionContent(this, e); } protected: bool isCircularlyDefined(Poincare::Context * context) const { return handle()->isCircularlyDefined(this, context); } diff --git a/apps/shared/storage_cartesian_function.h b/apps/shared/storage_cartesian_function.h index 0fb157e4d..e7a4d5439 100644 --- a/apps/shared/storage_cartesian_function.h +++ b/apps/shared/storage_cartesian_function.h @@ -11,11 +11,11 @@ class StorageCartesianFunction : public StorageFunction { public: static void DefaultName(char buffer[], size_t bufferSize); static char Symbol() { return 'x'; } - char symbol() const override { return Symbol(); }; static StorageCartesianFunction NewModel(Ion::Storage::Record::ErrorStatus * error, const char * baseName = nullptr); StorageCartesianFunction(Ion::Storage::Record record = Record()) : StorageFunction(record) {} + Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableHandle()->setContent(this, c, Symbol(), Poincare::Symbol::SpecialSymbols::UnknownX); } // Derivative bool displayDerivative() const; diff --git a/apps/shared/storage_expression_model_list_controller.cpp b/apps/shared/storage_expression_model_list_controller.cpp index 95c88cc1c..1a823d9cb 100644 --- a/apps/shared/storage_expression_model_list_controller.cpp +++ b/apps/shared/storage_expression_model_list_controller.cpp @@ -213,6 +213,17 @@ void StorageExpressionModelListController::reinitSelectedExpression(ExpiringPoin selectableTableView()->reloadData(); } +void StorageExpressionModelListController::replaceUnknownSymbolWithReadableSymbol(char * text) { + size_t textLength = strlen(text); + char unknownSymb = modelStore()->unknownSymbol(); + char symb = modelStore()->symbol(); + for (size_t i = 0; i < textLength; i++) { + if (unknownSymb != 0 && text[i] == unknownSymb) { + text[i] = symb; + } + } +} + void StorageExpressionModelListController::editExpression(Ion::Events::Event event) { char * initialText = nullptr; constexpr int initialTextContentMaxSize = Constant::MaxSerializedExpressionSize; @@ -223,12 +234,7 @@ void StorageExpressionModelListController::editExpression(Ion::Events::Event eve model->text(initialTextContent, initialTextContentMaxSize); initialText = initialTextContent; // Replace Poincare::Symbol::SpecialSymbols::UnknownX with 'x' - size_t initialTextLength = strlen(initialText); - for (size_t i = 0; i < initialTextLength; i++) { - if (initialTextContent[i] == Poincare::Symbol::SpecialSymbols::UnknownX) { - initialTextContent[i] = Poincare::Symbol::k_unknownXReadableChar; - } - } + replaceUnknownSymbolWithReadableSymbol(initialTextContent); } inputController()->edit(this, event, this, initialText, [](void * context, void * sender){ diff --git a/apps/shared/storage_expression_model_list_controller.h b/apps/shared/storage_expression_model_list_controller.h index dd9b7107b..078aa9078 100644 --- a/apps/shared/storage_expression_model_list_controller.h +++ b/apps/shared/storage_expression_model_list_controller.h @@ -27,6 +27,7 @@ protected: virtual void didChangeModelsList() { resetMemoization(); } virtual void reinitSelectedExpression(ExpiringPointer model); virtual void editExpression(Ion::Events::Event event); + void replaceUnknownSymbolWithReadableSymbol(char * initialText); virtual bool editSelectedRecordWithText(const char * text); virtual bool removeModelRow(Ion::Storage::Record record); virtual int modelIndexForRow(int j) { return j; } diff --git a/apps/shared/storage_expression_model_store.h b/apps/shared/storage_expression_model_store.h index 41cb5115c..f5393e292 100644 --- a/apps/shared/storage_expression_model_store.h +++ b/apps/shared/storage_expression_model_store.h @@ -14,6 +14,8 @@ class StorageExpressionModelStore { // TODO find better name (once we remove ExpressionModelStore?) public: StorageExpressionModelStore(); + virtual char symbol() const { return 0; } + virtual char unknownSymbol() const { return 0; } // Getters // By default, the number of models is not bounded diff --git a/apps/shared/storage_function.cpp b/apps/shared/storage_function.cpp index 3cd65fcbf..2af979fd6 100644 --- a/apps/shared/storage_function.cpp +++ b/apps/shared/storage_function.cpp @@ -1,7 +1,6 @@ #include "storage_function.h" #include "poincare_helpers.h" #include -#include #include "poincare/src/parsing/parser.h" #include #include @@ -76,13 +75,13 @@ int StorageFunction::nameWithArgument(char * buffer, size_t bufferSize, char arg } template -T StorageFunction::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const { +T StorageFunction::templatedApproximateAtAbscissa(T x, Poincare::Context * context, char unknownSymbol) const { if (isCircularlyDefined(context)) { return NAN; } constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; char unknownX[bufferSize]; - Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, Poincare::Symbol::UnknownX); + Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, unknownSymbol); return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(context), unknownX, x, *context); } @@ -94,5 +93,5 @@ StorageFunction::FunctionRecordData * StorageFunction::recordData() const { } -template float Shared::StorageFunction::templatedApproximateAtAbscissa(float, Poincare::Context*) const; -template double Shared::StorageFunction::templatedApproximateAtAbscissa(double, Poincare::Context*) const; +template float Shared::StorageFunction::templatedApproximateAtAbscissa(float, Poincare::Context*, char) const; +template double Shared::StorageFunction::templatedApproximateAtAbscissa(double, Poincare::Context*, char) const; diff --git a/apps/shared/storage_function.h b/apps/shared/storage_function.h index 9f8e50a19..047479735 100644 --- a/apps/shared/storage_function.h +++ b/apps/shared/storage_function.h @@ -2,6 +2,7 @@ #define SHARED_STORAGE_FUNCTION_H #include +#include #include "single_expression_model_handle.h" namespace Shared { @@ -32,10 +33,10 @@ public: // Evaluation virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const { - return templatedApproximateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, context, Poincare::Symbol::SpecialSymbols::UnknownX); } virtual double evaluateAtAbscissa(double x, Poincare::Context * context) const { - return templatedApproximateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, context, Poincare::Symbol::SpecialSymbols::UnknownX); } virtual double sumBetweenBounds(double start, double end, Poincare::Context * context) const = 0; protected: @@ -57,7 +58,7 @@ protected: bool m_active; }; private: - template T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const; + template T templatedApproximateAtAbscissa(T x, Poincare::Context * context, char unknownSymbol) const; FunctionRecordData * recordData() const; }; diff --git a/apps/shared/storage_function_store.h b/apps/shared/storage_function_store.h index 767d9c173..7195a48a8 100644 --- a/apps/shared/storage_function_store.h +++ b/apps/shared/storage_function_store.h @@ -19,7 +19,6 @@ public: ExpiringPointer modelForRecord(Ion::Storage::Record record) const { return ExpiringPointer(static_cast(privateModelForRecord(record))); } - virtual char symbol() const = 0; }; } diff --git a/poincare/include/poincare/derivative.h b/poincare/include/poincare/derivative.h index b4a76a19b..9cf6ee44f 100644 --- a/poincare/include/poincare/derivative.h +++ b/poincare/include/poincare/derivative.h @@ -25,7 +25,7 @@ public: // Properties Type type() const override { return Type::Derivative; } int polynomialDegree(Context & context, const char * symbolName) const override; - Expression replaceUnknown(const Symbol & symbol) override; + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override; private: // Layout diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 2e55c0543..20299e884 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -168,8 +168,8 @@ public: static constexpr int k_maxNumberOfPolynomialCoefficients = k_maxPolynomialDegree+1; int getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); } - Expression replaceUnknown(const Symbol & symbol); - Expression defaultReplaceUnknown(const Symbol & symbol); + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol); + Expression defaultReplaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol); /* Complex */ static bool EncounteredComplex(); diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 86ef3a646..fa9a924ad 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -116,7 +116,7 @@ public: virtual bool isNumber() const { return false; } virtual bool isRandom() const { return false; } /*!*/ virtual Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); - /*!*/ virtual Expression replaceUnknown(const Symbol & symbol); + /*!*/ virtual Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol); /*!*/ virtual Expression setSign(Sign s, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target); 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/integral.h b/poincare/include/poincare/integral.h index 241521fc2..196ee6359 100644 --- a/poincare/include/poincare/integral.h +++ b/poincare/include/poincare/integral.h @@ -21,7 +21,7 @@ public: // ExpressionNode Type type() const override { return Type::Integral; } int polynomialDegree(Context & context, const char * symbolName) const override; - Expression replaceUnknown(const Symbol & symbol) override; + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override; // Complex bool isReal(Context & context) const override { return true; } diff --git a/poincare/include/poincare/parametered_expression_helper.h b/poincare/include/poincare/parametered_expression_helper.h index d56888026..5198f8636 100644 --- a/poincare/include/poincare/parametered_expression_helper.h +++ b/poincare/include/poincare/parametered_expression_helper.h @@ -20,7 +20,7 @@ namespace ParameteredExpressionHelper { * unknowns: for instance, we want to change f(x)=diff(cos(x),x,x) into * f(X)=diff(cos(x),x,X), X being an unknown. ReplaceUnknownInExpression does * that. */ - Expression ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace); + Expression ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace, const Symbol & unknownSymbols); }; } diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index c9dbaeb66..578f3ffe0 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -16,7 +16,7 @@ public: #endif Type type() const override { return Type::Product; } - Expression replaceUnknown(const Symbol & symbol) override; + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override; private: float emptySequenceValue() const override { return 1.0f; } diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index 4256a18c5..81b549d52 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -16,7 +16,7 @@ public: #endif Type type() const override { return Type::Sum; } - Expression replaceUnknown(const Symbol & symbol) override; + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override; private: float emptySequenceValue() const override { return 0.0f; } diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index f608cb053..3763c722f 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -22,7 +22,7 @@ public: // Expression Properties Type type() const override { return Type::Symbol; } Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override; - Expression replaceUnknown(const Symbol & symbol) override; + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) 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; @@ -43,12 +43,12 @@ public: Evaluation approximate(SinglePrecision p, Context& context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } Evaluation approximate(DoublePrecision p, Context& context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } + bool isUnknown(char unknownSymbol) const; private: char m_name[0]; // MUST be the last member variable size_t nodeSize() const override { return sizeof(SymbolNode); } template Evaluation templatedApproximate(Context& context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; - bool isUnknownX() const; }; class Symbol final : public SymbolAbstract { @@ -58,11 +58,11 @@ class Symbol final : public SymbolAbstract { public: static constexpr int k_ansLength = 3; static constexpr char k_ans[k_ansLength+1] = "ans"; - static constexpr CodePoint k_unknownXReadableChar = 'x'; enum SpecialSymbols : char { /* We can use characters from 1 to 31 as they do not correspond to usual * characters but events as 'end of text', 'backspace'... */ - UnknownX = 1 //TODO LEA make sure there is no collision with the code points + UnknownX = 1, //TODO LEA make sure there is no collision with the code points + UnknownN = 2 //TODO LEA make sure there is no collision with the code points, }; Symbol(const SymbolNode * node) : SymbolAbstract(node) {} static Symbol Builder(const char * name, int length) { return SymbolAbstract::Builder(name, length); } @@ -71,14 +71,14 @@ public: static Expression UntypedBuilder(const char * name, size_t length, Context * context); // Symbol properties - bool isSystemSymbol() const { return name()[0] == SpecialSymbols::UnknownX && name()[1] == 0; } + bool isSystemSymbol() const { return node()->isUnknown(Symbol::SpecialSymbols::UnknownX) || node()->isUnknown(Symbol::SpecialSymbols::UnknownN); } static bool isSeriesSymbol(const char * c); static bool isRegressionSymbol(const char * c); // Expression Expression shallowReduce(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target); Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); - Expression replaceUnknown(const Symbol & symbol); + Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol); int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const; Expression shallowReplaceReplaceableSymbols(Context & context); private: diff --git a/poincare/src/derivative.cpp b/poincare/src/derivative.cpp index cb6f1de12..1c1d66a3e 100644 --- a/poincare/src/derivative.cpp +++ b/poincare/src/derivative.cpp @@ -27,8 +27,8 @@ int DerivativeNode::polynomialDegree(Context & context, const char * symbolName) return ExpressionNode::polynomialDegree(context, symbolName); } -Expression DerivativeNode::replaceUnknown(const Symbol & symbol) { - return ParameteredExpressionHelper::ReplaceUnknownInExpression(Derivative(this), symbol); +Expression DerivativeNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return ParameteredExpressionHelper::ReplaceUnknownInExpression(Derivative(this), symbol, unknownSymbol); } Layout DerivativeNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 6702e3f4b..147304004 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -336,14 +336,14 @@ int Expression::getPolynomialReducedCoefficients(const char * symbolName, Expres return degree; } -Expression Expression::replaceUnknown(const Symbol & symbol) { - return node()->replaceUnknown(symbol); +Expression Expression::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return node()->replaceUnknown(symbol, unknownSymbol); } -Expression Expression::defaultReplaceUnknown(const Symbol & symbol) { +Expression Expression::defaultReplaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { int nbChildren = numberOfChildren(); for (int i = 0; i < nbChildren; i++) { - childAtIndex(i).replaceUnknown(symbol); + childAtIndex(i).replaceUnknown(symbol, unknownSymbol); } return *this; } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index b87fbf347..b62f1f916 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -18,8 +18,8 @@ Expression ExpressionNode::replaceSymbolWithExpression(const SymbolAbstract & sy return Expression(this).defaultReplaceSymbolWithExpression(symbol, expression); } -Expression ExpressionNode::replaceUnknown(const Symbol & symbol) { - return Expression(this).defaultReplaceUnknown(symbol); +Expression ExpressionNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return Expression(this).defaultReplaceUnknown(symbol, unknownSymbol); } Expression ExpressionNode::setSign(Sign s, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target) { diff --git a/poincare/src/integral.cpp b/poincare/src/integral.cpp index 96c565d87..1b62e05a3 100644 --- a/poincare/src/integral.cpp +++ b/poincare/src/integral.cpp @@ -29,8 +29,8 @@ int IntegralNode::polynomialDegree(Context & context, const char * symbolName) c return ExpressionNode::polynomialDegree(context, symbolName); } -Expression IntegralNode::replaceUnknown(const Symbol & symbol) { - return ParameteredExpressionHelper::ReplaceUnknownInExpression(Integral(this), symbol); +Expression IntegralNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return ParameteredExpressionHelper::ReplaceUnknownInExpression(Integral(this), symbol, unknownSymbol); } Layout IntegralNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { diff --git a/poincare/src/parametered_expression_helper.cpp b/poincare/src/parametered_expression_helper.cpp index 944003c16..07f4acb4e 100644 --- a/poincare/src/parametered_expression_helper.cpp +++ b/poincare/src/parametered_expression_helper.cpp @@ -5,7 +5,7 @@ namespace Poincare { -Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace) { +Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace, const Symbol & unknownSymbol) { assert(!e.isUninitialized()); assert(e.type() == ExpressionNode::Type::Integral || e.type() == ExpressionNode::Type::Derivative @@ -22,10 +22,10 @@ Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e, Symbol& parameterChild = static_cast(child1); if (strcmp(parameterChild.name(), symbolToReplace.name()) != 0) { - return e.defaultReplaceUnknown(symbolToReplace); + return e.defaultReplaceUnknown(symbolToReplace, unknownSymbol); } for (int i = 2; i < numberOfChildren; i++) { - e.childAtIndex(i).replaceUnknown(symbolToReplace); + e.childAtIndex(i).replaceUnknown(symbolToReplace, unknownSymbol); } return e; } diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index ff6d7a8e0..551c97a70 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -14,8 +14,8 @@ namespace Poincare { constexpr Expression::FunctionHelper Product::s_functionHelper; -Expression ProductNode::replaceUnknown(const Symbol & symbol) { - return ParameteredExpressionHelper::ReplaceUnknownInExpression(Product(this), symbol); +Expression ProductNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return ParameteredExpressionHelper::ReplaceUnknownInExpression(Product(this), symbol, unknownSymbol); } Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const { diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index 549cfdba9..d83cf506c 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -14,8 +14,8 @@ namespace Poincare { constexpr Expression::FunctionHelper Sum::s_functionHelper; -Expression SumNode::replaceUnknown(const Symbol & symbol) { - return ParameteredExpressionHelper::ReplaceUnknownInExpression(Sum(this), symbol); +Expression SumNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return ParameteredExpressionHelper::ReplaceUnknownInExpression(Sum(this), symbol, unknownSymbol); } Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const { diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 52ef984ea..6074089bc 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -14,7 +14,6 @@ namespace Poincare { constexpr char Symbol::k_ans[]; -constexpr CodePoint Symbol::k_unknownXReadableChar; SymbolNode::SymbolNode(const char * newName, int length) : SymbolAbstractNode() { strlcpy(const_cast(name()), newName, length+1); @@ -24,8 +23,8 @@ Expression SymbolNode::replaceSymbolWithExpression(const SymbolAbstract & symbol return Symbol(this).replaceSymbolWithExpression(symbol, expression); } -Expression SymbolNode::replaceUnknown(const Symbol & symbol) { - return Symbol(this).replaceUnknown(symbol); +Expression SymbolNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { + return Symbol(this).replaceUnknown(symbol, unknownSymbol); } int SymbolNode::polynomialDegree(Context & context, const char * symbolName) const { @@ -67,7 +66,7 @@ int SymbolNode::getVariables(Context & context, isVariableTest isVariable, char } float SymbolNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { - return isUnknownX() ? NAN : 0.0f; + return isUnknown(Symbol::SpecialSymbols::UnknownX) ? NAN : 0.0f; } bool SymbolNode::isReal(Context & context) const { @@ -76,8 +75,11 @@ bool SymbolNode::isReal(Context & context) const { } Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (isUnknownX()) { - return CodePointLayout::Builder(Symbol::k_unknownXReadableChar); + if (isUnknown(Symbol::SpecialSymbols::UnknownX)) { + return CodePointLayout::Builder('x'); + } + if (isUnknown(Symbol::SpecialSymbols::UnknownN)) { + return CodePointLayout::Builder('n'); } // TODO return Parse(m_name).createLayout() ? if (strcmp(m_name, "u(n)") == 0) { @@ -145,8 +147,8 @@ Expression Symbol::UntypedBuilder(const char * name, size_t length, Context * co return Expression(); } -bool SymbolNode::isUnknownX() const { - bool result = UTF8Helper::CodePointIs(m_name, Symbol::SpecialSymbols::UnknownX); +bool SymbolNode::isUnknown(char unknownSymbol) const { + bool result = UTF8Helper::CodePointIs(m_name, unknownSymbol); if (result) { assert(m_name[1] == 0); } @@ -193,10 +195,11 @@ Expression Symbol::replaceSymbolWithExpression(const SymbolAbstract & symbol, co return *this; } -Expression Symbol::replaceUnknown(const Symbol & symbol) { +Expression Symbol::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) { assert(!symbol.isUninitialized()); assert(symbol.type() == ExpressionNode::Type::Symbol); - return replaceSymbolWithExpression(symbol, Symbol::Builder(SpecialSymbols::UnknownX)); + assert(unknownSymbol.type() == ExpressionNode::Type::Symbol); + return replaceSymbolWithExpression(symbol, unknownSymbol); } int Symbol::getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const { diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 5ac3f5546..27f53ffce 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -65,6 +65,7 @@ Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context & conte * symbols are defined circularly. */ e = Expression::ExpressionWithoutSymbols(e, context); if (!e.isUninitialized() && isFunction) { + // TODO: when SequenceFunction is created, we want to specify which unknown variable to replace (UnknownX or UnknownN) e = e.replaceSymbolWithExpression(Symbol::Builder(Symbol::SpecialSymbols::UnknownX), symbol.childAtIndex(0)); } return e; diff --git a/poincare/test/parser.cpp b/poincare/test/parser.cpp index 136b54165..7779d030a 100644 --- a/poincare/test/parser.cpp +++ b/poincare/test/parser.cpp @@ -350,6 +350,7 @@ QUIZ_CASE(poincare_parser_parse_store) { assert_raises_parsing_error("1→𝐢"); assert_raises_parsing_error("1→ℯ"); assert_raises_parsing_error("1→\1"); // UnknownX + assert_raises_parsing_error("1→\2"); // UnknownN assert_raises_parsing_error("1→acos"); assert_raises_parsing_error("1→f(2)"); assert_raises_parsing_error("1→f(f)");