aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp8
-rw-r--r--src/qml/parser/qqmljs.g39
-rw-r--r--src/qml/parser/qqmljsast.cpp6
-rw-r--r--src/qml/parser/qqmljsast_p.h30
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h4
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h2
-rw-r--r--src/qml/parser/qqmljslexer.cpp60
-rw-r--r--src/qml/parser/qqmljslexer_p.h8
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