diff options
| author | Luca Di Sera <luca.disera@qt.io> | 2024-04-26 10:26:29 +0200 |
|---|---|---|
| committer | Luca Di Sera <luca.disera@qt.io> | 2024-05-08 11:15:40 +0200 |
| commit | aac94b9cb6bbfe8e16c8282dcdaf11b36eea4d6e (patch) | |
| tree | f735f12c40b2d1dc5b10e53943562d3cc8aac275 /src | |
| parent | d73409cd3e9c0ac770d76494250dcf065910384d (diff) | |
QML: Allow numeric separators in numeric literals
ES2021 introduced numeric separators in numeric literals to improve
readability.
For example, one billion can be written "1_000_000_000" where "_" are
the numeric separators.
Update the QML lexer to allow numeric separators, based on
https://262.ecma-international.org/12.0/#prod-NumericLiteralSeparator.
Add a non-exhaustive test case to `tst_qqmlparser` to track the behavior.
Fixes: QTBUG-123792
Change-Id: Ie62d1f40fc8e0c7678e7dfea16408bdeeba6d150
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Reviewed-by: Dmitrii Akshintsev <dmitrii.akshintsev@qt.io>
Diffstat (limited to 'src')
| -rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index 704c7eb00d..cdb3dde5c6 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -1214,6 +1214,32 @@ int Lexer::scanString(ScanStringMode mode) int Lexer::scanNumber(QChar ch) { + auto scanOptionalNumericSeparator = [this](auto isNextCharacterValid){ + if (_state.currentChar == u'_') { + if (peekChar() == u'_') { + _state.errorCode = IllegalNumber; + _errorMessage = QCoreApplication::translate( + "QQmlParser", + "There can be at most one numeric separator beetwen digits" + ); + return false; + } + + if (!isNextCharacterValid()) { + _state.errorCode = IllegalNumber; + _errorMessage = QCoreApplication::translate( + "QQmlParser", + "A trailing numeric separator is not allowed in numeric literals" + ); + return false; + } + + scanChar(); + } + + return true; + }; + if (ch == u'0') { if (_state.currentChar == u'x' || _state.currentChar == u'X') { ch = _state.currentChar; // remember the x or X to use it in the error message below. @@ -1238,6 +1264,9 @@ int Lexer::scanNumber(QChar ch) d *= 16; d += digit; scanChar(); + + if (!scanOptionalNumericSeparator([this](){ return isHexDigit(peekChar()); })) + return T_ERROR; } _state.tokenValue = d; @@ -1265,6 +1294,12 @@ int Lexer::scanNumber(QChar ch) d *= 8; d += digit; scanChar(); + + if (!scanOptionalNumericSeparator([this](){ + return isOctalDigit(peekChar().unicode()); + })) { + return T_ERROR; + } } _state.tokenValue = d; @@ -1294,6 +1329,12 @@ int Lexer::scanNumber(QChar ch) d *= 2; d += digit; scanChar(); + + if (!scanOptionalNumericSeparator([this](){ + return peekChar().unicode() == u'0' || peekChar().unicode() == u'1'; + })) { + return T_ERROR; + } } _state.tokenValue = d; @@ -1311,9 +1352,15 @@ int Lexer::scanNumber(QChar ch) chars.append(ch.unicode()); if (ch != u'.') { + if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); })) + return T_ERROR; + while (_state.currentChar.isDigit()) { chars.append(_state.currentChar.unicode()); scanChar(); // consume the digit + + if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); })) + return T_ERROR; } if (_state.currentChar == u'.') { @@ -1325,6 +1372,9 @@ int Lexer::scanNumber(QChar ch) while (_state.currentChar.isDigit()) { chars.append(_state.currentChar.unicode()); scanChar(); + + if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); })) + return T_ERROR; } if (_state.currentChar == u'e' || _state.currentChar == u'E') { @@ -1342,6 +1392,9 @@ int Lexer::scanNumber(QChar ch) while (_state.currentChar.isDigit()) { chars.append(_state.currentChar.unicode()); scanChar(); + + if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); })) + return T_ERROR; } } } |
