diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-02-05 15:27:17 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-02-08 14:00:40 +0000 |
commit | 0e7dd897923bc5dd8e3eaf8b4f5255174c766199 (patch) | |
tree | d05b82a734e03acc7a336347f11d2ff28a90865a /src/qml | |
parent | 206f509c63e5952733db318fbc79c14494e18502 (diff) |
Add support for parsing of binary and octal numbers
In line with Chapter 11.8.3 of ECMAScript 6.
Change-Id: I3c67e001858eb8f055ec49f83ec51a1bf9c8154b
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/parser/qqmljsengine_p.cpp | 7 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 219 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer_p.h | 2 |
3 files changed, 105 insertions, 123 deletions
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp index 7a6d9c3826..5b105bc60c 100644 --- a/src/qml/parser/qqmljsengine_p.cpp +++ b/src/qml/parser/qqmljsengine_p.cpp @@ -112,13 +112,6 @@ double integerFromString(const char *buf, int size, int radix) return result; } -double integerFromString(const QString &str, int radix) -{ - QByteArray ba = QStringRef(&str).trimmed().toLatin1(); - return integerFromString(ba.constData(), ba.size(), radix); -} - - Engine::Engine() : _lexer(0), _directives(0) { } diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index fe19fd4a74..c0591f1b9b 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -223,6 +223,25 @@ inline bool isBinop(int tok) return false; } } + +int hexDigit(QChar c) +{ + if (c >= QLatin1Char('0') && c <= QLatin1Char('9')) + return c.unicode() - '0'; + if (c >= QLatin1Char('a') && c <= QLatin1Char('f')) + return c.unicode() - 'a' + 10; + if (c >= QLatin1Char('A') && c <= QLatin1Char('F')) + return c.unicode() - 'A' + 10; + return -1; +} + +int octalDigit(QChar c) +{ + if (c >= QLatin1Char('0') && c <= QLatin1Char('7')) + return c.unicode() - '0'; + return -1; +} + } // anonymous namespace int Lexer::lex() @@ -557,51 +576,8 @@ again: return T_DIVIDE_; case '.': - if (_char.isDigit()) { - QVarLengthArray<char,32> chars; - - chars.append(ch.unicode()); // append the `.' - - while (_char.isDigit()) { - chars.append(_char.unicode()); - scanChar(); - } - - if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { - if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && - _codePtr[1].isDigit())) { - - chars.append(_char.unicode()); - scanChar(); // consume `e' - - if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { - chars.append(_char.unicode()); - scanChar(); // consume the sign - } - - while (_char.isDigit()) { - chars.append(_char.unicode()); - scanChar(); - } - } - } - - chars.append('\0'); - - const char *begin = chars.constData(); - const char *end = 0; - bool ok = false; - - _tokenValue = qstrtod(begin, &end, &ok); - - if (end - begin != chars.size() - 1) { - _errorCode = IllegalExponentIndicator; - _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number"); - return T_ERROR; - } - - return T_NUMERIC_LITERAL; - } + if (isDecimalDigit(_char.unicode())) + return scanNumber(ch); return T_DOT; case '-': @@ -898,91 +874,110 @@ again: int Lexer::scanNumber(QChar ch) { - if (ch != QLatin1Char('0')) { - QVarLengthArray<char, 64> buf; - buf += ch.toLatin1(); - - QChar n = _char; - const QChar *code = _codePtr; - while (n.isDigit()) { - buf += n.toLatin1(); - n = *code++; - } + if (ch == QLatin1Char('0')) { + if (_char == QLatin1Char('x') || _char == QLatin1Char('X')) { + ch = _char; // remember the x or X to use it in the error message below. - if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) { - if (code != _codePtr) { - _codePtr = code - 1; + // parse hex integer literal + scanChar(); // consume 'x' + + if (!isHexDigit(_char)) { + _errorCode = IllegalNumber; + _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch); + return T_ERROR; + } + + double d = 0.; + while (1) { + int digit = ::hexDigit(_char); + if (digit < 0) + break; + d *= 16; + d += digit; scanChar(); } - buf.append('\0'); - _tokenValue = strtod(buf.constData(), 0); + + _tokenValue = d; return T_NUMERIC_LITERAL; - } - } else if (_char.isDigit() && !qmlMode()) { - _errorCode = IllegalCharacter; - _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'"); - return T_ERROR; - } + } else if (_char == QLatin1Char('o') || _char == QLatin1Char('O')) { + ch = _char; // remember the o or O to use it in the error message below. - QVarLengthArray<char,32> chars; - chars.append(ch.unicode()); + // parse octal integer literal + scanChar(); // consume 'o' - if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) { - ch = _char; // remember the x or X to use it in the error message below. + if (!isOctalDigit(_char.unicode())) { + _errorCode = IllegalNumber; + _errorMessage = QCoreApplication::translate("QQmlParser", "At least one octal digit is required after '0%1'").arg(ch); + return T_ERROR; + } - // parse hex integer literal - chars.append(_char.unicode()); - scanChar(); // consume `x' + double d = 0.; + while (1) { + int digit = ::octalDigit(_char); + if (digit < 0) + break; + d *= 8; + d += digit; + scanChar(); + } - while (isHexDigit(_char)) { - chars.append(_char.unicode()); - scanChar(); - } + _tokenValue = d; + return T_NUMERIC_LITERAL; + } else if (_char == QLatin1Char('b') || _char == QLatin1Char('B')) { + ch = _char; // remember the b or B to use it in the error message below. + + // parse binary integer literal + scanChar(); // consume 'b' - if (chars.size() < 3) { - _errorCode = IllegalHexNumber; - _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch); + if (_char.unicode() != '0' && _char.unicode() != '1') { + _errorCode = IllegalNumber; + _errorMessage = QCoreApplication::translate("QQmlParser", "At least one binary digit is required after '0%1'").arg(ch); + return T_ERROR; + } + + double d = 0.; + while (1) { + int digit = 0; + if (_char.unicode() == '1') + digit = 1; + else if (_char.unicode() != '0') + break; + d *= 2; + d += digit; + scanChar(); + } + + _tokenValue = d; + return T_NUMERIC_LITERAL; + } else if (_char.isDigit() && !qmlMode()) { + _errorCode = IllegalCharacter; + _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'"); return T_ERROR; } - - _tokenValue = integerFromString(chars.constData(), chars.size(), 16); - return T_NUMERIC_LITERAL; } // decimal integer literal - while (_char.isDigit()) { - chars.append(_char.unicode()); - scanChar(); // consume the digit - } - - if (_char == QLatin1Char('.')) { - chars.append(_char.unicode()); - scanChar(); // consume `.' + QVarLengthArray<char,32> chars; + chars.append(ch.unicode()); + if (ch != QLatin1Char('.')) { while (_char.isDigit()) { chars.append(_char.unicode()); - scanChar(); + scanChar(); // consume the digit } - if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { - if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && - _codePtr[1].isDigit())) { - - chars.append(_char.unicode()); - scanChar(); // consume `e' + if (_char == QLatin1Char('.')) { + chars.append(_char.unicode()); + scanChar(); // consume `.' + } + } - if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { - chars.append(_char.unicode()); - scanChar(); // consume the sign - } + while (_char.isDigit()) { + chars.append(_char.unicode()); + scanChar(); + } - while (_char.isDigit()) { - chars.append(_char.unicode()); - scanChar(); - } - } - } - } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { + if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && _codePtr[1].isDigit())) { @@ -1001,12 +996,6 @@ int Lexer::scanNumber(QChar ch) } } - if (chars.length() == 1) { - // if we ended up with a single digit, then it was a '0' - _tokenValue = 0; - return T_NUMERIC_LITERAL; - } - chars.append('\0'); const char *begin = chars.constData(); diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h index 03d434e3e6..902ac5ad7c 100644 --- a/src/qml/parser/qqmljslexer_p.h +++ b/src/qml/parser/qqmljslexer_p.h @@ -124,7 +124,7 @@ public: enum Error { NoError, IllegalCharacter, - IllegalHexNumber, + IllegalNumber, UnclosedStringLiteral, IllegalEscapeSequence, IllegalUnicodeEscapeSequence, |