mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
Merge branch 'omega-hotfix' into omega-dev
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()); }
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user