From a06660ee25cdf8b010c7fa93ae3d871b2335c4df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 27 Feb 2020 14:50:19 +0100 Subject: [PATCH] [poincare/vert_off_lay] Subscript layout serializes without _ This way there is no parsing confusion when copy pasting the subscript of a subscript layout --- poincare/src/parsing/parser.cpp | 59 +++++++++++++------------ poincare/src/parsing/parser.h | 2 +- poincare/src/vertical_offset_layout.cpp | 6 +-- poincare/test/parsing.cpp | 2 +- poincare/test/simplification.cpp | 8 ++-- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index c5671b602..2475a7583 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -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); } } diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index f0b41cf63..08e04a211 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -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); diff --git a/poincare/src/vertical_offset_layout.cpp b/poincare/src/vertical_offset_layout.cpp index 538855a04..df163f402 100644 --- a/poincare/src/vertical_offset_layout.cpp +++ b/poincare/src/vertical_offset_layout.cpp @@ -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(this)->indiceLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); diff --git a/poincare/test/parsing.cpp b/poincare/test/parsing.cpp index bc673d76b..328d50661 100644 --- a/poincare/test/parsing.cpp +++ b/poincare/test/parsing.cpp @@ -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))); diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 8808bda1e..0dd49cc10 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -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());