Merge branch 'omega-hotfix' into omega-dev

This commit is contained in:
Quentin Guidée
2020-03-06 16:13:02 +01:00
15 changed files with 75 additions and 56 deletions

View File

@@ -7,6 +7,8 @@
namespace Code {
static inline int minInt(int x, int y) { return x < y ? x : y; }
ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) :
HighlightCell(),
Responder(parentResponder),
@@ -65,9 +67,12 @@ void ConsoleEditCell::clearAndReduceSize() {
const char * ConsoleEditCell::shiftCurrentTextAndClear() {
size_t previousBufferSize = m_textField.draftTextBufferSize();
m_textField.setDraftTextBufferSize(previousBufferSize + 1);
char * textFieldBuffer = m_textField.draftTextBuffer();
char * textFieldBuffer = const_cast<char *>(m_textField.text());
char * newTextPosition = textFieldBuffer + 1;
strlcpy(newTextPosition, textFieldBuffer, previousBufferSize);
assert(previousBufferSize > 0);
size_t copyLength = minInt(previousBufferSize - 1, strlen(textFieldBuffer));
memmove(newTextPosition, textFieldBuffer, copyLength);
newTextPosition[copyLength] = 0;
textFieldBuffer[0] = 0;
return newTextPosition;
}

View File

@@ -106,11 +106,11 @@ void CurveView::setOkView(View * okView) {
* m_frame.height() - 1 yMin()
*/
const float CurveView::pixelWidth() const {
float CurveView::pixelWidth() const {
return (m_curveViewRange->xMax() - m_curveViewRange->xMin()) / (m_frame.width() - 1);
}
const float CurveView::pixelHeight() const {
float CurveView::pixelHeight() const {
return (m_curveViewRange->yMax() - m_curveViewRange->yMin()) / (m_frame.height() - 1);
}

View File

@@ -38,8 +38,8 @@ public:
void setBannerView(View * bannerView);
void setOkView(View * okView);
void setForceOkDisplay(bool force) { m_forceOkDisplay = force; }
const float pixelWidth() const;
const float pixelHeight() const;
float pixelWidth() const;
float pixelHeight() const;
protected:
CurveViewRange * curveViewRange() const { return m_curveViewRange; }
void setCurveViewRange(CurveViewRange * curveViewRange);

View File

@@ -17,8 +17,8 @@ public:
virtual float xMax() const = 0;
virtual float yMin() const = 0;
virtual float yMax() const = 0;
const float xCenter() const { return (xMin() + xMax()) / 2; }
const float yCenter() const { return (yMin() + yMax()) / 2; }
float xCenter() const { return (xMin() + xMax()) / 2; }
float yCenter() const { return (yMin() + yMax()) / 2; }
virtual float xGridUnit() const {
return computeGridUnit(k_minNumberOfXGridUnits, k_maxNumberOfXGridUnits, xMax() - xMin());
}

View File

@@ -112,6 +112,7 @@ class Expression : public TreeHandle {
friend class IntegralNode;
template<int T>
friend class LogarithmNode;
friend class MatrixNode;
friend class NaperianLogarithmNode;
friend class NAryExpressionNode;
friend class StoreNode;
@@ -274,7 +275,7 @@ public:
m_numberOfChildren(numberOfChildren),
m_untypedBuilder(builder) {}
const char * name() const { return m_name; }
const int numberOfChildren() const { return m_numberOfChildren; }
int numberOfChildren() const { return m_numberOfChildren; }
Expression build(Expression children) const { return (*m_untypedBuilder)(children); }
private:
const char * m_name;

View File

@@ -11,7 +11,7 @@ public:
m_numberOfRows(0),
m_numberOfColumns(0) {}
bool hasMatrixChild(Context * context) const;
int numberOfRows() const { return m_numberOfRows; }
int numberOfColumns() const { return m_numberOfColumns; }
virtual void setNumberOfRows(int rows) { assert(rows >= 0); m_numberOfRows = rows; }
@@ -87,7 +87,7 @@ public:
static constexpr int k_maxNumberOfCoefficients = 100;
// Expression
Expression shallowReduce();
Expression shallowReduce(Context * context);
private:
MatrixNode * node() const { return static_cast<MatrixNode *>(Expression::node()); }

View File

@@ -29,7 +29,7 @@ public:
m_exponent(exponent)
{}
const char * symbol() const { return m_symbol; }
const int8_t exponent() const { return m_exponent; }
int8_t exponent() const { return m_exponent; }
int serialize(char * buffer, int bufferSize) const;
private:
const char * m_symbol;
@@ -235,7 +235,7 @@ public:
Representative("week", "7*24*60*60*_s",
Representative::Prefixable::No,
NoPrefix),
Representative("month", "30*7*24*60*60*_s",
Representative("month", "365.25/12*24*60*60*_s",
Representative::Prefixable::No,
NoPrefix),
Representative("year", "365.25*24*60*60*_s",

View File

@@ -684,7 +684,6 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre
/* Case 1: the reduced expression is a matrix: We scan the matrix children to
* beautify them with the right complex format. */
if (e.type() == ExpressionNode::Type::Matrix) {
// TODO: this method enables to take the complex format into account when the result is a matrix of scalar. It won't work for nested matrices... Find a more elegant and general solution?
Matrix m = static_cast<Matrix &>(e);
*simplifiedExpression = Matrix::Builder();
if (approximateExpression) {
@@ -694,6 +693,7 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre
Expression simplifiedChild;
Expression approximateChild = approximateExpression ? Expression() : nullptr;
e.childAtIndex(i).beautifyAndApproximateScalar(&simplifiedChild, &approximateChild, userReductionContext, context, complexFormat, angleUnit);
assert(!simplifiedChild.deepIsMatrix(context));
static_cast<Matrix *>(simplifiedExpression)->addChildAtIndexInPlace(simplifiedChild, i, i);
if (approximateExpression) {
static_cast<Matrix *>(approximateExpression)->addChildAtIndexInPlace(approximateChild, i, i);
@@ -770,7 +770,7 @@ Expression Expression::mapOnMatrixFirstChild(ExpressionNode::ReductionContext re
}
matrix.setDimensions(static_cast<Matrix &>(c).numberOfRows(), static_cast<Matrix &>(c).numberOfColumns());
replaceWithInPlace(matrix);
return matrix.shallowReduce();
return matrix.shallowReduce(reductionContext.context());
}
Expression Expression::radianToAngleUnit(Preferences::AngleUnit angleUnit) {

View File

@@ -20,6 +20,15 @@ namespace Poincare {
static inline int minInt(int x, int y) { return x < y ? x : y; }
bool MatrixNode::hasMatrixChild(Context * context) const {
for (ExpressionNode * c : children()) {
if (Expression(c).deepIsMatrix(context)) {
return true;
}
}
return false;
}
void MatrixNode::didAddChildAtIndex(int newNumberOfChildren) {
setNumberOfRows(1);
setNumberOfColumns(newNumberOfChildren);
@@ -30,7 +39,7 @@ int MatrixNode::polynomialDegree(Context * context, const char * symbolName) con
}
Expression MatrixNode::shallowReduce(ReductionContext reductionContext) {
return Matrix(this).shallowReduce();
return Matrix(this).shallowReduce(reductionContext.context());
}
Layout MatrixNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
@@ -390,7 +399,7 @@ Expression Matrix::determinant(ExpressionNode::ReductionContext reductionContext
return result;
}
Expression Matrix::shallowReduce() {
Expression Matrix::shallowReduce(Context * context) {
{
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
@@ -398,6 +407,9 @@ Expression Matrix::shallowReduce() {
return e;
}
}
if (node()->hasMatrixChild(context)) {
return replaceWithUndefinedInPlace();
}
return *this;
}

View File

@@ -702,7 +702,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext
}
}
replaceWithInPlace(resultMatrix);
return resultMatrix.shallowReduce();
return resultMatrix.shallowReduce(reductionContext.context());
}
/* Step 4: Gather like terms. For example, turn pi^2*pi^3 into pi^5. Thanks to

View File

@@ -370,6 +370,25 @@ void Parser::parseUnit(Expression & leftHandSide, Token::Type stoppingType) {
void Parser::parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper) {
const char * name = (**functionHelper).name();
if (strcmp(name, "log") == 0 && popTokenIfType(Token::LeftBrace)) {
// Special case for the log function (e.g. "log{2}(8)")
Expression base = parseUntil(Token::RightBrace);
if (m_status != Status::Progress) {
} else if (!popTokenIfType(Token::RightBrace)) {
m_status = Status::Error; // Right brace missing.
} else {
Expression parameter = parseFunctionParameters();
if (m_status != Status::Progress) {
} else if (parameter.numberOfChildren() != 1) {
m_status = Status::Error; // Unexpected number of many parameters.
} else {
leftHandSide = Logarithm::Builder(parameter.childAtIndex(0), base);
}
}
return;
}
Expression parameters = parseFunctionParameters();
if (m_status != Status::Progress) {
return;
@@ -393,10 +412,12 @@ void Parser::parseReservedFunction(Expression & leftHandSide, const Expression::
}
}
void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter, Token::Type rightDelimiter) {
if (!popTokenIfType(leftDelimiter)) {
void Parser::parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter1, Token::Type rightDelimiter1, Token::Type leftDelimiter2, Token::Type rightDelimiter2) {
bool delimiterTypeIsOne = popTokenIfType(leftDelimiter1);
if (!delimiterTypeIsOne && !popTokenIfType(leftDelimiter2)) {
m_status = Status::Error; // Left delimiter missing.
} else {
Token::Type rightDelimiter = delimiterTypeIsOne ? rightDelimiter1 : rightDelimiter2;
Expression rank = parseUntil(rightDelimiter);
if (m_status != Status::Progress) {
} else if (!popTokenIfType(rightDelimiter)) {
@@ -424,32 +445,14 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) {
leftHandSide = Undefined::Builder();
} else if (m_currentToken.compareTo(Unreal::Name()) == 0) {
leftHandSide = Unreal::Builder();
} 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);
} 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);
} 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);
if (m_status != Status::Progress) {
} else if (!popTokenIfType(Token::RightBrace)) {
m_status = Status::Error; // Right brace missing.
} else {
Expression parameter = parseFunctionParameters();
if (m_status != Status::Progress) {
} else if (parameter.numberOfChildren() != 1) {
m_status = Status::Error; // Unexpected number of many parameters.
} else {
leftHandSide = Logarithm::Builder(parameter.childAtIndex(0), base);
}
}
}
} 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)", "u{n}", ...)
* We know that m_currentToken.text()[0] is either 'u', 'v' or 'w', so we do
* not need to pass a code point to parseSequence. */
parseSequence(leftHandSide, m_currentToken.text()[0], Token::LeftParenthesis, Token::RightParenthesis, Token::LeftBrace, Token::RightBrace);
}
}

View File

@@ -74,7 +74,7 @@ private:
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 parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter1, Token::Type rightDelimiter1, Token::Type leftDelimiter2, Token::Type rightDelimiter2);
void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions);
void defaultParseLeftParenthesis(bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType);

View File

@@ -156,11 +156,9 @@ int VerticalOffsetLayoutNode::serialize(char * buffer, int bufferSize, Preferenc
if (bufferSize == 1) {
return 0;
}
// If the layout is a subscript, write "_{indice}"
int numberOfChar = SerializationHelper::CodePoint(buffer, bufferSize, '_');
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
numberOfChar += SerializationHelper::CodePoint(buffer+numberOfChar, bufferSize-numberOfChar, '{');
// If the layout is a subscript, write "{indice}"
int numberOfChar = SerializationHelper::CodePoint(buffer, bufferSize, '{');
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
numberOfChar += const_cast<VerticalOffsetLayoutNode *>(this)->indiceLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits);

View File

@@ -385,7 +385,7 @@ QUIZ_CASE(poincare_parsing_identifiers) {
assert_parsed_expression_is("ln(1)", NaperianLogarithm::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("log(1)", CommonLogarithm::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("log(1,2)", Logarithm::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2)));
assert_parsed_expression_is("log_{2}(1)", Logarithm::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2)));
assert_parsed_expression_is("log{2}(1)", Logarithm::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2)));
assert_parsed_expression_is("permute(2,1)", PermuteCoefficient::Builder(BasedInteger::Builder(2),BasedInteger::Builder(1)));
assert_parsed_expression_is("prediction95(1,2)", PredictionInterval::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2)));
assert_parsed_expression_is("prediction(1,2)", SimplePredictionInterval::Builder(BasedInteger::Builder(1),BasedInteger::Builder(2)));

View File

@@ -1025,10 +1025,10 @@ QUIZ_CASE(poincare_simplification_unit_convert) {
assert_parsed_expression_simplify_to("1→u(n+1)", Undefined::Name());
assert_parsed_expression_simplify_to("1→v(n)", Undefined::Name());
assert_parsed_expression_simplify_to("1→v(n+1)", Undefined::Name());
assert_parsed_expression_simplify_to("1→u_{n}", Undefined::Name());
assert_parsed_expression_simplify_to("1→u_{n+1}", Undefined::Name());
assert_parsed_expression_simplify_to("1→v_{n}", Undefined::Name());
assert_parsed_expression_simplify_to("1→v_{n+1}", Undefined::Name());
assert_parsed_expression_simplify_to("1→u{n}", Undefined::Name());
assert_parsed_expression_simplify_to("1→u{n+1}", Undefined::Name());
assert_parsed_expression_simplify_to("1→v{n}", Undefined::Name());
assert_parsed_expression_simplify_to("1→v{n+1}", Undefined::Name());
assert_parsed_expression_simplify_to("1→inf", Undefined::Name());
assert_parsed_expression_simplify_to("1→undef", Undefined::Name());
assert_parsed_expression_simplify_to("1→π", Undefined::Name());