From 82d5ff7799b185c684f63f10a6e443cd3a80a120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 26 Mar 2019 14:49:11 +0100 Subject: [PATCH] [ion/unicode] Clean special code points --- apps/graph/cartesian_function_store.h | 4 +-- apps/sequence/list/list_controller.cpp | 2 +- apps/sequence/sequence.cpp | 6 ++++- apps/sequence/sequence.h | 2 +- apps/sequence/sequence_store.h | 4 +-- apps/shared/cartesian_function.cpp | 26 ++++++++++++++----- apps/shared/cartesian_function.h | 6 ++--- apps/shared/expression_model.cpp | 2 +- apps/shared/expression_model.h | 2 +- .../expression_model_list_controller.cpp | 2 +- apps/shared/expression_model_store.h | 4 +-- apps/shared/function.cpp | 14 +++++----- apps/shared/function.h | 8 +++--- apps/shared/sum_graph_controller.cpp | 2 +- ion/include/ion/unicode/code_point.h | 23 ++++++---------- poincare/include/poincare/symbol.h | 12 +++------ poincare/src/fraction_layout.cpp | 2 +- poincare/src/function.cpp | 8 +++--- poincare/src/store.cpp | 4 +-- poincare/src/symbol.cpp | 17 +++++++++--- poincare/src/symbol_abstract.cpp | 2 +- poincare/src/trigonometry.cpp | 6 ++++- poincare/test/properties.cpp | 22 ++++++++-------- poincare/test/user_variable.cpp | 14 ++++++---- 24 files changed, 108 insertions(+), 86 deletions(-) diff --git a/apps/graph/cartesian_function_store.h b/apps/graph/cartesian_function_store.h index cd47572ae..f2ff11601 100644 --- a/apps/graph/cartesian_function_store.h +++ b/apps/graph/cartesian_function_store.h @@ -11,8 +11,8 @@ namespace Graph { class CartesianFunctionStore : public Shared::FunctionStore { public: Shared::ExpiringPointer modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer(static_cast(privateModelForRecord(record))); } - char symbol() const override { return Shared::CartesianFunction::Symbol(); } - char unknownSymbol() const override { return Poincare::Symbol::SpecialSymbols::UnknownX; } + CodePoint symbol() const override { return Shared::CartesianFunction::Symbol(); } + CodePoint unknownSymbol() const override { return UCodePointUnknownX; } private: Ion::Storage::Record::ErrorStatus addEmptyModel() override; const char * modelExtension() const override { return Ion::Storage::funcExtension; } diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 08aab769f..3a38c38a7 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -104,7 +104,7 @@ void ListController::editExpression(int sequenceDefinition, Ion::Events::Event e break; } initialText = initialTextContent; - // Replace Poincare::Symbol::SpecialSymbols::UnknownN with 'n' + // Replace UCodePointUnknownN with 'n' replaceUnknownSymbolWithReadableSymbol(initialText); } App * myApp = (App *)app(); diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index 4f4272b15..02701e9fd 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -122,7 +122,11 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { if (n < initialRank() || n < 0) { return NAN; } - const char unknownN[2] = {Poincare::Symbol::SpecialSymbols::UnknownN, 0}; + constexpr int bufferSize = 5; + char unknownN[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(UCodePointUnknownN, unknownN, bufferSize); + assert(codePointSize <= bufferSize - 1); + unknownN[codePointSize] = 0; CacheContext ctx = CacheContext(sqctx); T un = sqctx->valueOfSequenceAtPreviousRank(0, 0); T unm1 = sqctx->valueOfSequenceAtPreviousRank(0, 1); diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index 61e43386e..e931da391 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -32,7 +32,7 @@ public: void setInitialRank(int rank); // Definition Poincare::Layout definitionName() { return m_definition.name(this); } - Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableModel()->setContent(this, c, Symbol(), Poincare::Symbol::SpecialSymbols::UnknownN); } + Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableModel()->setContent(this, c, Symbol(), UCodePointUnknownN); } // First initial condition Poincare::Layout firstInitialConditionName() { return m_firstInitialCondition.name(this); } void firstInitialConditionText(char * buffer, size_t bufferSize) const { return m_firstInitialCondition.text(this, buffer, bufferSize); } diff --git a/apps/sequence/sequence_store.h b/apps/sequence/sequence_store.h index b13f6c376..3bfb94e9f 100644 --- a/apps/sequence/sequence_store.h +++ b/apps/sequence/sequence_store.h @@ -12,8 +12,8 @@ namespace Sequence { class SequenceStore : public Shared::FunctionStore { public: using Shared::FunctionStore::FunctionStore; - char symbol() const override { return Sequence::Symbol(); } - char unknownSymbol() const override { return Poincare::Symbol::SpecialSymbols::UnknownN; } + CodePoint symbol() const override { return Sequence::Symbol(); } + CodePoint unknownSymbol() const override { return UCodePointUnknownN; } /* 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/cartesian_function.cpp b/apps/shared/cartesian_function.cpp index bc42ae84d..7faa5492e 100644 --- a/apps/shared/cartesian_function.cpp +++ b/apps/shared/cartesian_function.cpp @@ -64,7 +64,7 @@ CartesianFunction CartesianFunction::NewModel(Ion::Storage::Record::ErrorStatus return CartesianFunction(Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, Ion::Storage::funcExtension)); } -int CartesianFunction::derivativeNameWithArgument(char * buffer, size_t bufferSize, char arg) { +int CartesianFunction::derivativeNameWithArgument(char * buffer, size_t bufferSize, CodePoint arg) { // Fill buffer with f(x). Keep size for derivative sign. int derivativeSize = UTF8Decoder::CharSizeOfCodePoint('\''); int numberOfChars = nameWithArgument(buffer, bufferSize - derivativeSize, arg); @@ -87,7 +87,7 @@ void CartesianFunction::setDisplayDerivative(bool display) { } double CartesianFunction::approximateDerivative(double x, Poincare::Context * context) const { - Poincare::Derivative derivative = Poincare::Derivative::Builder(expressionReduced(context).clone(), Symbol::Builder(Symbol::SpecialSymbols::UnknownX), Poincare::Float::Builder(x)); // derivative takes ownership of Poincare::Float::Builder(x) and the clone of expression + Poincare::Derivative derivative = Poincare::Derivative::Builder(expressionReduced(context).clone(), Symbol::Builder(UCodePointUnknownX), Poincare::Float::Builder(x)); // derivative takes ownership of Poincare::Float::Builder(x) and the clone of expression /* TODO: when we approximate derivative, we might want to simplify the * derivative here. However, we might want to do it once for all x (to avoid * lagging in the derivative table. */ @@ -96,7 +96,7 @@ double CartesianFunction::approximateDerivative(double x, Poincare::Context * co double CartesianFunction::sumBetweenBounds(double start, double end, Poincare::Context * context) const { // TODO: this does not work yet because integral does not understand UnknownX - Poincare::Integral integral = Poincare::Integral::Builder(expressionReduced(context).clone(), Symbol::Builder(Symbol::SpecialSymbols::UnknownX), Poincare::Float::Builder(start), Poincare::Float::Builder(end)); // Integral takes ownership of args + Poincare::Integral integral = Poincare::Integral::Builder(expressionReduced(context).clone(), Symbol::Builder(UCodePointUnknownX), Poincare::Float::Builder(start), Poincare::Float::Builder(end)); // Integral takes ownership of args /* TODO: when we approximate integral, we might want to simplify the integral * here. However, we might want to do it once for all x (to avoid lagging in * the derivative table. */ @@ -104,22 +104,34 @@ double CartesianFunction::sumBetweenBounds(double start, double end, Poincare::C } Expression::Coordinate2D CartesianFunction::nextMinimumFrom(double start, double step, double max, Context * context) const { - const char unknownX[2] = {Poincare::Symbol::UnknownX, 0}; + constexpr int bufferSize = 3; + char unknownX[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(UCodePointUnknownX, unknownX, bufferSize); + assert(codePointSize <= bufferSize); return PoincareHelpers::NextMinimum(expressionReduced(context), unknownX, start, step, max, *context); } Expression::Coordinate2D CartesianFunction::nextMaximumFrom(double start, double step, double max, Context * context) const { - const char unknownX[2] = {Poincare::Symbol::UnknownX, 0}; + constexpr int bufferSize = 3; + char unknownX[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(UCodePointUnknownX, unknownX, bufferSize); + assert(codePointSize <= bufferSize); return PoincareHelpers::NextMaximum(expressionReduced(context), unknownX, start, step, max, *context); } double CartesianFunction::nextRootFrom(double start, double step, double max, Context * context) const { - const char unknownX[2] = {Poincare::Symbol::UnknownX, 0}; + constexpr int bufferSize = 3; + char unknownX[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(UCodePointUnknownX, unknownX, bufferSize); + assert(codePointSize <= bufferSize); return PoincareHelpers::NextRoot(expressionReduced(context), unknownX, start, step, max, *context); } Expression::Coordinate2D CartesianFunction::nextIntersectionFrom(double start, double step, double max, Poincare::Context * context, Expression e) const { - const char unknownX[2] = {Poincare::Symbol::UnknownX, 0}; + constexpr int bufferSize = 3; + char unknownX[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(UCodePointUnknownX, unknownX, bufferSize); + assert(codePointSize <= bufferSize); return PoincareHelpers::NextIntersection(expressionReduced(context), unknownX, start, step, max, *context, e); } diff --git a/apps/shared/cartesian_function.h b/apps/shared/cartesian_function.h index 0990816ca..899a4d1c6 100644 --- a/apps/shared/cartesian_function.h +++ b/apps/shared/cartesian_function.h @@ -10,17 +10,17 @@ namespace Shared { class CartesianFunction : public Function { public: static void DefaultName(char buffer[], size_t bufferSize); - static char Symbol() { return 'x'; } + static CodePoint Symbol() { return 'x'; } static CartesianFunction NewModel(Ion::Storage::Record::ErrorStatus * error, const char * baseName = nullptr); CartesianFunction(Ion::Storage::Record record = Record()) : Function(record) {} - Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableModel()->setContent(this, c, Symbol(), Poincare::Symbol::SpecialSymbols::UnknownX); } + Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableModel()->setContent(this, c, Symbol(), UCodePointUnknownX); } // Derivative bool displayDerivative() const; void setDisplayDerivative(bool display); - int derivativeNameWithArgument(char * buffer, size_t bufferSize, char arg); + int derivativeNameWithArgument(char * buffer, size_t bufferSize, CodePoint arg); double approximateDerivative(double x, Poincare::Context * context) const; // Integral double sumBetweenBounds(double start, double end, Poincare::Context * context) const override; diff --git a/apps/shared/expression_model.cpp b/apps/shared/expression_model.cpp index 54f7b7f28..142b9b4b7 100644 --- a/apps/shared/expression_model.cpp +++ b/apps/shared/expression_model.cpp @@ -65,7 +65,7 @@ Layout ExpressionModel::layout(const Storage::Record * record) const { return m_layout; } -Ion::Storage::Record::ErrorStatus ExpressionModel::setContent(Ion::Storage::Record * record, const char * c, char symbol, char unknownSymbol) { +Ion::Storage::Record::ErrorStatus ExpressionModel::setContent(Ion::Storage::Record * record, const char * c, CodePoint symbol, CodePoint unknownSymbol) { Expression e = ExpressionModel::BuildExpressionFromText(c, symbol, unknownSymbol); return setExpressionContent(record, e); } diff --git a/apps/shared/expression_model.h b/apps/shared/expression_model.h index 265a7b721..ab940071b 100644 --- a/apps/shared/expression_model.h +++ b/apps/shared/expression_model.h @@ -18,7 +18,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, char unknownSymbol = 0); + virtual Ion::Storage::Record::ErrorStatus setContent(Ion::Storage::Record * record, const char * c, CodePoint symbol = 0, CodePoint unknownSymbol = 0); Ion::Storage::Record::ErrorStatus setExpressionContent(Ion::Storage::Record * record, Poincare::Expression & e); // Property diff --git a/apps/shared/expression_model_list_controller.cpp b/apps/shared/expression_model_list_controller.cpp index 47a145611..fe4a33aa4 100644 --- a/apps/shared/expression_model_list_controller.cpp +++ b/apps/shared/expression_model_list_controller.cpp @@ -233,7 +233,7 @@ void ExpressionModelListController::editExpression(Ion::Events::Event event) { ExpiringPointer model = modelStore()->modelForRecord(record); model->text(initialTextContent, initialTextContentMaxSize); initialText = initialTextContent; - // Replace Poincare::Symbol::SpecialSymbols::UnknownX with 'x' + // Replace UCodePointUnknownX with 'x' replaceUnknownSymbolWithReadableSymbol(initialTextContent); } inputController()->edit(this, event, this, initialText, diff --git a/apps/shared/expression_model_store.h b/apps/shared/expression_model_store.h index a280bf7e7..31b93dd3f 100644 --- a/apps/shared/expression_model_store.h +++ b/apps/shared/expression_model_store.h @@ -14,8 +14,8 @@ class ExpressionModelStore { // TODO find better name (once we remove ExpressionModelStore?) public: ExpressionModelStore(); - virtual char symbol() const { return 0; } - virtual char unknownSymbol() const { return 0; } + virtual CodePoint symbol() const { return 0; } + virtual CodePoint unknownSymbol() const { return 0; } // Getters // By default, the number of models is not bounded diff --git a/apps/shared/function.cpp b/apps/shared/function.cpp index ea76cf015..bc454ed42 100644 --- a/apps/shared/function.cpp +++ b/apps/shared/function.cpp @@ -64,18 +64,20 @@ void Function::setActive(bool active) { recordData()->setActive(active); } -int Function::nameWithArgument(char * buffer, size_t bufferSize, char arg) { +int Function::nameWithArgument(char * buffer, size_t bufferSize, CodePoint arg) { + assert(UTF8Decoder::CharSizeOfCodePoint(arg) == 1); const char * functionName = fullName(); size_t baseNameLength = SymbolAbstract::TruncateExtension(buffer, functionName, bufferSize - k_parenthesedArgumentLength); int result = baseNameLength + strlcpy(&buffer[baseNameLength], k_parenthesedArgument, bufferSize-baseNameLength); - if (baseNameLength+1 < bufferSize - 1) { - buffer[baseNameLength+1] = arg; + int bufferRemainingSize = bufferSize - (baseNameLength+1); + if (bufferRemainingSize > 0) { + UTF8Decoder::CodePointToChars(arg, buffer+baseNameLength+1, bufferRemainingSize); } return result; } template -T Function::templatedApproximateAtAbscissa(T x, Poincare::Context * context, char unknownSymbol) const { +T Function::templatedApproximateAtAbscissa(T x, Poincare::Context * context, CodePoint unknownSymbol) const { if (isCircularlyDefined(context)) { return NAN; } @@ -93,5 +95,5 @@ Function::FunctionRecordDataBuffer * Function::recordData() const { } -template float Shared::Function::templatedApproximateAtAbscissa(float, Poincare::Context*, char) const; -template double Shared::Function::templatedApproximateAtAbscissa(double, Poincare::Context*, char) const; +template float Shared::Function::templatedApproximateAtAbscissa(float, Poincare::Context*, CodePoint) const; +template double Shared::Function::templatedApproximateAtAbscissa(double, Poincare::Context*, CodePoint) const; diff --git a/apps/shared/function.h b/apps/shared/function.h index 1148ed54d..a957dc45d 100644 --- a/apps/shared/function.h +++ b/apps/shared/function.h @@ -29,14 +29,14 @@ public: void setActive(bool active); // Name - int nameWithArgument(char * buffer, size_t bufferSize, char arg); + int nameWithArgument(char * buffer, size_t bufferSize, CodePoint arg); // Evaluation virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const { - return templatedApproximateAtAbscissa(x, context, Poincare::Symbol::SpecialSymbols::UnknownX); + return templatedApproximateAtAbscissa(x, context, UCodePointUnknownX); } virtual double evaluateAtAbscissa(double x, Poincare::Context * context) const { - return templatedApproximateAtAbscissa(x, context, Poincare::Symbol::SpecialSymbols::UnknownX); + return templatedApproximateAtAbscissa(x, context, UCodePointUnknownX); } virtual double sumBetweenBounds(double start, double end, Poincare::Context * context) const = 0; protected: @@ -60,7 +60,7 @@ protected: bool m_active; }; private: - template T templatedApproximateAtAbscissa(T x, Poincare::Context * context, char unknownSymbol) const; + template T templatedApproximateAtAbscissa(T x, Poincare::Context * context, CodePoint unknownSymbol) const; FunctionRecordDataBuffer * recordData() const; }; diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index c2e79a7be..5d18a4106 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -235,7 +235,7 @@ void SumGraphController::LegendView::setEditableZone(double d) { void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, Layout functionLayout) { assert(step == Step::Result || functionLayout.isUninitialized()); constexpr int sigmaLength = 2; - const CodePoint sigma[sigmaLength] = {UCodePointSpace, m_sumSymbol}; + const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol}; if (step == Step::FirstParameter) { m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); } else if (step == Step::SecondParameter) { diff --git a/ion/include/ion/unicode/code_point.h b/ion/include/ion/unicode/code_point.h index b5b409b42..c069f7e39 100644 --- a/ion/include/ion/unicode/code_point.h +++ b/ion/include/ion/unicode/code_point.h @@ -16,38 +16,31 @@ private: uint32_t m_code; }; - -// TODO LEA Remove unneeded values static constexpr CodePoint UCodePointNull = 0x0; + +/* 0x1 and 0x2 represent soh and stx. They are not used, so we can use them for + * another purpose */ +static constexpr CodePoint UCodePointUnknownX = 0x1; +static constexpr CodePoint UCodePointUnknownN = 0x2; + static constexpr CodePoint UCodePointTabulation = 0x9; static constexpr CodePoint UCodePointLineFeed = 0xa; -/* 0x11, 0x12, 0x13, 0x14 represent DEVICE CONTROL ONE TO FOUR. They are not - * used, so we can use them for another purpose */ +/* 0x11, 0x12, 0x13 represent DEVICE CONTROL ONE TO THREE. They are not used, so + * we can use them for another purpose */ static constexpr CodePoint UCodePointEmpty = 0x11; // Used to be parsed into EmptyExpression static constexpr CodePoint UCodePointLeftSuperscript = 0x12; // Used to parse Power static constexpr CodePoint UCodePointRightSuperscript = 0x13; // Used to parse Power -static constexpr CodePoint UCodePointUnknownX = 0x14; // Used to store expressions -static constexpr CodePoint UCodePointSpace = 0x20; // -static constexpr CodePoint UCodePointDegree = 0xb0; // ° static constexpr CodePoint UCodePointMiddleDot = 0xb7; // · static constexpr CodePoint UCodePointMultiplicationSign = 0xd7; // × -static constexpr CodePoint UCodePointGreekCapitalLetterGamma = 0x393; // Γ -static constexpr CodePoint UCodePointGreekCapitalLetterDelta = 0x394; // Δ -static constexpr CodePoint UCodePointGreekSmallLetterTheta = 0x3b8; // θ -static constexpr CodePoint UCodePointGreekSmallLetterLambda = 0x3bb; // λ static constexpr CodePoint UCodePointGreekSmallLetterPi = 0x3c0; // π -static constexpr CodePoint UCodePointGreekSmallLetterSigma = 0x3c3; // σ static constexpr CodePoint UCodePointLatinLetterSmallCapitalE = 0x1d07; // ᴇ static constexpr CodePoint UCodePointScriptSmallE = 0x212f; // ℯ static constexpr CodePoint UCodePointRightwardsArrow = 0x2192; // → static constexpr CodePoint UCodePointNArySummation = 0x2211; // ∑ static constexpr CodePoint UCodePointSquareRoot = 0x221a; // √ static constexpr CodePoint UCodePointIntegral = 0x222b; // ∫ -static constexpr CodePoint UCodePointAlmostEqualTo = 0x2248; // ≈ -static constexpr CodePoint UCodePointLessThanOrEqualTo = 0x2264; // ≤ -static constexpr CodePoint UCodePointGreaterThanOrEqualTo = 0x2265; // ≥ static constexpr CodePoint UCodePointMathematicalBoldSmallI = 0x1d422; // 𝐢 #endif diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 3763c722f..9abfdc876 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -43,7 +43,7 @@ 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; + bool isUnknown(CodePoint unknownSymbol) const; private: char m_name[0]; // MUST be the last member variable @@ -58,20 +58,14 @@ class Symbol final : public SymbolAbstract { public: static constexpr int k_ansLength = 3; static constexpr char k_ans[k_ansLength+1] = "ans"; - 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 - 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); } - static Symbol Builder(char name) { return Symbol::Builder(&name, 1); } + static Symbol Builder(CodePoint name); static Symbol Ans() { return Symbol::Builder(k_ans, k_ansLength); } static Expression UntypedBuilder(const char * name, size_t length, Context * context); // Symbol properties - bool isSystemSymbol() const { return node()->isUnknown(Symbol::SpecialSymbols::UnknownX) || node()->isUnknown(Symbol::SpecialSymbols::UnknownN); } + bool isSystemSymbol() const { return node()->isUnknown(UCodePointUnknownX) || node()->isUnknown(UCodePointUnknownN); } static bool isSeriesSymbol(const char * c); static bool isRegressionSymbol(const char * c); diff --git a/poincare/src/fraction_layout.cpp b/poincare/src/fraction_layout.cpp index 30d4b2a78..8b6c85f9c 100644 --- a/poincare/src/fraction_layout.cpp +++ b/poincare/src/fraction_layout.cpp @@ -215,4 +215,4 @@ void FractionLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionCo ctx->fillRect(KDRect(p.x()+Metric::FractionAndConjugateHorizontalMargin, fractionLineY, layoutSize().width()-2*Metric::FractionAndConjugateHorizontalMargin, k_fractionLineHeight), expressionColor); } -} \ No newline at end of file +} diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 50ed7e0b2..53b4a87d7 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -116,7 +116,7 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol, 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 - Symbol xSymbol = Symbol::Builder(Symbol::SpecialSymbols::UnknownX); + Symbol xSymbol = Symbol::Builder(UCodePointUnknownX); Expression xValue = childAtIndex(0); value = value.replaceSymbolWithExpression(xSymbol, xValue); Expression p = parent(); @@ -144,7 +144,7 @@ Expression Function::shallowReplaceReplaceableSymbols(Context & context) { if (e.isUninitialized()) { return *this; } - e.replaceSymbolWithExpression(Symbol::Builder(Symbol::SpecialSymbols::UnknownX), childAtIndex(0)); + e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), childAtIndex(0)); replaceWithInPlace(e); return e; } @@ -152,9 +152,9 @@ Expression Function::shallowReplaceReplaceableSymbols(Context & context) { // TODO: should we avoid replacing unknown X in-place but use a context instead? #if 0 VariableContext Function::unknownXContext(Context & parentContext) const { - Symbol unknownXSymbol = Symbol::Builder(Symbol::SpecialSymbols::UnknownX); + Symbol unknownXSymbol = Symbol::Builder(UCodePointUnknownX); Expression child = childAtIndex(0); - const char x[] = {Symbol::SpecialSymbols::UnknownX, 0}; + const char x[] = {UCodePointUnknownX, 0}; // UGLY, use decoder /* COMMENT */ if (child.type() == ExpressionNode::Type::Symbol && static_cast(child).isSystemSymbol()) { return parentContext; diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 12e7d917f..46fbacbbe 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -78,7 +78,7 @@ Expression Store::storeValueForSymbol(Context& context, Preferences::ComplexForm // In tata + 2 ->f(tata), replace tata with xUnknown symbol assert(symbol().childAtIndex(0).type() == ExpressionNode::Type::Symbol); Expression userDefinedUnknown = symbol().childAtIndex(0); - Symbol xUnknown = Symbol::Builder(Symbol::SpecialSymbols::UnknownX); + Symbol xUnknown = Symbol::Builder(UCodePointUnknownX); finalValue = childAtIndex(0).replaceSymbolWithExpression(static_cast(userDefinedUnknown), xUnknown); } else { assert(symbol().type() == ExpressionNode::Type::Symbol); @@ -95,7 +95,7 @@ Expression Store::storeValueForSymbol(Context& context, Preferences::ComplexForm // Replace the xUnknown symbol with the variable initially used assert(symbol().childAtIndex(0).type() == ExpressionNode::Type::Symbol); Expression userDefinedUnknown = symbol().childAtIndex(0); - Symbol xUnknown = Symbol::Builder(Symbol::SpecialSymbols::UnknownX); + Symbol xUnknown = Symbol::Builder(UCodePointUnknownX); storedExpression = storedExpression.replaceSymbolWithExpression(xUnknown, static_cast(userDefinedUnknown)); } return storedExpression; diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 6074089bc..a0711dc46 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,7 @@ int SymbolNode::getVariables(Context & context, isVariableTest isVariable, char } float SymbolNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { - return isUnknown(Symbol::SpecialSymbols::UnknownX) ? NAN : 0.0f; + return isUnknown(UCodePointUnknownX) ? NAN : 0.0f; } bool SymbolNode::isReal(Context & context) const { @@ -75,10 +76,10 @@ bool SymbolNode::isReal(Context & context) const { } Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - if (isUnknown(Symbol::SpecialSymbols::UnknownX)) { + if (isUnknown(UCodePointUnknownX)) { return CodePointLayout::Builder('x'); } - if (isUnknown(Symbol::SpecialSymbols::UnknownN)) { + if (isUnknown(UCodePointUnknownN)) { return CodePointLayout::Builder('n'); } // TODO return Parse(m_name).createLayout() ? @@ -147,7 +148,7 @@ Expression Symbol::UntypedBuilder(const char * name, size_t length, Context * co return Expression(); } -bool SymbolNode::isUnknown(char unknownSymbol) const { +bool SymbolNode::isUnknown(CodePoint unknownSymbol) const { bool result = UTF8Helper::CodePointIs(m_name, unknownSymbol); if (result) { assert(m_name[1] == 0); @@ -155,6 +156,14 @@ bool SymbolNode::isUnknown(char unknownSymbol) const { return result; } +Symbol Symbol::Builder(CodePoint name) { + constexpr int bufferSize = 5; + char buffer[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(name, buffer, bufferSize); + assert(codePointSize <= bufferSize); + return Symbol::Builder(buffer, codePointSize); +} + bool Symbol::isSeriesSymbol(const char * c) { // [NV][1-3] if (c[2] == 0 && (c[0] == 'N' || c[0] == 'V') && c[1] >= '1' && c[1] <= '3') { diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 27f53ffce..412ef5d43 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -66,7 +66,7 @@ Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context & conte 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)); + e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknownX), symbol.childAtIndex(0)); } return e; } diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index 5503cbc82..2c7403a5a 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -22,7 +22,11 @@ namespace Poincare { float Trigonometry::characteristicXRange(const Expression & e, Context & context, Preferences::AngleUnit angleUnit) { assert(e.numberOfChildren() == 1); - const char x[] = {Symbol::SpecialSymbols::UnknownX, 0}; + constexpr int size = 5; + char x[size]; + int zeroIndex = UTF8Decoder::CodePointToChars(UCodePointUnknownX, x, size); + assert(zeroIndex <= size - 1); + x[zeroIndex] = 0; int d = e.childAtIndex(0).polynomialDegree(context, x); if (d < 0 || d > 1) { // child(0) is not linear so we cannot easily find an interesting range diff --git a/poincare/test/properties.cpp b/poincare/test/properties.cpp index c122a1020..4f1cea9e4 100644 --- a/poincare/test/properties.cpp +++ b/poincare/test/properties.cpp @@ -76,19 +76,19 @@ void assert_expression_has_characteristic_range(Expression e, float range, Prefe } QUIZ_CASE(poincare_characteristic_range) { - assert_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)), 360.0f); - assert_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX))), 360.0f); - assert_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)), 2.0f*M_PI, Preferences::AngleUnit::Radian); - assert_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX))), 2.0f*M_PI, Preferences::AngleUnit::Radian); - assert_expression_has_characteristic_range(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)),Rational::Builder(10))), 40.0f); - assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX),Rational::Builder(2)))), 720.0f); - assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX),Rational::Builder(2)))), 4.0f*M_PI, Preferences::AngleUnit::Radian); - assert_expression_has_characteristic_range(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX), NAN); + assert_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknownX)), 360.0f); + assert_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknownX))), 360.0f); + assert_expression_has_characteristic_range(Cosine::Builder(Symbol::Builder(UCodePointUnknownX)), 2.0f*M_PI, Preferences::AngleUnit::Radian); + assert_expression_has_characteristic_range(Cosine::Builder(Opposite::Builder(Symbol::Builder(UCodePointUnknownX))), 2.0f*M_PI, Preferences::AngleUnit::Radian); + assert_expression_has_characteristic_range(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))), 40.0f); + assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 720.0f); + assert_expression_has_characteristic_range(Addition::Builder(Sine::Builder(Addition::Builder(Multiplication::Builder(Rational::Builder(9),Symbol::Builder(UCodePointUnknownX)),Rational::Builder(10))),Cosine::Builder(Division::Builder(Symbol::Builder(UCodePointUnknownX),Rational::Builder(2)))), 4.0f*M_PI, Preferences::AngleUnit::Radian); + assert_expression_has_characteristic_range(Symbol::Builder(UCodePointUnknownX), NAN); assert_expression_has_characteristic_range(Addition::Builder(Cosine::Builder(Rational::Builder(3)),Rational::Builder(2)), 0.0f); - assert_expression_has_characteristic_range(CommonLogarithm::Builder(Cosine::Builder(Multiplication::Builder(Rational::Builder(40),Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)))), 9.0f); - assert_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX))), 360.0f); + assert_expression_has_characteristic_range(CommonLogarithm::Builder(Cosine::Builder(Multiplication::Builder(Rational::Builder(40),Symbol::Builder(UCodePointUnknownX)))), 9.0f); + assert_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(UCodePointUnknownX))), 360.0f); assert_simplify("cos(x)→f(x)"); - assert_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(Poincare::Symbol::SpecialSymbols::UnknownX)), 360.0f); + assert_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(UCodePointUnknownX)), 360.0f); } void assert_parsed_expression_has_variables(const char * expression, const char * variables[], int trueNumberOfVariables) { diff --git a/poincare/test/user_variable.cpp b/poincare/test/user_variable.cpp index e946689c0..562aeae43 100644 --- a/poincare/test/user_variable.cpp +++ b/poincare/test/user_variable.cpp @@ -156,10 +156,14 @@ QUIZ_CASE(poincare_user_variable_functions_with_context) { // f : x→ x^2 assert_simplify("x^2→f(x)"); // Approximate f(?-2) with ? = 5 - const char x[] = {Symbol::SpecialSymbols::UnknownX, 0}; - assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(Symbol::SpecialSymbols::UnknownX), Rational::Builder(2))), x, 5.0, 9.0); + constexpr int bufferSize = 5; + char x[bufferSize]; + int codePointSize = UTF8Decoder::CodePointToChars(UCodePointUnknownX, x, bufferSize); + quiz_assert(codePointSize <= bufferSize - 1); + x[codePointSize] = 0; + assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(UCodePointUnknownX), Rational::Builder(2))), x, 5.0, 9.0); // Approximate f(?-1)+f(?+1) with ? = 3 - assert_parsed_expression_approximates_with_value_for_symbol(Addition::Builder(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(Symbol::SpecialSymbols::UnknownX), Rational::Builder(1))), Function::Builder("f", 1, Addition::Builder(Symbol::Builder(Symbol::SpecialSymbols::UnknownX), Rational::Builder(1)))), x, 3.0, 20.0); + assert_parsed_expression_approximates_with_value_for_symbol(Addition::Builder(Function::Builder("f", 1, Subtraction::Builder(Symbol::Builder(UCodePointUnknownX), Rational::Builder(1))), Function::Builder("f", 1, Addition::Builder(Symbol::Builder(UCodePointUnknownX), Rational::Builder(1)))), x, 3.0, 20.0); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -168,9 +172,9 @@ QUIZ_CASE(poincare_user_variable_functions_with_context) { assert_simplify("√(-1)×√(-1)→f(x)"); // Approximate f(?) with ? = 5 // Cartesian - assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(Symbol::SpecialSymbols::UnknownX)), x, 1.0, -1.0); + assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknownX)), x, 1.0, -1.0); // Real - assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(Symbol::SpecialSymbols::UnknownX)), x, 1.0, (double)NAN, Real); + assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknownX)), x, 1.0, (double)NAN, Real); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();