diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 8 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 39 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 6 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 30 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastfwd_p.h | 4 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor_p.h | 2 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 60 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer_p.h | 8 |
8 files changed, 139 insertions, 18 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 9d09842af4..7ed0a01cb0 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -649,11 +649,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node) return false; } - if (node->versionToken.isValid()) { - int major, minor; - extractVersion(textRefAt(node->versionToken), &major, &minor); - import->majorVersion = major; - import->minorVersion = minor; + if (node->version) { + import->majorVersion = node->version->majorVersion; + import->minorVersion = node->version->minorVersion; } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version")); return false; diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index aada928dea..daaa402ef1 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -58,6 +58,7 @@ %token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--" %token T_NEW "new" T_NOT "!" T_NOT_EQ "!=" %token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|" +%token T_VERSION_NUMBER "version number" %token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+" %token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?" %token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%" @@ -315,6 +316,7 @@ public: AST::UiArrayMemberList *UiArrayMemberList; AST::UiQualifiedId *UiQualifiedId; AST::UiEnumMemberList *UiEnumMemberList; + AST::UiVersionSpecifier *UiVersionSpecifier; }; public: @@ -802,20 +804,47 @@ UiImport: UiImportHead T_SEMICOLON; } break; ./ -UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON; -UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON; +UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER; /. case $rule_number: { - sym(1).UiImport->versionToken = loc(2); + auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, sym(3).dval); + version->majorToken = loc(1); + version->minorToken = loc(3); + sym(1).UiVersionSpecifier = version; + } break; +./ + + +UiVersionSpecifier: T_VERSION_NUMBER; +/. + case $rule_number: { + auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0); + version->majorToken = loc(1); + sym(1).UiVersionSpecifier = version; + } break; +./ + +UiImport: UiImportHead UiVersionSpecifier T_AUTOMATIC_SEMICOLON; +UiImport: UiImportHead UiVersionSpecifier T_SEMICOLON; +/. + case $rule_number: { + auto versionToken = loc(2); + auto version = sym(2).UiVersionSpecifier; + sym(1).UiImport->version = version; + if (version->minorToken.isValid()) { + versionToken.length += version->minorToken.length + (version->minorToken.offset - versionToken.offset - versionToken.length); + } + sym(1).UiImport->versionToken = versionToken; sym(1).UiImport->semicolonToken = loc(3); } break; ./ -UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON; -UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_SEMICOLON; +UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON; +UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_SEMICOLON; /. case $rule_number: { sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->version = sym(2).UiVersionSpecifier; sym(1).UiImport->asToken = loc(3); sym(1).UiImport->importIdToken = loc(4); sym(1).UiImport->importId = stringRef(4); diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index e5817ab763..1bc0e6e364 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1472,6 +1472,12 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast() return this; } +void UiVersionSpecifier::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + visitor->endVisit(this); +} } } // namespace QQmlJS::AST QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index b81553776d..606137b67d 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -234,7 +234,6 @@ public: Kind_PatternProperty, Kind_PatternPropertyList, - Kind_UiArrayBinding, Kind_UiImport, Kind_UiObjectBinding, @@ -251,7 +250,8 @@ public: Kind_UiSourceElement, Kind_UiHeaderItemList, Kind_UiEnumDeclaration, - Kind_UiEnumMemberList + Kind_UiEnumMemberList, + Kind_UiVersionSpecifier }; inline Node() {} @@ -492,7 +492,30 @@ public: SourceLocation literalToken; }; -class QML_PARSER_EXPORT StringLiteral: public LeftHandSideExpression +class QML_PARSER_EXPORT UiVersionSpecifier : public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiVersionSpecifier) + + UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override { return majorToken; } + + SourceLocation lastSourceLocation() const override + { + return minorToken.isValid() ? minorToken : majorToken; + } + + // attributes: + int majorVersion; + int minorVersion; + SourceLocation majorToken; + SourceLocation minorToken; +}; + +class QML_PARSER_EXPORT StringLiteral : public LeftHandSideExpression { public: QQMLJS_DECLARE_AST_NODE(StringLiteral) @@ -2855,6 +2878,7 @@ public: SourceLocation asToken; SourceLocation importIdToken; SourceLocation semicolonToken; + UiVersionSpecifier *version = nullptr; }; class QML_PARSER_EXPORT UiObjectMember: public Node diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index e9caa918d5..6fe108e425 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -178,8 +178,10 @@ class UiQualifiedId; class UiHeaderItemList; class UiEnumDeclaration; class UiEnumMemberList; +class UiVersionSpecifier; -} } // namespace AST +} // namespace AST +} // namespace QQmlJS QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 9115449a46..f3732cbba8 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -111,6 +111,7 @@ public: virtual bool visit(UiQualifiedId *) { return true; } virtual bool visit(UiEnumDeclaration *) { return true; } virtual bool visit(UiEnumMemberList *) { return true; } + virtual bool visit(UiVersionSpecifier *) { return true; } virtual void endVisit(UiProgram *) {} virtual void endVisit(UiImport *) {} @@ -129,6 +130,7 @@ public: virtual void endVisit(UiQualifiedId *) {} virtual void endVisit(UiEnumDeclaration *) {} virtual void endVisit(UiEnumMemberList *) { } + virtual void endVisit(UiVersionSpecifier *) {} // QQmlJS virtual bool visit(ThisExpression *) { return true; } diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index 1b3b129c6a..165925d2a2 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -47,6 +47,7 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qdebug.h> +#include <QtCore/QScopedValueRollback> QT_BEGIN_NAMESPACE Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); @@ -271,16 +272,29 @@ int Lexer::lex() ++_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: @@ -620,6 +634,8 @@ again: return T_DIVIDE_; case '.': + if (_importState == ImportState::SawImport) + return T_DOT; if (isDecimalDigit(_char.unicode())) return scanNumber(ch); if (_char == QLatin1Char('.')) { @@ -730,7 +746,10 @@ again: case '7': case '8': case '9': - return scanNumber(ch); + if (_importState == ImportState::SawImport) + return scanVersionNumber(ch); + else + return scanNumber(ch); default: { uint c = ch.unicode(); @@ -1148,6 +1167,26 @@ int Lexer::scanNumber(QChar ch) return T_NUMERIC_LITERAL; } +int Lexer::scanVersionNumber(QChar ch) +{ + if (ch == QLatin1Char('0')) { + _tokenValue = 0; + return T_VERSION_NUMBER; + } + + int acc = 0; + acc += ch.digitValue(); + + while (_char.isDigit()) { + acc *= 10; + acc += _char.digitValue(); + scanChar(); // consume the digit + } + + _tokenValue = acc; + return T_VERSION_NUMBER; +} + bool Lexer::scanRegExp(RegExpBodyPrefix prefix) { _tokenText.resize(0); @@ -1410,6 +1449,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) error->column = tokenStartColumn(); }; + QScopedValueRollback<bool> directivesGuard(_handlingDirectives, true); Q_ASSERT(!_qmlMode); lex(); // fetch the first token @@ -1465,8 +1505,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) } } else if (_tokenKind == T_IDENTIFIER) { - // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER - + // .import T_IDENTIFIER (. T_IDENTIFIER)* T_VERSION_NUMBER . T_VERSION_NUMBER as T_IDENTIFIER while (true) { if (!isUriToken(_tokenKind)) { setError(QCoreApplication::translate("QQmlParser","Invalid module URI")); @@ -1492,12 +1531,25 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) } } - if (_tokenKind != T_NUMERIC_LITERAL) { + if (_tokenKind != T_VERSION_NUMBER) { setError(QCoreApplication::translate("QQmlParser","Module import requires a version")); return false; // expected the module version number } version = tokenText(); + lex(); + if (_tokenKind != T_DOT) { + setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing dot)")); + return false; // expected the module version number + } + version += QLatin1Char('.'); + + lex(); + if (_tokenKind != T_VERSION_NUMBER) { + setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing number)")); + return false; // expected the module version number + } + version += tokenText(); } // diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h index 4fe40948e3..e2ee4ae351 100644 --- a/src/qml/parser/qqmljslexer_p.h +++ b/src/qml/parser/qqmljslexer_p.h @@ -124,6 +124,11 @@ public: StaticIsKeyword = 0x4 }; + enum class ImportState { + SawImport, + NoQmlImport + }; + public: Lexer(Engine *engine); @@ -188,6 +193,7 @@ private: inline void scanChar(); int scanToken(); int scanNumber(QChar ch); + int scanVersionNumber(QChar ch); enum ScanStringMode { SingleQuote = '\'', DoubleQuote = '"', @@ -242,6 +248,7 @@ private: int _tokenLength; int _tokenLine; int _tokenColumn; + ImportState _importState = ImportState::NoQmlImport; bool _validTokenText; bool _prohibitAutomaticSemicolon; @@ -253,6 +260,7 @@ private: bool _skipLinefeed = false; int _generatorLevel = 0; bool _staticIsKeyword = false; + bool _handlingDirectives = false; }; } // end of namespace QQmlJS |