diff options
Diffstat (limited to 'src/qml/parser')
-rw-r--r-- | src/qml/parser/qqmljsengine_p.cpp | 8 | ||||
-rw-r--r-- | src/qml/parser/qqmljsengine_p.h | 5 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 159 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer_p.h | 11 | ||||
-rw-r--r-- | src/qml/parser/qqmljsparser.cpp | 19 |
5 files changed, 176 insertions, 26 deletions
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp index 7ac5dbc9bb..fac2d82ff2 100644 --- a/src/qml/parser/qqmljsengine_p.cpp +++ b/src/qml/parser/qqmljsengine_p.cpp @@ -114,7 +114,7 @@ double integerFromString(const QString &str, int radix) Engine::Engine() - : _lexer(0) + : _lexer(0), _directives(0) { } Engine::~Engine() @@ -135,6 +135,12 @@ Lexer *Engine::lexer() const void Engine::setLexer(Lexer *lexer) { _lexer = lexer; } +Directives *Engine::directives() const +{ return _directives; } + +void Engine::setDirectives(Directives *directives) +{ _directives = directives; } + MemoryPool *Engine::pool() { return &_pool; } diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h index 661681d19c..81b2aa88e7 100644 --- a/src/qml/parser/qqmljsengine_p.h +++ b/src/qml/parser/qqmljsengine_p.h @@ -57,6 +57,7 @@ QT_QML_BEGIN_NAMESPACE namespace QQmlJS { class Lexer; +class Directives; class MemoryPool; class QML_PARSER_EXPORT DiagnosticMessage @@ -84,6 +85,7 @@ public: class QML_PARSER_EXPORT Engine { Lexer *_lexer; + Directives *_directives; MemoryPool _pool; QList<AST::SourceLocation> _comments; QString _extraCode; @@ -102,6 +104,9 @@ public: Lexer *lexer() const; void setLexer(Lexer *lexer); + Directives *directives() const; + void setDirectives(Directives *directives); + MemoryPool *pool(); inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); } diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index 2e2a4e5f8b..a69fa21c32 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -1224,12 +1224,60 @@ bool Lexer::canInsertAutomaticSemicolon(int token) const || _followsClosingBrace; } -bool Lexer::scanDirectives(Directives *directives) +static const int uriTokens[] = { + QQmlJSGrammar::T_IDENTIFIER, + QQmlJSGrammar::T_PROPERTY, + QQmlJSGrammar::T_SIGNAL, + QQmlJSGrammar::T_READONLY, + QQmlJSGrammar::T_ON, + QQmlJSGrammar::T_BREAK, + QQmlJSGrammar::T_CASE, + QQmlJSGrammar::T_CATCH, + QQmlJSGrammar::T_CONTINUE, + QQmlJSGrammar::T_DEFAULT, + QQmlJSGrammar::T_DELETE, + QQmlJSGrammar::T_DO, + QQmlJSGrammar::T_ELSE, + QQmlJSGrammar::T_FALSE, + QQmlJSGrammar::T_FINALLY, + QQmlJSGrammar::T_FOR, + QQmlJSGrammar::T_FUNCTION, + QQmlJSGrammar::T_IF, + QQmlJSGrammar::T_IN, + QQmlJSGrammar::T_INSTANCEOF, + QQmlJSGrammar::T_NEW, + QQmlJSGrammar::T_NULL, + QQmlJSGrammar::T_RETURN, + QQmlJSGrammar::T_SWITCH, + QQmlJSGrammar::T_THIS, + QQmlJSGrammar::T_THROW, + QQmlJSGrammar::T_TRUE, + QQmlJSGrammar::T_TRY, + QQmlJSGrammar::T_TYPEOF, + QQmlJSGrammar::T_VAR, + QQmlJSGrammar::T_VOID, + QQmlJSGrammar::T_WHILE, + QQmlJSGrammar::T_CONST, + QQmlJSGrammar::T_DEBUGGER, + QQmlJSGrammar::T_RESERVED_WORD, + QQmlJSGrammar::T_WITH, + + QQmlJSGrammar::EOF_SYMBOL +}; +static inline bool isUriToken(int token) { - if (_qmlMode) { - // the directives are a Javascript-only extension. - return false; + const int *current = uriTokens; + while (*current != QQmlJSGrammar::EOF_SYMBOL) { + if (*current == token) + return true; + ++current; } + return false; +} + +bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) +{ + Q_ASSERT(!_qmlMode); lex(); // fetch the first token @@ -1237,24 +1285,33 @@ bool Lexer::scanDirectives(Directives *directives) return true; do { - lex(); // skip T_DOT - const int lineNumber = tokenStartLine(); + const int column = tokenStartColumn(); + + lex(); // skip T_DOT if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD)) - return false; // expected a valid QML/JS directive + return true; // expected a valid QML/JS directive const QString directiveName = tokenText(); if (! (directiveName == QLatin1String("pragma") || - directiveName == QLatin1String("import"))) + directiveName == QLatin1String("import"))) { + error->message = QCoreApplication::translate("QQmlParser", "Syntax error"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); return false; // not a valid directive name + } // it must be a pragma or an import directive. if (directiveName == QLatin1String("pragma")) { // .pragma library - if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library"))) + if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library"))) { + error->message = QCoreApplication::translate("QQmlParser", "Syntax error"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); return false; // expected `library + } // we found a .pragma library directive directives->pragmaLibrary(); @@ -1273,22 +1330,53 @@ bool Lexer::scanDirectives(Directives *directives) fileImport = true; pathOrUri = tokenText(); + if (!pathOrUri.endsWith(QLatin1String("js"))) { + error->message = QCoreApplication::translate("QQmlParser","Imported file must be a script"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); + return false; + } + } else if (_tokenKind == T_IDENTIFIER) { // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER - pathOrUri = tokenText(); + while (true) { + if (!isUriToken(_tokenKind)) { + error->message = QCoreApplication::translate("QQmlParser","Invalid module URI"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); + return false; + } - lex(); // skip the first T_IDENTIFIER - for (; _tokenKind == T_DOT; lex()) { - if (lex() != T_IDENTIFIER) + pathOrUri.append(tokenText()); + + lex(); + if (tokenStartLine() != lineNumber) { + error->message = QCoreApplication::translate("QQmlParser","Invalid module URI"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); return false; + } + if (_tokenKind != QQmlJSGrammar::T_DOT) + break; + + pathOrUri.append(QLatin1Char('.')); - pathOrUri += QLatin1Char('.'); - pathOrUri += tokenText(); + lex(); + if (tokenStartLine() != lineNumber) { + error->message = QCoreApplication::translate("QQmlParser","Invalid module URI"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); + return false; + } } - if (_tokenKind != T_NUMERIC_LITERAL) + if (_tokenKind != T_NUMERIC_LITERAL) { + error->message = QCoreApplication::translate("QQmlParser","Module import requires a version"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); return false; // expected the module version number + } version = tokenText(); } @@ -1296,22 +1384,51 @@ bool Lexer::scanDirectives(Directives *directives) // // recognize the mandatory `as' followed by the module name // - if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("as"))) + if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("as") && tokenStartLine() == lineNumber)) { + if (fileImport) + error->message = QCoreApplication::translate("QQmlParser", "File import requires a qualifier"); + else + error->message = QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"); + if (tokenStartLine() != lineNumber) { + error->loc.startLine = lineNumber; + error->loc.startColumn = column; + } else { + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); + } return false; // expected `as' + } - if (lex() != T_IDENTIFIER) + if (lex() != T_IDENTIFIER || tokenStartLine() != lineNumber) { + if (fileImport) + error->message = QCoreApplication::translate("QQmlParser", "File import requires a qualifier"); + else + error->message = QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); return false; // expected module name + } const QString module = tokenText(); + if (!module.at(0).isUpper()) { + error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); + return false; + } if (fileImport) - directives->importFile(pathOrUri, module); + directives->importFile(pathOrUri, module, lineNumber, column); else - directives->importModule(pathOrUri, version, module); + directives->importModule(pathOrUri, version, module, lineNumber, column); } - if (tokenStartLine() != lineNumber) + if (tokenStartLine() != lineNumber) { + error->message = QCoreApplication::translate("QQmlParser", "Syntax error"); + error->loc.startLine = tokenStartLine(); + error->loc.startColumn = tokenStartColumn(); return false; // the directives cannot span over multiple lines + } // fetch the first token after the .pragma/.import directive lex(); diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h index 9106c94477..b5415f8777 100644 --- a/src/qml/parser/qqmljslexer_p.h +++ b/src/qml/parser/qqmljslexer_p.h @@ -55,6 +55,7 @@ QT_QML_BEGIN_NAMESPACE namespace QQmlJS { class Engine; +class DiagnosticMessage; class QML_PARSER_EXPORT Directives { public: @@ -64,17 +65,21 @@ public: { } - virtual void importFile(const QString &jsfile, const QString &module) + virtual void importFile(const QString &jsfile, const QString &module, int line, int column) { Q_UNUSED(jsfile); Q_UNUSED(module); + Q_UNUSED(line); + Q_UNUSED(column); } - virtual void importModule(const QString &uri, const QString &version, const QString &module) + virtual void importModule(const QString &uri, const QString &version, const QString &module, int line, int column) { Q_UNUSED(uri); Q_UNUSED(version); Q_UNUSED(module); + Q_UNUSED(line); + Q_UNUSED(column); } }; @@ -146,7 +151,7 @@ public: int lex(); bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); - bool scanDirectives(Directives *directives); + bool scanDirectives(Directives *directives, DiagnosticMessage *error); int regExpFlags() const { return _patternFlags; } QString regExpPattern() const { return _tokenText; } diff --git a/src/qml/parser/qqmljsparser.cpp b/src/qml/parser/qqmljsparser.cpp index 762e60c827..35eb0e3ad5 100644 --- a/src/qml/parser/qqmljsparser.cpp +++ b/src/qml/parser/qqmljsparser.cpp @@ -161,7 +161,24 @@ bool Parser::parse(int startToken) token_buffer[0].token = startToken; first_token = &token_buffer[0]; - last_token = &token_buffer[1]; + if (startToken == T_FEED_JS_PROGRAM && !lexer->qmlMode()) { + Directives ignoreDirectives; + Directives *directives = driver->directives(); + if (!directives) + directives = &ignoreDirectives; + DiagnosticMessage error; + if (!lexer->scanDirectives(directives, &error)) { + diagnostic_messages.append(error); + return false; + } + token_buffer[1].token = lexer->tokenKind(); + token_buffer[1].dval = lexer->tokenValue(); + token_buffer[1].loc = location(lexer); + token_buffer[1].spell = lexer->tokenSpell(); + last_token = &token_buffer[2]; + } else { + last_token = &token_buffer[1]; + } tos = -1; program = 0; |