2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2021 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2016-03-18 07:55:01 +01:00
|
|
|
#pragma once
|
2010-01-18 13:13:34 +01:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// W A R N I N G
|
|
|
|
|
// -------------
|
|
|
|
|
//
|
|
|
|
|
// This file is not part of the Qt API. It exists purely as an
|
|
|
|
|
// implementation detail. This header file may change from version to
|
|
|
|
|
// version without notice, or even be removed.
|
|
|
|
|
//
|
|
|
|
|
// We mean it.
|
|
|
|
|
//
|
|
|
|
|
|
2020-02-28 17:51:32 +01:00
|
|
|
#include "qmljs/parser/qmljsglobal_p.h"
|
|
|
|
|
#include "qmljs/parser/qmljsgrammar_p.h"
|
2013-11-06 14:17:23 +01:00
|
|
|
|
|
|
|
|
#include <QtCore/qstring.h>
|
2018-10-16 15:32:58 +02:00
|
|
|
#include <QtCore/qstack.h>
|
2010-01-18 13:13:34 +01:00
|
|
|
|
|
|
|
|
QT_QML_BEGIN_NAMESPACE
|
|
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
class QDebug;
|
|
|
|
|
|
2010-01-18 13:13:34 +01:00
|
|
|
namespace QmlJS {
|
|
|
|
|
|
|
|
|
|
class Engine;
|
2016-04-29 11:00:30 +02:00
|
|
|
class DiagnosticMessage;
|
2018-10-16 15:32:58 +02:00
|
|
|
class Directives;
|
2011-09-19 14:09:26 +02:00
|
|
|
|
2011-09-13 08:42:52 +02:00
|
|
|
class QML_PARSER_EXPORT Lexer: public QmlJSGrammar
|
2010-01-18 13:13:34 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2011-09-13 08:42:52 +02:00
|
|
|
enum {
|
|
|
|
|
T_ABSTRACT = T_RESERVED_WORD,
|
|
|
|
|
T_BOOLEAN = T_RESERVED_WORD,
|
|
|
|
|
T_BYTE = T_RESERVED_WORD,
|
|
|
|
|
T_CHAR = T_RESERVED_WORD,
|
|
|
|
|
T_DOUBLE = T_RESERVED_WORD,
|
|
|
|
|
T_FINAL = T_RESERVED_WORD,
|
|
|
|
|
T_FLOAT = T_RESERVED_WORD,
|
|
|
|
|
T_GOTO = T_RESERVED_WORD,
|
|
|
|
|
T_IMPLEMENTS = T_RESERVED_WORD,
|
|
|
|
|
T_INT = T_RESERVED_WORD,
|
|
|
|
|
T_INTERFACE = T_RESERVED_WORD,
|
|
|
|
|
T_LONG = T_RESERVED_WORD,
|
|
|
|
|
T_NATIVE = T_RESERVED_WORD,
|
|
|
|
|
T_PACKAGE = T_RESERVED_WORD,
|
|
|
|
|
T_PRIVATE = T_RESERVED_WORD,
|
|
|
|
|
T_PROTECTED = T_RESERVED_WORD,
|
|
|
|
|
T_SHORT = T_RESERVED_WORD,
|
|
|
|
|
T_SYNCHRONIZED = T_RESERVED_WORD,
|
|
|
|
|
T_THROWS = T_RESERVED_WORD,
|
|
|
|
|
T_TRANSIENT = T_RESERVED_WORD,
|
2013-01-22 11:15:23 +01:00
|
|
|
T_VOLATILE = T_RESERVED_WORD
|
2011-09-13 08:42:52 +02:00
|
|
|
};
|
2010-01-18 13:13:34 +01:00
|
|
|
|
|
|
|
|
enum Error {
|
|
|
|
|
NoError,
|
|
|
|
|
IllegalCharacter,
|
2018-10-16 15:32:58 +02:00
|
|
|
IllegalNumber,
|
2010-01-18 13:13:34 +01:00
|
|
|
UnclosedStringLiteral,
|
|
|
|
|
IllegalEscapeSequence,
|
|
|
|
|
IllegalUnicodeEscapeSequence,
|
|
|
|
|
UnclosedComment,
|
|
|
|
|
IllegalExponentIndicator,
|
2013-11-06 14:17:23 +01:00
|
|
|
IllegalIdentifier,
|
|
|
|
|
IllegalHexadecimalEscapeSequence
|
2010-01-18 13:13:34 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum RegExpBodyPrefix {
|
|
|
|
|
NoPrefix,
|
|
|
|
|
EqualPrefix
|
|
|
|
|
};
|
|
|
|
|
|
2011-09-19 14:09:26 +02:00
|
|
|
enum RegExpFlag {
|
|
|
|
|
RegExp_Global = 0x01,
|
|
|
|
|
RegExp_IgnoreCase = 0x02,
|
2018-10-16 15:32:58 +02:00
|
|
|
RegExp_Multiline = 0x04,
|
|
|
|
|
RegExp_Unicode = 0x08,
|
|
|
|
|
RegExp_Sticky = 0x10
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum ParseModeFlags {
|
|
|
|
|
QmlMode = 0x1,
|
|
|
|
|
YieldIsKeyword = 0x2,
|
|
|
|
|
StaticIsKeyword = 0x4
|
2011-09-19 14:09:26 +02:00
|
|
|
};
|
|
|
|
|
|
2019-10-04 16:11:02 +02:00
|
|
|
enum class ImportState {
|
|
|
|
|
SawImport,
|
|
|
|
|
NoQmlImport
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
enum class LexMode { WholeCode, LineByLine };
|
|
|
|
|
|
|
|
|
|
enum class CodeContinuation { Reset, Continue };
|
|
|
|
|
|
2011-09-13 08:42:52 +02:00
|
|
|
public:
|
2022-12-19 14:00:30 +01:00
|
|
|
Lexer(Engine *engine, LexMode lexMode = LexMode::WholeCode);
|
2011-09-13 08:42:52 +02:00
|
|
|
|
2018-10-16 15:32:58 +02:00
|
|
|
int parseModeFlags() const {
|
|
|
|
|
int flags = 0;
|
|
|
|
|
if (qmlMode())
|
|
|
|
|
flags |= QmlMode|StaticIsKeyword;
|
|
|
|
|
if (yieldIsKeyWord())
|
|
|
|
|
flags |= YieldIsKeyword;
|
|
|
|
|
if (_staticIsKeyword)
|
|
|
|
|
flags |= StaticIsKeyword;
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-07 11:16:26 +01:00
|
|
|
bool qmlMode() const;
|
2022-12-19 14:00:30 +01:00
|
|
|
bool yieldIsKeyWord() const { return _state.generatorLevel != 0; }
|
2018-10-16 15:32:58 +02:00
|
|
|
void setStaticIsKeyword(bool b) { _staticIsKeyword = b; }
|
2011-12-07 11:16:26 +01:00
|
|
|
|
2011-09-13 08:42:52 +02:00
|
|
|
QString code() const;
|
2022-12-19 14:00:30 +01:00
|
|
|
void setCode(const QString &code,
|
|
|
|
|
int lineno,
|
|
|
|
|
bool qmlMode = true,
|
|
|
|
|
CodeContinuation codeContinuation = CodeContinuation::Reset);
|
2011-09-13 08:42:52 +02:00
|
|
|
|
|
|
|
|
int lex();
|
|
|
|
|
|
2010-01-18 13:13:34 +01:00
|
|
|
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
|
2016-04-29 11:00:30 +02:00
|
|
|
bool scanDirectives(Directives *directives, DiagnosticMessage *error);
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
int regExpFlags() const { return _state.patternFlags; }
|
2011-09-13 08:42:52 +02:00
|
|
|
QString regExpPattern() const { return _tokenText; }
|
|
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
int tokenKind() const { return _state.tokenKind; }
|
|
|
|
|
int tokenOffset() const { return _currentOffset + _tokenStartPtr - _code.unicode(); }
|
2012-07-31 10:12:26 +02:00
|
|
|
int tokenLength() const { return _tokenLength; }
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2012-07-31 10:12:26 +02:00
|
|
|
int tokenStartLine() const { return _tokenLine; }
|
2018-10-16 15:32:58 +02:00
|
|
|
int tokenStartColumn() const { return _tokenColumn; }
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2020-09-16 15:08:57 +02:00
|
|
|
inline QStringView tokenSpell() const { return _tokenSpell; }
|
|
|
|
|
inline QStringView rawString() const { return _rawString; }
|
2022-12-19 14:00:30 +01:00
|
|
|
double tokenValue() const { return _state.tokenValue; }
|
2011-09-13 08:42:52 +02:00
|
|
|
QString tokenText() const;
|
|
|
|
|
|
|
|
|
|
Error errorCode() const;
|
|
|
|
|
QString errorMessage() const;
|
|
|
|
|
|
|
|
|
|
bool prevTerminator() const;
|
2011-09-19 14:09:26 +02:00
|
|
|
bool followsClosingBrace() const;
|
|
|
|
|
bool canInsertAutomaticSemicolon(int token) const;
|
2011-09-13 08:42:52 +02:00
|
|
|
|
|
|
|
|
enum ParenthesesState {
|
|
|
|
|
IgnoreParentheses,
|
|
|
|
|
CountParentheses,
|
|
|
|
|
BalancedParentheses
|
|
|
|
|
};
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
enum class CommentState { NoComment, HadComment, InMultilineComment };
|
|
|
|
|
|
|
|
|
|
void enterGeneratorBody() { ++_state.generatorLevel; }
|
|
|
|
|
void leaveGeneratorBody() { --_state.generatorLevel; }
|
|
|
|
|
|
|
|
|
|
struct State
|
|
|
|
|
{
|
|
|
|
|
Error errorCode = NoError;
|
|
|
|
|
|
|
|
|
|
QChar currentChar = u'\n';
|
|
|
|
|
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;
|
|
|
|
|
ImportState importState = ImportState::NoQmlImport;
|
|
|
|
|
|
|
|
|
|
bool validTokenText = false;
|
|
|
|
|
bool prohibitAutomaticSemicolon = false;
|
|
|
|
|
bool restrictedKeyword = false;
|
|
|
|
|
bool terminator = false;
|
|
|
|
|
bool followsClosingBrace = false;
|
|
|
|
|
bool delimited = true;
|
|
|
|
|
bool handlingDirectives = false;
|
|
|
|
|
CommentState comments = CommentState::NoComment;
|
|
|
|
|
int generatorLevel = 0;
|
|
|
|
|
|
|
|
|
|
friend bool operator==(State const &s1, State const &s2)
|
|
|
|
|
{
|
|
|
|
|
if (s1.errorCode != s2.errorCode)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.currentChar != s2.currentChar)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.tokenValue != s2.tokenValue)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.parenthesesState != s2.parenthesesState)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.parenthesesCount != s2.parenthesesCount)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.outerTemplateBraceCount != s2.outerTemplateBraceCount)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.bracesCount != s2.bracesCount)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.stackToken != s2.stackToken)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.patternFlags != s2.patternFlags)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.tokenKind != s2.tokenKind)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.importState != s2.importState)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.validTokenText != s2.validTokenText)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.prohibitAutomaticSemicolon != s2.prohibitAutomaticSemicolon)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.restrictedKeyword != s2.restrictedKeyword)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.terminator != s2.terminator)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.followsClosingBrace != s2.followsClosingBrace)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.delimited != s2.delimited)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.handlingDirectives != s2.handlingDirectives)
|
|
|
|
|
return false;
|
|
|
|
|
if (s1.generatorLevel != s2.generatorLevel)
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend bool operator!=(State const &s1, State const &s2) { return !(s1 == s2); }
|
|
|
|
|
|
|
|
|
|
friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, State const &s);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const State &state() const;
|
|
|
|
|
void setState(const State &state);
|
2018-10-16 15:32:58 +02:00
|
|
|
|
2011-12-07 11:16:26 +01:00
|
|
|
protected:
|
2018-10-16 15:32:58 +02:00
|
|
|
static int classify(const QChar *s, int n, int parseModeFlags);
|
2011-12-07 11:16:26 +01:00
|
|
|
|
2010-01-18 13:13:34 +01:00
|
|
|
private:
|
2011-09-13 08:42:52 +02:00
|
|
|
inline void scanChar();
|
2021-07-06 23:50:30 +02:00
|
|
|
inline QChar peekChar();
|
2011-09-13 08:42:52 +02:00
|
|
|
int scanToken();
|
2012-07-31 10:12:26 +02:00
|
|
|
int scanNumber(QChar ch);
|
2019-10-04 16:11:02 +02:00
|
|
|
int scanVersionNumber(QChar ch);
|
2018-10-16 15:32:58 +02:00
|
|
|
enum ScanStringMode {
|
|
|
|
|
SingleQuote = '\'',
|
|
|
|
|
DoubleQuote = '"',
|
|
|
|
|
TemplateHead = '`',
|
|
|
|
|
TemplateContinuation = 0
|
|
|
|
|
};
|
|
|
|
|
int scanString(ScanStringMode mode);
|
2011-09-13 08:42:52 +02:00
|
|
|
|
2010-01-18 13:13:34 +01:00
|
|
|
bool isLineTerminator() const;
|
2013-01-22 11:15:23 +01:00
|
|
|
unsigned isLineTerminatorSequence() const;
|
2011-09-13 08:42:52 +02:00
|
|
|
static bool isIdentLetter(QChar c);
|
2010-01-18 13:13:34 +01:00
|
|
|
static bool isDecimalDigit(ushort c);
|
2011-09-13 08:42:52 +02:00
|
|
|
static bool isHexDigit(QChar c);
|
|
|
|
|
static bool isOctalDigit(ushort c);
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2011-09-13 08:42:52 +02:00
|
|
|
void syncProhibitAutomaticSemicolon();
|
2018-10-16 15:32:58 +02:00
|
|
|
uint decodeUnicodeEscapeCharacter(bool *ok);
|
2013-11-06 14:17:23 +01:00
|
|
|
QChar decodeHexEscapeCharacter(bool *ok);
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, const Lexer &l);
|
|
|
|
|
|
2010-01-18 13:13:34 +01:00
|
|
|
private:
|
2011-09-13 08:42:52 +02:00
|
|
|
Engine *_engine;
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
LexMode _lexMode = LexMode::WholeCode;
|
2011-09-13 08:42:52 +02:00
|
|
|
QString _code;
|
2022-12-19 14:00:30 +01:00
|
|
|
const QChar *_endPtr;
|
|
|
|
|
bool _qmlMode;
|
|
|
|
|
bool _staticIsKeyword = false;
|
|
|
|
|
|
|
|
|
|
bool _skipLinefeed = false;
|
|
|
|
|
|
|
|
|
|
int _currentLineNumber = 0;
|
|
|
|
|
int _currentColumnNumber = 0;
|
|
|
|
|
int _currentOffset = 0;
|
|
|
|
|
|
|
|
|
|
int _tokenLength = 0;
|
|
|
|
|
int _tokenLine = 0;
|
|
|
|
|
int _tokenColumn = 0;
|
|
|
|
|
|
2011-09-13 08:42:52 +02:00
|
|
|
QString _tokenText;
|
|
|
|
|
QString _errorMessage;
|
2020-09-16 15:08:57 +02:00
|
|
|
QStringView _tokenSpell;
|
|
|
|
|
QStringView _rawString;
|
2010-01-18 13:13:34 +01:00
|
|
|
|
2022-12-19 14:00:30 +01:00
|
|
|
const QChar *_codePtr = nullptr;
|
|
|
|
|
const QChar *_tokenStartPtr = nullptr;
|
|
|
|
|
|
|
|
|
|
State _state;
|
2010-01-18 13:13:34 +01:00
|
|
|
};
|
|
|
|
|
|
2011-09-13 08:42:52 +02:00
|
|
|
} // end of namespace QmlJS
|
2010-01-18 13:13:34 +01:00
|
|
|
|
|
|
|
|
QT_QML_END_NAMESPACE
|
2017-03-16 17:13:46 +01:00
|
|
|
|