Clean up JS .import/.pragma directive scanning
There's a scanner in QQmlJS::Lexer::scanDirectives that can parse those, so let's get rid of extra parser that operates on a string. Instead this way we can do the scanning all in one shot, avoid detaching a copy of the source code string and (most importantly) bring the parser closer to the copy in Qt Creator, which uses the directives approach to extract imports and pragma. Change-Id: Iff6eb8d91a45d8a70f383f953115692be48259de Reviewed-by: Fawzi Mohamed <fawzi.mohamed@theqtcompany.com>
This commit is contained in:
parent
bede2a3ac7
commit
9d7b27f5bf
|
@ -216,60 +216,6 @@ static void replaceWithSpace(QString &str, int idx, int n)
|
||||||
*data++ = space;
|
*data++ = space;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_LINE if (l.tokenStartLine() != startLine) return;
|
|
||||||
#define CHECK_TOKEN(t) if (token != QQmlJSGrammar:: t) return;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
const int *current = uriTokens;
|
|
||||||
while (*current != QQmlJSGrammar::EOF_SYMBOL) {
|
|
||||||
if (*current == token)
|
|
||||||
return true;
|
|
||||||
++current;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Document::collectTypeReferences()
|
void Document::collectTypeReferences()
|
||||||
{
|
{
|
||||||
foreach (Object *obj, objects) {
|
foreach (Object *obj, objects) {
|
||||||
|
@ -296,198 +242,6 @@ void Document::collectTypeReferences()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::extractScriptMetaData(QString &script, QQmlJS::DiagnosticMessage *error)
|
|
||||||
{
|
|
||||||
Q_ASSERT(error);
|
|
||||||
|
|
||||||
const QString js(QLatin1String(".js"));
|
|
||||||
const QString library(QLatin1String("library"));
|
|
||||||
|
|
||||||
QQmlJS::MemoryPool *pool = jsParserEngine.pool();
|
|
||||||
|
|
||||||
QQmlJS::Lexer l(0);
|
|
||||||
l.setCode(script, 0);
|
|
||||||
|
|
||||||
int token = l.lex();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (token != QQmlJSGrammar::T_DOT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int startOffset = l.tokenOffset();
|
|
||||||
int startLine = l.tokenStartLine();
|
|
||||||
int startColumn = l.tokenStartColumn();
|
|
||||||
|
|
||||||
error->loc.startLine = startLine + 1; // 0-based, adjust to be 1-based
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
CHECK_LINE;
|
|
||||||
|
|
||||||
if (token == QQmlJSGrammar::T_IMPORT) {
|
|
||||||
|
|
||||||
// .import <URI> <Version> as <Identifier>
|
|
||||||
// .import <file.js> as <Identifier>
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
CHECK_LINE;
|
|
||||||
QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
|
|
||||||
|
|
||||||
if (token == QQmlJSGrammar::T_STRING_LITERAL) {
|
|
||||||
|
|
||||||
QString file = l.tokenText();
|
|
||||||
|
|
||||||
if (!file.endsWith(js)) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","Imported file must be a script");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool invalidImport = false;
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) {
|
|
||||||
invalidImport = true;
|
|
||||||
} else {
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine))
|
|
||||||
invalidImport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (invalidImport) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","File import requires a qualifier");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int endOffset = l.tokenLength() + l.tokenOffset();
|
|
||||||
|
|
||||||
QString importId = script.mid(l.tokenOffset(), l.tokenLength());
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceWithSpace(script, startOffset, endOffset - startOffset);
|
|
||||||
|
|
||||||
import->type = QV4::CompiledData::Import::ImportScript;
|
|
||||||
import->uriIndex = registerString(file);
|
|
||||||
import->qualifierIndex = registerString(importId);
|
|
||||||
import->location.line = startLine;
|
|
||||||
import->location.column = startColumn;
|
|
||||||
imports << import;
|
|
||||||
} else {
|
|
||||||
// URI
|
|
||||||
QString uri;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (!isUriToken(token)) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","Invalid module URI");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uri.append(l.tokenText());
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
CHECK_LINE;
|
|
||||||
if (token != QQmlJSGrammar::T_DOT)
|
|
||||||
break;
|
|
||||||
|
|
||||||
uri.append(QLatin1Char('.'));
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
CHECK_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token != QQmlJSGrammar::T_NUMERIC_LITERAL) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","Module import requires a version");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vmaj, vmin;
|
|
||||||
IRBuilder::extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()),
|
|
||||||
&vmaj, &vmin);
|
|
||||||
|
|
||||||
bool invalidImport = false;
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) {
|
|
||||||
invalidImport = true;
|
|
||||||
} else {
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine))
|
|
||||||
invalidImport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (invalidImport) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","Module import requires a qualifier");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int endOffset = l.tokenLength() + l.tokenOffset();
|
|
||||||
|
|
||||||
QString importId = script.mid(l.tokenOffset(), l.tokenLength());
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) {
|
|
||||||
error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier");
|
|
||||||
error->loc.startColumn = l.tokenStartColumn();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceWithSpace(script, startOffset, endOffset - startOffset);
|
|
||||||
|
|
||||||
import->type = QV4::CompiledData::Import::ImportLibrary;
|
|
||||||
import->uriIndex = registerString(uri);
|
|
||||||
import->majorVersion = vmaj;
|
|
||||||
import->minorVersion = vmin;
|
|
||||||
import->qualifierIndex = registerString(importId);
|
|
||||||
import->location.line = startLine;
|
|
||||||
import->location.column = startColumn;
|
|
||||||
imports << import;
|
|
||||||
}
|
|
||||||
} else if (token == QQmlJSGrammar::T_PRAGMA) {
|
|
||||||
token = l.lex();
|
|
||||||
|
|
||||||
CHECK_TOKEN(T_IDENTIFIER);
|
|
||||||
CHECK_LINE;
|
|
||||||
|
|
||||||
QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
|
|
||||||
int endOffset = l.tokenLength() + l.tokenOffset();
|
|
||||||
|
|
||||||
if (pragmaValue == library) {
|
|
||||||
unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary;
|
|
||||||
replaceWithSpace(script, startOffset, endOffset - startOffset);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
token = l.lex();
|
|
||||||
if (l.tokenStartLine() == startLine)
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Document::removeScriptPragmas(QString &script)
|
void Document::removeScriptPragmas(QString &script)
|
||||||
{
|
{
|
||||||
const QString pragma(QLatin1String("pragma"));
|
const QString pragma(QLatin1String("pragma"));
|
||||||
|
@ -541,6 +295,45 @@ Document::Document(bool debugMode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptDirectivesCollector::ScriptDirectivesCollector(QQmlJS::Engine *engine, QV4::Compiler::JSUnitGenerator *unitGenerator)
|
||||||
|
: engine(engine)
|
||||||
|
, jsGenerator(unitGenerator)
|
||||||
|
, hasPragmaLibrary(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptDirectivesCollector::pragmaLibrary()
|
||||||
|
{
|
||||||
|
hasPragmaLibrary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptDirectivesCollector::importFile(const QString &jsfile, const QString &module, int lineNumber, int column)
|
||||||
|
{
|
||||||
|
QV4::CompiledData::Import *import = engine->pool()->New<QV4::CompiledData::Import>();
|
||||||
|
import->type = QV4::CompiledData::Import::ImportScript;
|
||||||
|
import->uriIndex = jsGenerator->registerString(jsfile);
|
||||||
|
import->qualifierIndex = jsGenerator->registerString(module);
|
||||||
|
import->location.line = lineNumber;
|
||||||
|
import->location.column = column;
|
||||||
|
imports << import;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptDirectivesCollector::importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column)
|
||||||
|
{
|
||||||
|
QV4::CompiledData::Import *import = engine->pool()->New<QV4::CompiledData::Import>();
|
||||||
|
import->type = QV4::CompiledData::Import::ImportLibrary;
|
||||||
|
import->uriIndex = jsGenerator->registerString(uri);
|
||||||
|
int vmaj;
|
||||||
|
int vmin;
|
||||||
|
IRBuilder::extractVersion(QStringRef(&version), &vmaj, &vmin);
|
||||||
|
import->majorVersion = vmaj;
|
||||||
|
import->minorVersion = vmin;
|
||||||
|
import->qualifierIndex = jsGenerator->registerString(module);
|
||||||
|
import->location.line = lineNumber;
|
||||||
|
import->location.column = column;
|
||||||
|
imports << import;
|
||||||
|
}
|
||||||
|
|
||||||
IRBuilder::IRBuilder(const QSet<QString> &illegalNames)
|
IRBuilder::IRBuilder(const QSet<QString> &illegalNames)
|
||||||
: illegalNames(illegalNames)
|
: illegalNames(illegalNames)
|
||||||
, _object(0)
|
, _object(0)
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <private/qqmljsmemorypool_p.h>
|
#include <private/qqmljsmemorypool_p.h>
|
||||||
#include <private/qv4codegen_p.h>
|
#include <private/qv4codegen_p.h>
|
||||||
#include <private/qv4compiler_p.h>
|
#include <private/qv4compiler_p.h>
|
||||||
|
#include <private/qqmljslexer_p.h>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
@ -326,10 +327,23 @@ struct Q_QML_PRIVATE_EXPORT Document
|
||||||
int registerString(const QString &str) { return jsGenerator.registerString(str); }
|
int registerString(const QString &str) { return jsGenerator.registerString(str); }
|
||||||
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
|
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
|
||||||
|
|
||||||
void extractScriptMetaData(QString &script, QQmlJS::DiagnosticMessage *error);
|
|
||||||
static void removeScriptPragmas(QString &script);
|
static void removeScriptPragmas(QString &script);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
|
||||||
|
{
|
||||||
|
ScriptDirectivesCollector(QQmlJS::Engine *engine, QV4::Compiler::JSUnitGenerator *unitGenerator);
|
||||||
|
|
||||||
|
QQmlJS::Engine *engine;
|
||||||
|
QV4::Compiler::JSUnitGenerator *jsGenerator;
|
||||||
|
QList<const QV4::CompiledData::Import *> imports;
|
||||||
|
bool hasPragmaLibrary;
|
||||||
|
|
||||||
|
virtual void pragmaLibrary();
|
||||||
|
virtual void importFile(const QString &jsfile, const QString &module, int lineNumber, int column);
|
||||||
|
virtual void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column);
|
||||||
|
};
|
||||||
|
|
||||||
struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
|
struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
|
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
|
||||||
|
|
|
@ -321,12 +321,14 @@ Function *Script::function()
|
||||||
return vmFunction;
|
return vmFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
|
QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors, QQmlJS::Directives *directivesCollector)
|
||||||
{
|
{
|
||||||
using namespace QQmlJS;
|
using namespace QQmlJS;
|
||||||
using namespace QQmlJS::AST;
|
using namespace QQmlJS::AST;
|
||||||
|
|
||||||
QQmlJS::Engine ee;
|
QQmlJS::Engine ee;
|
||||||
|
if (directivesCollector)
|
||||||
|
ee.setDirectives(directivesCollector);
|
||||||
QQmlJS::Lexer lexer(&ee);
|
QQmlJS::Lexer lexer(&ee);
|
||||||
lexer.setCode(source, /*line*/1, /*qml mode*/false);
|
lexer.setCode(source, /*line*/1, /*qml mode*/false);
|
||||||
QQmlJS::Parser parser(&ee);
|
QQmlJS::Parser parser(&ee);
|
||||||
|
|
|
@ -43,6 +43,10 @@ QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QQmlContextData;
|
class QQmlContextData;
|
||||||
|
|
||||||
|
namespace QQmlJS {
|
||||||
|
class Directives;
|
||||||
|
}
|
||||||
|
|
||||||
namespace QV4 {
|
namespace QV4 {
|
||||||
|
|
||||||
struct ContextStateSaver {
|
struct ContextStateSaver {
|
||||||
|
@ -137,7 +141,8 @@ struct Q_QML_EXPORT Script {
|
||||||
|
|
||||||
Function *function();
|
Function *function();
|
||||||
|
|
||||||
static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
|
static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source,
|
||||||
|
QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0);
|
||||||
|
|
||||||
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject);
|
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject);
|
||||||
};
|
};
|
||||||
|
|
|
@ -114,7 +114,7 @@ double integerFromString(const QString &str, int radix)
|
||||||
|
|
||||||
|
|
||||||
Engine::Engine()
|
Engine::Engine()
|
||||||
: _lexer(0)
|
: _lexer(0), _directives(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Engine::~Engine()
|
Engine::~Engine()
|
||||||
|
@ -135,6 +135,12 @@ Lexer *Engine::lexer() const
|
||||||
void Engine::setLexer(Lexer *lexer)
|
void Engine::setLexer(Lexer *lexer)
|
||||||
{ _lexer = lexer; }
|
{ _lexer = lexer; }
|
||||||
|
|
||||||
|
Directives *Engine::directives() const
|
||||||
|
{ return _directives; }
|
||||||
|
|
||||||
|
void Engine::setDirectives(Directives *directives)
|
||||||
|
{ _directives = directives; }
|
||||||
|
|
||||||
MemoryPool *Engine::pool()
|
MemoryPool *Engine::pool()
|
||||||
{ return &_pool; }
|
{ return &_pool; }
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ QT_QML_BEGIN_NAMESPACE
|
||||||
namespace QQmlJS {
|
namespace QQmlJS {
|
||||||
|
|
||||||
class Lexer;
|
class Lexer;
|
||||||
|
class Directives;
|
||||||
class MemoryPool;
|
class MemoryPool;
|
||||||
|
|
||||||
class QML_PARSER_EXPORT DiagnosticMessage
|
class QML_PARSER_EXPORT DiagnosticMessage
|
||||||
|
@ -84,6 +85,7 @@ public:
|
||||||
class QML_PARSER_EXPORT Engine
|
class QML_PARSER_EXPORT Engine
|
||||||
{
|
{
|
||||||
Lexer *_lexer;
|
Lexer *_lexer;
|
||||||
|
Directives *_directives;
|
||||||
MemoryPool _pool;
|
MemoryPool _pool;
|
||||||
QList<AST::SourceLocation> _comments;
|
QList<AST::SourceLocation> _comments;
|
||||||
QString _extraCode;
|
QString _extraCode;
|
||||||
|
@ -102,6 +104,9 @@ public:
|
||||||
Lexer *lexer() const;
|
Lexer *lexer() const;
|
||||||
void setLexer(Lexer *lexer);
|
void setLexer(Lexer *lexer);
|
||||||
|
|
||||||
|
Directives *directives() const;
|
||||||
|
void setDirectives(Directives *directives);
|
||||||
|
|
||||||
MemoryPool *pool();
|
MemoryPool *pool();
|
||||||
|
|
||||||
inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); }
|
inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); }
|
||||||
|
|
|
@ -1224,12 +1224,60 @@ bool Lexer::canInsertAutomaticSemicolon(int token) const
|
||||||
|| _followsClosingBrace;
|
|| _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) {
|
const int *current = uriTokens;
|
||||||
// the directives are a Javascript-only extension.
|
while (*current != QQmlJSGrammar::EOF_SYMBOL) {
|
||||||
return false;
|
if (*current == token)
|
||||||
|
return true;
|
||||||
|
++current;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!_qmlMode);
|
||||||
|
|
||||||
lex(); // fetch the first token
|
lex(); // fetch the first token
|
||||||
|
|
||||||
|
@ -1237,24 +1285,33 @@ bool Lexer::scanDirectives(Directives *directives)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
const int lineNumber = tokenStartLine();
|
||||||
|
const int column = tokenStartColumn();
|
||||||
|
|
||||||
lex(); // skip T_DOT
|
lex(); // skip T_DOT
|
||||||
|
|
||||||
const int lineNumber = tokenStartLine();
|
|
||||||
|
|
||||||
if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD))
|
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();
|
const QString directiveName = tokenText();
|
||||||
|
|
||||||
if (! (directiveName == QLatin1String("pragma") ||
|
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
|
return false; // not a valid directive name
|
||||||
|
}
|
||||||
|
|
||||||
// it must be a pragma or an import directive.
|
// it must be a pragma or an import directive.
|
||||||
if (directiveName == QLatin1String("pragma")) {
|
if (directiveName == QLatin1String("pragma")) {
|
||||||
// .pragma library
|
// .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
|
return false; // expected `library
|
||||||
|
}
|
||||||
|
|
||||||
// we found a .pragma library directive
|
// we found a .pragma library directive
|
||||||
directives->pragmaLibrary();
|
directives->pragmaLibrary();
|
||||||
|
@ -1273,22 +1330,53 @@ bool Lexer::scanDirectives(Directives *directives)
|
||||||
fileImport = true;
|
fileImport = true;
|
||||||
pathOrUri = tokenText();
|
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) {
|
} else if (_tokenKind == T_IDENTIFIER) {
|
||||||
// .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER
|
// .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER
|
||||||
|
|
||||||
pathOrUri = tokenText();
|
while (true) {
|
||||||
|
if (!isUriToken(_tokenKind)) {
|
||||||
lex(); // skip the first T_IDENTIFIER
|
error->message = QCoreApplication::translate("QQmlParser","Invalid module URI");
|
||||||
for (; _tokenKind == T_DOT; lex()) {
|
error->loc.startLine = tokenStartLine();
|
||||||
if (lex() != T_IDENTIFIER)
|
error->loc.startColumn = tokenStartColumn();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pathOrUri += QLatin1Char('.');
|
pathOrUri.append(tokenText());
|
||||||
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 != QQmlJSGrammar::T_DOT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pathOrUri.append(QLatin1Char('.'));
|
||||||
|
|
||||||
|
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
|
return false; // expected the module version number
|
||||||
|
}
|
||||||
|
|
||||||
version = tokenText();
|
version = tokenText();
|
||||||
}
|
}
|
||||||
|
@ -1296,22 +1384,51 @@ bool Lexer::scanDirectives(Directives *directives)
|
||||||
//
|
//
|
||||||
// recognize the mandatory `as' followed by the module name
|
// 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'
|
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
|
return false; // expected module name
|
||||||
|
}
|
||||||
|
|
||||||
const QString module = tokenText();
|
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)
|
if (fileImport)
|
||||||
directives->importFile(pathOrUri, module);
|
directives->importFile(pathOrUri, module, lineNumber, column);
|
||||||
else
|
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
|
return false; // the directives cannot span over multiple lines
|
||||||
|
}
|
||||||
|
|
||||||
// fetch the first token after the .pragma/.import directive
|
// fetch the first token after the .pragma/.import directive
|
||||||
lex();
|
lex();
|
||||||
|
|
|
@ -55,6 +55,7 @@ QT_QML_BEGIN_NAMESPACE
|
||||||
namespace QQmlJS {
|
namespace QQmlJS {
|
||||||
|
|
||||||
class Engine;
|
class Engine;
|
||||||
|
class DiagnosticMessage;
|
||||||
|
|
||||||
class QML_PARSER_EXPORT Directives {
|
class QML_PARSER_EXPORT Directives {
|
||||||
public:
|
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(jsfile);
|
||||||
Q_UNUSED(module);
|
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(uri);
|
||||||
Q_UNUSED(version);
|
Q_UNUSED(version);
|
||||||
Q_UNUSED(module);
|
Q_UNUSED(module);
|
||||||
|
Q_UNUSED(line);
|
||||||
|
Q_UNUSED(column);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,7 +151,7 @@ public:
|
||||||
int lex();
|
int lex();
|
||||||
|
|
||||||
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
|
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
|
||||||
bool scanDirectives(Directives *directives);
|
bool scanDirectives(Directives *directives, DiagnosticMessage *error);
|
||||||
|
|
||||||
int regExpFlags() const { return _patternFlags; }
|
int regExpFlags() const { return _patternFlags; }
|
||||||
QString regExpPattern() const { return _tokenText; }
|
QString regExpPattern() const { return _tokenText; }
|
||||||
|
|
|
@ -161,7 +161,24 @@ bool Parser::parse(int startToken)
|
||||||
|
|
||||||
token_buffer[0].token = startToken;
|
token_buffer[0].token = startToken;
|
||||||
first_token = &token_buffer[0];
|
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;
|
tos = -1;
|
||||||
program = 0;
|
program = 0;
|
||||||
|
|
|
@ -2584,20 +2584,10 @@ void QQmlScriptBlob::dataReceived(const Data &data)
|
||||||
|
|
||||||
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
|
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
|
||||||
QmlIR::Document irUnit(v4->debugger != 0);
|
QmlIR::Document irUnit(v4->debugger != 0);
|
||||||
QQmlJS::DiagnosticMessage metaDataError;
|
QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator);
|
||||||
irUnit.extractScriptMetaData(source, &metaDataError);
|
|
||||||
if (!metaDataError.message.isEmpty()) {
|
|
||||||
QQmlError e;
|
|
||||||
e.setUrl(finalUrl());
|
|
||||||
e.setLine(metaDataError.loc.startLine);
|
|
||||||
e.setColumn(metaDataError.loc.startColumn);
|
|
||||||
e.setDescription(metaDataError.message);
|
|
||||||
setError(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QQmlError> errors;
|
QList<QQmlError> errors;
|
||||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors);
|
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors, &collector);
|
||||||
// No need to addref on unit, it's initial refcount is 1
|
// No need to addref on unit, it's initial refcount is 1
|
||||||
source.clear();
|
source.clear();
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
|
@ -2608,6 +2598,9 @@ void QQmlScriptBlob::dataReceived(const Data &data)
|
||||||
unit.take(new EmptyCompilationUnit);
|
unit.take(new EmptyCompilationUnit);
|
||||||
}
|
}
|
||||||
irUnit.javaScriptCompilationUnit = unit;
|
irUnit.javaScriptCompilationUnit = unit;
|
||||||
|
irUnit.imports = collector.imports;
|
||||||
|
if (collector.hasPragmaLibrary)
|
||||||
|
irUnit.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary;
|
||||||
|
|
||||||
QmlIR::QmlUnitGenerator qmlGenerator;
|
QmlIR::QmlUnitGenerator qmlGenerator;
|
||||||
QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit);
|
QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit);
|
||||||
|
|
|
@ -107,9 +107,12 @@ void tst_qmlmin::initTestCase()
|
||||||
invalidFiles << "tests/auto/qml/parserstress/tests/ecma_3/Unicode/regress-352044-02-n.js";
|
invalidFiles << "tests/auto/qml/parserstress/tests/ecma_3/Unicode/regress-352044-02-n.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon_error1.qml";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon_error1.qml";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedFileQualifier.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedFileQualifier.js";
|
||||||
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedFileQualifier.2.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedImport.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedImport.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModule.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModule.js";
|
||||||
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedFile.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModuleQualifier.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModuleQualifier.js";
|
||||||
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModuleQualifier.2.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModuleVersion.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/malformedModuleVersion.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/missingFileQualifier.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/missingFileQualifier.js";
|
||||||
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/missingModuleQualifier.js";
|
invalidFiles << "tests/auto/qml/qqmlecmascript/data/jsimportfail/missingModuleQualifier.js";
|
||||||
|
|
|
@ -4107,7 +4107,7 @@ void tst_qqmlecmascript::importScripts_data()
|
||||||
<< testFileUrl("jsimportfail/malformedImport.qml")
|
<< testFileUrl("jsimportfail/malformedImport.qml")
|
||||||
<< false /* compilation should succeed */
|
<< false /* compilation should succeed */
|
||||||
<< QString()
|
<< QString()
|
||||||
<< (QStringList() << testFileUrl("jsimportfail/malformedImport.js").toString() + QLatin1String(":1:1: Syntax error"))
|
<< (QStringList() << testFileUrl("jsimportfail/malformedImport.js").toString() + QLatin1String(":1:2: Syntax error"))
|
||||||
<< QStringList()
|
<< QStringList()
|
||||||
<< QVariantList();
|
<< QVariantList();
|
||||||
|
|
||||||
|
@ -4139,7 +4139,7 @@ void tst_qqmlecmascript::importScripts_data()
|
||||||
<< testFileUrl("jsimportfail/malformedFileQualifier.2.qml")
|
<< testFileUrl("jsimportfail/malformedFileQualifier.2.qml")
|
||||||
<< false /* compilation should succeed */
|
<< false /* compilation should succeed */
|
||||||
<< QString()
|
<< QString()
|
||||||
<< (QStringList() << testFileUrl("jsimportfail/malformedFileQualifier.2.js").toString() + QLatin1String(":1:1: Invalid import qualifier"))
|
<< (QStringList() << testFileUrl("jsimportfail/malformedFileQualifier.2.js").toString() + QLatin1String(":1:23: Invalid import qualifier"))
|
||||||
<< QStringList()
|
<< QStringList()
|
||||||
<< QVariantList();
|
<< QVariantList();
|
||||||
|
|
||||||
|
@ -4187,7 +4187,7 @@ void tst_qqmlecmascript::importScripts_data()
|
||||||
<< testFileUrl("jsimportfail/malformedModuleQualifier.2.qml")
|
<< testFileUrl("jsimportfail/malformedModuleQualifier.2.qml")
|
||||||
<< false /* compilation should succeed */
|
<< false /* compilation should succeed */
|
||||||
<< QString()
|
<< QString()
|
||||||
<< (QStringList() << testFileUrl("jsimportfail/malformedModuleQualifier.2.js").toString() + QLatin1String(":1:1: Invalid import qualifier"))
|
<< (QStringList() << testFileUrl("jsimportfail/malformedModuleQualifier.2.js").toString() + QLatin1String(":1:24: Invalid import qualifier"))
|
||||||
<< QStringList()
|
<< QStringList()
|
||||||
<< QVariantList();
|
<< QVariantList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,6 +246,41 @@ static QVariantList findQmlImportsInQmlFile(const QString &filePath)
|
||||||
return findQmlImportsInQmlCode(filePath, code);
|
return findQmlImportsInQmlCode(filePath, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ImportCollector : public QQmlJS::Directives
|
||||||
|
{
|
||||||
|
QVariantList imports;
|
||||||
|
|
||||||
|
virtual void importFile(const QString &jsfile, const QString &module, int line, int column)
|
||||||
|
{
|
||||||
|
QVariantMap entry;
|
||||||
|
entry[QLatin1String("type")] = QStringLiteral("javascript");
|
||||||
|
entry[QLatin1String("path")] = jsfile;
|
||||||
|
imports << entry;
|
||||||
|
|
||||||
|
Q_UNUSED(module);
|
||||||
|
Q_UNUSED(line);
|
||||||
|
Q_UNUSED(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void importModule(const QString &uri, const QString &version, const QString &module, int line, int column)
|
||||||
|
{
|
||||||
|
QVariantMap entry;
|
||||||
|
if (uri.contains(QLatin1Char('/'))) {
|
||||||
|
entry[QLatin1String("type")] = QStringLiteral("directory");
|
||||||
|
entry[QLatin1String("name")] = uri;
|
||||||
|
} else {
|
||||||
|
entry[QLatin1String("type")] = QStringLiteral("module");
|
||||||
|
entry[QLatin1String("name")] = uri;
|
||||||
|
entry[QLatin1String("version")] = version;
|
||||||
|
}
|
||||||
|
imports << entry;
|
||||||
|
|
||||||
|
Q_UNUSED(module);
|
||||||
|
Q_UNUSED(line);
|
||||||
|
Q_UNUSED(column);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Scan a single javascrupt file for import statements
|
// Scan a single javascrupt file for import statements
|
||||||
QVariantList findQmlImportsInJavascriptFile(const QString &filePath)
|
QVariantList findQmlImportsInJavascriptFile(const QString &filePath)
|
||||||
{
|
{
|
||||||
|
@ -256,42 +291,22 @@ QVariantList findQmlImportsInJavascriptFile(const QString &filePath)
|
||||||
return QVariantList();
|
return QVariantList();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList imports;
|
|
||||||
|
|
||||||
QString sourceCode = QString::fromUtf8(file.readAll());
|
QString sourceCode = QString::fromUtf8(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
QmlIR::Document doc(/*debug mode*/false);
|
|
||||||
QQmlJS::DiagnosticMessage error;
|
|
||||||
doc.extractScriptMetaData(sourceCode, &error);
|
|
||||||
if (!error.message.isEmpty())
|
|
||||||
return imports;
|
|
||||||
|
|
||||||
foreach (const QV4::CompiledData::Import *import, doc.imports) {
|
QQmlJS::Engine ee;
|
||||||
QVariantMap entry;
|
ImportCollector collector;
|
||||||
const QString name = doc.stringAt(import->uriIndex);
|
ee.setDirectives(&collector);
|
||||||
switch (import->type) {
|
QQmlJS::Lexer lexer(&ee);
|
||||||
case QV4::CompiledData::Import::ImportScript:
|
lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false);
|
||||||
entry[QStringLiteral("type")] = QStringLiteral("javascript");
|
QQmlJS::Parser parser(&ee);
|
||||||
entry[QStringLiteral("path")] = name;
|
parser.parseProgram();
|
||||||
break;
|
|
||||||
case QV4::CompiledData::Import::ImportLibrary:
|
|
||||||
if (name.contains(QLatin1Char('/'))) {
|
|
||||||
entry[QStringLiteral("type")] = QStringLiteral("directory");
|
|
||||||
entry[QStringLiteral("name")] = name;
|
|
||||||
} else {
|
|
||||||
entry[QStringLiteral("type")] = QStringLiteral("module");
|
|
||||||
entry[QStringLiteral("name")] = name;
|
|
||||||
entry[QStringLiteral("version")] = QString::number(import->majorVersion) + QLatin1Char('.') + QString::number(import->minorVersion);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
imports << entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return imports;
|
foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages())
|
||||||
|
if (m.isError())
|
||||||
|
return QVariantList();
|
||||||
|
|
||||||
|
return collector.imports;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan a single qml or js file for import statements
|
// Scan a single qml or js file for import statements
|
||||||
|
|
|
@ -93,7 +93,7 @@ public:
|
||||||
_directives += QLatin1String(".pragma library\n");
|
_directives += QLatin1String(".pragma library\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void importFile(const QString &jsfile, const QString &module)
|
virtual void importFile(const QString &jsfile, const QString &module, int line, int column)
|
||||||
{
|
{
|
||||||
_directives += QLatin1String(".import");
|
_directives += QLatin1String(".import");
|
||||||
_directives += QLatin1Char('"');
|
_directives += QLatin1Char('"');
|
||||||
|
@ -102,9 +102,11 @@ public:
|
||||||
_directives += QLatin1String("as ");
|
_directives += QLatin1String("as ");
|
||||||
_directives += module;
|
_directives += module;
|
||||||
_directives += QLatin1Char('\n');
|
_directives += QLatin1Char('\n');
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
_directives += QLatin1String(".import ");
|
_directives += QLatin1String(".import ");
|
||||||
_directives += uri;
|
_directives += uri;
|
||||||
|
@ -113,6 +115,8 @@ public:
|
||||||
_directives += QLatin1String(" as ");
|
_directives += QLatin1String(" as ");
|
||||||
_directives += module;
|
_directives += module;
|
||||||
_directives += QLatin1Char('\n');
|
_directives += QLatin1Char('\n');
|
||||||
|
Q_UNUSED(line);
|
||||||
|
Q_UNUSED(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -262,7 +266,8 @@ bool Minify::parse(int startToken)
|
||||||
|
|
||||||
if (startToken == T_FEED_JS_PROGRAM) {
|
if (startToken == T_FEED_JS_PROGRAM) {
|
||||||
// parse optional pragma directive
|
// parse optional pragma directive
|
||||||
if (scanDirectives(this)) {
|
DiagnosticMessage error;
|
||||||
|
if (scanDirectives(this, &error)) {
|
||||||
// append the scanned directives to the minifier code.
|
// append the scanned directives to the minifier code.
|
||||||
append(directives());
|
append(directives());
|
||||||
|
|
||||||
|
@ -433,7 +438,8 @@ bool Tokenize::parse(int startToken)
|
||||||
|
|
||||||
if (startToken == T_FEED_JS_PROGRAM) {
|
if (startToken == T_FEED_JS_PROGRAM) {
|
||||||
// parse optional pragma directive
|
// parse optional pragma directive
|
||||||
if (scanDirectives(this)) {
|
DiagnosticMessage error;
|
||||||
|
if (scanDirectives(this, &error)) {
|
||||||
// append the scanned directives as one token to
|
// append the scanned directives as one token to
|
||||||
// the token stream.
|
// the token stream.
|
||||||
_minifiedCode.append(directives());
|
_minifiedCode.append(directives());
|
||||||
|
|
Loading…
Reference in New Issue