Files
qt-creator/src/libs/qmljs/parser/qmljslexer_p.h

311 lines
8.6 KiB
C
Raw Normal View History

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
//
// 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.
//
#include "qmljs/parser/qmljsglobal_p.h"
#include "qmljs/parser/qmljsgrammar_p.h"
#include <QtCore/qstring.h>
#include <QtCore/qstack.h>
QT_BEGIN_NAMESPACE
class QDebug;
QT_END_NAMESPACE
QT_QML_BEGIN_NAMESPACE
namespace QmlJS {
class Engine;
class DiagnosticMessage;
class Directives;
class QML_PARSER_EXPORT Lexer: public QmlJSGrammar
{
public:
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,
T_VOLATILE = T_RESERVED_WORD
};
enum Error {
NoError,
IllegalCharacter,
IllegalNumber,
UnclosedStringLiteral,
IllegalEscapeSequence,
IllegalUnicodeEscapeSequence,
UnclosedComment,
IllegalExponentIndicator,
IllegalIdentifier,
IllegalHexadecimalEscapeSequence
};
enum RegExpBodyPrefix {
NoPrefix,
EqualPrefix
};
enum RegExpFlag {
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04,
RegExp_Unicode = 0x08,
RegExp_Sticky = 0x10
};
enum ParseModeFlags {
QmlMode = 0x1,
YieldIsKeyword = 0x2,
StaticIsKeyword = 0x4
};
enum class ImportState {
SawImport,
NoQmlImport
};
enum class LexMode { WholeCode, LineByLine };
enum class CodeContinuation { Reset, Continue };
public:
Lexer(Engine *engine, LexMode lexMode = LexMode::WholeCode);
int parseModeFlags() const {
int flags = 0;
if (qmlMode())
flags |= QmlMode|StaticIsKeyword;
if (yieldIsKeyWord())
flags |= YieldIsKeyword;
if (_staticIsKeyword)
flags |= StaticIsKeyword;
return flags;
}
bool qmlMode() const;
bool yieldIsKeyWord() const { return _state.generatorLevel != 0; }
void setStaticIsKeyword(bool b) { _staticIsKeyword = b; }
QString code() const;
void setCode(const QString &code,
int lineno,
bool qmlMode = true,
CodeContinuation codeContinuation = CodeContinuation::Reset);
int lex();
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
bool scanDirectives(Directives *directives, DiagnosticMessage *error);
int regExpFlags() const { return _state.patternFlags; }
QString regExpPattern() const { return _tokenText; }
int tokenKind() const { return _state.tokenKind; }
int tokenOffset() const { return _currentOffset + _tokenStartPtr - _code.unicode(); }
int tokenLength() const { return _tokenLength; }
int tokenStartLine() const { return _tokenLine; }
int tokenStartColumn() const { return _tokenColumn; }
inline QStringView tokenSpell() const { return _tokenSpell; }
inline QStringView rawString() const { return _rawString; }
double tokenValue() const { return _state.tokenValue; }
QString tokenText() const;
Error errorCode() const;
QString errorMessage() const;
bool prevTerminator() const;
bool followsClosingBrace() const;
bool canInsertAutomaticSemicolon(int token) const;
enum ParenthesesState {
IgnoreParentheses,
CountParentheses,
BalancedParentheses
};
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);
protected:
static int classify(const QChar *s, int n, int parseModeFlags);
private:
inline void scanChar();
inline QChar peekChar();
int scanToken();
int scanNumber(QChar ch);
int scanVersionNumber(QChar ch);
enum ScanStringMode {
SingleQuote = '\'',
DoubleQuote = '"',
TemplateHead = '`',
TemplateContinuation = 0
};
int scanString(ScanStringMode mode);
bool isLineTerminator() const;
unsigned isLineTerminatorSequence() const;
static bool isIdentLetter(QChar c);
static bool isDecimalDigit(ushort c);
static bool isHexDigit(QChar c);
static bool isOctalDigit(ushort c);
void syncProhibitAutomaticSemicolon();
uint decodeUnicodeEscapeCharacter(bool *ok);
QChar decodeHexEscapeCharacter(bool *ok);
friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, const Lexer &l);
private:
Engine *_engine;
LexMode _lexMode = LexMode::WholeCode;
QString _code;
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;
QString _tokenText;
QString _errorMessage;
QStringView _tokenSpell;
QStringView _rawString;
const QChar *_codePtr = nullptr;
const QChar *_tokenStartPtr = nullptr;
State _state;
};
} // end of namespace QmlJS
QT_QML_END_NAMESPACE