summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/qmlcompiler.cpp54
-rw-r--r--src/declarative/qml/qmlcompiler_p.h1
-rw-r--r--src/declarative/qml/qmlcontext.cpp15
-rw-r--r--src/declarative/qml/qmlcontext_p.h3
-rw-r--r--src/declarative/qml/qmlinstruction.cpp2
-rw-r--r--src/declarative/qml/qmlinstruction_p.h2
-rw-r--r--src/declarative/qml/qmlparser.cpp54
-rw-r--r--src/declarative/qml/qmlparser_p.h11
-rw-r--r--src/declarative/qml/qmlscriptparser.cpp8
-rw-r--r--src/declarative/qml/qmlvme.cpp7
-rw-r--r--tests/auto/declarative/qmlecmascript/data/externalScript.1.qml11
-rw-r--r--tests/auto/declarative/qmlecmascript/data/externalScript.2.js8
-rw-r--r--tests/auto/declarative/qmlecmascript/data/externalScript.2.qml11
-rw-r--r--tests/auto/declarative/qmlecmascript/data/externalScript.3.qml13
-rw-r--r--tests/auto/declarative/qmlecmascript/data/externalScript.4.qml15
-rw-r--r--tests/auto/declarative/qmlecmascript/data/externalScript.js6
-rw-r--r--tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp48
17 files changed, 227 insertions, 42 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 9000339..a4e14b2 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -846,13 +846,13 @@ void QmlCompiler::genObject(QmlParser::Object *obj)
}
// Set any script blocks
- for (int ii = 0; ii < obj->scriptBlocks.count(); ++ii) {
+ for (int ii = 0; ii < obj->scripts.count(); ++ii) {
QmlInstruction script;
script.type = QmlInstruction::StoreScript;
script.line = 0; // ###
- script.storeScript.fileName = output->indexForString(obj->scriptBlocksFile.at(ii));
- script.storeScript.lineNumber = obj->scriptBlocksLineNumber.at(ii);
- script.storeScript.value = output->indexForString(obj->scriptBlocks.at(ii));
+ int idx = output->scripts.count();
+ output->scripts << obj->scripts.at(ii);
+ script.storeScript.value = idx;
output->bytecode << script;
}
@@ -1086,9 +1086,7 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj,
bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script)
{
- QString scriptCode;
- QString sourceUrl;
- int lineNumber = 1;
+ Object::ScriptBlock scriptBlock;
if (script->properties.count() == 1 &&
script->properties.begin().key() == QByteArray("source")) {
@@ -1098,22 +1096,37 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script)
COMPILE_EXCEPTION(source, qApp->translate("QmlCompiler","Invalid Script block. Specify either the source property or inline script"));
if (source->value || source->values.count() != 1 ||
- source->values.at(0)->object || !source->values.at(0)->value.isString())
+ source->values.at(0)->object || !source->values.at(0)->value.isStringList())
COMPILE_EXCEPTION(source, qApp->translate("QmlCompiler","Invalid Script source value"));
- sourceUrl = output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString();
+ QStringList sources = source->values.at(0)->value.asStringList();
- for (int ii = 0; ii < unit->resources.count(); ++ii) {
- if (unit->resources.at(ii)->url == sourceUrl) {
- scriptCode = QString::fromUtf8(unit->resources.at(ii)->data);
- break;
+ for (int jj = 0; jj < sources.count(); ++jj) {
+ QString sourceUrl = output->url.resolved(QUrl(sources.at(jj))).toString();
+ QString scriptCode;
+ int lineNumber = 1;
+
+ for (int ii = 0; ii < unit->resources.count(); ++ii) {
+ if (unit->resources.at(ii)->url == sourceUrl) {
+ scriptCode = QString::fromUtf8(unit->resources.at(ii)->data);
+ break;
+ }
+ }
+
+ if (!scriptCode.isEmpty()) {
+ scriptBlock.codes.append(scriptCode);
+ scriptBlock.files.append(sourceUrl);
+ scriptBlock.lineNumbers.append(lineNumber);
}
}
} else if (!script->properties.isEmpty()) {
COMPILE_EXCEPTION(*script->properties.begin(), qApp->translate("QmlCompiler","Properties cannot be set on Script block"));
} else if (script->defaultProperty) {
- sourceUrl = output->url.toString();
+
+ QString scriptCode;
+ int lineNumber = 1;
+ QString sourceUrl = output->url.toString();
QmlParser::Location currentLocation;
@@ -1141,14 +1154,17 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script)
currentLocation = v->location.end;
currentLocation.column++;
}
- }
- if (!scriptCode.isEmpty()) {
- obj->scriptBlocks.append(scriptCode);
- obj->scriptBlocksFile.append(sourceUrl);
- obj->scriptBlocksLineNumber.append(lineNumber);
+ if (!scriptCode.isEmpty()) {
+ scriptBlock.codes.append(scriptCode);
+ scriptBlock.files.append(sourceUrl);
+ scriptBlock.lineNumbers.append(lineNumber);
+ }
}
+ if (!scriptBlock.codes.isEmpty())
+ obj->scripts << scriptBlock;
+
return true;
}
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 9597753..b54a62a 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -116,6 +116,7 @@ public:
QList<QScriptProgram *> programs;
QList<QmlPropertyCache *> propertyCaches;
QList<QmlIntegerCache *> contextCaches;
+ QList<QmlParser::Object::ScriptBlock> scripts;
void dumpInstructions();
private:
diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp
index 42f467b..38cbcfa 100644
--- a/src/declarative/qml/qmlcontext.cpp
+++ b/src/declarative/qml/qmlcontext.cpp
@@ -59,8 +59,7 @@ QmlContextPrivate::QmlContextPrivate()
{
}
-void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject,
- const QString &fileName, int lineNumber)
+void QmlContextPrivate::addScript(const QmlParser::Object::ScriptBlock &script, QObject *scopeObject)
{
Q_Q(QmlContext);
@@ -76,12 +75,14 @@ void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject,
QScriptValue scope = scriptEngine->newObject();
scriptContext->setActivationObject(scope);
- QScriptValue val = scriptEngine->evaluate(script, fileName, lineNumber);
+ for (int ii = 0; ii < script.codes.count(); ++ii) {
+ scriptEngine->evaluate(script.codes.at(ii), script.files.at(ii), script.lineNumbers.at(ii));
- if (scriptEngine->hasUncaughtException()) {
- QmlError error;
- QmlExpressionPrivate::exceptionToError(scriptEngine, error);
- qWarning().nospace() << qPrintable(error.toString());
+ if (scriptEngine->hasUncaughtException()) {
+ QmlError error;
+ QmlExpressionPrivate::exceptionToError(scriptEngine, error);
+ qWarning().nospace() << qPrintable(error.toString());
+ }
}
scriptEngine->popContext();
diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h
index a9c25a3..c8d0b2d 100644
--- a/src/declarative/qml/qmlcontext_p.h
+++ b/src/declarative/qml/qmlcontext_p.h
@@ -92,8 +92,7 @@ public:
int highPriorityCount;
QList<QScriptValue> scripts;
- void addScript(const QString &script, QObject *scope,
- const QString &fileName = QString(), int lineNumber = 1);
+ void addScript(const QmlParser::Object::ScriptBlock &, QObject *);
QUrl url;
diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp
index 6bab1c4..65d070c 100644
--- a/src/declarative/qml/qmlinstruction.cpp
+++ b/src/declarative/qml/qmlinstruction.cpp
@@ -140,7 +140,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx)
qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value);
break;
case QmlInstruction::StoreScript:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT\t\t" << instr->storeScript.value << "\t" << instr->storeScript.fileName << "\t" << instr->storeScript.lineNumber;
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT\t\t" << instr->storeScript.value;
break;
case QmlInstruction::StoreScriptString:
qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope;
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index 50d4b62..a5fc40c 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -252,8 +252,6 @@ public:
} storeScriptString;
struct {
int value;
- int fileName;
- int lineNumber;
} storeScript;
struct {
int propertyIndex;
diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp
index ee69b14..402c93e 100644
--- a/src/declarative/qml/qmlparser.cpp
+++ b/src/declarative/qml/qmlparser.cpp
@@ -54,10 +54,13 @@
#include "private/qmetaobjectbuilder_p.h"
#include <private/qmlvmemetaobject_p.h>
#include <private/qmlcompiler_p.h>
+#include "parser/qmljsast_p.h"
+#include "parser/qmljsengine_p.h"
#include <QtDebug>
QT_BEGIN_NAMESPACE
+using namespace QmlJS;
using namespace QmlParser;
QmlParser::Object::Object()
@@ -327,4 +330,55 @@ QmlJS::AST::Node *QmlParser::Variant::asAST() const
return 0;
}
+bool QmlParser::Variant::isStringList() const
+{
+ if (isString())
+ return true;
+
+ if (type() != Script || !n)
+ return false;
+
+ AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
+ if (!array)
+ return false;
+
+ AST::ElementList *elements = array->elements;
+
+ while (elements) {
+
+ if (!AST::cast<AST::StringLiteral *>(elements->expression))
+ return false;
+
+ elements = elements->next;
+ }
+
+ return true;
+}
+
+QStringList QmlParser::Variant::asStringList() const
+{
+ QStringList rv;
+ if (isString()) {
+ rv << asString();
+ return rv;
+ }
+
+ AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
+ if (!array)
+ return rv;
+
+ AST::ElementList *elements = array->elements;
+ while (elements) {
+
+ AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression);
+ if (!string)
+ return QStringList();
+ rv.append(string->value->asString());
+
+ elements = elements->next;
+ }
+
+ return rv;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h
index 2ece51f..73bb498 100644
--- a/src/declarative/qml/qmlparser_p.h
+++ b/src/declarative/qml/qmlparser_p.h
@@ -169,9 +169,12 @@ namespace QmlParser
QList<QPair<Property *, int> > scriptStringProperties;
// Script blocks that were nested under this object
- QStringList scriptBlocks;
- QStringList scriptBlocksFile;
- QList<int> scriptBlocksLineNumber;
+ struct ScriptBlock {
+ QStringList codes;
+ QStringList files;
+ QList<int> lineNumbers;
+ };
+ QList<ScriptBlock> scripts;
// The bytes to cast instances by to get to the QmlParserStatus
// interface. -1 indicates the type doesn't support this interface.
@@ -243,12 +246,14 @@ namespace QmlParser
bool isNumber() const { return type() == Number; }
bool isString() const { return type() == String; }
bool isScript() const { return type() == Script; }
+ bool isStringList() const;
bool asBoolean() const;
QString asString() const;
double asNumber() const;
QString asScript() const;
QmlJS::AST::Node *asAST() const;
+ QStringList asStringList() const;
private:
Type t;
diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp
index b622c24..23c050c 100644
--- a/src/declarative/qml/qmlscriptparser.cpp
+++ b/src/declarative/qml/qmlscriptparser.cpp
@@ -383,10 +383,12 @@ Object *ProcessAST::defineObjectBinding(AST::UiQualifiedId *qualifiedId,
QString propertyName = asString(scriptBinding->qualifiedId);
if (propertyName == QLatin1String("source")) {
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(scriptBinding->statement)) {
- AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(stmt->expression);
- if (string) {
+ QmlParser::Variant string = getVariant(stmt->expression);
+ if (string.isStringList()) {
+ QStringList urls = string.asStringList();
// We need to add this as a resource
- _parser->_refUrls << QUrl(string->value->asString());
+ for (int ii = 0; ii < urls.count(); ++ii)
+ _parser->_refUrls << QUrl(urls.at(ii));
}
}
}
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index da09288..f2fb217 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -142,7 +142,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt,
const QList<int> &intData = comp->intData;
const QList<float> &floatData = comp->floatData;
const QList<QmlPropertyCache *> &propertyCaches = comp->propertyCaches;
-
+ const QList<QmlParser::Object::ScriptBlock> &scripts = comp->scripts;
QmlEnginePrivate::SimpleList<QmlAbstractBinding> bindValues;
QmlEnginePrivate::SimpleList<QmlParserStatus> parserStatus;
@@ -224,7 +224,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt,
case QmlInstruction::SetId:
{
QObject *target = stack.top();
-// ctxt->setContextProperty(primitives.at(instr.setId.value), target);
cp->setIdProperty(instr.setId.index, target);
}
break;
@@ -551,9 +550,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt,
case QmlInstruction::StoreScript:
{
QObject *target = stack.top();
- cp->addScript(primitives.at(instr.storeScript.value), target,
- primitives.at(instr.storeScript.fileName),
- instr.storeScript.lineNumber);
+ cp->addScript(scripts.at(instr.storeScript.value), target);
}
break;
diff --git a/tests/auto/declarative/qmlecmascript/data/externalScript.1.qml b/tests/auto/declarative/qmlecmascript/data/externalScript.1.qml
new file mode 100644
index 0000000..2ac7b6e
--- /dev/null
+++ b/tests/auto/declarative/qmlecmascript/data/externalScript.1.qml
@@ -0,0 +1,11 @@
+import Qt 4.6
+
+QtObject {
+ property int test: external_script_func();
+
+ Script {
+ // Single source as non-array literal
+ source: "externalScript.js"
+ }
+}
+
diff --git a/tests/auto/declarative/qmlecmascript/data/externalScript.2.js b/tests/auto/declarative/qmlecmascript/data/externalScript.2.js
new file mode 100644
index 0000000..78c3a86
--- /dev/null
+++ b/tests/auto/declarative/qmlecmascript/data/externalScript.2.js
@@ -0,0 +1,8 @@
+function external_script_func2() {
+ return a;
+}
+
+function is_a_undefined() {
+ return a == undefined;
+}
+
diff --git a/tests/auto/declarative/qmlecmascript/data/externalScript.2.qml b/tests/auto/declarative/qmlecmascript/data/externalScript.2.qml
new file mode 100644
index 0000000..dec657c
--- /dev/null
+++ b/tests/auto/declarative/qmlecmascript/data/externalScript.2.qml
@@ -0,0 +1,11 @@
+import Qt 4.6
+
+QtObject {
+ property int test: external_script_func();
+
+ Script {
+ // Single source as array
+ source: [ "externalScript.js" ]
+ }
+}
+
diff --git a/tests/auto/declarative/qmlecmascript/data/externalScript.3.qml b/tests/auto/declarative/qmlecmascript/data/externalScript.3.qml
new file mode 100644
index 0000000..d7acf38
--- /dev/null
+++ b/tests/auto/declarative/qmlecmascript/data/externalScript.3.qml
@@ -0,0 +1,13 @@
+import Qt 4.6
+
+QtObject {
+ property int test: external_script_func();
+ property int test2: external_script_func2();
+ property bool test3: is_a_undefined();
+
+ Script {
+ // Multiple script
+ source: [ "externalScript.js", "externalScript.2.js" ]
+ }
+}
+
diff --git a/tests/auto/declarative/qmlecmascript/data/externalScript.4.qml b/tests/auto/declarative/qmlecmascript/data/externalScript.4.qml
new file mode 100644
index 0000000..16211aa
--- /dev/null
+++ b/tests/auto/declarative/qmlecmascript/data/externalScript.4.qml
@@ -0,0 +1,15 @@
+import Qt 4.6
+
+QtObject {
+ property int test: external_script_func();
+ property bool test2: is_a_undefined();
+
+ // Disconnected scripts
+ Script {
+ source: "externalScript.js"
+ }
+
+ Script {
+ source: "externalScript.2.js"
+ }
+}
diff --git a/tests/auto/declarative/qmlecmascript/data/externalScript.js b/tests/auto/declarative/qmlecmascript/data/externalScript.js
new file mode 100644
index 0000000..8928652
--- /dev/null
+++ b/tests/auto/declarative/qmlecmascript/data/externalScript.js
@@ -0,0 +1,6 @@
+var a = 92;
+
+function external_script_func() {
+ return a;
+}
+
diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp
index fe3ae6b..fb8bfb3 100644
--- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp
+++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp
@@ -108,6 +108,7 @@ private slots:
void exceptionClearsOnReeval();
void transientErrors();
void shutdownErrors();
+ void externalScript();
private:
QmlEngine engine;
@@ -946,6 +947,53 @@ void tst_qmlecmascript::shutdownErrors()
QCOMPARE(transientErrorsMsgCount, 0);
}
+// Check that Script::source property works as expected
+void tst_qmlecmascript::externalScript()
+{
+ {
+ QmlComponent component(&engine, TEST_FILE("externalScript.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 92);
+
+ delete object;
+ }
+
+ {
+ QmlComponent component(&engine, TEST_FILE("externalScript.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 92);
+
+ delete object;
+ }
+
+ {
+ QmlComponent component(&engine, TEST_FILE("externalScript.3.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 92);
+ QCOMPARE(object->property("test2").toInt(), 92);
+ QCOMPARE(object->property("test3").toBool(), false);
+
+ delete object;
+ }
+
+ {
+ QmlComponent component(&engine, TEST_FILE("externalScript.4.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 92);
+ QCOMPARE(object->property("test2").toBool(), true);
+
+ delete object;
+ }
+}
+
QTEST_MAIN(tst_qmlecmascript)
#include "tst_qmlecmascript.moc"