mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[poincare/parser] Add context
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
11
escher/include/escher/context_provider.h
Normal file
11
escher/include/escher/context_provider.h
Normal 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
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user