[poincare/parser] Add context

This commit is contained in:
Léa Saviot
2020-01-16 11:13:22 +01:00
parent 158a45e94d
commit 756eeeb2d8
38 changed files with 182 additions and 156 deletions

View File

@@ -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());
}
}

View File

@@ -62,7 +62,7 @@ bool App::layoutFieldDidReceiveEvent(::LayoutField * layoutField, Ion::Events::E
bool App::isAcceptableExpression(const Poincare::Expression expression) {
{
Expression ansExpression = static_cast<Snapshot *>(snapshot())->calculationStore()->ansExpression(localContext());
if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, true, ansExpression)) {
if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, true, ansExpression, localContext())) {
return false;
}
}

View File

@@ -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<double>(exp, context);
}

View File

@@ -78,7 +78,7 @@ ExpiringPointer<Calculation> 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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -95,7 +95,7 @@ Poincare::Expression ContinuousFunction::expressionReduced(Poincare::Context * c
static_cast<Poincare::Matrix&>(result).numberOfRows() != 2 ||
static_cast<Poincare::Matrix&>(result).numberOfColumns() != 1)
) {
return Poincare::Expression::Parse("[[undef][undef]]");
return Poincare::Expression::Parse("[[undef][undef]]", nullptr);
}
return result;
}

View File

@@ -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);

View File

@@ -1,6 +1,7 @@
#include "expression_model.h"
#include "global_context.h"
#include "poincare_helpers.h"
#include <apps/apps_container.h>
#include <poincare/horizontal_layout.h>
#include <poincare/undefined.h>
#include <string.h>
@@ -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));
}

View File

@@ -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);

View File

@@ -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<ExpressionFieldDelegateApp *>(Container::activeApp());

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
};
}

View File

@@ -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);

View File

@@ -9,6 +9,7 @@
#include <escher/view_controller.h>
#include <escher/warning_controller.h>
#include <ion/storage.h>
#include <poincare/context.h>
/* 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;

View File

@@ -0,0 +1,11 @@
#ifndef ESCHER_CONTEXT_PROVIDER_H
#define ESCHER_CONTEXT_PROVIDER_H
#include <poincare/context.h>
class ContextProvider {
public:
virtual Poincare::Context * context() const { return nullptr; }
};
#endif

View File

@@ -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();

View File

@@ -1,12 +1,13 @@
#ifndef ESCHER_LAYOUT_FIELD_DELEGATE_H
#define ESCHER_LAYOUT_FIELD_DELEGATE_H
#include <escher/context_provider.h>
#include <ion/events.h>
#include <poincare/layout.h>
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;

View File

@@ -1,9 +1,11 @@
#ifndef ESCHER_SELECTABLE_TABLE_VIEW_DELEGATE_H
#define ESCHER_SELECTABLE_TABLE_VIEW_DELEGATE_H
#include <escher/context_provider.h>
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,

View File

@@ -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();
}

View File

@@ -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()) {

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -2,6 +2,7 @@
#define POINCARE_LAYOUT_REFERENCE_H
#include <poincare/array_builder.h>
#include <poincare/context.h>
#include <poincare/layout_node.h>
#include <poincare/tree_handle.h>
#include <escher/palette.h>
@@ -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);

View File

@@ -23,12 +23,12 @@ static bool sApproximationEncounteredComplex = false;
Expression Expression::clone() const { TreeHandle c = TreeHandle::clone(); return static_cast<Expression&>(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<double>(context, complexFormat, angleUnit);
}

View File

@@ -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;

View File

@@ -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<Addition &>(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<Multiplication &>(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<SymbolAbstract&>(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;
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -6,7 +6,7 @@ using namespace Poincare;
template<typename T>
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<T>(&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<T>()), expression);
}
@@ -212,8 +212,8 @@ QUIZ_CASE(poincare_approximation_logarithm) {
template<typename T>
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<T>(&globalContext, Cartesian, Radian);
quiz_assert_print_if_failure(result >= lowBound, expression);
quiz_assert_print_if_failure(result < upBound || (result == upBound && upBoundIncluded), expression);

View File

@@ -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);

View File

@@ -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];

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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 */
}