From 756eeeb2d80a815a8f8461c7d07ec079b5a9092e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 16 Jan 2020 11:13:22 +0100 Subject: [PATCH] [poincare/parser] Add context --- .../expressions_list_controller.cpp | 2 +- apps/calculation/app.cpp | 2 +- apps/calculation/calculation.cpp | 6 +- apps/calculation/calculation_store.cpp | 2 +- .../edit_expression_controller.cpp | 5 +- apps/graph/list/type_helper.cpp | 2 +- apps/sequence/list/sequence_toolbox.cpp | 2 +- apps/shared/continuous_function.cpp | 2 +- apps/shared/expression_field_delegate_app.cpp | 2 +- apps/shared/expression_model.cpp | 3 +- apps/shared/function_app.cpp | 2 +- apps/shared/layout_field_delegate.h | 1 + apps/shared/store_controller.cpp | 2 +- apps/shared/text_field_delegate_app.cpp | 6 +- apps/shared/text_field_delegate_app.h | 4 +- .../equation_models_parameter_controller.cpp | 2 +- escher/include/escher/app.h | 2 + escher/include/escher/context_provider.h | 11 ++ escher/include/escher/layout_field.h | 3 +- escher/include/escher/layout_field_delegate.h | 3 +- .../escher/selectable_table_view_delegate.h | 4 +- escher/src/expression_field.cpp | 2 +- escher/src/layout_field.cpp | 12 +- escher/src/selectable_table_view.cpp | 2 +- poincare/include/poincare/expression.h | 2 +- poincare/include/poincare/layout.h | 3 +- poincare/src/expression.cpp | 12 +- poincare/src/layout.cpp | 4 +- poincare/src/parsing/parser.cpp | 118 +++++++++--------- poincare/src/parsing/parser.h | 60 ++++----- poincare/src/trigonometry_cheat_table.cpp | 2 +- poincare/test/approximation.cpp | 4 +- poincare/test/expression_properties.cpp | 24 ++-- poincare/test/expression_to_layout.cpp | 4 +- poincare/test/helper.cpp | 8 +- poincare/test/helper.h | 2 +- poincare/test/layout_to_expression.cpp | 4 +- poincare/test/parsing.cpp | 7 +- 38 files changed, 182 insertions(+), 156 deletions(-) create mode 100644 escher/include/escher/context_provider.h diff --git a/apps/calculation/additional_outputs/expressions_list_controller.cpp b/apps/calculation/additional_outputs/expressions_list_controller.cpp index 680fa75d9..515ec3b4a 100644 --- a/apps/calculation/additional_outputs/expressions_list_controller.cpp +++ b/apps/calculation/additional_outputs/expressions_list_controller.cpp @@ -60,7 +60,7 @@ Poincare::Layout ExpressionsListController::layoutAtIndex(int index) { } int ExpressionsListController::textAtIndex(char * buffer, size_t bufferSize, int index) { - return m_layouts[index].serializeParsedExpression(buffer, bufferSize); + return m_layouts[index].serializeParsedExpression(buffer, bufferSize, App::app()->localContext()); } } diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 26f9ca1c9..a880ec224 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -62,7 +62,7 @@ bool App::layoutFieldDidReceiveEvent(::LayoutField * layoutField, Ion::Events::E bool App::isAcceptableExpression(const Poincare::Expression expression) { { Expression ansExpression = static_cast(snapshot())->calculationStore()->ansExpression(localContext()); - if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, true, ansExpression)) { + if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, true, ansExpression, localContext())) { return false; } } diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index edde1f021..6894b91d1 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -47,7 +47,7 @@ const char * Calculation::approximateOutputText() const { } Expression Calculation::input() { - return Expression::Parse(m_inputText); + return Expression::Parse(m_inputText, nullptr); } Expression Calculation::exactOutput() { @@ -55,7 +55,7 @@ Expression Calculation::exactOutput() { * thereby avoid turning cos(Pi/4) into sqrt(2)/2 and displaying * 'sqrt(2)/2 = 0.999906' (which is totally wrong) instead of * 'cos(pi/4) = 0.999906' (which is true in degree). */ - Expression exactOutput = Expression::Parse(exactOutputText()); + Expression exactOutput = Expression::Parse(exactOutputText(), nullptr); assert(!exactOutput.isUninitialized()); return exactOutput; } @@ -63,7 +63,7 @@ Expression Calculation::exactOutput() { Expression Calculation::approximateOutput(Context * context) { /* To ensure that the expression 'm_output' is a matrix or a complex, we * call 'evaluate'. */ - Expression exp = Expression::Parse(approximateOutputText()); + Expression exp = Expression::Parse(approximateOutputText(), nullptr); assert(!exp.isUninitialized()); return PoincareHelpers::Approximate(exp, context); } diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index e8f224efd..8b91792f3 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -78,7 +78,7 @@ ExpiringPointer CalculationStore::push(const char * text, Context * * want to keep Ans symbol in the calculation store. */ const char * inputSerialization = nextSerializationLocation; { - Expression input = Expression::Parse(text).replaceSymbolWithExpression(Symbol::Ans(), ans); + Expression input = Expression::Parse(text, context).replaceSymbolWithExpression(Symbol::Ans(), ans); if (!serializeExpression(input, nextSerializationLocation, &newCalculationsLocation)) { /* If the input does not fit in the store (event if the current * calculation is the only calculation), just replace the calculation with diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index e9b3b6bfe..22f76615b 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -139,13 +139,14 @@ bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event bool EditExpressionController::inputViewDidFinishEditing(const char * text, Layout layoutR) { + Context * context = textFieldDelegateApp()->localContext(); if (layoutR.isUninitialized()) { assert(text); strlcpy(m_cacheBuffer, text, k_cacheBufferSize); } else { - layoutR.serializeParsedExpression(m_cacheBuffer, k_cacheBufferSize); + layoutR.serializeParsedExpression(m_cacheBuffer, k_cacheBufferSize, context); } - m_calculationStore->push(m_cacheBuffer, textFieldDelegateApp()->localContext()); + m_calculationStore->push(m_cacheBuffer, context); m_historyController->reload(); m_contentView.expressionField()->setEditing(true, true); return true; diff --git a/apps/graph/list/type_helper.cpp b/apps/graph/list/type_helper.cpp index ee1a1d871..130e90160 100644 --- a/apps/graph/list/type_helper.cpp +++ b/apps/graph/list/type_helper.cpp @@ -28,7 +28,7 @@ Poincare::Layout Layout(int index) { if (index < 2) { return Poincare::LayoutHelper::String(text, strlen(text)); } - Poincare::Expression parametric = Poincare::Expression::Parse(text); + Poincare::Expression parametric = Poincare::Expression::Parse(text, nullptr); // No need for context return parametric.createLayout(Poincare::Preferences::PrintFloatMode::Decimal, 1); } diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index d3ad8dc6c..a25ce35cf 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -94,7 +94,7 @@ void SequenceToolbox::buildExtraCellsLayouts(const char * sequenceName, int recu bool SequenceToolbox::selectAddedCell(int selectedRow){ constexpr int bufferSize = 10; char buffer[bufferSize]; - m_addedCellLayout[selectedRow].serializeParsedExpression(buffer, bufferSize); + m_addedCellLayout[selectedRow].serializeParsedExpression(buffer, bufferSize, nullptr); // No need of context here sender()->handleEventWithText(buffer); Container::activeApp()->dismissModalViewController(); return true; diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp index b37499950..273b8af75 100644 --- a/apps/shared/continuous_function.cpp +++ b/apps/shared/continuous_function.cpp @@ -95,7 +95,7 @@ Poincare::Expression ContinuousFunction::expressionReduced(Poincare::Context * c static_cast(result).numberOfRows() != 2 || static_cast(result).numberOfColumns() != 1) ) { - return Poincare::Expression::Parse("[[undef][undef]]"); + return Poincare::Expression::Parse("[[undef][undef]]", nullptr); } return result; } diff --git a/apps/shared/expression_field_delegate_app.cpp b/apps/shared/expression_field_delegate_app.cpp index 2b6c9b95c..25f32a16b 100644 --- a/apps/shared/expression_field_delegate_app.cpp +++ b/apps/shared/expression_field_delegate_app.cpp @@ -39,7 +39,7 @@ bool ExpressionFieldDelegateApp::layoutFieldDidReceiveEvent(LayoutField * layout return true; } // Step 2: Parsing - Poincare::Expression e = Poincare::Expression::Parse(buffer); + Poincare::Expression e = Poincare::Expression::Parse(buffer, layoutField->context()); if (e.isUninitialized()) { // Unparsable expression displayWarning(I18n::Message::SyntaxError); diff --git a/apps/shared/expression_model.cpp b/apps/shared/expression_model.cpp index f893404f8..8153155ea 100644 --- a/apps/shared/expression_model.cpp +++ b/apps/shared/expression_model.cpp @@ -1,6 +1,7 @@ #include "expression_model.h" #include "global_context.h" #include "poincare_helpers.h" +#include #include #include #include @@ -159,7 +160,7 @@ Poincare::Expression ExpressionModel::BuildExpressionFromText(const char * c, Co // if c = "", we want to reinit the Expression if (c && *c != 0) { // Compute the expression to store, without replacing symbols - expressionToStore = Expression::Parse(c); + expressionToStore = Expression::Parse(c, Container::activeApp()->localContext()); if (!expressionToStore.isUninitialized() && symbol != 0) { expressionToStore = expressionToStore.replaceSymbolWithExpression(Symbol::Builder(symbol), Symbol::Builder(UCodePointUnknown)); } diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 2b746e3e2..5a80460b5 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -37,7 +37,7 @@ void FunctionApp::willBecomeInactive() { bool FunctionApp::isAcceptableExpression(const Poincare::Expression expression) { /* We forbid functions whose type is equal because the input "2+f(3)" would be * simplify to an expression with an nested equal node which makes no sense. */ - if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, false, Expression()) || expression.type() == ExpressionNode::Type::Equal) { + if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, false, Expression(), localContext()) || expression.type() == ExpressionNode::Type::Equal) { return false; } return TextFieldDelegateApp::isAcceptableExpression(expression); diff --git a/apps/shared/layout_field_delegate.h b/apps/shared/layout_field_delegate.h index 042d7dfe2..79f25607d 100644 --- a/apps/shared/layout_field_delegate.h +++ b/apps/shared/layout_field_delegate.h @@ -12,6 +12,7 @@ public: bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::Layout layoutR, Ion::Events::Event event) override; bool layoutFieldDidAbortEditing(LayoutField * layoutField) override; void layoutFieldDidChangeSize(LayoutField * layoutField) override; + Poincare::Context * context() const override { return expressionFieldDelegateApp()->localContext(); } protected: ExpressionFieldDelegateApp * expressionFieldDelegateApp() const { return static_cast(Container::activeApp()); diff --git a/apps/shared/store_controller.cpp b/apps/shared/store_controller.cpp index c9fff64e4..a5e08767f 100644 --- a/apps/shared/store_controller.cpp +++ b/apps/shared/store_controller.cpp @@ -82,7 +82,7 @@ bool StoreController::textFieldShouldFinishEditing(TextField * textField, Ion::E bool StoreController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { if (textField == m_contentView.formulaInputView()->textField()) { // Handle formula input - Expression expression = Expression::Parse(textField->text()); + Expression expression = Expression::Parse(textField->text(), storeContext()); if (expression.isUninitialized()) { Container::activeApp()->displayWarning(I18n::Message::SyntaxError); return false; diff --git a/apps/shared/text_field_delegate_app.cpp b/apps/shared/text_field_delegate_app.cpp index 1cd9e3a7a..ece157f9b 100644 --- a/apps/shared/text_field_delegate_app.cpp +++ b/apps/shared/text_field_delegate_app.cpp @@ -32,7 +32,7 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion:: bool TextFieldDelegateApp::isAcceptableText(const char * text) { - Expression exp = Expression::Parse(text); + Expression exp = Expression::Parse(text, localContext()); bool isAcceptable = isAcceptableExpression(exp); if (!isAcceptable) { displayWarning(I18n::Message::SyntaxError); @@ -94,7 +94,7 @@ bool TextFieldDelegateApp::isAcceptableExpression(const Expression exp) { return true; } -bool TextFieldDelegateApp::ExpressionCanBeSerialized(const Expression expression, bool replaceAns, Expression ansExpression) { +bool TextFieldDelegateApp::ExpressionCanBeSerialized(const Expression expression, bool replaceAns, Expression ansExpression, Context * context) { if (expression.isUninitialized()) { return false; } @@ -113,7 +113,7 @@ bool TextFieldDelegateApp::ExpressionCanBeSerialized(const Expression expression return false; } if (replaceAns) { - exp = Expression::Parse(buffer); + exp = Expression::Parse(buffer, context); if (exp.isUninitialized()) { // The ans replacement made the expression unparsable return false; diff --git a/apps/shared/text_field_delegate_app.h b/apps/shared/text_field_delegate_app.h index 09cacc5d4..185646dd6 100644 --- a/apps/shared/text_field_delegate_app.h +++ b/apps/shared/text_field_delegate_app.h @@ -13,7 +13,7 @@ namespace Shared { class TextFieldDelegateApp : public InputEventHandlerDelegateApp, public TextFieldDelegate { public: virtual ~TextFieldDelegateApp() = default; - virtual Poincare::Context * localContext(); + Poincare::Context * localContext() override; virtual bool XNTCanBeOverriden() const { return true; } virtual CodePoint XNT() { return 'x'; } bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; @@ -26,7 +26,7 @@ protected: bool fieldDidReceiveEvent(EditableField * field, Responder * responder, Ion::Events::Event event); bool isFinishingEvent(Ion::Events::Event event); virtual bool isAcceptableExpression(const Poincare::Expression expression); - static bool ExpressionCanBeSerialized(const Poincare::Expression expression, bool replaceAns, Poincare::Expression ansExpression); + static bool ExpressionCanBeSerialized(const Poincare::Expression expression, bool replaceAns, Poincare::Expression ansExpression, Poincare::Context * context); }; } diff --git a/apps/solver/equation_models_parameter_controller.cpp b/apps/solver/equation_models_parameter_controller.cpp index 6b001b578..32aff0988 100644 --- a/apps/solver/equation_models_parameter_controller.cpp +++ b/apps/solver/equation_models_parameter_controller.cpp @@ -22,7 +22,7 @@ EquationModelsParameterController::EquationModelsParameterController(Responder * m_selectableTableView.setMargins(0); m_selectableTableView.setDecoratorType(ScrollView::Decorator::Type::None); for (int i = 0; i < k_numberOfExpressionCells; i++) { - Poincare::Expression e = Expression::Parse(k_models[i+1]); + Poincare::Expression e = Expression::Parse(k_models[i+1], nullptr); // No context needed m_layouts[i] = e.createLayout(Poincare::Preferences::PrintFloatMode::Decimal, Preferences::ShortNumberOfSignificantDigits); m_modelCells[i].setLayout(m_layouts[i]); m_modelCells[i].setParentResponder(&m_selectableTableView); diff --git a/escher/include/escher/app.h b/escher/include/escher/app.h index 6d91b8491..b9bc94400 100644 --- a/escher/include/escher/app.h +++ b/escher/include/escher/app.h @@ -9,6 +9,7 @@ #include #include #include +#include /* An app is fed events and outputs drawing calls. * @@ -63,6 +64,7 @@ public: View * modalView(); virtual int numberOfTimers(); virtual Timer * timerAtIndex(int i); + virtual Poincare::Context * localContext() { return nullptr; } protected: App(Snapshot * snapshot, ViewController * rootViewController, I18n::Message warningMessage = (I18n::Message)0); ModalViewController m_modalViewController; diff --git a/escher/include/escher/context_provider.h b/escher/include/escher/context_provider.h new file mode 100644 index 000000000..3f7458847 --- /dev/null +++ b/escher/include/escher/context_provider.h @@ -0,0 +1,11 @@ +#ifndef ESCHER_CONTEXT_PROVIDER_H +#define ESCHER_CONTEXT_PROVIDER_H + +#include + +class ContextProvider { +public: + virtual Poincare::Context * context() const { return nullptr; } +}; + +#endif diff --git a/escher/include/escher/layout_field.h b/escher/include/escher/layout_field.h index 5dc8021b2..9237f63bc 100644 --- a/escher/include/escher/layout_field.h +++ b/escher/include/escher/layout_field.h @@ -20,6 +20,7 @@ public: m_delegate(delegate) {} void setDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, LayoutFieldDelegate * delegate) { m_inputEventHandlerDelegate = inputEventHandlerDelegate; m_delegate = delegate; } + Poincare::Context * context() const; bool isEditing() const override { return m_contentView.isEditing(); } void setEditing(bool isEditing) override; void clearLayout() { m_contentView.clearLayout(); } @@ -77,7 +78,7 @@ private: Poincare::Layout * selectionEnd() { return &m_selectionEnd; } void addSelection(Poincare::Layout addedLayout); bool resetSelection(); // returns true if the selection was indeed reset - void copySelection(); + void copySelection(Poincare::Context * context); bool selectionIsEmpty() const; void deleteSelection(); diff --git a/escher/include/escher/layout_field_delegate.h b/escher/include/escher/layout_field_delegate.h index 3d81702be..ce9dfaf02 100644 --- a/escher/include/escher/layout_field_delegate.h +++ b/escher/include/escher/layout_field_delegate.h @@ -1,12 +1,13 @@ #ifndef ESCHER_LAYOUT_FIELD_DELEGATE_H #define ESCHER_LAYOUT_FIELD_DELEGATE_H +#include #include #include class LayoutField; -class LayoutFieldDelegate { +class LayoutFieldDelegate : public ContextProvider{ public: virtual bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) = 0; virtual bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) = 0; diff --git a/escher/include/escher/selectable_table_view_delegate.h b/escher/include/escher/selectable_table_view_delegate.h index e8f11864a..f8413478b 100644 --- a/escher/include/escher/selectable_table_view_delegate.h +++ b/escher/include/escher/selectable_table_view_delegate.h @@ -1,9 +1,11 @@ #ifndef ESCHER_SELECTABLE_TABLE_VIEW_DELEGATE_H #define ESCHER_SELECTABLE_TABLE_VIEW_DELEGATE_H +#include + class SelectableTableView; -class SelectableTableViewDelegate { +class SelectableTableViewDelegate : public ContextProvider { public: /* withinTemporarySelection flag indicates when the selection change happens * in a temporary deselection: indeed, when reloading the data of the table, diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index 9c7dbab8a..1a413ae41 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -40,7 +40,7 @@ bool ExpressionField::isEditing() const { const char * ExpressionField::text() { if (!editionIsInTextField()) { - m_layoutField.layout().serializeParsedExpression(m_textField.draftTextBuffer(), k_textFieldBufferSize); + m_layoutField.layout().serializeParsedExpression(m_textField.draftTextBuffer(), k_textFieldBufferSize, m_layoutField.context()); } return m_textField.draftTextBuffer(); } diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 2f809449d..84570e1ad 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -159,7 +159,7 @@ bool LayoutField::ContentView::resetSelection() { return true; } -void LayoutField::ContentView::copySelection() { +void LayoutField::ContentView::copySelection(Context * context) { if (selectionIsEmpty()) { return; } @@ -167,7 +167,7 @@ void LayoutField::ContentView::copySelection() { char buffer[bufferSize]; if (m_selectionStart == m_selectionEnd) { - m_selectionStart.serializeParsedExpression(buffer, bufferSize); + m_selectionStart.serializeParsedExpression(buffer, bufferSize, context); if (buffer[0] == 0) { int offset = 0; if (m_selectionStart.type() == LayoutNode::Type::VerticalOffsetLayout) { @@ -283,6 +283,10 @@ void LayoutField::setEditing(bool isEditing) { } } +Context * LayoutField::context() const { + return (m_delegate != nullptr) ? m_delegate->context() : nullptr; +} + CodePoint LayoutField::XNTCodePoint(CodePoint defaultXNTCodePoint) { CodePoint xnt = m_contentView.cursor()->layout().XNTCodePoint(); if (xnt != UCodePointNull) { @@ -340,7 +344,7 @@ bool LayoutField::handleEventWithText(const char * text, bool indentation, bool } else if ((strcmp(text, "[") == 0) || (strcmp(text, "]") == 0)) { m_contentView.cursor()->addEmptyMatrixLayout(); } else { - Expression resultExpression = Expression::Parse(text); + Expression resultExpression = Expression::Parse(text, nullptr); if (resultExpression.isUninitialized()) { // The text is not parsable (for instance, ",") and is added char by char. KDSize previousLayoutSize = minimalSizeForOptimalDisplay(); @@ -468,7 +472,7 @@ bool LayoutField::privateHandleEvent(Ion::Events::Event event) { return true; } if (event == Ion::Events::Copy && isEditing()) { - m_contentView.copySelection(); + m_contentView.copySelection(context()); return true; } if (event == Ion::Events::Clear && isEditing()) { diff --git a/escher/src/selectable_table_view.cpp b/escher/src/selectable_table_view.cpp index 24169c068..c7922a42c 100644 --- a/escher/src/selectable_table_view.cpp +++ b/escher/src/selectable_table_view.cpp @@ -149,7 +149,7 @@ bool SelectableTableView::handleEvent(Ion::Events::Event event) { if (!l.isUninitialized()) { constexpr int bufferSize = TextField::maxBufferSize(); char buffer[bufferSize]; - l.serializeParsedExpression(buffer, bufferSize); + l.serializeParsedExpression(buffer, bufferSize, m_delegate == nullptr ? nullptr : m_delegate->context()); Clipboard::sharedClipboard()->store(buffer); return true; } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 44c0f7466..15792a564 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -121,7 +121,7 @@ public: /* Constructor & Destructor */ Expression() : TreeHandle() {} Expression clone() const; - static Expression Parse(char const * string, bool addMissingParenthesis = true); + static Expression Parse(char const * string, Context * context, bool addMissingParenthesis = true); static Expression ExpressionFromAddress(const void * address, size_t size); /* Circuit breaker */ diff --git a/poincare/include/poincare/layout.h b/poincare/include/poincare/layout.h index 66e423f7d..d24294289 100644 --- a/poincare/include/poincare/layout.h +++ b/poincare/include/poincare/layout.h @@ -2,6 +2,7 @@ #define POINCARE_LAYOUT_REFERENCE_H #include +#include #include #include #include @@ -44,7 +45,7 @@ public: // Serialization int serializeForParsing(char * buffer, int bufferSize) const { return node()->serialize(buffer, bufferSize); } - int serializeParsedExpression(char * buffer, int bufferSize) const; + int serializeParsedExpression(char * buffer, int bufferSize, Context * context) const; // Layout properties typedef bool (*LayoutTest)(const Layout l); diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index e1c04f0af..f5d61bf67 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -23,12 +23,12 @@ static bool sApproximationEncounteredComplex = false; Expression Expression::clone() const { TreeHandle c = TreeHandle::clone(); return static_cast(c); } -Expression Expression::Parse(char const * string, bool addParentheses) { +Expression Expression::Parse(char const * string, Context * context, bool addParentheses) { if (string[0] == 0) { return Expression(); } Parser p(string); - Expression expression = p.parse(); + Expression expression = p.parse(context); if (p.getStatus() != Parser::Status::Success) { expression = Expression(); } @@ -546,7 +546,7 @@ int Expression::serialize(char * buffer, int bufferSize, Preferences::PrintFloat /* Simplification */ Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicSimplification) { - Expression exp = Parse(text, false); + Expression exp = Parse(text, context, false); if (exp.isUninitialized()) { return Undefined::Builder(); } @@ -554,14 +554,14 @@ Expression Expression::ParseAndSimplify(const char * text, Context * context, Pr /* simplify might have been interrupted, in which case the resulting * expression is uninitialized, so we need to check that. */ if (exp.isUninitialized()) { - return Parse(text); + return Parse(text, context); } return exp; } void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation) { assert(simplifiedExpression); - Expression exp = Parse(text, false); + Expression exp = Parse(text, context, false); if (exp.isUninitialized()) { *simplifiedExpression = Undefined::Builder(); *approximateExpression = Undefined::Builder(); @@ -571,7 +571,7 @@ void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * /* simplify might have been interrupted, in which case the resulting * expression is uninitialized, so we need to check that. */ if (simplifiedExpression->isUninitialized()) { - *simplifiedExpression = Parse(text); + *simplifiedExpression = Parse(text, context); if (approximateExpression) { *approximateExpression = simplifiedExpression->approximate(context, complexFormat, angleUnit); } diff --git a/poincare/src/layout.cpp b/poincare/src/layout.cpp index 8e977fb8c..9a810cd28 100644 --- a/poincare/src/layout.cpp +++ b/poincare/src/layout.cpp @@ -18,7 +18,7 @@ Layout Layout::clone() const { return cast; } -int Layout::serializeParsedExpression(char * buffer, int bufferSize) const { +int Layout::serializeParsedExpression(char * buffer, int bufferSize, Context * context) const { /* This method fixes the following problem: * Some layouts have a special serialization so they can be parsed afterwards, * such has logBase3(2) that serializes as log_{3}(2). When handling the @@ -29,7 +29,7 @@ int Layout::serializeParsedExpression(char * buffer, int bufferSize) const { return 0; } serializeForParsing(buffer, bufferSize); - Poincare::Expression e = Poincare::Expression::Parse(buffer); + Poincare::Expression e = Poincare::Expression::Parse(buffer, context); if (e.isUninitialized()) { buffer[0] = 0; return 0; diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 961f16d5d..e109b9656 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -8,8 +8,8 @@ static inline Token::Type maxToken(Token::Type x, Token::Type y) { return ((int) constexpr const Expression::FunctionHelper * Parser::s_reservedFunctions[]; -Expression Parser::parse() { - Expression result = parseUntil(Token::EndOfStream); +Expression Parser::parse(Context * context) { + Expression result = parseUntil(context, Token::EndOfStream); if (m_status == Status::Progress) { m_status = Status::Success; return result; @@ -56,8 +56,8 @@ bool Parser::IsSpecialIdentifierName(const char * name, size_t nameLength) { ); } -Expression Parser::parseUntil(Token::Type stoppingType) { - typedef void (Parser::*TokenParser)(Expression & leftHandSide, Token::Type stoppingType); +Expression Parser::parseUntil(Context * context, Token::Type stoppingType) { + typedef void (Parser::*TokenParser)(Context * context, Expression & leftHandSide, Token::Type stoppingType); static constexpr TokenParser tokenParsers[] = { &Parser::parseUnexpected, // Token::EndOfStream &Parser::parseStore, // Token::Store @@ -90,7 +90,7 @@ Expression Parser::parseUntil(Token::Type stoppingType) { Expression leftHandSide; do { popToken(); - (this->*(tokenParsers[m_currentToken.type()]))(leftHandSide, stoppingType); + (this->*(tokenParsers[m_currentToken.type()]))(context, leftHandSide, stoppingType); } while (m_status == Status::Progress && nextTokenHasPrecedenceOver(stoppingType)); return leftHandSide; } @@ -144,11 +144,11 @@ void Parser::isThereImplicitMultiplication() { ); } -void Parser::parseUnexpected(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseUnexpected(Context * context, Expression & leftHandSide, Token::Type stoppingType) { m_status = Status::Error; // Unexpected Token } -void Parser::parseNumber(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseNumber(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (!leftHandSide.isUninitialized()) { m_status = Status::Error; //FIXME return; @@ -164,9 +164,9 @@ void Parser::parseNumber(Expression & leftHandSide, Token::Type stoppingType) { isThereImplicitMultiplication(); } -void Parser::parsePlus(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parsePlus(Context * context, Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; - if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Plus)) { + if (parseBinaryOperator(context, leftHandSide, rightHandSide, Token::Plus)) { if (leftHandSide.type() == ExpressionNode::Type::Addition) { int childrenCount = leftHandSide.numberOfChildren(); static_cast(leftHandSide).addChildAtIndexInPlace(rightHandSide, childrenCount, childrenCount); @@ -176,7 +176,7 @@ void Parser::parsePlus(Expression & leftHandSide, Token::Type stoppingType) { } } -void Parser::parseEmpty(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseEmpty(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (!leftHandSide.isUninitialized()) { m_status = Status::Error; //FIXME return; @@ -184,15 +184,15 @@ void Parser::parseEmpty(Expression & leftHandSide, Token::Type stoppingType) { leftHandSide = EmptyExpression::Builder(); } -void Parser::parseMinus(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseMinus(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (leftHandSide.isUninitialized()) { - Expression rightHandSide = parseUntil(maxToken(stoppingType, Token::Minus)); + Expression rightHandSide = parseUntil(context, maxToken(stoppingType, Token::Minus)); if (m_status != Status::Progress) { return; } leftHandSide = Opposite::Builder(rightHandSide); } else { - Expression rightHandSide = parseUntil(Token::Minus); // Subtraction is left-associative + Expression rightHandSide = parseUntil(context, Token::Minus); // Subtraction is left-associative if (m_status != Status::Progress) { return; } @@ -200,9 +200,9 @@ void Parser::parseMinus(Expression & leftHandSide, Token::Type stoppingType) { } } -void Parser::parseTimes(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseTimes(Context * context, Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; - if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Times)) { + if (parseBinaryOperator(context, leftHandSide, rightHandSide, Token::Times)) { if (leftHandSide.type() == ExpressionNode::Type::Multiplication) { int childrenCount = leftHandSide.numberOfChildren(); static_cast(leftHandSide).addChildAtIndexInPlace(rightHandSide, childrenCount, childrenCount); @@ -212,28 +212,28 @@ void Parser::parseTimes(Expression & leftHandSide, Token::Type stoppingType) { } } -void Parser::parseSlash(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseSlash(Context * context, Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; - if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Slash)) { + if (parseBinaryOperator(context, leftHandSide, rightHandSide, Token::Slash)) { leftHandSide = Division::Builder(leftHandSide, rightHandSide); } } -void Parser::parseImplicitTimes(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseImplicitTimes(Context * context, Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; - if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Slash)) { + if (parseBinaryOperator(context, leftHandSide, rightHandSide, Token::Slash)) { leftHandSide = Multiplication::Builder(leftHandSide, rightHandSide); } } -void Parser::parseCaret(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseCaret(Context * context, Expression & leftHandSide, Token::Type stoppingType) { Expression rightHandSide; - if (parseBinaryOperator(leftHandSide, rightHandSide, Token::ImplicitTimes)) { + if (parseBinaryOperator(context, leftHandSide, rightHandSide, Token::ImplicitTimes)) { leftHandSide = Power::Builder(leftHandSide, rightHandSide); } } -void Parser::parseCaretWithParenthesis(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseCaretWithParenthesis(Context * context, Expression & leftHandSide, Token::Type stoppingType) { /* When parsing 2^(4) ! (with system parentheses), the factorial should stay * out of the power. To do this, we tokenized ^( as one token that should be * matched by a closing parenthesis. Otherwise, the ! would take precendence @@ -243,7 +243,7 @@ void Parser::parseCaretWithParenthesis(Expression & leftHandSide, Token::Type st return; } Token::Type endToken = Token::Type::RightSystemParenthesis; - Expression rightHandSide = parseUntil(endToken); + Expression rightHandSide = parseUntil(context, endToken); if (m_status != Status::Progress) { return; } @@ -255,13 +255,13 @@ void Parser::parseCaretWithParenthesis(Expression & leftHandSide, Token::Type st isThereImplicitMultiplication(); } -void Parser::parseEqual(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseEqual(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (leftHandSide.isUninitialized()) { m_status = Status::Error; // Equal must have a left operand return; } Expression rightHandSide; - if (parseBinaryOperator(leftHandSide, rightHandSide, Token::Equal)) { + if (parseBinaryOperator(context, leftHandSide, rightHandSide, Token::Equal)) { /* We parse until finding a token of lesser precedence than Equal. The next * token is thus either EndOfStream or Store. */ leftHandSide = Equal::Builder(leftHandSide, rightHandSide); @@ -272,7 +272,7 @@ void Parser::parseEqual(Expression & leftHandSide, Token::Type stoppingType) { } } -void Parser::parseStore(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseStore(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (leftHandSide.isUninitialized()) { m_status = Status::Error; // Left-hand side missing. return; @@ -284,7 +284,7 @@ void Parser::parseStore(Expression & leftHandSide, Token::Type stoppingType) { return; } Expression rightHandSide; - parseCustomIdentifier(rightHandSide, m_currentToken.text(), m_currentToken.length()); + parseCustomIdentifier(context, rightHandSide, m_currentToken.text(), m_currentToken.length()); if (m_status != Status::Progress) { return; } @@ -298,12 +298,12 @@ void Parser::parseStore(Expression & leftHandSide, Token::Type stoppingType) { leftHandSide = Store::Builder(leftHandSide, static_cast(rightHandSide)); } -bool Parser::parseBinaryOperator(const Expression & leftHandSide, Expression & rightHandSide, Token::Type stoppingType) { +bool Parser::parseBinaryOperator(Context * context, const Expression & leftHandSide, Expression & rightHandSide, Token::Type stoppingType) { if (leftHandSide.isUninitialized()) { m_status = Status::Error; // Left-hand side missing. return false; } - rightHandSide = parseUntil(stoppingType); + rightHandSide = parseUntil(context, stoppingType); if (m_status != Status::Progress) { return false; } @@ -314,15 +314,15 @@ bool Parser::parseBinaryOperator(const Expression & leftHandSide, Expression & r return true; } -void Parser::parseLeftParenthesis(Expression & leftHandSide, Token::Type stoppingType) { - defaultParseLeftParenthesis(false, leftHandSide, stoppingType); +void Parser::parseLeftParenthesis(Context * context, Expression & leftHandSide, Token::Type stoppingType) { + defaultParseLeftParenthesis(context, false, leftHandSide, stoppingType); } -void Parser::parseLeftSystemParenthesis(Expression & leftHandSide, Token::Type stoppingType) { - defaultParseLeftParenthesis(true, leftHandSide, stoppingType); +void Parser::parseLeftSystemParenthesis(Context * context, Expression & leftHandSide, Token::Type stoppingType) { + defaultParseLeftParenthesis(context, true, leftHandSide, stoppingType); } -void Parser::parseBang(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseBang(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (leftHandSide.isUninitialized()) { m_status = Status::Error; // Left-hand side missing } else { @@ -331,14 +331,14 @@ void Parser::parseBang(Expression & leftHandSide, Token::Type stoppingType) { isThereImplicitMultiplication(); } -void Parser::parseConstant(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseConstant(Context * context, Expression & leftHandSide, Token::Type stoppingType) { leftHandSide = Constant::Builder(m_currentToken.codePoint()); isThereImplicitMultiplication(); } -void Parser::parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper) { +void Parser::parseReservedFunction(Context * context, Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper) { const char * name = (**functionHelper).name(); - Expression parameters = parseFunctionParameters(); + Expression parameters = parseFunctionParameters(context); if (m_status != Status::Progress) { return; } @@ -361,11 +361,11 @@ void Parser::parseReservedFunction(Expression & leftHandSide, const Expression:: } } -void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter) { +void Parser::parseSequence(Context * context, Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter) { if (!popTokenIfType(leftDelimiter)) { m_status = Status::Error; // Left delimiter missing. } else { - Expression rank = parseUntil(rightDelimiter); + Expression rank = parseUntil(context, rightDelimiter); if (m_status != Status::Progress) { } else if (!popTokenIfType(rightDelimiter)) { m_status = Status::Error; // Right delimiter missing. @@ -383,7 +383,7 @@ void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Ty } } -void Parser::parseSpecialIdentifier(Expression & leftHandSide) { +void Parser::parseSpecialIdentifier(Context * context, Expression & leftHandSide) { if (m_currentToken.compareTo(Symbol::k_ans) == 0) { leftHandSide = Symbol::Ans(); } else if (m_currentToken.compareTo(Infinity::Name()) == 0) { @@ -395,21 +395,21 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) { } else if (m_currentToken.compareTo("u_") == 0 || m_currentToken.compareTo("v_") == 0 || m_currentToken.compareTo("w_") == 0) { // Special case for sequences (e.g. "u_{n}") /* We now that m_currentToken.text()[0] is either 'u' or 'v', so we do not * need to pass a code point to parseSequence. */ - parseSequence(leftHandSide, m_currentToken.text()[0], Token::LeftBrace, Token::RightBrace); + parseSequence(context, leftHandSide, m_currentToken.text()[0], Token::LeftBrace, Token::RightBrace); } else if (m_currentToken.compareTo("u") == 0 || m_currentToken.compareTo("v") == 0|| m_currentToken.compareTo("w") == 0) { // Special case for sequences (e.g. "u(n)") /* We now that m_currentToken.text()[0] is either 'u' or 'v', so we do not * need to pass a code point to parseSequence. */ - parseSequence(leftHandSide, m_currentToken.text()[0], Token::LeftParenthesis, Token::RightParenthesis); + parseSequence(context, leftHandSide, m_currentToken.text()[0], Token::LeftParenthesis, Token::RightParenthesis); } else if (m_currentToken.compareTo("log_") == 0) { // Special case for the log function (e.g. "log_{2}(8)") if (!popTokenIfType(Token::LeftBrace)) { m_status = Status::Error; // Left brace missing. } else { - Expression base = parseUntil(Token::RightBrace); + Expression base = parseUntil(context, Token::RightBrace); if (m_status != Status::Progress) { } else if (!popTokenIfType(Token::RightBrace)) { m_status = Status::Error; // Right brace missing. } else { - Expression parameter = parseFunctionParameters(); + Expression parameter = parseFunctionParameters(context); if (m_status != Status::Progress) { } else if (parameter.numberOfChildren() != 1) { m_status = Status::Error; // Unexpected number of many parameters. @@ -437,7 +437,7 @@ void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, } poppedParenthesisIsSystem = true; } - Expression parameter = parseCommaSeparatedList(); + Expression parameter = parseCommaSeparatedList(context); if (m_status != Status::Progress) { return; } @@ -459,23 +459,23 @@ void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, } } -void Parser::parseIdentifier(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseIdentifier(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (!leftHandSide.isUninitialized()) { m_status = Status::Error; //FIXME return; } const Expression::FunctionHelper * const * functionHelper = GetReservedFunction(m_currentToken.text(), m_currentToken.length()); if (functionHelper != nullptr) { - parseReservedFunction(leftHandSide, functionHelper); + parseReservedFunction(context, leftHandSide, functionHelper); } else if (IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length())) { - parseSpecialIdentifier(leftHandSide); + parseSpecialIdentifier(context, leftHandSide); } else { - parseCustomIdentifier(leftHandSide, m_currentToken.text(), m_currentToken.length()); + parseCustomIdentifier(context, leftHandSide, m_currentToken.text(), m_currentToken.length()); } isThereImplicitMultiplication(); } -Expression Parser::parseFunctionParameters() { +Expression Parser::parseFunctionParameters(Context * context) { bool poppedParenthesisIsSystem = false; /* The function parentheses can be system parentheses, if serialized using * SerializationHelper::Prefix.*/ @@ -490,7 +490,7 @@ Expression Parser::parseFunctionParameters() { if (popTokenIfType(correspondingRightParenthesis)) { return Matrix::Builder(); // The function has no parameter. } - Expression commaSeparatedList = parseCommaSeparatedList(); + Expression commaSeparatedList = parseCommaSeparatedList(context); if (m_status != Status::Progress) { return Expression(); } @@ -501,7 +501,7 @@ Expression Parser::parseFunctionParameters() { return commaSeparatedList; } -void Parser::parseMatrix(Expression & leftHandSide, Token::Type stoppingType) { +void Parser::parseMatrix(Context * context, Expression & leftHandSide, Token::Type stoppingType) { if (!leftHandSide.isUninitialized()) { m_status = Status::Error; //FIXME return; @@ -510,7 +510,7 @@ void Parser::parseMatrix(Expression & leftHandSide, Token::Type stoppingType) { int numberOfRows = 0; int numberOfColumns = 0; while (!popTokenIfType(Token::RightBracket)) { - Expression row = parseVector(); + Expression row = parseVector(context); if (m_status != Status::Progress) { return; } @@ -530,12 +530,12 @@ void Parser::parseMatrix(Expression & leftHandSide, Token::Type stoppingType) { isThereImplicitMultiplication(); } -Expression Parser::parseVector() { +Expression Parser::parseVector(Context * context) { if (!popTokenIfType(Token::LeftBracket)) { m_status = Status::Error; // Left bracket missing. return Expression(); } - Expression commaSeparatedList = parseCommaSeparatedList(); + Expression commaSeparatedList = parseCommaSeparatedList(context); if (m_status != Status::Progress) { // There has been an error during the parsing of the comma separated list return Expression(); @@ -547,11 +547,11 @@ Expression Parser::parseVector() { return commaSeparatedList; } -Expression Parser::parseCommaSeparatedList() { +Expression Parser::parseCommaSeparatedList(Context * context) { Matrix commaSeparatedList = Matrix::Builder(); int length = 0; do { - Expression item = parseUntil(Token::Comma); + Expression item = parseUntil(context, Token::Comma); if (m_status != Status::Progress) { return Expression(); } @@ -561,13 +561,13 @@ Expression Parser::parseCommaSeparatedList() { return std::move(commaSeparatedList); } -void Parser::defaultParseLeftParenthesis(bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType) { +void Parser::defaultParseLeftParenthesis(Context * context, bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType) { if (!leftHandSide.isUninitialized()) { m_status = Status::Error; //FIXME return; } Token::Type endToken = isSystemParenthesis ? Token::Type::RightSystemParenthesis : Token::Type::RightParenthesis; - leftHandSide = parseUntil(endToken); + leftHandSide = parseUntil(context, endToken); if (m_status != Status::Progress) { return; } diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index 93d3c11c5..b286a150e 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -27,7 +27,7 @@ public: m_nextToken(m_tokenizer.popToken()), m_pendingImplicitMultiplication(false) {} - Expression parse(); + Expression parse(Context * context); Status getStatus() const { return m_status; } static bool IsReservedName(const char * name, size_t nameLength); @@ -36,7 +36,7 @@ private: static const Expression::FunctionHelper * const * GetReservedFunction(const char * name, size_t nameLength); static bool IsSpecialIdentifierName(const char * name, size_t nameLength); - Expression parseUntil(Token::Type stoppingType); + Expression parseUntil(Context * context, Token::Type stoppingType); // Methods on Tokens void popToken(); @@ -45,36 +45,36 @@ private: void isThereImplicitMultiplication(); // Specific Token parsers - void parseUnexpected(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseNumber(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseConstant(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseIdentifier(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseEmpty(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseMatrix(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseLeftParenthesis(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseLeftSystemParenthesis(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseBang(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parsePlus(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseMinus(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseTimes(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseSlash(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseImplicitTimes(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseCaret(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseCaretWithParenthesis(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseEqual(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseStore(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); - void parseLeftSuperscript(Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseUnexpected(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseNumber(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseConstant(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseIdentifier(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseEmpty(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseMatrix(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseLeftParenthesis(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseLeftSystemParenthesis(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseBang(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parsePlus(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseMinus(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseTimes(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseSlash(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseImplicitTimes(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseCaret(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseCaretWithParenthesis(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseEqual(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseStore(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); + void parseLeftSuperscript(Context * context, Expression & leftHandSide, Token::Type stoppingType = (Token::Type)0); // Parsing helpers - bool parseBinaryOperator(const Expression & leftHandSide, Expression & rightHandSide, Token::Type stoppingType); - Expression parseVector(); - Expression parseFunctionParameters(); - Expression parseCommaSeparatedList(); - void parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper); - void parseSpecialIdentifier(Expression & leftHandSide); - void parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter); - void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length); - void defaultParseLeftParenthesis(bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType); + bool parseBinaryOperator(Context * context, const Expression & leftHandSide, Expression & rightHandSide, Token::Type stoppingType); + Expression parseVector(Context * context); + Expression parseFunctionParameters(Context * context); + Expression parseCommaSeparatedList(Context * context); + void parseReservedFunction(Context * context, Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper); + void parseSpecialIdentifier(Context * context, Expression & leftHandSide); + void parseSequence(Context * context, Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter); + void parseCustomIdentifier(Context * context, Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions); + void defaultParseLeftParenthesis(Context * context, bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType); // Data members Status m_status; diff --git a/poincare/src/trigonometry_cheat_table.cpp b/poincare/src/trigonometry_cheat_table.cpp index eac4f3a4b..9cd3f9ef0 100644 --- a/poincare/src/trigonometry_cheat_table.cpp +++ b/poincare/src/trigonometry_cheat_table.cpp @@ -9,7 +9,7 @@ static constexpr TrigonometryCheatTable::Type s_targetType[] = { }; Expression TrigonometryCheatTable::Row::Pair::reducedExpression(bool assertNotUninitialized, ExpressionNode::ReductionContext reductionContext) const { - Expression e = Expression::Parse(m_expression); + Expression e = Expression::Parse(m_expression, nullptr); // No context needed if (assertNotUninitialized) { assert(!e.isUninitialized()); } else { diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 7d03c09d9..46629f390 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -6,7 +6,7 @@ using namespace Poincare; template void assert_expression_approximates_to_scalar(const char * expression, T approximation, Preferences::AngleUnit angleUnit = Degree, Preferences::ComplexFormat complexFormat = Cartesian) { Shared::GlobalContext globalContext; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &globalContext, false); T result = e.approximateToScalar(&globalContext, complexFormat, angleUnit); quiz_assert_print_if_failure((std::isnan(result) && std::isnan(approximation)) || (std::isinf(result) && std::isinf(approximation) && result*approximation >= 0) || (std::fabs(result - approximation) <= Poincare::Expression::Epsilon()), expression); } @@ -212,8 +212,8 @@ QUIZ_CASE(poincare_approximation_logarithm) { template void assert_expression_approximation_is_bounded(const char * expression, T lowBound, T upBound, bool upBoundIncluded = false) { - Expression e = parse_expression(expression, true); Shared::GlobalContext globalContext; + Expression e = parse_expression(expression, &globalContext, true); T result = e.approximateToScalar(&globalContext, Cartesian, Radian); quiz_assert_print_if_failure(result >= lowBound, expression); quiz_assert_print_if_failure(result < upBound || (result == upBound && upBoundIncluded), expression); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index f93205732..af4a873f3 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -34,12 +34,12 @@ QUIZ_CASE(poincare_properties_is_parametered_expression) { } void assert_expression_has_property(const char * expression, Context * context, Expression::ExpressionTest test) { - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, context, false); quiz_assert_print_if_failure(e.recursivelyMatches(test, context, true), expression); } void assert_expression_has_not_property(const char * expression, Context * context, Expression::ExpressionTest test) { - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, context, false); quiz_assert_print_if_failure(!e.recursivelyMatches(test, context, true), expression); } @@ -68,13 +68,13 @@ QUIZ_CASE(poincare_properties_is_matrix) { void assert_expression_is_deep_matrix(const char * expression) { Shared::GlobalContext context; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &context, false); quiz_assert_print_if_failure(e.deepIsMatrix(&context), expression); } void assert_expression_is_not_deep_matrix(const char * expression) { Shared::GlobalContext context; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &context, false); quiz_assert_print_if_failure(!e.deepIsMatrix(&context), expression); } @@ -104,7 +104,7 @@ constexpr Poincare::ExpressionNode::Sign Unknown = Poincare::ExpressionNode::Sig void assert_reduced_expression_sign(const char * expression, Poincare::ExpressionNode::Sign sign, Preferences::ComplexFormat complexFormat = Cartesian, Preferences::AngleUnit angleUnit = Radian) { Shared::GlobalContext globalContext; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &globalContext, false); e = e.reduce(&globalContext, complexFormat, angleUnit); quiz_assert_print_if_failure(e.sign(&globalContext) == sign, expression); } @@ -163,14 +163,14 @@ QUIZ_CASE(poincare_properties_sign) { void assert_expression_is_real(const char * expression) { Shared::GlobalContext context; // isReal can be call only on reduced expressions - Expression e = parse_expression(expression, false).reduce(&context, Cartesian, Radian); + Expression e = parse_expression(expression, &context, false).reduce(&context, Cartesian, Radian); quiz_assert_print_if_failure(e.isReal(&context), expression); } void assert_expression_is_not_real(const char * expression) { Shared::GlobalContext context; // isReal can be call only on reduced expressions - Expression e = parse_expression(expression, false).reduce(&context, Cartesian, Radian); + Expression e = parse_expression(expression, &context, false).reduce(&context, Cartesian, Radian); quiz_assert_print_if_failure(!e.isReal(&context), expression); } @@ -206,7 +206,7 @@ QUIZ_CASE(poincare_properties_is_real) { void assert_reduced_expression_polynomial_degree(const char * expression, int degree, const char * symbolName = "x", Preferences::ComplexFormat complexFormat = Cartesian, Preferences::AngleUnit angleUnit = Radian) { Shared::GlobalContext globalContext; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &globalContext, false); Expression result = e.reduce(&globalContext, complexFormat, angleUnit); quiz_assert_print_if_failure(result.polynomialDegree(&globalContext, symbolName) == degree, expression); } @@ -276,10 +276,10 @@ QUIZ_CASE(poincare_properties_characteristic_range) { } void assert_expression_has_variables(const char * expression, const char * variables[], int trueNumberOfVariables) { - Expression e = parse_expression(expression, false); + Shared::GlobalContext globalContext; + Expression e = parse_expression(expression, &globalContext, false); constexpr static int k_maxVariableSize = Poincare::SymbolAbstract::k_maxNameSize; char variableBuffer[Expression::k_maxNumberOfVariables+1][k_maxVariableSize] = {{0}}; - Shared::GlobalContext globalContext; int numberOfVariables = e.getVariables(&globalContext, [](const char * symbol) { return true; }, (char *)variableBuffer, k_maxVariableSize); quiz_assert_print_if_failure(trueNumberOfVariables == numberOfVariables, expression); if (numberOfVariables < 0) { @@ -315,12 +315,12 @@ QUIZ_CASE(poincare_preperties_get_variables) { void assert_reduced_expression_has_polynomial_coefficient(const char * expression, const char * symbolName, const char ** coefficients, Preferences::ComplexFormat complexFormat = Cartesian, Preferences::AngleUnit angleUnit = Radian) { Shared::GlobalContext globalContext; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &globalContext, false); e = e.reduce(&globalContext, complexFormat, angleUnit, SystemForAnalysis); Expression coefficientBuffer[Poincare::Expression::k_maxNumberOfPolynomialCoefficients]; int d = e.getPolynomialReducedCoefficients(symbolName, coefficientBuffer, &globalContext, complexFormat, Radian); for (int i = 0; i <= d; i++) { - Expression f = parse_expression(coefficients[i], false); + Expression f = parse_expression(coefficients[i], &globalContext, false); quiz_assert(!f.isUninitialized()); coefficientBuffer[i] = coefficientBuffer[i].reduce(&globalContext, complexFormat, angleUnit); f = f.reduce(&globalContext, complexFormat, angleUnit); diff --git a/poincare/test/expression_to_layout.cpp b/poincare/test/expression_to_layout.cpp index 5b7bd4e98..7290b9e89 100644 --- a/poincare/test/expression_to_layout.cpp +++ b/poincare/test/expression_to_layout.cpp @@ -4,7 +4,7 @@ using namespace Poincare; void assert_parsed_expression_layouts_to(const char * expression, Layout l) { - Expression e = parse_expression(expression, true); + Expression e = parse_expression(expression, nullptr, true); Layout el = e.createLayout(DecimalMode, PrintFloat::k_numberOfStoredSignificantDigits); quiz_assert_print_if_failure(el.isIdenticalTo(l), expression); } @@ -115,7 +115,7 @@ QUIZ_CASE(poincare_expression_to_layout_multiplication_operator) { } void assert_parsed_expression_layout_serialize_to_self(const char * expressionLayout) { - Expression e = parse_expression(expressionLayout, true); + Expression e = parse_expression(expressionLayout, nullptr, true); Layout el = e.createLayout(DecimalMode, PrintFloat::k_numberOfStoredSignificantDigits); constexpr int bufferSize = 255; char buffer[bufferSize]; diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 4f62cac12..a2df1adb6 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -39,7 +39,7 @@ void quiz_assert_log_if_failure(bool test, TreeHandle tree) { void assert_parsed_expression_process_to(const char * expression, const char * result, ExpressionNode::ReductionTarget target, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation, ProcessExpression process, int numberOfSignifiantDigits) { Shared::GlobalContext globalContext; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &globalContext, false); Expression m = process(e, &globalContext, target, complexFormat, angleUnit, symbolicComputation); constexpr int bufferSize = 500; char buffer[bufferSize]; @@ -70,15 +70,15 @@ void assert_parsed_expression_process_to(const char * expression, const char * r quiz_assert_print_if_failure(test, information); } -Poincare::Expression parse_expression(const char * expression, bool addParentheses) { - Expression result = Expression::Parse(expression, addParentheses); +Poincare::Expression parse_expression(const char * expression, Context * context, bool addParentheses) { + Expression result = Expression::Parse(expression, context, addParentheses); quiz_assert(!result.isUninitialized()); return result; } void assert_simplify(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) { Shared::GlobalContext globalContext; - Expression e = parse_expression(expression, false); + Expression e = parse_expression(expression, &globalContext, false); quiz_assert_print_if_failure(!e.isUninitialized(), expression); e = e.simplify(&globalContext, complexFormat, angleUnit, target); quiz_assert_print_if_failure(!(e.isUninitialized()), expression); diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 7a110e016..905c9253a 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -27,7 +27,7 @@ void assert_parsed_expression_process_to(const char * expression, const char * r // Parsing -Poincare::Expression parse_expression(const char * expression, bool addParentheses); +Poincare::Expression parse_expression(const char * expression, Poincare::Context * context, bool addParentheses); // Simplification diff --git a/poincare/test/layout_to_expression.cpp b/poincare/test/layout_to_expression.cpp index 327f65619..fc6a819cc 100644 --- a/poincare/test/layout_to_expression.cpp +++ b/poincare/test/layout_to_expression.cpp @@ -7,7 +7,7 @@ void assert_layout_is_not_parsed(Layout l) { constexpr int bufferSize = 500; char buffer[bufferSize]; l.serializeForParsing(buffer, bufferSize); - Expression e = Expression::Parse(buffer, false); + Expression e = Expression::Parse(buffer, nullptr, false); quiz_assert_print_if_failure(e.isUninitialized(), buffer); } @@ -262,7 +262,7 @@ void assert_parsed_layout_is(Layout l, Poincare::Expression r) { constexpr int bufferSize = 500; char buffer[bufferSize]; l.serializeForParsing(buffer, bufferSize); - Expression e = parse_expression(buffer, true); + Expression e = parse_expression(buffer, nullptr, true); quiz_assert_print_if_failure(e.isIdenticalTo(r), buffer); } diff --git a/poincare/test/parsing.cpp b/poincare/test/parsing.cpp index e7c9c02ec..596df2b73 100644 --- a/poincare/test/parsing.cpp +++ b/poincare/test/parsing.cpp @@ -41,7 +41,8 @@ void assert_text_not_parsable(const char * text) { } void assert_parsed_expression_is(const char * expression, Poincare::Expression r, bool addParentheses = false) { - Expression e = parse_expression(expression, addParentheses); + Shared::GlobalContext context; + Expression e = parse_expression(expression, &context, addParentheses); quiz_assert_print_if_failure(e.isIdenticalTo(r), expression); } @@ -90,7 +91,7 @@ QUIZ_CASE(poincare_parsing_memory_exhaustion) { if (ExceptionRun(ecp)) { Addition a = Addition::Builder(); while (true) { - Expression e = Expression::Parse("1+2+3+4+5+6+7+8+9+10"); + Expression e = Expression::Parse("1+2+3+4+5+6+7+8+9+10", nullptr); a.addChildAtIndexInPlace(e, 0, a.numberOfChildren()); } } else { @@ -101,7 +102,7 @@ QUIZ_CASE(poincare_parsing_memory_exhaustion) { quiz_assert(memoryFailureHasBeenHandled); assert_pool_size(initialPoolSize); - Expression e = Expression::Parse("1+1"); + Expression e = Expression::Parse("1+1", nullptr); /* Stupid check to make sure the global variable generated by Bison is not * ruining everything */ }