diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-07-14 03:54:55 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-07-15 07:30:16 (GMT) |
commit | 4f7e21dc04ce93531ef68f7694a5e8969448de8b (patch) | |
tree | ce7e8170b5be6c974420d012a03f620f86cd6d8d | |
parent | 9eca9e028884fb82d97e284826faa7965af356bd (diff) | |
download | Qt-4f7e21dc04ce93531ef68f7694a5e8969448de8b.zip Qt-4f7e21dc04ce93531ef68f7694a5e8969448de8b.tar.gz Qt-4f7e21dc04ce93531ef68f7694a5e8969448de8b.tar.bz2 |
Rework compiler to a two phase analyse/generate approach
52 files changed, 1252 insertions, 1050 deletions
diff --git a/demos/declarative/flickr/content/Star.qml b/demos/declarative/flickr/content/Star.qml index 2c2807a..0828bc0 100644 --- a/demos/declarative/flickr/content/Star.qml +++ b/demos/declarative/flickr/content/Star.qml @@ -3,8 +3,8 @@ Item { width: 24 height: 24 - property string rating - property string on + property int rating + property bool on signal clicked diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 8775c5c..e6817fe 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1167,8 +1167,10 @@ static QByteArray buildParameterNames // Build a QMetaObject in "buf" based on the information in "d". // If "buf" is null, then return the number of bytes needed to -// build the QMetaObject. -static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) +// build the QMetaObject. Returns -1 if the metaobject if +// relocatable is set, but the metaobject contains extradata. +static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, + bool relocatable) { int size = 0; int dataIndex; @@ -1176,18 +1178,23 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) int index; bool hasNotifySignals = false; + if (relocatable && + (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction)) + return -1; + // Create the main QMetaObject structure at the start of the buffer. QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf); size += sizeof(QMetaObject); ALIGN(size, int); if (buf) { - meta->d.superdata = d->superClass; + if (!relocatable) meta->d.superdata = d->superClass; meta->d.extradata = 0; } // Populate the QMetaObjectPrivate structure. QMetaObjectPrivate *pmeta = reinterpret_cast<QMetaObjectPrivate *>(buf + size); + int pmetaSize = size; dataIndex = 13; // Number of fields in the QMetaObjectPrivate. for (index = 0; index < d->properties.size(); ++index) { if (d->properties[index].notifySignal != -1) { @@ -1246,8 +1253,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) size += dataIndex * sizeof(int); char *str = reinterpret_cast<char *>(buf + size); if (buf) { - meta->d.stringdata = str; - meta->d.data = reinterpret_cast<uint *>(data); + if (relocatable) { + meta->d.stringdata = reinterpret_cast<const char *>((intptr_t)size); + meta->d.data = reinterpret_cast<uint *>((intptr_t)pmetaSize); + } else { + meta->d.stringdata = str; + meta->d.data = reinterpret_cast<uint *>(data); + } } // Reset the current data position to just past the QMetaObjectPrivate. @@ -1422,12 +1434,67 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) */ QMetaObject *QMetaObjectBuilder::toMetaObject() const { - int size = buildMetaObject(d, 0); + int size = buildMetaObject(d, 0, false); char *buf = reinterpret_cast<char *>(qMalloc(size)); - buildMetaObject(d, buf); + buildMetaObject(d, buf, false); return reinterpret_cast<QMetaObject *>(buf); } +/* + \internal + + Converts this meta object builder into relocatable data. This data can + be stored, copied and later passed to fromRelocatableData() to create a + concrete QMetaObject. + + The data is specific to the architecture on which it was created, but is not + specific to the process that created it. Not all meta object builder's can + be converted to data in this way. If \a ok is provided, it will be set to + true if the conversion succeeds, and false otherwise. If a + staticMetacallFunction() or any relatedMetaObject()'s are specified the + conversion to relocatable data will fail. +*/ +QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const +{ + int size = buildMetaObject(d, 0, true); + if (size == -1) { + if (ok) *ok = false; + return QByteArray(); + } + + QByteArray data; + data.resize(size); + char *buf = data.data(); + buildMetaObject(d, buf, true); + if (ok) *ok = true; + return data; +} + +/* + \internal + + Sets the \a data returned from toRelocatableData() onto a concrete + QMetaObject instance, \a output. As the meta object's super class is not + saved in the relocatable data, it must be passed as \a superClass. +*/ +void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output, + const QMetaObject *superclass, + const QByteArray &data) +{ + if (!output) + return; + + const char *buf = data.constData(); + const QMetaObject *dataMo = reinterpret_cast<const QMetaObject *>(buf); + + intptr_t stringdataOffset = (intptr_t)dataMo->d.stringdata; + intptr_t dataOffset = (intptr_t)dataMo->d.data; + + output->d.superdata = superclass; + output->d.stringdata = buf + stringdataOffset; + output->d.data = reinterpret_cast<const uint *>(buf + dataOffset); +} + /*! \typedef QMetaObjectBuilder::StaticMetacallFunction diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h index 952364a..d503163 100644 --- a/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -169,6 +169,8 @@ public: void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value); QMetaObject *toMetaObject() const; + QByteArray toRelocatableData(bool * = 0) const; + static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &); #ifndef QT_NO_DATASTREAM void serialize(QDataStream& stream) const; diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index f549a5e..d8f0f7f 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -12,6 +12,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlproxymetaobject.cpp \ qml/qmlvme.cpp \ qml/qmlcompiler.cpp \ + qml/qmlcompileddata.cpp \ qml/qmlcompiledcomponent.cpp \ qml/qmlboundsignal.cpp \ qml/qmldom.cpp \ diff --git a/src/declarative/qml/qmlcompiledcomponent.cpp b/src/declarative/qml/qmlcompiledcomponent.cpp index bea736a..6ce89b7 100644 --- a/src/declarative/qml/qmlcompiledcomponent.cpp +++ b/src/declarative/qml/qmlcompiledcomponent.cpp @@ -50,7 +50,6 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); QmlCompiledComponent::QmlCompiledComponent() -: dumpStatus(NoDump) { } @@ -60,7 +59,6 @@ QmlCompiledComponent::~QmlCompiledComponent() qFree(synthesizedMetaObjects.at(ii)); } - void QmlCompiledComponent::dumpInstructions() { if (!compilerDump()) @@ -76,21 +74,4 @@ void QmlCompiledComponent::dumpInstructions() qWarning() << "-------------------------------------------------------------------------------"; } -void QmlCompiledComponent::dumpPre() -{ - if (!(dumpStatus & DumpPre)) { - dumpInstructions(); - dumpStatus = (DumpStatus)(dumpStatus | DumpPre); - } -} - -void QmlCompiledComponent::dumpPost() -{ - if (!(dumpStatus & DumpPost)) { - dumpInstructions(); - dumpStatus = (DumpStatus)(dumpStatus | DumpPost); - } - -} - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiledcomponent_p.h b/src/declarative/qml/qmlcompiledcomponent_p.h index 0945892..ddc1124 100644 --- a/src/declarative/qml/qmlcompiledcomponent_p.h +++ b/src/declarative/qml/qmlcompiledcomponent_p.h @@ -74,12 +74,8 @@ public: QmlCompiledComponent(); ~QmlCompiledComponent(); - void dumpPre(); - void dumpPost(); - -private: - enum DumpStatus { NoDump = 0x00, DumpPre = 0x01, DumpPost = 0x02 } dumpStatus; void dumpInstructions(); +private: void dump(QmlInstruction *, int idx = -1); friend class QmlCompiler; friend class QmlDomDocument; diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b04c932..dafc581 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -71,90 +71,6 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; -int QmlCompiledData::indexForString(const QString &data) -{ - int idx = primitives.indexOf(data); - if (idx == -1) { - idx = primitives.count(); - primitives << data; - } - return idx; -} - -int QmlCompiledData::indexForByteArray(const QByteArray &data) -{ - int idx = datas.indexOf(data); - if (idx == -1) { - idx = datas.count(); - datas << data; - } - return idx; -} - -int QmlCompiledData::indexForFloat(float *data, int count) -{ - Q_ASSERT(count > 0); - - for (int ii = 0; ii <= floatData.count() - count; ++ii) { - bool found = true; - for (int jj = 0; jj < count; ++jj) { - if (floatData.at(ii + jj) != data[jj]) { - found = false; - break; - } - } - - if (found) - return ii; - } - - int idx = floatData.count(); - for (int ii = 0; ii < count; ++ii) - floatData << data[ii]; - - return idx; -} - -int QmlCompiledData::indexForInt(int *data, int count) -{ - Q_ASSERT(count > 0); - - for (int ii = 0; ii <= intData.count() - count; ++ii) { - bool found = true; - for (int jj = 0; jj < count; ++jj) { - if (intData.at(ii + jj) != data[jj]) { - found = false; - break; - } - } - - if (found) - return ii; - } - - int idx = intData.count(); - for (int ii = 0; ii < count; ++ii) - intData << data[ii]; - - return idx; -} - -int QmlCompiledData::indexForLocation(const QmlParser::Location &l) -{ - // ### FIXME - int rv = locations.count(); - locations << l; - return rv; -} - -int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) -{ - // ### FIXME - int rv = locations.count(); - locations << l.start << l.end; - return rv; -} - QmlCompiler::QmlCompiler() : output(0) { @@ -241,14 +157,13 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) } // Compile a simple assignment of v to prop into instr -bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - QmlParser::Value *v) +bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) { QString string = v->value.asScript(); if (!prop.isWritable()) - COMPILE_EXCEPTION2(v, "Cannot assign literal value to read-only property" << prop.name()); + COMPILE_EXCEPTION2(v, "Invalid property assignment: read-only property"); if (prop.isEnumType()) { int value; @@ -257,12 +172,136 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, } else value = prop.enumerator().keyToValue(string.toLatin1().constData()); if (value == -1) - COMPILE_EXCEPTION2(v, "Cannot assign unknown enumeration to property" << prop.name()); + COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown enumeration"); + return true; + } + int type = prop.userType(); + switch(type) { + case -1: + break; + case QVariant::String: + if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: string expected"); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: url expected"); + break; + case QVariant::UInt: + { + bool ok; + string.toUInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: unsigned int expected"); + } + break; + case QVariant::Int: + { + bool ok; + string.toInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: int expected"); + } + break; + case QMetaType::Float: + { + bool ok; + string.toFloat(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: float expected"); + } + break; + case QVariant::Double: + { + bool ok; + string.toDouble(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: double expected"); + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(string); + if (!c.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: color expected"); + } + break; + case QVariant::Date: + { + QDate d = QDate::fromString(string, Qt::ISODate); + if (!d.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: date expected"); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(string, Qt::ISODate); + if (!time.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: time expected"); + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (!dateTime.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: datetime expected"); + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QmlStringConverters::pointFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: point expected"); + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: size expected"); + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: rect expected"); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION2(v, "Invalid property assignment: boolean expected"); + } + break; + default: + { + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (!converter) + COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown type" << prop.type()); + } + break; + } + return true; +} + +void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) +{ + QString string = v->value.asScript(); + + QmlInstruction instr; + instr.line = v->location.start.line; + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toLatin1().constData()); + } else + value = prop.enumerator().keyToValue(string.toLatin1().constData()); + instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); instr.storeInteger.value = value; - return true; + output->bytecode << instr; + return; } + int type = prop.userType(); switch(type) { case -1: @@ -291,51 +330,33 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, { instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); - bool ok; - int value = string.toUInt(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to unsigned integer"); - instr.storeInteger.value = value; + instr.storeInteger.value = string.toUInt(); } break; case QVariant::Int: { instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); - bool ok; - int value = string.toInt(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to integer"); - instr.storeInteger.value = value; + instr.storeInteger.value = string.toInt(); } break; case QMetaType::Float: { instr.type = QmlInstruction::StoreFloat; instr.storeFloat.propertyIndex = prop.propertyIndex(); - bool ok; - float value = string.toFloat(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to float number"); - instr.storeFloat.value = value; + instr.storeFloat.value = string.toFloat(); } break; case QVariant::Double: { instr.type = QmlInstruction::StoreDouble; instr.storeDouble.propertyIndex = prop.propertyIndex(); - bool ok; - double value = string.toDouble(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to double number"); - instr.storeDouble.value = value; + instr.storeDouble.value = string.toDouble(); } break; case QVariant::Color: { QColor c = QmlStringConverters::colorFromString(string); - if (!c.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to color"); instr.type = QmlInstruction::StoreColor; instr.storeColor.propertyIndex = prop.propertyIndex(); instr.storeColor.value = c.rgba(); @@ -344,8 +365,6 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Date: { QDate d = QDate::fromString(string, Qt::ISODate); - if (!d.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date"); instr.type = QmlInstruction::StoreDate; instr.storeDate.propertyIndex = prop.propertyIndex(); instr.storeDate.value = d.toJulianDay(); @@ -354,9 +373,8 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Time: { QTime time = QTime::fromString(string, Qt::ISODate); - if (!time.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to time"); - int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; + int data[] = { time.hour(), time.minute(), + time.second(), time.msec() }; int index = output->indexForInt(data, 4); instr.type = QmlInstruction::StoreTime; instr.storeTime.propertyIndex = prop.propertyIndex(); @@ -366,8 +384,6 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::DateTime: { QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); - if (!dateTime.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date and time"); int data[] = { dateTime.date().toJulianDay(), dateTime.time().hour(), dateTime.time().minute(), @@ -382,90 +398,76 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Point: case QVariant::PointF: { - bool ok; - QPointF point = QmlStringConverters::pointFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to point"); - float data[] = { point.x(), point.y() }; - int index = output->indexForFloat(data, 2); - if (type == QVariant::PointF) - instr.type = QmlInstruction::StorePointF; - else - instr.type = QmlInstruction::StorePoint; - instr.storeRealPair.propertyIndex = prop.propertyIndex(); - instr.storeRealPair.valueIndex = index; + bool ok; + QPointF point = + QmlStringConverters::pointFFromString(string, &ok); + float data[] = { point.x(), point.y() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QmlInstruction::StorePointF; + else + instr.type = QmlInstruction::StorePoint; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; } break; case QVariant::Size: case QVariant::SizeF: { - bool ok; - QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to size"); - float data[] = { size.width(), size.height() }; - int index = output->indexForFloat(data, 2); - if (type == QVariant::SizeF) - instr.type = QmlInstruction::StoreSizeF; - else - instr.type = QmlInstruction::StoreSize; - instr.storeRealPair.propertyIndex = prop.propertyIndex(); - instr.storeRealPair.valueIndex = index; + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + float data[] = { size.width(), size.height() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QmlInstruction::StoreSizeF; + else + instr.type = QmlInstruction::StoreSize; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; } break; case QVariant::Rect: case QVariant::RectF: { - bool ok; - QRectF rect = QmlStringConverters::rectFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to rect"); - float data[] = { rect.x(), rect.y(), - rect.width(), rect.height() }; - int index = output->indexForFloat(data, 4); - if (type == QVariant::RectF) - instr.type = QmlInstruction::StoreRectF; - else - instr.type = QmlInstruction::StoreRect; - instr.storeRect.propertyIndex = prop.propertyIndex(); - instr.storeRect.valueIndex = index; + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + float data[] = { rect.x(), rect.y(), + rect.width(), rect.height() }; + int index = output->indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QmlInstruction::StoreRectF; + else + instr.type = QmlInstruction::StoreRect; + instr.storeRect.propertyIndex = prop.propertyIndex(); + instr.storeRect.valueIndex = index; } break; case QVariant::Bool: { - bool ok; - bool b = QmlStringConverters::boolFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to boolean"); - instr.type = QmlInstruction::StoreBool; - instr.storeBool.propertyIndex = prop.propertyIndex(); - instr.storeBool.value = b; + bool b = v->value.asBoolean(); + instr.type = QmlInstruction::StoreBool; + instr.storeBool.propertyIndex = prop.propertyIndex(); + instr.storeBool.value = b; } break; default: { - int t = prop.type(); - if (t == QVariant::UserType) - t = prop.userType(); - QmlMetaType::StringConverter converter = - QmlMetaType::customStringConverter(t); - if (converter) { - int index = output->customTypeData.count(); - instr.type = QmlInstruction::AssignCustomType; - instr.assignCustomType.propertyIndex = prop.propertyIndex(); - instr.assignCustomType.valueIndex = index; - - QmlCompiledData::CustomTypeData data; - data.index = output->indexForString(string); - data.type = t; - output->customTypeData << data; - break; - } + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + int index = output->customTypeData.count(); + instr.type = QmlInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = prop.propertyIndex(); + instr.assignCustomType.valueIndex = index; + + QmlCompiledData::CustomTypeData data; + data.index = output->indexForString(string); + data.type = t; + output->customTypeData << data; } - COMPILE_EXCEPTION2(v, "Cannot assign to property" << prop.name() << "of unknown type" << prop.type()); break; } - return true; + output->bytecode << instr; } void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) @@ -530,7 +532,7 @@ bool QmlCompiler::compile(QmlEngine *engine, compileTree(root); if (!isError()) { - out->dumpPre(); + out->dumpInstructions(); } else { reset(out, true); } @@ -544,24 +546,23 @@ void QmlCompiler::compileTree(Object *tree) { compileState.root = tree; + if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) + return; + QmlInstruction init; init.type = QmlInstruction::Init; init.line = 0; - init.init.dataSize = 0; - init.init.bindingsSize = 0; - init.init.parserStatusSize = 0; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; output->bytecode << init; - if (!compileObject(tree, 0)) // Compile failed - return; + genObject(tree); QmlInstruction def; init.line = 0; def.type = QmlInstruction::SetDefault; output->bytecode << def; - finalizeComponent(0); - if (tree->metatype) static_cast<QMetaObject &>(output->root) = *tree->metaObject(); else @@ -569,55 +570,35 @@ void QmlCompiler::compileTree(Object *tree) } -bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT (obj->type != -1); - const QmlCompiledData::TypeReference &tr = output->types.at(obj->type); + const QmlCompiledData::TypeReference &tr = + output->types.at(obj->type); obj->metatype = tr.metaObject(); + if (tr.component) obj->url = tr.component->url(); - if (output->types.at(obj->type).className == "Component") { - COMPILE_CHECK(compileComponent(obj, ctxt)); + // This object is a "Component" element + if (obj->metatype == &QmlComponent::staticMetaObject) { + COMPILE_CHECK(buildComponent(obj, ctxt)); return true; } + // Object instantiations reset the binding context BindingContext objCtxt(obj); - int createInstrIdx = output->bytecode.count(); - // Create the object - QmlInstruction create; - create.type = QmlInstruction::CreateObject; - create.line = obj->location.start.line; - create.create.data = -1; - create.create.type = obj->type; - output->bytecode << create; - - // Create the synthesized meta object - COMPILE_CHECK(compileDynamicMeta(obj)); + // Create the synthesized meta object, ignoring aliases + COMPILE_CHECK(mergeDynamicMetaProperties(obj)); + COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); // Find the native type and check for the QmlParserStatus interface - // ### Optimize - const QMetaObject *mo = obj->metatype; - QmlType *type = 0; - while (!type && mo) { - type = QmlMetaType::qmlType(mo); - mo = mo->superClass(); - } + QmlType *type = toQmlType(obj); Q_ASSERT(type); - int parserStatusCast = type->parserStatusCast(); - - // If the type support the QmlParserStatusInterface we need to invoke - // classBegin() - if (parserStatusCast != -1) { - QmlInstruction begin; - begin.type = QmlInstruction::BeginObject; - begin.begin.castValue = parserStatusCast; - begin.line = obj->location.start.line; - output->bytecode << begin; - + obj->parserStatusCast = type->parserStatusCast(); + if (obj->parserStatusCast != -1) compileState.parserStatusCount++; - } // Check if this is a custom parser type. Custom parser types allow // assignments to non-existant properties. These assignments are then @@ -626,57 +607,72 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) output->types.at(obj->type).type->customParser() != 0; QList<QmlCustomParserProperty> customProps; - QStringList deferred = deferredProperties(obj); - QList<Property *> deferredProps; + // Fetch the list of deferred properties + QStringList deferredList = deferredProperties(obj); + + // Must do id property first. This is to ensure that the id given to any + // id reference created matches the order in which the objects are + // instantiated + foreach(Property *prop, obj->properties) { + if (prop->name == "id") { + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + break; + } + } - // Compile all explicit properties specified + // Build all explicit properties specified foreach(Property *prop, obj->properties) { + if (prop->name == "id") + continue; + + bool canDefer = false; if (isCustomParser) { - // Custom parser types don't support signal properties if (testProperty(prop, obj)) { - if (deferred.contains(QString::fromLatin1(prop->name.constData()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - if (isSignalPropertyName(prop->name)) { - COMPILE_CHECK(compileSignal(prop,obj)); + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); } else { - if (deferred.contains(QString::fromLatin1(prop->name.constData()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } } + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(prop->name)) + prop->isDeferred = true; + } - // Compile the default property + // Build the default property if (obj->defaultProperty) { Property *prop = obj->defaultProperty; + bool canDefer = false; if (isCustomParser) { if (testProperty(prop, obj)) { - QMetaProperty p = deferred.isEmpty()?QMetaProperty():QmlMetaType::defaultProperty(obj->metaObject()); - if (deferred.contains(QString::fromLatin1(p.name()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - QMetaProperty p = deferred.isEmpty()?QMetaProperty():QmlMetaType::defaultProperty(obj->metaObject()); - if (deferred.contains(QString::fromLatin1(p.name()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(prop->name)) + prop->isDeferred = true; } // Compile custom parser parts @@ -684,16 +680,83 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) // ### Check for failure bool ok = false; QmlCustomParser *cp = output->types.at(obj->type).type->customParser(); - QByteArray customData = cp->compile(customProps, &ok); + obj->custom = cp->compile(customProps, &ok); if(!ok) COMPILE_EXCEPTION("Failure compiling custom type"); - if(!customData.isEmpty()) - output->bytecode[createInstrIdx].create.data = - output->indexForByteArray(customData); } - // Build the deferred block - if (!deferredProps.isEmpty()) { + return true; +} + +void QmlCompiler::genObject(QmlParser::Object *obj) +{ + if (obj->metatype == &QmlComponent::staticMetaObject) { + genComponent(obj); + return; + } + + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->location.start.line; + create.create.data = -1; + if (!obj->custom.isEmpty()) + create.create.data = output->indexForByteArray(obj->custom); + create.create.type = obj->type; + output->bytecode << create; + + // Setup the synthesized meta object if necessary + if (!obj->metadata.isEmpty()) { + QmlInstruction meta; + meta.type = QmlInstruction::StoreMetaObject; + meta.line = -1; + meta.storeMeta.data = output->indexForByteArray(obj->metadata); + meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); + meta.storeMeta.slotData = -1; + output->bytecode << meta; + } + + // Set the object id + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = -1; + id.setId.value = output->indexForString(obj->id); + output->bytecode << id; + } + + // Begin the class + if (obj->parserStatusCast != -1) { + QmlInstruction begin; + begin.type = QmlInstruction::BeginObject; + begin.begin.castValue = obj->parserStatusCast; + begin.line = obj->location.start.line; + output->bytecode << begin; + } + + genObjectBody(obj); + + // Complete the the class + if (obj->parserStatusCast != -1) { + QmlInstruction complete; + complete.type = QmlInstruction::CompleteObject; + complete.complete.castValue = obj->parserStatusCast; + complete.line = obj->location.start.line; + output->bytecode << complete; + } +} + +void QmlCompiler::genObjectBody(QmlParser::Object *obj) +{ + bool seenDefer = false; + foreach(Property *prop, obj->valueProperties) { + if (prop->isDeferred) { + seenDefer = true; + continue; + } + genValueProperty(prop, obj); + } + if (seenDefer) { QmlInstruction defer; defer.type = QmlInstruction::Defer; defer.line = 0; @@ -701,44 +764,147 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) int deferIdx = output->bytecode.count(); output->bytecode << defer; - // ### This is lame, we should check if individual properties have - // ids defined within them - int idCount = compileState.ids.count(); - foreach (Property *prop, deferredProps) { - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + foreach(Property *prop, obj->valueProperties) { + if (!prop->isDeferred) + continue; + genValueProperty(prop, obj); } - if (idCount == compileState.ids.count()) - output->bytecode[deferIdx].defer.deferCount = - output->bytecode.count() - deferIdx - 1; + + output->bytecode[deferIdx].defer.deferCount = + output->bytecode.count() - deferIdx - 1; } - // If the type support the QmlParserStatusInterface we need to invoke - // classComplete() - if (parserStatusCast != -1) { - QmlInstruction complete; - complete.type = QmlInstruction::CompleteObject; - complete.complete.castValue = parserStatusCast; - complete.line = obj->location.start.line; - output->bytecode << complete; - } + foreach(Property *prop, obj->signalProperties) { - return true; + QmlParser::Value *v = prop->values.at(0); + + if (v->type == Value::SignalObject) { + + genObject(v->object); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignalObject; + assign.line = v->location.start.line; + assign.assignSignalObject.signal = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + } else if (v->type == Value::SignalExpression) { + + QmlInstruction store; + store.type = QmlInstruction::StoreSignal; + store.line = v->location.start.line; + store.storeSignal.signalIndex = prop->index; + store.storeSignal.value = + output->indexForString(v->value.asScript().trimmed()); + output->bytecode << store; + + } + + } + + foreach(Property *prop, obj->attachedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchAttached; + fetch.line = prop->location.start.line; + fetch.fetchAttached.id = prop->index; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->groupedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.line = prop->location.start.line; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } +} + +void QmlCompiler::genComponent(QmlParser::Object *obj) +{ + QmlParser::Object *root = obj->defaultProperty->values.at(0)->object; + Q_ASSERT(root); + + QmlInstruction create; + create.type = QmlInstruction::CreateComponent; + create.line = root->location.start.line; + create.createComponent.endLine = root->location.end.line; + output->bytecode << create; + int count = output->bytecode.count(); + + ComponentCompileState oldCompileState = compileState; + compileState = componentState(root); + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.line = obj->location.start.line; + output->bytecode << init; + + genObject(root); + + output->bytecode[count - 1].createComponent.count = + output->bytecode.count() - count; + + compileState = oldCompileState; + + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = -1; + id.setId.value = output->indexForString(obj->id);; + output->bytecode << id; + } } -bool QmlCompiler::compileComponent(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildComponent(QmlParser::Object *obj, + const BindingContext &ctxt) { + // The special "Component" element can only have the id property and a + // default property, that actually defines the component's tree + + // Find, check and set the "id" property (if any) Property *idProp = 0; if (obj->properties.count() > 1 || (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) COMPILE_EXCEPTION("Invalid component specification"); + + if (obj->properties.count()) + idProp = *obj->properties.begin(); + if (idProp && (idProp->value || idProp->values.count() > 1 || !isValidId(idProp->values.first()->primitive()))) + COMPILE_EXCEPTION("Invalid component id specification"); + + if (idProp) { + QString idVal = idProp->values.first()->primitive().toUtf8(); + + if (compileState.ids.contains(idVal)) + COMPILE_EXCEPTION("id is not unique"); + + addId(idVal, obj); + + obj->id = idVal.toUtf8(); + } + + // Check the Component tree is well formed if (obj->defaultProperty && (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) COMPILE_EXCEPTION("Invalid component body specification"); - if (obj->properties.count()) - idProp = *obj->properties.begin(); - if (idProp && (idProp->value || idProp->values.count() > 1)) - COMPILE_EXCEPTION("Invalid component id specification"); Object *root = 0; if (obj->defaultProperty && obj->defaultProperty->values.count()) @@ -747,84 +913,68 @@ bool QmlCompiler::compileComponent(Object *obj, const BindingContext &ctxt) if (!root) COMPILE_EXCEPTION("Cannot create empty component specification"); - COMPILE_CHECK(compileComponentFromRoot(root, ctxt)); - - if (idProp && idProp->values.count()) { - QString val = idProp->values.at(0)->primitive(); - if (!isValidId(val)) - COMPILE_EXCEPTION("Invalid id property value"); - - if (compileState.ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); - - IdReference reference; - reference.id = val; - reference.object = obj; - reference.instructionIdx = output->bytecode.count(); - reference.idx = compileState.ids.count(); - compileState.ids.insert(val, reference); - - int pref = output->indexForString(val); - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = idProp->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - - output->bytecode << id; - } + // Build the component tree + COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); return true; } -bool QmlCompiler::compileComponentFromRoot(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj, + const BindingContext &ctxt) { - output->bytecode.push_back(QmlInstruction()); - QmlInstruction &create = output->bytecode.last(); - create.type = QmlInstruction::CreateComponent; - create.line = obj->location.start.line; - create.createComponent.endLine = obj->location.end.line; - int count = output->bytecode.count(); - - QmlInstruction init; - init.type = QmlInstruction::Init; - init.init.dataSize = 0; - init.init.bindingsSize = 0; - init.init.parserStatusSize = 0; - init.line = obj->location.start.line; - output->bytecode << init; - ComponentCompileState oldComponentCompileState = compileState; compileState = ComponentCompileState(); compileState.root = obj; + if (obj) - COMPILE_CHECK(compileObject(obj, ctxt)); + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); - COMPILE_CHECK(finalizeComponent(count)); - create.createComponent.count = output->bytecode.count() - count; compileState = oldComponentCompileState; + return true; } -bool QmlCompiler::compileFetchedObject(Object *obj, const BindingContext &ctxt) + +// Build a sub-object. A sub-object is one that was not created directly by +// QML - such as a grouped property object, or an attached object. Sub-object's +// can't have an id, involve a custom parser, have attached properties etc. +bool QmlCompiler::buildSubObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); + Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context if (obj->defaultProperty) - COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + COMPILE_CHECK(buildProperty(obj->defaultProperty, obj, ctxt)); foreach(Property *prop, obj->properties) { if (isSignalPropertyName(prop->name)) { - COMPILE_CHECK(compileSignal(prop, obj)); + COMPILE_CHECK(buildSignal(prop, obj, ctxt)); } else { - COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); } } return true; } -int QmlCompiler::signalByName(const QMetaObject *mo, const QByteArray &name) +int QmlCompiler::componentTypeRef() +{ + QmlType *t = QmlMetaType::qmlType("Component"); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) + return ii; + } + QmlCompiledData::TypeReference ref; + ref.className = "Component"; + ref.type = t; + output->types << ref; + return output->types.count() - 1; +} + +int QmlCompiler::findSignalByName(const QMetaObject *mo, const QByteArray &name) { int methods = mo->methodCount(); for (int ii = methods - 1; ii >= 0; --ii) { @@ -839,15 +989,13 @@ int QmlCompiler::signalByName(const QMetaObject *mo, const QByteArray &name) return -1; } -bool QmlCompiler::compileSignal(Property *prop, Object *obj) +bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(obj->metaObject()); - if (prop->values.isEmpty() && !prop->value) - return true; - - if (prop->value || prop->values.count() > 1) - COMPILE_EXCEPTION("Incorrectly specified signal"); + if (prop->isEmpty()) + COMPILE_EXCEPTION2(prop, "Empty property assignment"); QByteArray name = prop->name; Q_ASSERT(name.startsWith("on")); @@ -855,47 +1003,26 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) if(name[0] >= 'A' && name[0] <= 'Z') name[0] = name[0] - 'A' + 'a'; - int sigIdx = signalByName(obj->metaObject(), name); + int sigIdx = findSignalByName(obj->metaObject(), name); if (sigIdx == -1) { - COMPILE_CHECK(compileProperty(prop, obj, 0)); + // If the "on<Signal>" name doesn't resolve into a signal, try it as a + // property. + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); } else { - if (prop->values.at(0)->object) { - int pr = output->indexForByteArray(prop->name); - - bool rv = compileObject(prop->values.at(0)->object, 0); + if (prop->value || prop->values.count() > 1) + COMPILE_EXCEPTION("Incorrectly specified signal"); - if (rv) { - QmlInstruction assign; - assign.type = QmlInstruction::AssignSignalObject; - assign.line = prop->values.at(0)->location.start.line; - assign.assignSignalObject.signal = pr; - - output->bytecode << assign; - - prop->values.at(0)->type = Value::SignalObject; - } - - return rv; + prop->index = sigIdx; + obj->addSignalProperty(prop); + if (prop->values.at(0)->object) { + COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); + prop->values.at(0)->type = Value::SignalObject; } else { - QString script = prop->values.at(0)->value.asScript().trimmed(); - if (script.isEmpty()) - return true; - - int idx = output->indexForString(script); - - QmlInstruction store; - store.line = prop->values.at(0)->location.start.line; - store.type = QmlInstruction::StoreSignal; - store.storeSignal.signalIndex = sigIdx; - store.storeSignal.value = idx; - - output->bytecode << store; - prop->values.at(0)->type = Value::SignalExpression; } } @@ -903,6 +1030,7 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) return true; } + // Returns true if prop exists on obj, false otherwise bool QmlCompiler::testProperty(QmlParser::Property *prop, QmlParser::Object *obj) @@ -924,9 +1052,11 @@ bool QmlCompiler::testProperty(QmlParser::Property *prop, return false; } -bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { - if (prop->values.isEmpty() && !prop->value) + if (prop->isEmpty()) COMPILE_EXCEPTION2(prop, "Empty property assignment"); const QMetaObject *metaObject = obj->metaObject(); @@ -934,13 +1064,21 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingCont if (isAttachedPropertyName(prop->name)) { // Setup attached property data + + if (ctxt.isSubContext()) { + // Attached properties cannot be used on sub-objects. Sub-objects + // always exist in a binding sub-context, which is what we test + // for here. + COMPILE_EXCEPTION2(prop, "Attached properties cannot be used here"); + } + QmlType *type = QmlMetaType::qmlType(prop->name); if (!type || !type->attachedPropertiesType()) COMPILE_EXCEPTION2(prop, "Non-existant attached object"); if (!prop->value) - COMPILE_EXCEPTION2(prop, "Cannot assign directly to attached object"); + COMPILE_EXCEPTION2(prop, "Invalid attached object assignment"); prop->value->metatype = type->attachedPropertiesType(); } else { @@ -976,125 +1114,259 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingCont } } - if (!prop->isDefault && prop->name == "id") { + if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { - COMPILE_CHECK(compileIdProperty(prop, obj)); + // The magic "id" behaviour doesn't apply when "id" is resolved as a + // default property or to sub-objects (which are always in binding + // sub-contexts) + COMPILE_CHECK(buildIdProperty(prop, obj)); + if (prop->type == QVariant::String && + prop->values.at(0)->value.isString()) + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); } else if (isAttachedPropertyName(prop->name)) { - COMPILE_CHECK(compileAttachedProperty(prop, ctxt)); + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); } else if (prop->index == -1) { if (prop->isDefault) { - COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant default property"); + COMPILE_EXCEPTION2(prop->values.first(), "Cannot assign to non-existant default property"); } else { COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant property" << prop->name); } } else if (prop->value) { - COMPILE_CHECK(compileNestedProperty(prop, ctxt)); + COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); } else if (QmlMetaType::isQmlList(prop->type) || QmlMetaType::isList(prop->type)) { - COMPILE_CHECK(compileListProperty(prop, obj, ctxt)); + COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); } else { - COMPILE_CHECK(compilePropertyAssignment(prop, obj, ctxt)); + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); } return true; } -bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, - QmlParser::Object *obj) +void QmlCompiler::genValueProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if (QmlMetaType::isQmlList(prop->type) || QmlMetaType::isList(prop->type)) { + genListProperty(prop, obj); + } else { + genPropertyAssignment(prop, obj); + } +} + +void QmlCompiler::genListProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + QmlInstruction::Type fetchType; + QmlInstruction::Type storeType; + int listType; + + if (QmlMetaType::isQmlList(prop->type)) { + fetchType = QmlInstruction::FetchQmlList; + storeType = QmlInstruction::StoreObjectQmlList; + listType = QmlMetaType::qmlListType(prop->type); + } else { + fetchType = QmlInstruction::FetchQList; + storeType = QmlInstruction::StoreObjectQList; + listType = QmlMetaType::listType(prop->type); + } + + QmlInstruction fetch; + fetch.type = fetchType; + fetch.line = prop->location.start.line; + fetch.fetchQmlList.property = prop->index; + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; + output->bytecode << fetch; + + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + if (listTypeIsInterface) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->location.start.line; + output->bytecode << assign; + } else { + QmlInstruction store; + store.type = storeType; + store.line = prop->location.start.line; + output->bytecode << store; + } + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } + + } + + QmlInstruction pop; + pop.type = QmlInstruction::PopQList; + pop.line = prop->location.start.line; + output->bytecode << pop; +} + +void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + for (int ii = 0; ii < prop->values.count(); ++ii) { + QmlParser::Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + + if (QmlMetaType::isInterface(prop->type)) { + + QmlInstruction store; + store.type = QmlInstruction::StoreInterface; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else if (prop->type == -1) { + + QmlInstruction store; + store.type = QmlInstruction::StoreVariantObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else { + + QmlInstruction store; + store.type = QmlInstruction::StoreObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } + } else if (v->type == Value::ValueSource) { + + genObject(v->object); + + QmlInstruction store; + store.type = QmlInstruction::StoreValueSource; + store.line = v->object->location.start.line; + store.assignValueSource.property = prop->index; + output->bytecode << store; + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } else if (v->type == Value::Literal) { + + QMetaProperty mp = obj->metaObject()->property(prop->index); + genLiteralAssignment(mp, v); + + } + + } +} + +bool QmlCompiler::buildIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj) { - if (prop->value) - COMPILE_EXCEPTION2(prop,"The id property cannot be fetched"); - if (prop->values.count() > 1) - COMPILE_EXCEPTION2(prop, "The object id may only be set once"); + if (prop->value || + prop->values.count() > 1 || + prop->values.at(0)->object) + COMPILE_EXCEPTION2(prop, "Invalid use of id property"); - if (prop->values.at(0)->object) - COMPILE_EXCEPTION("Cannot assign an object as an id"); QString val = prop->values.at(0)->primitive(); + if (!isValidId(val)) - COMPILE_EXCEPTION(val << "is not a valid id"); + COMPILE_EXCEPTION2(prop, val << "is not a valid object id"); + if (compileState.ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); + COMPILE_EXCEPTION2(prop, "id is not unique"); - int pref = output->indexForString(val); + obj->id = val.toUtf8(); - if (prop->type == QVariant::String) { - QmlInstruction assign; - assign.type = QmlInstruction::StoreString; - assign.storeString.propertyIndex = prop->index; - assign.storeString.value = pref; - assign.line = prop->values.at(0)->location.start.line; - output->bytecode << assign; + prop->values.at(0)->type = Value::Id; - prop->values.at(0)->type = Value::Id; - } else { - prop->values.at(0)->type = Value::Literal; - } + addId(val, obj); + return true; +} + +void QmlCompiler::addId(const QString &id, QmlParser::Object *obj) +{ IdReference reference; - reference.id = val; + reference.id = id; reference.object = obj; - reference.instructionIdx = output->bytecode.count(); reference.idx = compileState.ids.count(); - compileState.ids.insert(val, reference); + compileState.ids.insert(id, reference); +} - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = prop->values.at(0)->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - output->bytecode << id; +void QmlCompiler::addBindingReference(const BindingReference &ref) +{ + int id = compileState.bindings.count(); + compileState.bindings << ref; + compileState.bindingMap.insert(ref.value, id); +} - obj->id = val.toLatin1(); +void QmlCompiler::saveComponentState() +{ + Q_ASSERT(compileState.root); + Q_ASSERT(!savedCompileStates.contains(compileState.root)); - return true; + savedCompileStates.insert(compileState.root, compileState); } -// Compile attached property object. In this example, +QmlCompiler::ComponentCompileState +QmlCompiler::componentState(QmlParser::Object *obj) +{ + Q_ASSERT(savedCompileStates.contains(obj)); + return savedCompileStates.value(obj); +} + +// Build attached property object. In this example, // Text { // GridView.row: 10 // } // GridView is an attached property object. -bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, - const BindingContext &ctxt) +bool QmlCompiler::buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(prop->value); int id = QmlMetaType::attachedPropertiesFuncId(prop->name); Q_ASSERT(id != -1); // This is checked in compileProperty() - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchAttached; - fetch.line = prop->location.start.line; - fetch.fetchAttached.id = id; - output->bytecode << fetch; - - COMPILE_CHECK(compileFetchedObject(prop->value, ctxt.incr())); + prop->index = id; + obj->addAttachedProperty(prop); - QmlInstruction pop; - pop.type = QmlInstruction::PopFetchedObject; - pop.line = prop->location.start.line; - output->bytecode << pop; + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); return true; } -// Compile "nested" properties. In this example: + +// Build "grouped" properties. In this example: // Text { // font.size: 12 +// font.family: "Helvetica" // } -// font is a nested property. size is not. -bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, - const BindingContext &ctxt) +// font is a nested property. size and family are not. +bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(prop->type != 0); Q_ASSERT(prop->index != -1); @@ -1104,132 +1376,90 @@ bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, if (!prop->value->metatype) COMPILE_EXCEPTION2(prop, "Cannot nest non-QObject property" << prop->name); - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchObject; - fetch.fetch.property = prop->index; - fetch.fetch.isObject = true; - fetch.line = prop->location.start.line; - output->bytecode << fetch; + obj->addGroupedProperty(prop); - COMPILE_CHECK(compileFetchedObject(prop->value, ctxt.incr())); - - QmlInstruction pop; - pop.type = QmlInstruction::PopFetchedObject; - pop.line = prop->location.start.line; - output->bytecode << pop; + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); return true; } -// Compile assignments to QML lists. QML lists are properties of type + +// Build assignments to QML lists. QML lists are properties of type // QList<T *> * and QmlList<T *> *. // // QList<T *> * types can accept a list of objects, or a single binding // QmlList<T *> * types can accept a list of objects -bool QmlCompiler::compileListProperty(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt) +bool QmlCompiler::buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(QmlMetaType::isList(prop->type) || QmlMetaType::isQmlList(prop->type)); int t = prop->type; + obj->addValueProperty(prop); + if (QmlMetaType::isQmlList(t)) { - QmlInstruction fetch; - fetch.line = prop->location.start.line; - fetch.type = QmlInstruction::FetchQmlList; - fetch.fetchQmlList.property = prop->index; int listType = QmlMetaType::qmlListType(t); bool listTypeIsInterface = QmlMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; - output->bytecode << fetch; for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; - COMPILE_CHECK(compileObject(v->object, ctxt)); + COMPILE_CHECK(buildObject(v->object, ctxt)); + // We check object coercian here. We check interface assignment + // at runtime. if (!listTypeIsInterface) { - if (canConvert(listType, v->object)) { - QmlInstruction store; - store.type = QmlInstruction::StoreObjectQmlList; - store.line = prop->location.start.line; - output->bytecode << store; - } else { + if (!canCoerce(listType, v->object)) { COMPILE_EXCEPTION("Cannot assign object to list"); } - - } else { - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = prop->location.start.line; - output->bytecode << assign; } + } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } } - QmlInstruction pop; - pop.type = QmlInstruction::PopQList; - pop.line = prop->location.start.line; - output->bytecode << pop; } else { - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchQList; - fetch.line = prop->location.start.line; - fetch.fetchQmlList.property = prop->index; int listType = QmlMetaType::listType(t); bool listTypeIsInterface = QmlMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; - output->bytecode << fetch; bool assignedBinding = false; for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; - COMPILE_CHECK(compileObject(v->object, ctxt)); + COMPILE_CHECK(buildObject(v->object, ctxt)); + // We check object coercian here. We check interface assignment + // at runtime. if (!listTypeIsInterface) { - if (canConvert(listType, v->object)) { - QmlInstruction store; - store.type = QmlInstruction::StoreObjectQList; - store.line = prop->location.start.line; - output->bytecode << store; - } else { + if (!canCoerce(listType, v->object)) { COMPILE_EXCEPTION("Cannot assign object to list"); } - } else { - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = v->location.start.line; - output->bytecode << assign; - } + } + } else if (v->value.isScript()) { if (assignedBinding) COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - COMPILE_CHECK(compileBinding(v, prop, ctxt)); + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } } - QmlInstruction pop; - pop.line = prop->location.start.line; - pop.type = QmlInstruction::PopQList; - output->bytecode << pop; } return true; } -// Compile regular property assignments of the form property: <value> +// Compile regular property assignments of the form "property: <value>" // // ### The following problems exist // @@ -1244,19 +1474,21 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, // } // // We allow assignming multiple values to single value properties -bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { + obj->addValueProperty(prop); + for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { - COMPILE_CHECK(compilePropertyObjectAssignment(prop, v, ctxt)); + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); } else { - COMPILE_CHECK(compilePropertyLiteralAssignment(prop, obj, v, ctxt)); + COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); } } @@ -1265,9 +1497,10 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, } // Compile assigning a single object instance to a regular property -bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Value *v, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); @@ -1275,30 +1508,18 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, if (QmlMetaType::isInterface(prop->type)) { // Assigning an object to an interface ptr property - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreInterface; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else if (prop->type == -1) { // Assigning an object to a QVariant - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreVariantObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else { - // Normally compileObject() will set this up, but we need the static + // Normally buildObject() will set this up, but we need the static // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing @@ -1333,39 +1554,29 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, if (isAssignable) { // Simple assignment - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else if (propertyMetaObject == &QmlComponent::staticMetaObject) { // Automatic "Component" insertion - COMPILE_CHECK(compileComponentFromRoot(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; - - v->type = Value::Component; + QmlParser::Object *root = v->object; + QmlParser::Object *component = new QmlParser::Object; + component->type = componentTypeRef(); + component->typeName = "Component"; + component->metatype = &QmlComponent::staticMetaObject; + component->location = root->location; + QmlParser::Value *componentValue = new QmlParser::Value; + componentValue->object = root; + component->getDefaultProperty()->addValue(componentValue); + v->object = component; + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); } else if (isPropertyValue) { // Assign as a property value source - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreValueSource; - assign.line = v->object->location.start.line; - assign.assignValueSource.property = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::ValueSource; } else { - COMPILE_EXCEPTION2(v->object, "Unassignable object"); + COMPILE_EXCEPTION2(v->object, "Cannot assign object to property"); } } @@ -1373,25 +1584,22 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, } // Compile assigning a literal or binding to a regular property -bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - QmlParser::Value *v, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v, prop, ctxt)); + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { - QmlInstruction assign; - assign.line = v->location.start.line; - COMPILE_CHECK(compileStoreInstruction(assign, obj->metaObject()->property(prop->index), v)); - output->bytecode << assign; + COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); v->type = Value::Literal; } @@ -1399,31 +1607,99 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) +// Ensures that the dynamic meta specification on obj is valid +bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) +{ + QSet<QByteArray> propNames; + QSet<QByteArray> methodNames; + bool seenDefaultProperty = false; + + // Check properties + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const QmlParser::Object::DynamicProperty &prop = + obj->dynamicProperties.at(ii); + + if (prop.isDefaultProperty) { + if (seenDefaultProperty) + COMPILE_EXCEPTION("Duplicate default property"); + seenDefaultProperty = true; + } + + if (propNames.contains(prop.name)) + COMPILE_EXCEPTION("Duplicate property name"); + + propNames.insert(prop.name); + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + QByteArray name = obj->dynamicSignals.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION("Duplicate signal name"); + methodNames.insert(name); + } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + QByteArray name = obj->dynamicSlots.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION("Duplicate method name"); + methodNames.insert(name); + } + + return true; +} + +bool QmlCompiler::mergeDynamicMetaProperties(QmlParser::Object *obj) +{ + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) + continue; + + Property *property = 0; + if (p.isDefaultProperty) + property = obj->getDefaultProperty(); + else + property = obj->getProperty(p.name); + + if (property->value) + COMPILE_EXCEPTION2(property, "Invalid property nesting"); + + for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { + Value *v = p.defaultValue->values.at(ii); + v->addref(); + property->values.append(v); + } + } + return true; +} + +bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) { - // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty() && obj->dynamicSlots.isEmpty()) return true; + COMPILE_CHECK(checkDynamicMeta(obj)); + QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0); QMetaObjectBuilder builder; if (obj->metatype) - builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); - + builder.setClassName(QByteArray(obj->metatype->className()) + "_QML"); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + bool hasAlias = false; for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); if (p.isDefaultProperty && - (p.type != Object::DynamicProperty::Alias || preAlias != -1)) + (p.type != Object::DynamicProperty::Alias || + mode == ResolveAliases)) builder.addClassInfo("DefaultProperty", p.name); QByteArray type; - int propertyType; + int propertyType = 0; switch(p.type) { case Object::DynamicProperty::Alias: hasAlias = true; @@ -1471,7 +1747,7 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) builder.addProperty(p.name, type, ii); } - if (preAlias != -1) { + if (mode == ResolveAliases) { for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); @@ -1495,8 +1771,6 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) ((QmlVMEMetaData *)dynamicData.data())->signalCount++; } - int slotStart = obj->dynamicSlots.isEmpty()?-1:output->primitives.count(); - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); QByteArray sig(s.name + "("); @@ -1509,57 +1783,37 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) b.setParameterNames(s.parameterNames); ((QmlVMEMetaData *)dynamicData.data())->methodCount++; - QmlVMEMetaData::MethodData methodData = { s.parameterNames.count() }; - dynamicData.append((char *)&methodData, sizeof(methodData)); + QmlVMEMetaData::MethodData methodData = + { s.parameterNames.count(), 0, s.body.length(), 0 }; - if (preAlias == -1) - output->primitives << s.body; + dynamicData.append((char *)&methodData, sizeof(methodData)); } - if (obj->metatype) - builder.setSuperClass(obj->metatype); - - obj->extObjectData = builder.toMetaObject(); - static_cast<QMetaObject &>(obj->extObject) = *obj->extObjectData; - - if (preAlias != -1) { - QmlInstruction &store = output->bytecode[preAlias]; - - store.storeMeta.aliasData = output->indexForByteArray(dynamicData); - qFree(output->synthesizedMetaObjects.at(store.storeMeta.data)); - output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData; - - } else { - output->synthesizedMetaObjects << obj->extObjectData; - QmlInstruction store; - store.type = QmlInstruction::StoreMetaObject; - store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; - store.storeMeta.slotData = slotStart; - store.storeMeta.aliasData = output->indexForByteArray(dynamicData); - store.line = obj->location.start.line; - output->bytecode << store; - - if (hasAlias) { - AliasReference alias; - alias.object = obj; - alias.instructionIdx = output->bytecode.count() - 1; - compileState.aliases << alias; - } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + QmlVMEMetaData::MethodData *data = + ((QmlVMEMetaData *)dynamicData.data())->methodData() + ii; + + data->bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)s.body.constData(), + (s.body.length() * sizeof(QChar))); } - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + obj->metadata = builder.toRelocatableData(); + builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); - if (p.type == Object::DynamicProperty::Alias) - continue; + // ### Remove me + obj->extObjectData = &obj->extObject; - if (p.defaultValue) { - p.defaultValue->name = p.name; - p.defaultValue->isDefault = false; - COMPILE_CHECK(compileProperty(p.defaultValue, obj, 0)); - } + if (mode == IgnoreAliases && hasAlias) { + AliasReference alias; + alias.object = obj; + compileState.aliases << alias; } + obj->synthdata = dynamicData; + return true; } @@ -1623,9 +1877,9 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, return true; } -bool QmlCompiler::compileBinding(QmlParser::Value *value, - QmlParser::Property *prop, - const BindingContext &ctxt) +bool QmlCompiler::buildBinding(QmlParser::Value *value, + QmlParser::Property *prop, + const BindingContext &ctxt) { Q_ASSERT(prop->index); Q_ASSERT(prop->parent); @@ -1633,7 +1887,7 @@ bool QmlCompiler::compileBinding(QmlParser::Value *value, QMetaProperty mp = prop->parent->metaObject()->property(prop->index); if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) - COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); + COMPILE_EXCEPTION2(prop, "Invalid property assignment: read-only property"); BindingReference reference; reference.expression = value->value; @@ -1641,185 +1895,104 @@ bool QmlCompiler::compileBinding(QmlParser::Value *value, reference.value = value; reference.instructionIdx = output->bytecode.count(); reference.bindingContext = ctxt; - compileState.bindings << reference; - - output->bytecode << QmlInstruction();; + addBindingReference(reference); return true; } -#if 0 - -#include <iostream> -#ifdef Q_CC_GNU -#include <cxxabi.h> -#endif - -//////////////////////////////////////////////////////////////////////////////// -// AST Dump -//////////////////////////////////////////////////////////////////////////////// -class Dump: protected QmlJS::AST::Visitor -{ - std::ostream &out; - int depth; - -public: - Dump(std::ostream &out) - : out(out), depth(-1) - { } - - void operator()(QmlJS::AST::Node *node) - { QmlJS::AST::Node::acceptChild(node, this); } - -protected: - virtual bool preVisit(QmlJS::AST::Node *node) - { - const char *name = typeid(*node).name(); -#ifdef Q_CC_GNU - name = abi::__cxa_demangle(name, 0, 0, 0) + 17; -#endif - std::cout << std::string(++depth, ' ') << name << std::endl; - return true; - } - - virtual void postVisit(QmlJS::AST::Node *) - { - --depth; - } -}; -#endif - -// Update the init instruction with final data, and optimize some simple -// bindings -bool QmlCompiler::finalizeComponent(int patch) +void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj) { - for (int ii = 0; ii < compileState.bindings.count(); ++ii) { - const BindingReference &binding = compileState.bindings.at(ii); - finalizeBinding(binding); - } + Q_ASSERT(compileState.bindingMap.contains(binding)); - for (int ii = 0; ii < compileState.aliases.count(); ++ii) { - const AliasReference &alias = compileState.aliases.at(ii); - COMPILE_CHECK(finalizeAlias(alias)); + const BindingReference &ref = + compileState.bindings.at(compileState.bindingMap.value(binding)); + + QMetaProperty mp = obj->metaObject()->property(prop->index); + + QmlInstruction store; + int dataRef; + if (ref.compiledData.isEmpty()) { + dataRef = output->indexForString(ref.expression.asScript()); + store.type = QmlInstruction::StoreBinding; + } else { + dataRef = output->indexForByteArray(ref.compiledData); + store.type = QmlInstruction::StoreCompiledBinding; } - output->bytecode[patch].init.dataSize = compileState.savedObjects;; - output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); - output->bytecode[patch].init.parserStatusSize = - compileState.parserStatusCount; + store.assignBinding.property = prop->index; + store.assignBinding.value = dataRef; + store.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + store.assignBinding.context = ref.bindingContext.stack; - return true; + output->bytecode << store; } -bool QmlCompiler::finalizeAlias(const AliasReference &alias) +bool QmlCompiler::completeComponentBuild() { - COMPILE_CHECK(compileDynamicMeta(alias.object, alias.instructionIdx)); -} + saveComponentState(); + + for (int ii = 0; ii < compileState.aliases.count(); ++ii) { + const AliasReference &alias = compileState.aliases.at(ii); + COMPILE_CHECK(buildDynamicMeta(alias.object, ResolveAliases)); + } + -void QmlCompiler::finalizeBinding(const BindingReference &binding) -{ - QmlBasicScript bs; QmlBasicScript::Expression expr; expr.component = compileState.root; - expr.context = binding.bindingContext.object; - expr.property = binding.property; - expr.expression = binding.expression; - foreach (const IdReference &id, compileState.ids) + foreach (const IdReference &id, compileState.ids) { expr.ids.insert(id.id, qMakePair(id.object, id.idx)); + } - bs.compile(expr); - - QmlInstruction &instr = output->bytecode[binding.instructionIdx]; - instr.line = binding.value->location.start.line; - - // Single load optimization - if (bs.isValid() && bs.isSingleLoad()) { - - QString singleLoadTarget = QLatin1String(bs.singleLoadTarget()); - - if (singleLoadTarget.at(0).isUpper() && - compileState.ids.contains(singleLoadTarget) && - QmlMetaType::isObject(binding.property->type)) { - - IdReference reference = compileState.ids[singleLoadTarget]; - - const QMetaObject *idMo = reference.object->metaObject(); - const QMetaObject *storeMo = - QmlMetaType::rawMetaObjectForType(binding.property->type); - - Q_ASSERT(idMo); - Q_ASSERT(storeMo); - - bool canAssign = false; - while (!canAssign && idMo) { - if (idMo == storeMo) - canAssign = true; - else - idMo = idMo->superClass(); - } - - if (canAssign) { - int instructionIdx = reference.instructionIdx; - if (output->bytecode.at(instructionIdx).setId.save == -1) { - output->bytecode[instructionIdx].setId.save = - compileState.savedObjects++; - } - int saveId = output->bytecode.at(instructionIdx).setId.save; + for (int ii = 0; ii < compileState.bindings.count(); ++ii) { + BindingReference &binding = compileState.bindings[ii]; - instr.type = QmlInstruction::PushProperty; - instr.pushProperty.property = binding.property->index; - QmlInstruction store; - store.type = QmlInstruction::StoreStackObject; - store.line = 0; - store.assignStackObject.property = - compileState.pushedProperties++; - store.assignStackObject.object = saveId; - output->bytecode << store; - return; - } - } - } + QmlBasicScript bs; + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; - // General binding fallback - int bref; - if (bs.isValid()) { - bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); - } else { - bref = output->indexForString(binding.expression.asScript()); + bs.compile(expr); + if (bs.isValid()) + binding.compiledData = + QByteArray(bs.compileData(), bs.compileDataSize()); } - instr.assignBinding.context = binding.bindingContext.stack; - - if (bs.isValid()) - instr.type = QmlInstruction::StoreCompiledBinding; - else - instr.type = QmlInstruction::StoreBinding; - - instr.assignBinding.property = binding.property->index; - instr.assignBinding.value = bref; - QMetaProperty mp = binding.property->parent->metaObject()->property(binding.property->index); - instr.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + return true; } /*! - Returns true if object can be assigned to a (QObject) property of type - convertType. + Returns true if from can be assigned to a (QObject) property of type + to. */ -bool QmlCompiler::canConvert(int convertType, QmlParser::Object *object) +bool QmlCompiler::canCoerce(int to, QmlParser::Object *from) { - const QMetaObject *convertTypeMo = - QmlMetaType::rawMetaObjectForType(convertType); - const QMetaObject *objectMo = object->metaObject(); + const QMetaObject *toMo = + QmlMetaType::rawMetaObjectForType(to); + const QMetaObject *fromMo = from->metaObject(); - while (objectMo) { - if (objectMo == convertTypeMo) + while (fromMo) { + if (fromMo == toMo) return true; - objectMo = objectMo->superClass(); + fromMo = fromMo->superClass(); } return false; } +QmlType *QmlCompiler::toQmlType(QmlParser::Object *from) +{ + // ### Optimize + const QMetaObject *mo = from->metatype; + QmlType *type = 0; + while (!type && mo) { + type = QmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + return type; +} + QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) { const QMetaObject *mo = obj->metatype; @@ -1833,63 +2006,4 @@ QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) return rv; } -QmlCompiledData::QmlCompiledData() -{ -} - -QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) -{ - *this = other; -} - -QmlCompiledData::~QmlCompiledData() -{ - for (int ii = 0; ii < types.count(); ++ii) { - if (types.at(ii).ref) - types.at(ii).ref->release(); - } -} - -QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) -{ - types = other.types; - root = other.root; - primitives = other.primitives; - floatData = other.floatData; - intData = other.intData; - customTypeData = other.customTypeData; - datas = other.datas; - synthesizedMetaObjects = other.synthesizedMetaObjects; - bytecode = other.bytecode; - return *this; -} - -QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt) const -{ - if (type) { - QObject *rv = type->create(); - if (rv) - QmlEngine::setContextForObject(rv, ctxt); - return rv; - } else { - Q_ASSERT(component); - QObject *rv = component->create(ctxt); - QmlContext *ctxt = qmlContext(rv); - if(ctxt) { - static_cast<QmlContextPrivate *>(QObjectPrivate::get(ctxt))->typeName = className; - } - return rv; - } -} - -const QMetaObject *QmlCompiledData::TypeReference::metaObject() const -{ - if (type) { - return type->metaObject(); - } else { - Q_ASSERT(component); - return &static_cast<QmlComponentPrivate *>(QObjectPrivate::get(component))->cc->root; - } -} - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 1c45f57..b97de19 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -109,7 +109,10 @@ public: QList<QmlInstruction> bytecode; private: + QByteArray packData; friend class QmlCompiler; + int pack(const char *, size_t); + int indexForString(const QString &); int indexForByteArray(const QByteArray &); int indexForFloat(float *, int); @@ -146,57 +149,79 @@ private: rv.stack = stack + 1; return rv; } + bool isSubContext() const { return stack != 0; } int stack; QmlParser::Object *object; }; void compileTree(QmlParser::Object *tree); - bool compileObject(QmlParser::Object *obj, const BindingContext &); - bool compileComponent(QmlParser::Object *obj, const BindingContext &); - bool compileComponentFromRoot(QmlParser::Object *obj, const BindingContext &); - bool compileFetchedObject(QmlParser::Object *obj, const BindingContext &); - bool compileSignal(QmlParser::Property *prop, QmlParser::Object *obj); - bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); - int signalByName(const QMetaObject *, const QByteArray &name); - bool compileProperty(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &); - bool compileIdProperty(QmlParser::Property *prop, - QmlParser::Object *obj); - bool compileAttachedProperty(QmlParser::Property *prop, - const BindingContext &ctxt); - bool compileNestedProperty(QmlParser::Property *prop, + + + bool buildObject(QmlParser::Object *obj, const BindingContext &); + bool buildComponent(QmlParser::Object *obj, const BindingContext &); + bool buildSubObject(QmlParser::Object *obj, const BindingContext &); + bool buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildProperty(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildIdProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, const BindingContext &ctxt); - bool compileListProperty(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt); - bool compilePropertyAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt); - bool compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Value *value, - const BindingContext &ctxt); - bool compilePropertyLiteralAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - QmlParser::Value *value, - const BindingContext &ctxt); - bool compileStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - QmlParser::Value *value); - - bool compileDynamicMeta(QmlParser::Object *obj, int preAlias = -1); + bool buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + enum DynamicMetaMode { IgnoreAliases, ResolveAliases }; + bool mergeDynamicMetaProperties(QmlParser::Object *obj); + bool buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode); + bool checkDynamicMeta(QmlParser::Object *obj); + bool buildBinding(QmlParser::Value *, QmlParser::Property *prop, + const BindingContext &ctxt); + bool buildComponentFromRoot(QmlParser::Object *obj, const BindingContext &); bool compileAlias(QMetaObjectBuilder &, QByteArray &data, QmlParser::Object *obj, const QmlParser::Object::DynamicProperty &); - bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, - const BindingContext &ctxt); + bool completeComponentBuild(); - bool finalizeComponent(int patch); - struct BindingReference; - void finalizeBinding(const BindingReference &); - struct AliasReference; - bool finalizeAlias(const AliasReference &); - bool canConvert(int, QmlParser::Object *); + void genObject(QmlParser::Object *obj); + void genObjectBody(QmlParser::Object *obj); + void genComponent(QmlParser::Object *obj); + void genValueProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genListProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj); + void genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + void genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj); + + + int componentTypeRef(); + + static int findSignalByName(const QMetaObject *, const QByteArray &name); + static bool canCoerce(int to, QmlParser::Object *from); + static QmlType *toQmlType(QmlParser::Object *from); + QStringList deferredProperties(QmlParser::Object *); struct IdReference { @@ -205,6 +230,7 @@ private: int instructionIdx; int idx; }; + void addId(const QString &, QmlParser::Object *); struct AliasReference { QmlParser::Object *object; @@ -215,28 +241,35 @@ private: QmlParser::Variant expression; QmlParser::Property *property; QmlParser::Value *value; + QByteArray compiledData; int instructionIdx; BindingContext bindingContext; }; + void addBindingReference(const BindingReference &); struct ComponentCompileState { - ComponentCompileState() : parserStatusCount(0), savedObjects(0), pushedProperties(0), root(0) {} + ComponentCompileState() + : parserStatusCount(0), savedObjects(0), + pushedProperties(0), root(0) {} QHash<QString, IdReference> ids; int parserStatusCount; int savedObjects; int pushedProperties; QList<BindingReference> bindings; + QHash<QmlParser::Value *, int> bindingMap; QList<AliasReference> aliases; QmlParser::Object *root; }; ComponentCompileState compileState; + void saveComponentState(); + ComponentCompileState componentState(QmlParser::Object *); + QHash<QmlParser::Object *, ComponentCompileState> savedCompileStates; + QList<QmlError> exceptions; QmlCompiledData *output; - }; - QT_END_NAMESPACE #endif // QMLCOMPILER_P_H diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index ef77803..c7ef765 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -110,8 +110,6 @@ QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) if (!compiler.compile(engine, this, compiledComponent)) { status = Error; errors = compiler.errors(); - for(int ii = 0; ii < errors.count(); ++ii) - errors[ii].setUrl(compiledComponent->url); compiledComponent->release(); compiledComponent = 0; } diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 0b2742d..c3cee4c 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -73,6 +73,8 @@ void QmlContextPrivate::dump(int depth) void QmlContextPrivate::destroyed(QObject *obj) { + Q_Q(QmlContext); + defaultObjects.removeAll(obj); QVariant variantObject = QVariant::fromValue(obj); @@ -84,10 +86,9 @@ void QmlContextPrivate::destroyed(QObject *obj) } } - // ### Work around bug in shutdown - // for (int ii = 0; ii < notifies.count(); ++ii) { - // QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); - // } + for (int ii = 0; ii < notifies.count(); ++ii) { + QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + } } void QmlContextPrivate::init() diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 648eb36..b5d3c80 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -1379,7 +1379,6 @@ QmlDomValue::Type QmlDomValue::type() const return PropertyBinding; case QmlParser::Value::ValueSource: return ValueSource; - case QmlParser::Value::Component: case QmlParser::Value::CreatedObject: return Object; case QmlParser::Value::SignalObject: diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 1647a12..863ff9a 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -54,13 +54,13 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) switch(instr->type) { case QmlInstruction::Init: - qWarning() << idx << "\t" << line << "\t" << "INIT\t\t\t" << instr->init.dataSize; + qWarning() << idx << "\t" << line << "\t" << "INIT"; break; case QmlInstruction::CreateObject: qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; break; case QmlInstruction::SetId: - qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t" << instr->setId.save << "\t\t" << primitives.at(instr->setId.value); + qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t\t" << primitives.at(instr->setId.value); break; case QmlInstruction::SetDefault: qWarning() << idx << "\t" << line << "\t" << "SET_DEFAULT"; @@ -125,8 +125,11 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::StoreObject: qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; break; - case QmlInstruction::AssignCustomType: - qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + case QmlInstruction::StoreVariantObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreInterface: + qWarning() << idx << "\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; break; case QmlInstruction::StoreSignal: qWarning() << idx << "\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); @@ -134,6 +137,9 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::AssignSignalObject: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); break; + case QmlInstruction::AssignCustomType: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; case QmlInstruction::StoreBinding: qWarning() << idx << "\t" << line << "\t" << "STORE_BINDING\t\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << primitives.at(instr->assignBinding.value); break; @@ -149,6 +155,12 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::CompleteObject: qWarning() << idx << "\t" << line << "\t" << "COMPLETE\t\t" << instr->complete.castValue; break; + case QmlInstruction::StoreObjectQmlList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QMLLIST"; + break; + case QmlInstruction::StoreObjectQList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QLIST"; + break; case QmlInstruction::AssignObjectList: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_OBJECT_LIST\t"; break; @@ -170,14 +182,11 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::PopQList: qWarning() << idx << "\t" << line << "\t" << "POP_QLIST"; break; - case QmlInstruction::PushProperty: - qWarning() << idx << "\t" << line << "\t" << "PUSH_PROPERTY" << "\t\t" << instr->pushProperty.property; - break; - case QmlInstruction::StoreStackObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_STACK_OBJ" << "\t" << instr->assignStackObject.property << "\t" << instr->assignStackObject.object; + case QmlInstruction::Defer: + qWarning() << idx << "\t" << line << "\t" << "DEFER" << "\t\t" << instr->defer.deferCount; break; default: - qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION"; + qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION" << "\t" << instr->type; break; } } diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 40f9a32..39196a1 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -118,8 +118,6 @@ public: StoreSignal, /* storeSignal */ - // XXX need to handle storing objects in variants - // // Unresolved single assignment // @@ -154,14 +152,6 @@ public: // Deferred creation // Defer, /* defer */ - - // - // Expression optimizations - // - // PushProperty - Save the property for later use - // StoreStackObject - Assign the stack object (no checks) - PushProperty, /* pushProperty */ - StoreStackObject /* assignStackObject */ }; QmlInstruction() : line(0) {} @@ -170,7 +160,6 @@ public: unsigned short line; union { struct { - int dataSize; int bindingsSize; int parserStatusSize; } init; @@ -185,7 +174,6 @@ public: } storeMeta; struct { int value; - int save; } setId; struct { int property; @@ -198,7 +186,6 @@ public: } assignBinding; struct { int property; - bool isObject; } fetch; struct { int property; @@ -281,13 +268,6 @@ public: int id; } fetchAttached; struct { - int property; - } pushProperty; - struct { - int property; - int object; - } assignStackObject; - struct { int deferCount; } defer; }; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index e158adf..6602021 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -663,9 +663,6 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) return; } - if (!value.isValid()) - return; - int t = propertyType(); int vt = value.userType(); int category = propertyCategory(); @@ -684,19 +681,22 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) QObject *o = QmlMetaType::toQObject(value); - if (!o) - return; + const QMetaObject *valMo = 0; - const QMetaObject *valMo = o->metaObject(); - const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t); + if (o) { + + valMo = o->metaObject(); + const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t); + + while (valMo) { + if (valMo == propMo) + break; + valMo = valMo->superClass(); + } - while (valMo) { - if (valMo == propMo) - break; - valMo = valMo->superClass(); } - if (valMo) { + if (valMo || !o) { void *args[] = { &o, 0 }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 8daab6a..02f229e 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -62,7 +62,8 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObjectData(0), defaultProperty(0) +: type(-1), metatype(0), extObjectData(0), defaultProperty(0), + parserStatusCast(-1) { } @@ -71,6 +72,10 @@ QmlParser::Object::~Object() if (defaultProperty) defaultProperty->release(); foreach(Property *prop, properties) prop->release(); + foreach(Property *prop, valueProperties) + prop->release(); + foreach(Property *prop, signalProperties) + prop->release(); } const QMetaObject *Object::metaObject() const @@ -90,6 +95,30 @@ QmlParser::Property *Object::getDefaultProperty() return defaultProperty; } +void QmlParser::Object::addValueProperty(Property *p) +{ + p->addref(); + valueProperties << p; +} + +void QmlParser::Object::addSignalProperty(Property *p) +{ + p->addref(); + signalProperties << p; +} + +void QmlParser::Object::addAttachedProperty(Property *p) +{ + p->addref(); + attachedProperties << p; +} + +void QmlParser::Object::addGroupedProperty(Property *p) +{ + p->addref(); + groupedProperties << p; +} + Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { @@ -160,12 +189,13 @@ void QmlParser::Object::dump(int indent) const } QmlParser::Property::Property() -: parent(0), type(0), index(-1), value(0), isDefault(true) +: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false) { } QmlParser::Property::Property(const QByteArray &n) -: parent(0), type(0), index(-1), value(0), name(n), isDefault(false) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false), + isDeferred(false) { } @@ -187,6 +217,11 @@ void QmlParser::Property::addValue(Value *v) values << v; } +bool QmlParser::Property::isEmpty() const +{ + return !value && values.isEmpty(); +} + void QmlParser::Property::dump(int indent) const { QByteArray ba(indent * 4, ' '); @@ -232,9 +267,6 @@ void QmlParser::Value::dump(int indent) const case Value::SignalExpression: type = "SignalExpression"; break; - case Value::Component: - type = "Component"; - break; case Value::Id: type = "Id"; break; diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 7550870..d96a43e 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -110,8 +110,8 @@ namespace QmlParser virtual ~Object(); // Type of the object. The integer is an index into the - // QmlCompiledData::types array, or -1 if the object is a fetched - // object. + // QmlCompiledData::types array, or -1 if the object is a property + // group. int type; // The url of this object if it is an external type. Used by the DOM QUrl url; @@ -131,6 +131,8 @@ namespace QmlParser // this type. Otherwise null QMetaObject *extObjectData; QAbstractDynamicMetaObject extObject; + QByteArray metadata; // Generated by compiler + QByteArray synthdata; // Generated by compiler Property *getDefaultProperty(); Property *getProperty(const QByteArray &name, bool create=true); @@ -138,6 +140,22 @@ namespace QmlParser Property *defaultProperty; QHash<QByteArray, Property *> properties; + // Output of the compilation phase (these properties continue to exist + // in either the defaultProperty or properties members too) + void addValueProperty(Property *); + void addSignalProperty(Property *); + void addAttachedProperty(Property *); + void addGroupedProperty(Property *); + QList<Property *> valueProperties; + QList<Property *> signalProperties; + QList<Property *> attachedProperties; + QList<Property *> groupedProperties; + + // The bytes to cast instances by to get to the QmlParserStatus + // interface. -1 indicates the type doesn't support this interface. + // Set by the QmlCompiler. + int parserStatusCast; + LocationSpan location; struct DynamicProperty { @@ -242,8 +260,6 @@ namespace QmlParser SignalObject, // This is used as a signal expression assignment SignalExpression, - // This is used as an implicit component creation - Component, // This is used as an id assignment only Id }; @@ -281,6 +297,9 @@ namespace QmlParser // The metaobject index of this property, or -1 if unknown. int index; + // Returns true if this is an empty property - both value and values + // are unset. + bool isEmpty() const; // The list of values assigned to this property. Content in values // and value are mutually exclusive QList<Value *> values; @@ -291,6 +310,9 @@ namespace QmlParser QByteArray name; // True if this property was accessed as the default property. bool isDefault; + // True if the setting of this property will be deferred. Set by the + // QmlCompiler + bool isDeferred; LocationSpan location; LocationRange listValueRange; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 2acf1e2..dfb066b 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -152,7 +152,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp QStack<ListInstance> qliststack; QStack<QmlMetaProperty> pushedProperties; - QObject **savedObjects = 0; vmeErrors.clear(); @@ -162,12 +161,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp switch(instr.type) { case QmlInstruction::Init: { - if (instr.init.dataSize) { - savedObjects = new QObject*[instr.init.dataSize]; - ::memset(savedObjects, 0, - sizeof(QObject *)*instr.init.dataSize); - } - if (instr.init.bindingsSize) bindValues = QmlEnginePrivate::SimpleList<QmlBindableValue>(instr.init.bindingsSize); if (instr.init.parserStatusSize) @@ -214,9 +207,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp QmlContext *ctxt = QmlContext::activeContext(); ctxt->setContextProperty(primitives.at(instr.setId.value), target); - - if (instr.setId.save != -1) - savedObjects[instr.setId.save] = target; } break; @@ -239,7 +229,16 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp case QmlInstruction::StoreMetaObject: { QObject *target = stack.top(); - new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); + + QMetaObject mo; + const QByteArray &metadata = datas.at(instr.storeMeta.data); + QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + + const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + + (void)new QmlVMEMetaObject(target, &mo, data, comp); + + // new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); } break; @@ -545,15 +544,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp } break; - case QmlInstruction::PushProperty: - { - QObject *target = stack.top(); - QmlMetaProperty mp(target, instr.pushProperty.property, - QmlMetaProperty::Object); - pushedProperties.push(mp); - } - break; - case QmlInstruction::StoreCompiledBinding: { QObject *target = stack.top(); @@ -745,22 +735,12 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp QObject *target = stack.top(); QObject *obj = 0; - if (instr.fetch.isObject) { - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = &obj; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.fetch.property, a); - } else { - void *a[1]; - QVariant var; - a[0] = &var; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.fetch.property, a); - obj = QmlMetaType::toQObject(var); - - } + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = &obj; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); if (!obj) VME_EXCEPTION("Cannot set properties on" << target->metaObject()->property(instr.fetch.property).name() << "as it is null"); @@ -795,21 +775,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp } break; - case QmlInstruction::StoreStackObject: - { - const QmlMetaProperty &prop = - pushedProperties.at(instr.assignStackObject.property); - QObject *obj = savedObjects[instr.assignStackObject.object]; - - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = (void *)&obj; - QMetaObject::metacall(prop.object(), QMetaObject::WriteProperty, - prop.coreIndex(), a); - } - break; - default: qFatal("QmlCompiledComponent: Internal error - unknown instruction %d", instr.type); break; @@ -832,11 +797,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp if (parserStatus.count) ep->parserStatus << parserStatus; - comp->dumpPost(); - - if (savedObjects) - delete [] savedObjects; - if (stack.isEmpty()) return 0; else diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index 6d14689..33a31a4 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -53,12 +53,9 @@ QT_BEGIN_NAMESPACE QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, - QList<QString> *strData, - int slotData, const QmlVMEMetaData *meta, QmlRefCount *rc) -: object(obj), ref(rc), metaData(meta), slotData(strData), - slotDataIdx(slotData), parent(0) +: object(obj), ref(rc), metaData(meta), parent(0) { if (ref) ref->addref(); @@ -208,7 +205,11 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) id -= plainSignals; if (id < metaData->methodCount) { - QString code = slotData->at(id + slotDataIdx); + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); QmlContext *ctxt = qmlContext(object); if (0 == (metaData->methodData() + id)->parameterCount) { diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 6421c3f..931d22c 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -78,6 +78,9 @@ struct QmlVMEMetaData struct MethodData { int parameterCount; + int bodyOffset; + int bodyLength; + int _dummy; }; PropertyData *propertyData() const { @@ -89,7 +92,7 @@ struct QmlVMEMetaData } MethodData *methodData() const { - return (MethodData *)(aliasData() + propertyCount); + return (MethodData *)(aliasData() + aliasCount); } }; @@ -97,7 +100,8 @@ class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, const QmlVMEMetaData *data, QmlRefCount * = 0); + QmlVMEMetaObject(QObject *, const QMetaObject *, const QmlVMEMetaData *data, + QmlRefCount * = 0); ~QmlVMEMetaObject(); protected: @@ -114,8 +118,10 @@ private: QVariant *data; QBitArray aConnected; +#if 0 QList<QString> *slotData; int slotDataIdx; +#endif QAbstractDynamicMetaObject *parent; diff --git a/tests/auto/declarative/qmlbindengine/testtypes.h b/tests/auto/declarative/qmlbindengine/testtypes.h index df31f7a..f5b309e 100644 --- a/tests/auto/declarative/qmlbindengine/testtypes.h +++ b/tests/auto/declarative/qmlbindengine/testtypes.h @@ -8,8 +8,8 @@ class MyQmlObject : public QObject { Q_OBJECT - Q_PROPERTY(bool trueProperty READ trueProperty) - Q_PROPERTY(bool falseProperty READ falseProperty) + Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT) + Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged); public: @@ -64,14 +64,14 @@ QML_DECLARE_TYPE(MyQmlObject); class MyQmlContainer : public QObject { Q_OBJECT - Q_PROPERTY(QList<MyQmlContainer*>* children READ children) + Q_PROPERTY(QList<MyQmlObject*>* children READ children) public: MyQmlContainer() {} - QList<MyQmlContainer*> *children() { return &m_children; } + QList<MyQmlObject*> *children() { return &m_children; } private: - QList<MyQmlContainer*> m_children; + QList<MyQmlObject*> m_children; }; QML_DECLARE_TYPE(MyQmlContainer); @@ -94,8 +94,8 @@ public: class MyDefaultObject1 : public QObject { Q_OBJECT - Q_PROPERTY(int horseLegs READ horseLegs); - Q_PROPERTY(int antLegs READ antLegs); + Q_PROPERTY(int horseLegs READ horseLegs CONSTANT); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); public: int horseLegs() const { return 4; } int antLegs() const { return 6; } @@ -104,8 +104,8 @@ public: class MyDefaultObject2 : public QObject { Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int emuLegs READ emuLegs); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); + Q_PROPERTY(int emuLegs READ emuLegs CONSTANT); public: int antLegs() const { return 5; } // Had an accident int emuLegs() const { return 2; } @@ -114,8 +114,8 @@ public: class MyDefaultObject3 : public QObject { Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int humanLegs READ humanLegs); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); + Q_PROPERTY(int humanLegs READ humanLegs CONSTANT); public: int antLegs() const { return 7; } // Mutant int humanLegs() const { return 2; } diff --git a/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt b/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt index b03f735..99f4c7c 100644 --- a/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt +++ b/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt @@ -1 +1 @@ -3:5:id is not unique +3:19:id is not unique diff --git a/tests/auto/declarative/qmlparser/failingComponent.errors.txt b/tests/auto/declarative/qmlparser/failingComponent.errors.txt index 12fb4e7..a18f2e7 100644 --- a/tests/auto/declarative/qmlparser/failingComponent.errors.txt +++ b/tests/auto/declarative/qmlparser/failingComponent.errors.txt @@ -1,2 +1,2 @@ -1:-1:Unable to create type FailingComponent -2:5:Cannot assign value to non-existant property "a" +2:5:Cannot assign to non-existant property "a" diff --git a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt index a94b38e..25f22ce 100644 --- a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt @@ -1 +1 @@ -2:11:Cannot assign value to non-existant property "something" +2:5:Cannot nest non-QObject property "value" diff --git a/tests/auto/declarative/qmlparser/idProperty.txt b/tests/auto/declarative/qmlparser/idProperty.txt index 9c7d6fb..c3c2e50 100644 --- a/tests/auto/declarative/qmlparser/idProperty.txt +++ b/tests/auto/declarative/qmlparser/idProperty.txt @@ -2,6 +2,6 @@ MyContainer { property var object : MyObjectId MyTypeObject { - id: MyObjectId + id: "MyObjectId" } } diff --git a/tests/auto/declarative/qmlparser/invalidID.2.errors.txt b/tests/auto/declarative/qmlparser/invalidID.2.errors.txt index 6380750..9c54aab 100644 --- a/tests/auto/declarative/qmlparser/invalidID.2.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.2.errors.txt @@ -1,2 +1,2 @@ -1:1:"" is not a valid id +2:5:"" is not a valid object id diff --git a/tests/auto/declarative/qmlparser/invalidID.3.errors.txt b/tests/auto/declarative/qmlparser/invalidID.3.errors.txt index 05937f0..36cd489 100644 --- a/tests/auto/declarative/qmlparser/invalidID.3.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.3.errors.txt @@ -1 +1 @@ -2:5:The id property cannot be fetched +2:5:Invalid use of id property diff --git a/tests/auto/declarative/qmlparser/invalidID.4.errors.txt b/tests/auto/declarative/qmlparser/invalidID.4.errors.txt index 50c8960..bb811cf 100644 --- a/tests/auto/declarative/qmlparser/invalidID.4.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.4.errors.txt @@ -1 +1 @@ -3:5:The object id may only be set once +3:5:Invalid use of id property diff --git a/tests/auto/declarative/qmlparser/invalidID.errors.txt b/tests/auto/declarative/qmlparser/invalidID.errors.txt index eed1869..7cefb7e 100644 --- a/tests/auto/declarative/qmlparser/invalidID.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.errors.txt @@ -1 +1 @@ -1:1:"1" is not a valid id +2:5:"1" is not a valid object id diff --git a/tests/auto/declarative/qmlparser/missingSignal.errors.txt b/tests/auto/declarative/qmlparser/missingSignal.errors.txt index 5c612cc..bcee331 100644 --- a/tests/auto/declarative/qmlparser/missingSignal.errors.txt +++ b/tests/auto/declarative/qmlparser/missingSignal.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "onClicked" +2:5:Cannot assign to non-existant property "onClicked" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt index e8f1a91..6f85946 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt @@ -1 +1 @@ -1:15:Cannot assign value to non-existant property "something" +1:15:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt index c154f91..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt @@ -1 +1 @@ -2:5:Cannot assign value to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt index a254d7d..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt index a254d7d..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt index 3183b6d..fac833e 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt @@ -1 +1 @@ -2:-1:Cannot assign to default property +2:5:Cannot assign to non-existant default property diff --git a/tests/auto/declarative/qmlparser/readOnly.1.errors.txt b/tests/auto/declarative/qmlparser/readOnly.1.errors.txt index 89009ce..8608370 100644 --- a/tests/auto/declarative/qmlparser/readOnly.1.errors.txt +++ b/tests/auto/declarative/qmlparser/readOnly.1.errors.txt @@ -1 +1 @@ -2:21:Cannot assign value "Hello World" to the read-only property readOnlyString +2:21:Invalid property assignment: read-only property diff --git a/tests/auto/declarative/qmlparser/readOnly.2.errors.txt b/tests/auto/declarative/qmlparser/readOnly.2.errors.txt index ab27946..633d56f 100644 --- a/tests/auto/declarative/qmlparser/readOnly.2.errors.txt +++ b/tests/auto/declarative/qmlparser/readOnly.2.errors.txt @@ -1 +1 @@ -2:-1:Cannot assign a binding to read-only property "readOnlyString" +2:5:Invalid property assignment: read-only property diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp index cdc2a72..7023263 100644 --- a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp +++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp @@ -98,7 +98,7 @@ void tst_qmlparser::errors_data() QTest::newRow("nonExistantProperty.3") << "nonexistantProperty.3.txt" << "nonexistantProperty.3.errors.txt" << false; QTest::newRow("nonExistantProperty.4") << "nonexistantProperty.4.txt" << "nonexistantProperty.4.errors.txt" << false; QTest::newRow("nonExistantProperty.5") << "nonexistantProperty.5.txt" << "nonexistantProperty.5.errors.txt" << false; - QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << true; + QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << false; QTest::newRow("wrongType (string for int)") << "wrongType.1.txt" << "wrongType.1.errors.txt" << false; QTest::newRow("wrongType (int for bool)") << "wrongType.2.txt" << "wrongType.2.errors.txt" << false; @@ -117,7 +117,7 @@ void tst_qmlparser::errors_data() QTest::newRow("wrongType (int for string)") << "wrongType.14.txt" << "wrongType.14.errors.txt" << false; QTest::newRow("readOnly.1") << "readOnly.1.txt" << "readOnly.1.errors.txt" << false; - QTest::newRow("readOnly.2") << "readOnly.2.txt" << "readOnly.2.errors.txt" << true; + QTest::newRow("readOnly.2") << "readOnly.2.txt" << "readOnly.2.errors.txt" << false; QTest::newRow("listAssignment.1") << "listAssignment.1.txt" << "listAssignment.1.errors.txt" << false; QTest::newRow("listAssignment.2") << "listAssignment.2.txt" << "listAssignment.2.errors.txt" << false; @@ -344,8 +344,8 @@ void tst_qmlparser::dynamicProperties() QVERIFY(object != 0); QCOMPARE(object->property("intProperty"), QVariant(10)); QCOMPARE(object->property("boolProperty"), QVariant(false)); - QCOMPARE(object->property("doubleProperty"), QVariant((float)-10.1)); - QCOMPARE(object->property("realProperty"), QVariant((float)-19.9)); + QCOMPARE(object->property("doubleProperty"), QVariant(-10.1)); + QCOMPARE(object->property("realProperty"), QVariant((qreal)-19.9)); QCOMPARE(object->property("stringProperty"), QVariant("Hello World!")); QCOMPARE(object->property("colorProperty"), QVariant(QColor("red"))); QCOMPARE(object->property("dateProperty"), QVariant(QDate(1945, 9, 2))); diff --git a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt index a067ecb..7ccfc75 100644 --- a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt @@ -1 +1 @@ -2:5:Cannot assign value to property matrix of unknown type +2:13:Invalid property assignment: unknown type QVariant::QMatrix diff --git a/tests/auto/declarative/qmlparser/wrongType.1.errors.txt b/tests/auto/declarative/qmlparser/wrongType.1.errors.txt index 8976ee1..194da94 100644 --- a/tests/auto/declarative/qmlparser/wrongType.1.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.1.errors.txt @@ -1 +1 @@ -2:12:Cannot assign value "hello" to property value +2:12:Invalid property assignment: int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.10.errors.txt b/tests/auto/declarative/qmlparser/wrongType.10.errors.txt index 562cd6c..f391e2a 100644 --- a/tests/auto/declarative/qmlparser/wrongType.10.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.10.errors.txt @@ -1 +1 @@ -2:23:Cannot assign value "12" to property dateTimeProperty +2:23:Invalid property assignment: datetime expected diff --git a/tests/auto/declarative/qmlparser/wrongType.11.errors.txt b/tests/auto/declarative/qmlparser/wrongType.11.errors.txt index 24d27d5..9f5ebc9 100644 --- a/tests/auto/declarative/qmlparser/wrongType.11.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.11.errors.txt @@ -1 +1 @@ -2:20:Cannot assign value "apples" to property pointProperty +2:20:Invalid property assignment: point expected diff --git a/tests/auto/declarative/qmlparser/wrongType.12.errors.txt b/tests/auto/declarative/qmlparser/wrongType.12.errors.txt index b57e70e..4bbb2bf 100644 --- a/tests/auto/declarative/qmlparser/wrongType.12.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.12.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "red" to property sizeProperty +2:19:Invalid property assignment: size expected diff --git a/tests/auto/declarative/qmlparser/wrongType.13.errors.txt b/tests/auto/declarative/qmlparser/wrongType.13.errors.txt index 7ff4bf3..194da94 100644 --- a/tests/auto/declarative/qmlparser/wrongType.13.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.13.errors.txt @@ -1 +1 @@ -2:12:Cannot assign value "12" to property value +2:12:Invalid property assignment: int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.14.errors.txt b/tests/auto/declarative/qmlparser/wrongType.14.errors.txt index ec41e01..f90b8c6 100644 --- a/tests/auto/declarative/qmlparser/wrongType.14.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.14.errors.txt @@ -1 +1 @@ -2:23:Cannot assign value 10 to property stringProperty +2:21:Invalid property assignment: string expected diff --git a/tests/auto/declarative/qmlparser/wrongType.2.errors.txt b/tests/auto/declarative/qmlparser/wrongType.2.errors.txt index 301d258..4353165 100644 --- a/tests/auto/declarative/qmlparser/wrongType.2.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.2.errors.txt @@ -1 +1 @@ -2:14:Cannot assign value "5" to property enabled +2:14:Invalid property assignment: boolean expected diff --git a/tests/auto/declarative/qmlparser/wrongType.3.errors.txt b/tests/auto/declarative/qmlparser/wrongType.3.errors.txt index 3afcc2b..87b4eed 100644 --- a/tests/auto/declarative/qmlparser/wrongType.3.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.3.errors.txt @@ -1 +1 @@ -2:11:Cannot assign value "5,5x10" to property rect +2:11:Invalid property assignment: rect expected diff --git a/tests/auto/declarative/qmlparser/wrongType.4.errors.txt b/tests/auto/declarative/qmlparser/wrongType.4.errors.txt index 6bf88be..57a0744 100644 --- a/tests/auto/declarative/qmlparser/wrongType.4.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.4.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "InvalidEnumName" to property enumProperty +2:19:Invalid property assignment: unknown enumeration diff --git a/tests/auto/declarative/qmlparser/wrongType.5.errors.txt b/tests/auto/declarative/qmlparser/wrongType.5.errors.txt index 0e40d84..0023d1d 100644 --- a/tests/auto/declarative/qmlparser/wrongType.5.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.5.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "-13" to property uintProperty +2:19:Invalid property assignment: unsigned int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.6.errors.txt b/tests/auto/declarative/qmlparser/wrongType.6.errors.txt index 9692997..06349e7 100644 --- a/tests/auto/declarative/qmlparser/wrongType.6.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.6.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "Hello" to property realProperty +2:19:Invalid property assignment: double expected diff --git a/tests/auto/declarative/qmlparser/wrongType.7.errors.txt b/tests/auto/declarative/qmlparser/wrongType.7.errors.txt index f44073a..e053f3b 100644 --- a/tests/auto/declarative/qmlparser/wrongType.7.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.7.errors.txt @@ -1 +1 @@ -2:20:Cannot assign value "12" to property colorProperty +2:20:Invalid property assignment: color expected diff --git a/tests/auto/declarative/qmlparser/wrongType.8.errors.txt b/tests/auto/declarative/qmlparser/wrongType.8.errors.txt index 8a45ffb..b11f92b 100644 --- a/tests/auto/declarative/qmlparser/wrongType.8.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.8.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "12" to property dateProperty +2:19:Invalid property assignment: date expected diff --git a/tests/auto/declarative/qmlparser/wrongType.9.errors.txt b/tests/auto/declarative/qmlparser/wrongType.9.errors.txt index cba3339..419a5ce 100644 --- a/tests/auto/declarative/qmlparser/wrongType.9.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.9.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "12" to property timeProperty +2:19:Invalid property assignment: time expected |