diff --git a/ion/include/ion/charset.h b/ion/include/ion/charset.h index 6fc2291aa..9368f280b 100644 --- a/ion/include/ion/charset.h +++ b/ion/include/ion/charset.h @@ -27,7 +27,8 @@ enum Charset : char { MiddleDot = (char)149, AlmostEqual = (char)150, Degree = (char)151, - Empty = (char)152 // This char is used to be parsed into EmptyExpression. + Empty = (char)152, // This char is used to be parsed into EmptyExpression + Superscript = (char)153 // This char is used to parse Power }; } diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 2dcb316b7..1803de31e 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -54,6 +54,7 @@ Expression Parser::parseUntil(Token::Type stoppingType) { &Parser::parseUnexpected, // Token::EndOfStream &Parser::parseStore, // Token::Store &Parser::parseEqual, // Token::Equal + &Parser::parseSuperscript, // Token::Superscript &Parser::parseUnexpected, // Token::RightBracket &Parser::parseUnexpected, // Token::RightParenthesis &Parser::parseUnexpected, // Token::RightBrace @@ -250,6 +251,23 @@ void Parser::parseStore(Expression & leftHandSide) { leftHandSide = Store(leftHandSide, static_cast(rightHandSide)); } +void Parser::parseSuperscript(Expression & leftHandSide) { + if (leftHandSide.isUninitialized()) { + m_status = Status::Error; // Power must have a left operand + return; + } + Expression rightHandSide = parseUntil(Token::Superscript); + if (m_status != Status::Progress) { + return; + } + if (!popTokenIfType(Token::Superscript)) { + m_status = Status::Error; // Right superscript marker missing. + return; + } + leftHandSide = Power(leftHandSide, rightHandSide); + isThereImplicitMultiplication(); +} + bool Parser::parseBinaryOperator(const Expression & leftHandSide, Expression & rightHandSide, Token::Type stoppingType) { if (leftHandSide.isUninitialized()) { m_status = Status::Error; // Left-hand side missing. diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index 3c0f3cdf9..131a24f38 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -61,6 +61,7 @@ private: void parseCaret(Expression & leftHandSide); void parseEqual(Expression & leftHandSide); void parseStore(Expression & leftHandSide); + void parseSuperscript(Expression & leftHandSide); // Parsing helpers bool parseBinaryOperator(const Expression & leftHandSide, Expression & rightHandSide, Token::Type stoppingType); diff --git a/poincare/src/parsing/token.h b/poincare/src/parsing/token.h index 59e682646..1887dbf07 100644 --- a/poincare/src/parsing/token.h +++ b/poincare/src/parsing/token.h @@ -24,6 +24,9 @@ public: * token of lesser precedence than Equal, and this prevents expressions * such as "3=4>a". Tokenizer::parseStore uses a special algorithm that * prevents (3>4=a). */ + Superscript, + /* Superscript marks the limit of a power. For instance: + * 2 Superscript 3! Superscript ! is (2^(3!))! */ RightBracket, RightParenthesis, RightBrace, diff --git a/poincare/src/parsing/tokenizer.cpp b/poincare/src/parsing/tokenizer.cpp index eed88bc24..00e3756de 100644 --- a/poincare/src/parsing/tokenizer.cpp +++ b/poincare/src/parsing/tokenizer.cpp @@ -122,6 +122,12 @@ Token Tokenizer::popToken() { if (currentChar == Ion::Charset::MultiplicationSign || currentChar == Ion::Charset::MiddleDot) { return Token(Token::Times); } + if (currentChar == '^') { + return Token(Token::Caret); + } + if (currentChar == Ion::Charset::Superscript) { + return Token(Token::Superscript); + } if (currentChar == '!') { return Token(Token::Bang); } @@ -134,9 +140,6 @@ Token Tokenizer::popToken() { if (currentChar == ']') { return Token(Token::RightBracket); } - if (currentChar == '^') { - return Token(Token::Caret); - } if (currentChar == '{') { return Token(Token::LeftBrace); } diff --git a/poincare/src/vertical_offset_layout.cpp b/poincare/src/vertical_offset_layout.cpp index 8966dcbfe..029d26934 100644 --- a/poincare/src/vertical_offset_layout.cpp +++ b/poincare/src/vertical_offset_layout.cpp @@ -174,20 +174,14 @@ int VerticalOffsetLayoutNode::serialize(char * buffer, int bufferSize, Preferenc return numberOfChar; } assert(m_type == Type::Superscript); - // If the layout is a superscript, write "^(indice)" - int numberOfChar = SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "^"); + // If the layout is a superscript, write "Ion::Charset::Superscript indice Ion::Charset::Superscript" + int numberOfChar = SerializationHelper::Char(buffer, bufferSize, Ion::Charset::Superscript); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + numberOfChar += const_cast(this)->indiceLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + numberOfChar += SerializationHelper::Char(buffer+numberOfChar, bufferSize-numberOfChar, Ion::Charset::Superscript); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - // Add a multiplication if omitted. - int indexInParent = -1; - LayoutNode * parentNode = parent(); - if (parentNode != nullptr) { - indexInParent = parentNode->indexOfChild(this); - } - if (indexInParent >= 0 && indexInParent < (parentNode->numberOfChildren() - 1) && parentNode->isHorizontal() && parentNode->childAtIndex(indexInParent + 1)->canBeOmittedMultiplicationRightFactor()) { - buffer[numberOfChar++] = Ion::Charset::MiddleDot; - if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - } buffer[numberOfChar] = 0; return numberOfChar; }