aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/parser
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2022-02-09 16:29:40 +0100
committerMaximilian Goldstein <max.goldstein@qt.io>2022-02-18 12:13:47 +0100
commitae12302a9e0776fe6ecbe0b0823554223e030e6b (patch)
treebfa485fac6b134f0ba7cc897dfb68250cbebbbc7 /src/qml/parser
parent6ff2669b36d1c5632c4eed385e866403368fe331 (diff)
qqmljslexer: Make lexer restartable
Moves all variables that represent the lexers state into a separate struct that can be read and modified from the outside. This is necessary in order to enable per-line formatting in qmldom Change-Id: Iedde139cec6380bd62fa12c5ddec2a943a3b50f9 Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/parser')
-rw-r--r--src/qml/parser/qqmljslexer.cpp877
-rw-r--r--src/qml/parser/qqmljslexer_p.h117
2 files changed, 509 insertions, 485 deletions
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 1b58f687e2..3ae5c405f2 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -80,31 +80,7 @@ static inline QChar convertHex(QChar c1, QChar c2)
return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
}
-Lexer::Lexer(Engine *engine)
- : _engine(engine)
- , _codePtr(nullptr)
- , _endPtr(nullptr)
- , _tokenStartPtr(nullptr)
- , _char(u'\n')
- , _errorCode(NoError)
- , _currentLineNumber(0)
- , _currentColumnNumber(0)
- , _tokenValue(0)
- , _parenthesesState(IgnoreParentheses)
- , _parenthesesCount(0)
- , _stackToken(-1)
- , _patternFlags(0)
- , _tokenKind(0)
- , _tokenLength(0)
- , _tokenLine(0)
- , _tokenColumn(0)
- , _validTokenText(false)
- , _prohibitAutomaticSemicolon(false)
- , _restrictedKeyword(false)
- , _terminator(false)
- , _followsClosingBrace(false)
- , _delimited(true)
- , _qmlMode(true)
+Lexer::Lexer(Engine *engine) : _engine(engine), _endPtr(nullptr), _qmlMode(true)
{
if (engine)
engine->setLexer(this);
@@ -127,66 +103,67 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_qmlMode = qmlMode;
_code = code;
- _tokenText.clear();
- _tokenText.reserve(1024);
- _errorMessage.clear();
- _tokenSpell = QStringView();
- _rawString = QStringView();
- _codePtr = code.unicode();
- _endPtr = _codePtr + code.length();
- _tokenStartPtr = _codePtr;
+ _state.tokenText.clear();
+ _state.tokenText.reserve(1024);
+ _state.errorMessage.clear();
+ _state.tokenSpell = QStringView();
+ _state.rawString = QStringView();
- _char = u'\n';
- _errorCode = NoError;
+ _state.codePtr = code.unicode();
+ _endPtr = _state.codePtr + code.length();
+ _state.tokenStartPtr = _state.codePtr;
- _currentLineNumber = lineno;
- _currentColumnNumber = 0;
- _tokenValue = 0;
+ _state.currentChar = u'\n';
+ _state.errorCode = NoError;
+
+ _state.currentLineNumber = lineno;
+ _state.currentColumnNumber = 0;
+ _state.tokenValue = 0;
// parentheses state
- _parenthesesState = IgnoreParentheses;
- _parenthesesCount = 0;
-
- _stackToken = -1;
-
- _patternFlags = 0;
- _tokenLength = 0;
- _tokenLine = lineno;
- _tokenColumn = 0;
-
- _validTokenText = false;
- _prohibitAutomaticSemicolon = false;
- _restrictedKeyword = false;
- _terminator = false;
- _followsClosingBrace = false;
- _delimited = true;
+ _state.parenthesesState = IgnoreParentheses;
+ _state.parenthesesCount = 0;
+
+ _state.stackToken = -1;
+
+ _state.patternFlags = 0;
+ _state.tokenLength = 0;
+ _state.tokenLine = lineno;
+ _state.tokenColumn = 0;
+
+ _state.validTokenText = false;
+ _state.prohibitAutomaticSemicolon = false;
+ _state.restrictedKeyword = false;
+ _state.terminator = false;
+ _state.followsClosingBrace = false;
+ _state.delimited = true;
}
void Lexer::scanChar()
{
- if (_skipLinefeed) {
- Q_ASSERT(*_codePtr == u'\n');
- ++_codePtr;
- _skipLinefeed = false;
+ if (_state.skipLinefeed) {
+ Q_ASSERT(*_state.codePtr == u'\n');
+ ++_state.codePtr;
+ _state.skipLinefeed = false;
}
- _char = *_codePtr++;
- ++_currentColumnNumber;
+ _state.currentChar = *_state.codePtr++;
+ ++_state.currentColumnNumber;
if (isLineTerminator()) {
- if (_char == u'\r') {
- if (_codePtr < _endPtr && *_codePtr == u'\n')
- _skipLinefeed = true;
- _char = u'\n';
+ if (_state.currentChar == u'\r') {
+ if (_state.codePtr < _endPtr && *_state.codePtr == u'\n')
+ _state.skipLinefeed = true;
+ _state.currentChar = u'\n';
}
- ++_currentLineNumber;
- _currentColumnNumber = 0;
+ ++_state.currentLineNumber;
+ _state.currentColumnNumber = 0;
}
}
QChar Lexer::peekChar()
{
- auto peekPtr = _codePtr;
+ auto peekPtr = _state.codePtr;
if (peekPtr < _endPtr)
return *peekPtr;
return QChar();
@@ -259,107 +236,107 @@ int octalDigit(QChar c)
int Lexer::lex()
{
- const int previousTokenKind = _tokenKind;
+ const int previousTokenKind = _state.tokenKind;
again:
- _tokenSpell = QStringView();
- _rawString = QStringView();
- _tokenKind = scanToken();
- _tokenLength = _codePtr - _tokenStartPtr - 1;
-
- _delimited = false;
- _restrictedKeyword = false;
- _followsClosingBrace = (previousTokenKind == T_RBRACE);
-
- // update the flags
- switch (_tokenKind) {
- case T_LBRACE:
- if (_bracesCount > 0)
- ++_bracesCount;
- Q_FALLTHROUGH();
- case T_SEMICOLON:
- _importState = ImportState::NoQmlImport;
- Q_FALLTHROUGH();
- case T_QUESTION:
- case T_COLON:
- case T_TILDE:
- _delimited = true;
- break;
- case T_AUTOMATIC_SEMICOLON:
- case T_AS:
- _importState = ImportState::NoQmlImport;
- Q_FALLTHROUGH();
- default:
- if (isBinop(_tokenKind))
- _delimited = true;
- break;
-
- case T_IMPORT:
- if (qmlMode() || (_handlingDirectives && previousTokenKind == T_DOT))
- _importState = ImportState::SawImport;
- if (isBinop(_tokenKind))
- _delimited = true;
- break;
-
- case T_IF:
- case T_FOR:
- case T_WHILE:
- case T_WITH:
- _parenthesesState = CountParentheses;
- _parenthesesCount = 0;
- break;
-
- case T_ELSE:
- case T_DO:
- _parenthesesState = BalancedParentheses;
- break;
-
- case T_CONTINUE:
- case T_BREAK:
- case T_RETURN:
- case T_YIELD:
- case T_THROW:
- _restrictedKeyword = true;
- break;
- case T_RBRACE:
- if (_bracesCount > 0)
- --_bracesCount;
- if (_bracesCount == 0)
- goto again;
- } // switch
+ _state.tokenSpell = QStringView();
+ _state.rawString = QStringView();
+ _state.tokenKind = scanToken();
+ _state.tokenLength = _state.codePtr - _state.tokenStartPtr - 1;
+
+ _state.delimited = false;
+ _state.restrictedKeyword = false;
+ _state.followsClosingBrace = (previousTokenKind == T_RBRACE);
+
+ // update the flags
+ switch (_state.tokenKind) {
+ case T_LBRACE:
+ if (_state.bracesCount > 0)
+ ++_state.bracesCount;
+ Q_FALLTHROUGH();
+ case T_SEMICOLON:
+ _state.importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
+ case T_QUESTION:
+ case T_COLON:
+ case T_TILDE:
+ _state.delimited = true;
+ break;
+ case T_AUTOMATIC_SEMICOLON:
+ case T_AS:
+ _state.importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
+ default:
+ if (isBinop(_state.tokenKind))
+ _state.delimited = true;
+ break;
+
+ case T_IMPORT:
+ if (qmlMode() || (_state.handlingDirectives && previousTokenKind == T_DOT))
+ _state.importState = ImportState::SawImport;
+ if (isBinop(_state.tokenKind))
+ _state.delimited = true;
+ break;
+
+ case T_IF:
+ case T_FOR:
+ case T_WHILE:
+ case T_WITH:
+ _state.parenthesesState = CountParentheses;
+ _state.parenthesesCount = 0;
+ break;
+
+ case T_ELSE:
+ case T_DO:
+ _state.parenthesesState = BalancedParentheses;
+ break;
+
+ case T_CONTINUE:
+ case T_BREAK:
+ case T_RETURN:
+ case T_YIELD:
+ case T_THROW:
+ _state.restrictedKeyword = true;
+ break;
+ case T_RBRACE:
+ if (_state.bracesCount > 0)
+ --_state.bracesCount;
+ if (_state.bracesCount == 0)
+ goto again;
+ } // switch
// update the parentheses state
- switch (_parenthesesState) {
- case IgnoreParentheses:
- break;
-
- case CountParentheses:
- if (_tokenKind == T_RPAREN) {
- --_parenthesesCount;
- if (_parenthesesCount == 0)
- _parenthesesState = BalancedParentheses;
- } else if (_tokenKind == T_LPAREN) {
- ++_parenthesesCount;
- }
- break;
-
- case BalancedParentheses:
- if (_tokenKind != T_DO && _tokenKind != T_ELSE)
- _parenthesesState = IgnoreParentheses;
- break;
- } // switch
-
- return _tokenKind;
+ switch (_state.parenthesesState) {
+ case IgnoreParentheses:
+ break;
+
+ case CountParentheses:
+ if (_state.tokenKind == T_RPAREN) {
+ --_state.parenthesesCount;
+ if (_state.parenthesesCount == 0)
+ _state.parenthesesState = BalancedParentheses;
+ } else if (_state.tokenKind == T_LPAREN) {
+ ++_state.parenthesesCount;
+ }
+ break;
+
+ case BalancedParentheses:
+ if (_state.tokenKind != T_DO && _state.tokenKind != T_ELSE)
+ _state.parenthesesState = IgnoreParentheses;
+ break;
+ } // switch
+
+ return _state.tokenKind;
}
uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
{
- Q_ASSERT(_char == u'u');
+ Q_ASSERT(_state.currentChar == u'u');
scanChar(); // skip u
- if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) {
+ if (_state.codePtr + 4 <= _endPtr && isHexDigit(_state.currentChar)) {
uint codePoint = 0;
for (int i = 0; i < 4; ++i) {
- int digit = hexDigit(_char);
+ int digit = hexDigit(_state.currentChar);
if (digit < 0)
goto error;
codePoint *= 16;
@@ -369,15 +346,15 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
*ok = true;
return codePoint;
- } else if (_codePtr < _endPtr && _char == u'{') {
+ } else if (_state.codePtr < _endPtr && _state.currentChar == u'{') {
scanChar(); // skip '{'
uint codePoint = 0;
- if (!isHexDigit(_char))
+ if (!isHexDigit(_state.currentChar))
// need at least one hex digit
goto error;
- while (_codePtr <= _endPtr) {
- int digit = hexDigit(_char);
+ while (_state.codePtr <= _endPtr) {
+ int digit = hexDigit(_state.currentChar);
if (digit < 0)
break;
codePoint *= 16;
@@ -387,7 +364,7 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
scanChar();
}
- if (_char != u'}')
+ if (_state.currentChar != u'}')
goto error;
scanChar(); // skip '}'
@@ -398,8 +375,9 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
}
error:
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ _state.errorCode = IllegalUnicodeEscapeSequence;
+ _state.errorMessage =
+ QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
*ok = false;
return 0;
@@ -407,13 +385,13 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
QChar Lexer::decodeHexEscapeCharacter(bool *ok)
{
- if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
+ if (isHexDigit(_state.codePtr[0]) && isHexDigit(_state.codePtr[1])) {
scanChar();
- const QChar c1 = _char;
+ const QChar c1 = _state.currentChar;
scanChar();
- const QChar c2 = _char;
+ const QChar c2 = _state.currentChar;
scanChar();
if (ok)
@@ -481,36 +459,36 @@ static bool isIdentifierPart(uint ch)
int Lexer::scanToken()
{
- if (_stackToken != -1) {
- int tk = _stackToken;
- _stackToken = -1;
+ if (_state.stackToken != -1) {
+ int tk = _state.stackToken;
+ _state.stackToken = -1;
return tk;
}
- if (_bracesCount == 0) {
+ if (_state.bracesCount == 0) {
// we're inside a Template string
return scanString(TemplateContinuation);
}
-
- _terminator = false;
+ _state.terminator = false;
again:
- _validTokenText = false;
+ _state.validTokenText = false;
// handle comment can be called after a '/' has been read
// and returns true if it actually encountered a comment
- auto handleComment = [this](){
- if (_char == u'*') {
+ auto handleComment = [this]() {
+ if (_state.currentChar == u'*') {
scanChar();
- while (_codePtr <= _endPtr) {
- if (_char == u'*') {
+ while (_state.codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
scanChar();
- if (_char == u'/') {
+ if (_state.currentChar == u'/') {
scanChar();
if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
+ _engine->addComment(tokenOffset() + 2,
+ _state.codePtr - _state.tokenStartPtr - 1 - 4,
tokenStartLine(), tokenStartColumn() + 2);
}
@@ -520,30 +498,30 @@ again:
scanChar();
}
}
- } else if (_char == u'/') {
- while (_codePtr <= _endPtr && !isLineTerminator()) {
+ } else if (_state.currentChar == u'/') {
+ while (_state.codePtr <= _endPtr && !isLineTerminator()) {
scanChar();
}
if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
- tokenStartLine(), tokenStartColumn() + 2);
+ _engine->addComment(tokenOffset() + 2,
+ _state.codePtr - _state.tokenStartPtr - 1 - 2, tokenStartLine(),
+ tokenStartColumn() + 2);
}
return true;
}
return false;
};
-
- while (_char.isSpace()) {
+ while (_state.currentChar.isSpace()) {
if (isLineTerminator()) {
- if (_restrictedKeyword) {
+ if (_state.restrictedKeyword) {
// automatic semicolon insertion
- _tokenLine = _currentLineNumber;
- _tokenColumn = _currentColumnNumber;
- _tokenStartPtr = _codePtr - 1;
+ _state.tokenLine = _state.currentLineNumber;
+ _state.tokenColumn = _state.currentColumnNumber;
+ _state.tokenStartPtr = _state.codePtr - 1;
return T_SEMICOLON;
} else {
- _terminator = true;
+ _state.terminator = true;
syncProhibitAutomaticSemicolon();
}
}
@@ -551,14 +529,14 @@ again:
scanChar();
}
- _tokenStartPtr = _codePtr - 1;
- _tokenLine = _currentLineNumber;
- _tokenColumn = _currentColumnNumber;
+ _state.tokenStartPtr = _state.codePtr - 1;
+ _state.tokenLine = _state.currentLineNumber;
+ _state.tokenColumn = _state.currentColumnNumber;
- if (_codePtr > _endPtr)
+ if (_state.codePtr > _endPtr)
return EOF_SYMBOL;
- const QChar ch = _char;
+ const QChar ch = _state.currentChar;
scanChar();
switch (ch.unicode()) {
@@ -566,10 +544,10 @@ again:
case u'}': return T_RBRACE;
case u'|':
- if (_char == u'|') {
+ if (_state.currentChar == u'|') {
scanChar();
return T_OR_OR;
- } else if (_char == u'=') {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_OR_EQ;
}
@@ -578,7 +556,7 @@ again:
case u'{': return T_LBRACE;
case u'^':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_XOR_EQ;
}
@@ -587,11 +565,11 @@ again:
case u']': return T_RBRACKET;
case u'[': return T_LBRACKET;
case u'?': {
- if (_char == u'?') {
+ if (_state.currentChar == u'?') {
scanChar();
return T_QUESTION_QUESTION;
}
- if (_char == u'.' && !peekChar().isDigit()) {
+ if (_state.currentChar == u'.' && !peekChar().isDigit()) {
scanChar();
return T_QUESTION_DOT;
}
@@ -600,47 +578,47 @@ again:
}
case u'>':
- if (_char == u'>') {
+ if (_state.currentChar == u'>') {
scanChar();
- if (_char == u'>') {
+ if (_state.currentChar == u'>') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_GT_GT_GT_EQ;
}
return T_GT_GT_GT;
- } else if (_char == u'=') {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_GT_GT_EQ;
}
return T_GT_GT;
- } else if (_char == u'=') {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_GE;
}
return T_GT;
case u'=':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_EQ_EQ_EQ;
}
return T_EQ_EQ;
- } else if (_char == u'>') {
+ } else if (_state.currentChar == u'>') {
scanChar();
return T_ARROW;
}
return T_EQ;
case u'<':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_LE;
- } else if (_char == u'<') {
+ } else if (_state.currentChar == u'<') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_LT_LT_EQ;
}
@@ -654,39 +632,41 @@ again:
case u'/':
if (handleComment())
goto again;
- else if (_char == u'=') {
+ else if (_state.currentChar == u'=') {
scanChar();
return T_DIVIDE_EQ;
}
return T_DIVIDE_;
case u'.':
- if (_importState == ImportState::SawImport)
+ if (_state.importState == ImportState::SawImport)
return T_DOT;
- if (isDecimalDigit(_char.unicode()))
+ if (isDecimalDigit(_state.currentChar.unicode()))
return scanNumber(ch);
- if (_char == u'.') {
+ if (_state.currentChar == u'.') {
scanChar();
- if (_char == u'.') {
+ if (_state.currentChar == u'.') {
scanChar();
return T_ELLIPSIS;
} else {
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unexpected token '.'");
+ _state.errorCode = IllegalCharacter;
+ _state.errorMessage =
+ QCoreApplication::translate("QQmlParser", "Unexpected token '.'");
return T_ERROR;
}
}
return T_DOT;
case u'-':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_MINUS_EQ;
- } else if (_char == u'-') {
+ } else if (_state.currentChar == u'-') {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
- _stackToken = T_MINUS_MINUS;
+ if (_state.terminator && !_state.delimited && !_state.prohibitAutomaticSemicolon
+ && _state.tokenKind != T_LPAREN) {
+ _state.stackToken = T_MINUS_MINUS;
return T_SEMICOLON;
}
@@ -697,14 +677,15 @@ again:
case u',': return T_COMMA;
case u'+':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_PLUS_EQ;
- } else if (_char == u'+') {
+ } else if (_state.currentChar == u'+') {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
- _stackToken = T_PLUS_PLUS;
+ if (_state.terminator && !_state.delimited && !_state.prohibitAutomaticSemicolon
+ && _state.tokenKind != T_LPAREN) {
+ _state.stackToken = T_PLUS_PLUS;
return T_SEMICOLON;
}
@@ -713,12 +694,12 @@ again:
return T_PLUS;
case u'*':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_STAR_EQ;
- } else if (_char == u'*') {
+ } else if (_state.currentChar == u'*') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_STAR_STAR_EQ;
}
@@ -732,26 +713,26 @@ again:
case u'@': return T_AT;
case u'&':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_AND_EQ;
- } else if (_char == u'&') {
+ } else if (_state.currentChar == u'&') {
scanChar();
return T_AND_AND;
}
return T_AND;
case u'%':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_REMAINDER_EQ;
}
return T_REMAINDER;
case u'!':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_NOT_EQ_EQ;
}
@@ -760,7 +741,7 @@ again:
return T_NOT;
case u'`':
- _outerTemplateBraceCount.push(_bracesCount);
+ _state.outerTemplateBraceCount.push(_state.bracesCount);
Q_FALLTHROUGH();
case u'\'':
case u'"':
@@ -775,19 +756,19 @@ again:
case u'7':
case u'8':
case u'9':
- if (_importState == ImportState::SawImport)
+ if (_state.importState == ImportState::SawImport)
return scanVersionNumber(ch);
else
return scanNumber(ch);
case '#':
- if (_currentLineNumber == 1 && _currentColumnNumber == 2) {
+ if (_state.currentLineNumber == 1 && _state.currentColumnNumber == 2) {
// shebang support
- while (_codePtr <= _endPtr && !isLineTerminator()) {
+ while (_state.codePtr <= _endPtr && !isLineTerminator()) {
scanChar();
}
if (_engine) {
- _engine->addComment(tokenOffset(), _codePtr - _tokenStartPtr - 1,
+ _engine->addComment(tokenOffset(), _state.codePtr - _state.tokenStartPtr - 1,
tokenStartLine(), tokenStartColumn());
}
goto again;
@@ -797,10 +778,10 @@ again:
default: {
uint c = ch.unicode();
bool identifierWithEscapeChars = false;
- if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) {
- c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_state.currentChar.unicode())) {
+ c = QChar::surrogateToUcs4(ushort(c), _state.currentChar.unicode());
scanChar();
- } else if (c == '\\' && _char == u'u') {
+ } else if (c == '\\' && _state.currentChar == u'u') {
identifierWithEscapeChars = true;
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
@@ -809,26 +790,27 @@ again:
}
if (isIdentifierStart(c)) {
if (identifierWithEscapeChars) {
- _tokenText.resize(0);
+ _state.tokenText.resize(0);
if (QChar::requiresSurrogates(c)) {
- _tokenText += QChar(QChar::highSurrogate(c));
- _tokenText += QChar(QChar::lowSurrogate(c));
+ _state.tokenText += QChar(QChar::highSurrogate(c));
+ _state.tokenText += QChar(QChar::lowSurrogate(c));
} else {
- _tokenText += QChar(c);
+ _state.tokenText += QChar(c);
}
- _validTokenText = true;
+ _state.validTokenText = true;
}
- while (_codePtr <= _endPtr) {
- c = _char.unicode();
- if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) {
+ while (_state.codePtr <= _endPtr) {
+ c = _state.currentChar.unicode();
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_state.codePtr->unicode())) {
scanChar();
- c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
- } else if (_char == u'\\' && _codePtr[0] == u'u') {
+ c = QChar::surrogateToUcs4(ushort(c), _state.currentChar.unicode());
+ } else if (_state.currentChar == u'\\' && _state.codePtr[0] == u'u') {
if (!identifierWithEscapeChars) {
identifierWithEscapeChars = true;
- _tokenText.resize(0);
- _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
- _validTokenText = true;
+ _state.tokenText.resize(0);
+ _state.tokenText.insert(0, _state.tokenStartPtr,
+ _state.codePtr - _state.tokenStartPtr - 1);
+ _state.validTokenText = true;
}
scanChar(); // skip '\\'
@@ -841,10 +823,10 @@ again:
break;
if (QChar::requiresSurrogates(c)) {
- _tokenText += QChar(QChar::highSurrogate(c));
- _tokenText += QChar(QChar::lowSurrogate(c));
+ _state.tokenText += QChar(QChar::highSurrogate(c));
+ _state.tokenText += QChar(QChar::lowSurrogate(c));
} else {
- _tokenText += QChar(c);
+ _state.tokenText += QChar(c);
}
continue;
}
@@ -854,42 +836,43 @@ again:
if (identifierWithEscapeChars) {
if (QChar::requiresSurrogates(c)) {
- _tokenText += QChar(QChar::highSurrogate(c));
- _tokenText += QChar(QChar::lowSurrogate(c));
+ _state.tokenText += QChar(QChar::highSurrogate(c));
+ _state.tokenText += QChar(QChar::lowSurrogate(c));
} else {
- _tokenText += QChar(c);
+ _state.tokenText += QChar(c);
}
}
scanChar();
}
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ _state.tokenLength = _state.codePtr - _state.tokenStartPtr - 1;
int kind = T_IDENTIFIER;
if (!identifierWithEscapeChars)
- kind = classify(_tokenStartPtr, _tokenLength, parseModeFlags());
+ kind = classify(_state.tokenStartPtr, _state.tokenLength, parseModeFlags());
if (kind == T_FUNCTION) {
continue_skipping:
- while (_codePtr < _endPtr && _char.isSpace())
- scanChar();
- if (_char == u'*') {
- _tokenLength = _codePtr - _tokenStartPtr - 1;
- kind = T_FUNCTION_STAR;
- scanChar();
- } else if (_char == u'/') {
- scanChar();
- if (handleComment())
- goto continue_skipping;
- }
+ while (_state.codePtr < _endPtr && _state.currentChar.isSpace())
+ scanChar();
+ if (_state.currentChar == u'*') {
+ _state.tokenLength = _state.codePtr - _state.tokenStartPtr - 1;
+ kind = T_FUNCTION_STAR;
+ scanChar();
+ } else if (_state.currentChar == u'/') {
+ scanChar();
+ if (handleComment())
+ goto continue_skipping;
+ }
}
if (_engine) {
if (kind == T_IDENTIFIER && identifierWithEscapeChars)
- _tokenSpell = _engine->newStringRef(_tokenText);
+ _state.tokenSpell = _engine->newStringRef(_state.tokenText);
else
- _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
+ _state.tokenSpell = _engine->midRef(_state.tokenStartPtr - _code.unicode(),
+ _state.tokenLength);
}
return kind;
@@ -907,34 +890,36 @@ int Lexer::scanString(ScanStringMode mode)
QChar quote = (mode == TemplateContinuation) ? QChar(TemplateHead) : QChar(mode);
bool multilineStringLiteral = false;
- const QChar *startCode = _codePtr - 1;
+ const QChar *startCode = _state.codePtr - 1;
// in case we just parsed a \r, we need to reset this flag to get things working
// correctly in the loop below and afterwards
- _skipLinefeed = false;
+ _state.skipLinefeed = false;
bool first = true;
if (_engine) {
- while (_codePtr <= _endPtr) {
+ while (_state.codePtr <= _endPtr) {
if (isLineTerminator()) {
if ((quote == u'`' || qmlMode())) {
if (first)
- --_currentLineNumber; // will be read again in scanChar()
+ --_state.currentLineNumber; // will be read again in scanChar()
break;
}
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Stray newline in string literal");
+ _state.errorCode = IllegalCharacter;
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Stray newline in string literal");
return T_ERROR;
- } else if (_char == u'\\') {
+ } else if (_state.currentChar == u'\\') {
break;
- } else if (_char == u'$' && quote == u'`') {
+ } else if (_state.currentChar == u'$' && quote == u'`') {
break;
- } else if (_char == quote) {
- _tokenSpell = _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1);
- _rawString = _tokenSpell;
+ } else if (_state.currentChar == quote) {
+ _state.tokenSpell = _engine->midRef(startCode - _code.unicode(),
+ _state.codePtr - startCode - 1);
+ _state.rawString = _state.tokenSpell;
scanChar();
if (quote == u'`')
- _bracesCount = _outerTemplateBraceCount.pop();
+ _state.bracesCount = _state.outerTemplateBraceCount.pop();
if (mode == TemplateHead)
return T_NO_SUBSTITUTION_TEMPLATE;
@@ -944,40 +929,40 @@ int Lexer::scanString(ScanStringMode mode)
return T_STRING_LITERAL;
}
// don't use scanChar() here, that would transform \r sequences and the midRef() call would create the wrong result
- _char = *_codePtr++;
- ++_currentColumnNumber;
+ _state.currentChar = *_state.codePtr++;
+ ++_state.currentColumnNumber;
first = false;
}
}
// rewind by one char, so things gets scanned correctly
- --_codePtr;
- --_currentColumnNumber;
+ --_state.codePtr;
+ --_state.currentColumnNumber;
- _validTokenText = true;
- _tokenText = QString(startCode, _codePtr - startCode);
+ _state.validTokenText = true;
+ _state.tokenText = QString(startCode, _state.codePtr - startCode);
auto setRawString = [&](const QChar *end) {
QString raw(startCode, end - startCode - 1);
raw.replace(QLatin1String("\r\n"), QLatin1String("\n"));
raw.replace(u'\r', u'\n');
- _rawString = _engine->newStringRef(raw);
+ _state.rawString = _engine->newStringRef(raw);
};
scanChar();
- while (_codePtr <= _endPtr) {
- if (_char == quote) {
+ while (_state.codePtr <= _endPtr) {
+ if (_state.currentChar == quote) {
scanChar();
if (_engine) {
- _tokenSpell = _engine->newStringRef(_tokenText);
+ _state.tokenSpell = _engine->newStringRef(_state.tokenText);
if (quote == u'`')
- setRawString(_codePtr - 1);
+ setRawString(_state.codePtr - 1);
}
if (quote == u'`')
- _bracesCount = _outerTemplateBraceCount.pop();
+ _state.bracesCount = _state.outerTemplateBraceCount.pop();
if (mode == TemplateContinuation)
return T_TEMPLATE_TAIL;
@@ -985,27 +970,28 @@ int Lexer::scanString(ScanStringMode mode)
return T_NO_SUBSTITUTION_TEMPLATE;
return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
- } else if (quote == u'`' && _char == u'$' && *_codePtr == u'{') {
+ } else if (quote == u'`' && _state.currentChar == u'$' && *_state.codePtr == u'{') {
scanChar();
scanChar();
- _bracesCount = 1;
+ _state.bracesCount = 1;
if (_engine) {
- _tokenSpell = _engine->newStringRef(_tokenText);
- setRawString(_codePtr - 2);
+ _state.tokenSpell = _engine->newStringRef(_state.tokenText);
+ setRawString(_state.codePtr - 2);
}
return (mode == TemplateHead ? T_TEMPLATE_HEAD : T_TEMPLATE_MIDDLE);
- } else if (_char == u'\\') {
+ } else if (_state.currentChar == u'\\') {
scanChar();
- if (_codePtr > _endPtr) {
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence");
+ if (_state.codePtr > _endPtr) {
+ _state.errorCode = IllegalEscapeSequence;
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "End of file reached at escape sequence");
return T_ERROR;
}
QChar u;
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
// unicode escape sequence
case u'u': {
bool ok = false;
@@ -1014,7 +1000,7 @@ int Lexer::scanString(ScanStringMode mode)
return T_ERROR;
if (QChar::requiresSurrogates(codePoint)) {
// need to use a surrogate pair
- _tokenText += QChar(QChar::highSurrogate(codePoint));
+ _state.tokenText += QChar(QChar::highSurrogate(codePoint));
u = QChar::lowSurrogate(codePoint);
} else {
u = QChar(codePoint);
@@ -1026,8 +1012,9 @@ int Lexer::scanString(ScanStringMode mode)
bool ok = false;
u = decodeHexEscapeCharacter(&ok);
if (!ok) {
- _errorCode = IllegalHexadecimalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal hexadecimal escape sequence");
+ _state.errorCode = IllegalHexadecimalEscapeSequence;
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Illegal hexadecimal escape sequence");
return T_ERROR;
}
} break;
@@ -1044,7 +1031,7 @@ int Lexer::scanString(ScanStringMode mode)
case u'v': u = u'\v'; scanChar(); break;
case u'0':
- if (! _codePtr->isDigit()) {
+ if (!_state.codePtr->isDigit()) {
scanChar();
u = u'\0';
break;
@@ -1059,8 +1046,9 @@ int Lexer::scanString(ScanStringMode mode)
case u'7':
case u'8':
case u'9':
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Octal escape sequences are not allowed");
+ _state.errorCode = IllegalEscapeSequence;
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Octal escape sequences are not allowed");
return T_ERROR;
case u'\r':
@@ -1072,40 +1060,45 @@ int Lexer::scanString(ScanStringMode mode)
default:
// non escape character
- u = _char;
+ u = _state.currentChar;
scanChar();
}
- _tokenText += u;
+ _state.tokenText += u;
} else {
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
}
}
- _errorCode = UnclosedStringLiteral;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
+ _state.errorCode = UnclosedStringLiteral;
+ _state.errorMessage =
+ QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
return T_ERROR;
}
int Lexer::scanNumber(QChar ch)
{
if (ch == u'0') {
- if (_char == u'x' || _char == u'X') {
- ch = _char; // remember the x or X to use it in the error message below.
+ 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.
// 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);
+ if (!isHexDigit(_state.currentChar)) {
+ _state.errorCode = IllegalNumber;
+ _state.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);
+ int digit = ::hexDigit(_state.currentChar);
if (digit < 0)
break;
d *= 16;
@@ -1113,23 +1106,26 @@ int Lexer::scanNumber(QChar ch)
scanChar();
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char == u'o' || _char == u'O') {
- ch = _char; // remember the o or O to use it in the error message below.
+ } else if (_state.currentChar == u'o' || _state.currentChar == u'O') {
+ ch = _state.currentChar; // remember the o or O to use it in the error message below.
// parse octal integer literal
scanChar(); // consume 'o'
- if (!isOctalDigit(_char.unicode())) {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one octal digit is required after '0%1'").arg(ch);
+ if (!isOctalDigit(_state.currentChar.unicode())) {
+ _state.errorCode = IllegalNumber;
+ _state.errorMessage =
+ QCoreApplication::translate(
+ "QQmlParser", "At least one octal digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
- int digit = ::octalDigit(_char);
+ int digit = ::octalDigit(_state.currentChar);
if (digit < 0)
break;
d *= 8;
@@ -1137,37 +1133,41 @@ int Lexer::scanNumber(QChar ch)
scanChar();
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char == u'b' || _char == u'B') {
- ch = _char; // remember the b or B to use it in the error message below.
+ } else if (_state.currentChar == u'b' || _state.currentChar == u'B') {
+ ch = _state.currentChar; // remember the b or B to use it in the error message below.
// parse binary integer literal
scanChar(); // consume 'b'
- if (_char.unicode() != u'0' && _char.unicode() != u'1') {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one binary digit is required after '0%1'").arg(ch);
+ if (_state.currentChar.unicode() != u'0' && _state.currentChar.unicode() != u'1') {
+ _state.errorCode = IllegalNumber;
+ _state.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() == u'1')
+ if (_state.currentChar.unicode() == u'1')
digit = 1;
- else if (_char.unicode() != u'0')
+ else if (_state.currentChar.unicode() != u'0')
break;
d *= 2;
d += digit;
scanChar();
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char.isDigit() && !qmlMode()) {
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
+ } else if (_state.currentChar.isDigit() && !qmlMode()) {
+ _state.errorCode = IllegalCharacter;
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Decimal numbers can't start with '0'");
return T_ERROR;
}
}
@@ -1177,36 +1177,37 @@ int Lexer::scanNumber(QChar ch)
chars.append(ch.unicode());
if (ch != u'.') {
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume the digit
}
- if (_char == u'.') {
- chars.append(_char.unicode());
+ if (_state.currentChar == u'.') {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume `.'
}
}
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar();
}
- if (_char == u'e' || _char == u'E') {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == u'+' || _codePtr[0] == u'-') &&
- _codePtr[1].isDigit())) {
+ if (_state.currentChar == u'e' || _state.currentChar == u'E') {
+ if (_state.codePtr[0].isDigit()
+ || ((_state.codePtr[0] == u'+' || _state.codePtr[0] == u'-')
+ && _state.codePtr[1].isDigit())) {
- chars.append(_char.unicode());
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume `e'
- if (_char == u'+' || _char == u'-') {
- chars.append(_char.unicode());
+ if (_state.currentChar == u'+' || _state.currentChar == u'-') {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume the sign
}
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar();
}
}
@@ -1216,11 +1217,12 @@ int Lexer::scanNumber(QChar ch)
const char *end = nullptr;
bool ok = false;
- _tokenValue = qstrntod(begin, chars.size(), &end, &ok);
+ _state.tokenValue = qstrntod(begin, chars.size(), &end, &ok);
if (end - begin != chars.size()) {
- _errorCode = IllegalExponentIndicator;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+ _state.errorCode = IllegalExponentIndicator;
+ _state.errorMessage =
+ QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
return T_ERROR;
}
@@ -1230,108 +1232,114 @@ int Lexer::scanNumber(QChar ch)
int Lexer::scanVersionNumber(QChar ch)
{
if (ch == u'0') {
- _tokenValue = 0;
+ _state.tokenValue = 0;
return T_VERSION_NUMBER;
}
int acc = 0;
acc += ch.digitValue();
- while (_char.isDigit()) {
+ while (_state.currentChar.isDigit()) {
acc *= 10;
- acc += _char.digitValue();
+ acc += _state.currentChar.digitValue();
scanChar(); // consume the digit
}
- _tokenValue = acc;
+ _state.tokenValue = acc;
return T_VERSION_NUMBER;
}
bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
{
- _tokenText.resize(0);
- _validTokenText = true;
- _patternFlags = 0;
+ _state.tokenText.resize(0);
+ _state.validTokenText = true;
+ _state.patternFlags = 0;
if (prefix == EqualPrefix)
- _tokenText += u'=';
+ _state.tokenText += u'=';
while (true) {
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
case u'/':
scanChar();
// scan the flags
- _patternFlags = 0;
- while (isIdentLetter(_char)) {
- int flag = regExpFlagFromChar(_char);
- if (flag == 0 || _patternFlags & flag) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Invalid regular expression flag '%0'")
- .arg(QChar(_char));
+ _state.patternFlags = 0;
+ while (isIdentLetter(_state.currentChar)) {
+ int flag = regExpFlagFromChar(_state.currentChar);
+ if (flag == 0 || _state.patternFlags & flag) {
+ _state.errorMessage =
+ QCoreApplication::translate("QQmlParser",
+ "Invalid regular expression flag '%0'")
+ .arg(QChar(_state.currentChar));
return false;
}
- _patternFlags |= flag;
+ _state.patternFlags |= flag;
scanChar();
}
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ _state.tokenLength = _state.codePtr - _state.tokenStartPtr - 1;
return true;
case u'\\':
// regular expression backslash sequence
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
- if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ if (_state.codePtr > _endPtr || isLineTerminator()) {
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression backslash sequence");
return false;
}
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
break;
case u'[':
// regular expression class
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
- while (_codePtr <= _endPtr && ! isLineTerminator()) {
- if (_char == u']')
+ while (_state.codePtr <= _endPtr && !isLineTerminator()) {
+ if (_state.currentChar == u']')
break;
- else if (_char == u'\\') {
+ else if (_state.currentChar == u'\\') {
// regular expression backslash sequence
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
- if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ if (_state.codePtr > _endPtr || isLineTerminator()) {
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression backslash sequence");
return false;
}
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
} else {
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
}
}
- if (_char != u']') {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression class");
+ if (_state.currentChar != u']') {
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression class");
return false;
}
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar(); // skip ]
break;
default:
- if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression literal");
+ if (_state.codePtr > _endPtr || isLineTerminator()) {
+ _state.errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression literal");
return false;
} else {
- _tokenText += _char;
+ _state.tokenText += _state.currentChar;
scanChar();
}
} // switch
@@ -1342,7 +1350,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
bool Lexer::isLineTerminator() const
{
- const ushort unicode = _char.unicode();
+ const ushort unicode = _state.currentChar.unicode();
return unicode == 0x000Au
|| unicode == 0x000Du
|| unicode == 0x2028u
@@ -1351,13 +1359,13 @@ bool Lexer::isLineTerminator() const
unsigned Lexer::isLineTerminatorSequence() const
{
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
case 0x000Au:
case 0x2028u:
case 0x2029u:
return 1;
case 0x000Du:
- if (_codePtr->unicode() == 0x000Au)
+ if (_state.codePtr->unicode() == 0x000Au)
return 2;
else
return 1;
@@ -1398,54 +1406,52 @@ bool Lexer::isOctalDigit(ushort c)
QString Lexer::tokenText() const
{
- if (_validTokenText)
- return _tokenText;
+ if (_state.validTokenText)
+ return _state.tokenText;
- if (_tokenKind == T_STRING_LITERAL)
- return QString(_tokenStartPtr + 1, _tokenLength - 2);
+ if (_state.tokenKind == T_STRING_LITERAL)
+ return QString(_state.tokenStartPtr + 1, _state.tokenLength - 2);
- return QString(_tokenStartPtr, _tokenLength);
+ return QString(_state.tokenStartPtr, _state.tokenLength);
}
Lexer::Error Lexer::errorCode() const
{
- return _errorCode;
+ return _state.errorCode;
}
QString Lexer::errorMessage() const
{
- return _errorMessage;
+ return _state.errorMessage;
}
void Lexer::syncProhibitAutomaticSemicolon()
{
- if (_parenthesesState == BalancedParentheses) {
+ if (_state.parenthesesState == BalancedParentheses) {
// we have seen something like "if (foo)", which means we should
// never insert an automatic semicolon at this point, since it would
// then be expanded into an empty statement (ECMA-262 7.9.1)
- _prohibitAutomaticSemicolon = true;
- _parenthesesState = IgnoreParentheses;
+ _state.prohibitAutomaticSemicolon = true;
+ _state.parenthesesState = IgnoreParentheses;
} else {
- _prohibitAutomaticSemicolon = false;
+ _state.prohibitAutomaticSemicolon = false;
}
}
bool Lexer::prevTerminator() const
{
- return _terminator;
+ return _state.terminator;
}
bool Lexer::followsClosingBrace() const
{
- return _followsClosingBrace;
+ return _state.followsClosingBrace;
}
bool Lexer::canInsertAutomaticSemicolon(int token) const
{
- return token == T_RBRACE
- || token == EOF_SYMBOL
- || _terminator
- || _followsClosingBrace;
+ return token == T_RBRACE || token == EOF_SYMBOL || _state.terminator
+ || _state.followsClosingBrace;
}
static const int uriTokens[] = {
@@ -1509,12 +1515,12 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
error->loc.startColumn = tokenStartColumn();
};
- QScopedValueRollback<bool> directivesGuard(_handlingDirectives, true);
+ QScopedValueRollback<bool> directivesGuard(_state.handlingDirectives, true);
Q_ASSERT(!_qmlMode);
lex(); // fetch the first token
- if (_tokenKind != T_DOT)
+ if (_state.tokenKind != T_DOT)
return true;
do {
@@ -1523,7 +1529,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
lex(); // skip T_DOT
- if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_IMPORT))
+ if (!(_state.tokenKind == T_IDENTIFIER || _state.tokenKind == T_IMPORT))
return true; // expected a valid QML/JS directive
const QString directiveName = tokenText();
@@ -1553,7 +1559,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
QString version;
bool fileImport = false; // file or uri import
- if (_tokenKind == T_STRING_LITERAL) {
+ if (_state.tokenKind == T_STRING_LITERAL) {
// .import T_STRING_LITERAL as T_IDENTIFIER
fileImport = true;
@@ -1565,10 +1571,10 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
}
lex();
- } else if (_tokenKind == T_IDENTIFIER) {
+ } else if (_state.tokenKind == T_IDENTIFIER) {
// .import T_IDENTIFIER (. T_IDENTIFIER)* (T_VERSION_NUMBER (. T_VERSION_NUMBER)?)? as T_IDENTIFIER
while (true) {
- if (!isUriToken(_tokenKind)) {
+ if (!isUriToken(_state.tokenKind)) {
setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
@@ -1580,7 +1586,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
- if (_tokenKind != QQmlJSGrammar::T_DOT)
+ if (_state.tokenKind != QQmlJSGrammar::T_DOT)
break;
pathOrUri.append(u'.');
@@ -1592,13 +1598,13 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
}
}
- if (_tokenKind == T_VERSION_NUMBER) {
+ if (_state.tokenKind == T_VERSION_NUMBER) {
version = tokenText();
lex();
- if (_tokenKind == T_DOT) {
+ if (_state.tokenKind == T_DOT) {
version += u'.';
lex();
- if (_tokenKind != T_VERSION_NUMBER) {
+ if (_state.tokenKind != T_VERSION_NUMBER) {
setError(QCoreApplication::translate(
"QQmlParser", "Incomplete version number (dot but no minor)"));
return false; // expected the module version number
@@ -1612,7 +1618,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
//
// recognize the mandatory `as' followed by the module name
//
- if (! (_tokenKind == T_AS && tokenStartLine() == lineNumber)) {
+ if (!(_state.tokenKind == T_AS && tokenStartLine() == lineNumber)) {
if (fileImport)
setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier"));
else
@@ -1651,7 +1657,16 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
// fetch the first token after the .pragma/.import directive
lex();
- } while (_tokenKind == T_DOT);
+ } while (_state.tokenKind == T_DOT);
return true;
}
+
+const Lexer::State &Lexer::state() const
+{
+ return _state;
+}
+void Lexer::setState(const Lexer::State &state)
+{
+ _state = state;
+}
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index b7ac4a3940..8c2f526de5 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -144,7 +144,7 @@ public:
}
bool qmlMode() const;
- bool yieldIsKeyWord() const { return _generatorLevel != 0; }
+ bool yieldIsKeyWord() const { return _state.generatorLevel != 0; }
void setStaticIsKeyword(bool b) { _staticIsKeyword = b; }
QString code() const;
@@ -155,19 +155,19 @@ public:
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
bool scanDirectives(Directives *directives, DiagnosticMessage *error);
- int regExpFlags() const { return _patternFlags; }
- QString regExpPattern() const { return _tokenText; }
+ int regExpFlags() const { return _state.patternFlags; }
+ QString regExpPattern() const { return _state.tokenText; }
- int tokenKind() const { return _tokenKind; }
- int tokenOffset() const { return _tokenStartPtr - _code.unicode(); }
- int tokenLength() const { return _tokenLength; }
+ int tokenKind() const { return _state.tokenKind; }
+ int tokenOffset() const { return _state.tokenStartPtr - _code.unicode(); }
+ int tokenLength() const { return _state.tokenLength; }
- int tokenStartLine() const { return _tokenLine; }
- int tokenStartColumn() const { return _tokenColumn; }
+ int tokenStartLine() const { return _state.tokenLine; }
+ int tokenStartColumn() const { return _state.tokenColumn; }
- inline QStringView tokenSpell() const { return _tokenSpell; }
- inline QStringView rawString() const { return _rawString; }
- double tokenValue() const { return _tokenValue; }
+ inline QStringView tokenSpell() const { return _state.tokenSpell; }
+ inline QStringView rawString() const { return _state.rawString; }
+ double tokenValue() const { return _state.tokenValue; }
QString tokenText() const;
Error errorCode() const;
@@ -183,8 +183,56 @@ public:
BalancedParentheses
};
- void enterGeneratorBody() { ++_generatorLevel; }
- void leaveGeneratorBody() { --_generatorLevel; }
+ void enterGeneratorBody() { ++_state.generatorLevel; }
+ void leaveGeneratorBody() { --_state.generatorLevel; }
+
+ struct State
+ {
+ QString tokenText;
+ QString errorMessage;
+ QStringView tokenSpell;
+ QStringView rawString;
+
+ const QChar *codePtr = nullptr;
+ const QChar *tokenStartPtr = nullptr;
+
+ QChar currentChar = u'\n';
+ Error errorCode = NoError;
+
+ int currentLineNumber = 0;
+ int currentColumnNumber = 0;
+ double tokenValue = 0;
+
+ // parentheses state
+ ParenthesesState parenthesesState = IgnoreParentheses;
+ int parenthesesCount = 0;
+
+ // template string stack
+ QStack<int> outerTemplateBraceCount;
+ int bracesCount = -1;
+
+ int stackToken = -1;
+
+ int patternFlags = 0;
+ int tokenKind = 0;
+ int tokenLength = 0;
+ int tokenLine = 0;
+ int tokenColumn = 0;
+ ImportState importState = ImportState::NoQmlImport;
+
+ bool validTokenText = false;
+ bool prohibitAutomaticSemicolon = false;
+ bool restrictedKeyword = false;
+ bool terminator = false;
+ bool followsClosingBrace = false;
+ bool delimited = true;
+ bool skipLinefeed = false;
+ bool handlingDirectives = false;
+ int generatorLevel = 0;
+ };
+
+ const State &state() const;
+ void setState(const State &state);
protected:
static int classify(const QChar *s, int n, int parseModeFlags);
@@ -218,50 +266,11 @@ private:
Engine *_engine;
QString _code;
- QString _tokenText;
- QString _errorMessage;
- QStringView _tokenSpell;
- QStringView _rawString;
-
- const QChar *_codePtr;
const QChar *_endPtr;
- const QChar *_tokenStartPtr;
-
- QChar _char;
- Error _errorCode;
-
- int _currentLineNumber;
- int _currentColumnNumber;
- double _tokenValue;
-
- // parentheses state
- ParenthesesState _parenthesesState;
- int _parenthesesCount;
-
- // template string stack
- QStack<int> _outerTemplateBraceCount;
- int _bracesCount = -1;
-
- int _stackToken;
-
- int _patternFlags;
- int _tokenKind;
- int _tokenLength;
- int _tokenLine;
- int _tokenColumn;
- ImportState _importState = ImportState::NoQmlImport;
-
- bool _validTokenText;
- bool _prohibitAutomaticSemicolon;
- bool _restrictedKeyword;
- bool _terminator;
- bool _followsClosingBrace;
- bool _delimited;
bool _qmlMode;
- bool _skipLinefeed = false;
- int _generatorLevel = 0;
bool _staticIsKeyword = false;
- bool _handlingDirectives = false;
+
+ State _state;
};
} // end of namespace QQmlJS