aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLuca Di Sera <luca.disera@qt.io>2024-04-26 10:26:29 +0200
committerLuca Di Sera <luca.disera@qt.io>2024-05-08 11:15:40 +0200
commitaac94b9cb6bbfe8e16c8282dcdaf11b36eea4d6e (patch)
treef735f12c40b2d1dc5b10e53943562d3cc8aac275 /src
parentd73409cd3e9c0ac770d76494250dcf065910384d (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.cpp53
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;
}
}
}