diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-05-27 03:41:53 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-05-27 03:41:53 (GMT) |
commit | e4e735ea8c5ae8e65668938d7af2fb11e1cb6c0e (patch) | |
tree | 5073fa9433a31baa06df3fbce781eeeb4a2ba942 /src/declarative/qml/qmlcompiler.cpp | |
parent | 65ba2e6f8a57058305e4ca3bdf77c4e8fed3c243 (diff) | |
download | Qt-e4e735ea8c5ae8e65668938d7af2fb11e1cb6c0e.zip Qt-e4e735ea8c5ae8e65668938d7af2fb11e1cb6c0e.tar.gz Qt-e4e735ea8c5ae8e65668938d7af2fb11e1cb6c0e.tar.bz2 |
Simplify and comment compiler
Diffstat (limited to 'src/declarative/qml/qmlcompiler.cpp')
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 373 |
1 files changed, 221 insertions, 152 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index c5ffeda..cce8109 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -184,16 +184,27 @@ bool QmlCompiler::isValidId(const QString &val) } /*! - Returns true if property name \a name refers to an attached property, false - otherwise. + Returns true if \a name refers to an attached property, false otherwise. Attached property names are those that start with a capital letter. */ -bool QmlCompiler::isAttachedProperty(const QByteArray &name) +bool QmlCompiler::isAttachedPropertyName(const QByteArray &name) { return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; } +/*! + Returns true if \a name refers to a signal property, false otherwise. + + Signal property names are those that start with "on", followed by a capital + letter. +*/ +bool QmlCompiler::isSignalPropertyName(const QByteArray &name) +{ + return name.length() >= 3 && name.startsWith("on") && + 'A' <= name.at(2) && 'Z' >= name.at(2); +} + #define COMPILE_EXCEPTION2(token, desc) \ { \ QString exceptionDescription; \ @@ -227,10 +238,10 @@ bool QmlCompiler::isAttachedProperty(const QByteArray &name) if (!a) return false; \ } -bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - int coreIdx, - QmlParser::Value *v) +// Compile a simple assignment of v to prop into instr +bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, + const QMetaProperty &prop, + QmlParser::Value *v) { QString string = v->value.asScript(); @@ -246,7 +257,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, if (value == -1) COMPILE_EXCEPTION2(v, "Cannot assign unknown enumeration to property" << prop.name()); instr.type = QmlInstruction::StoreInteger; - instr.storeInteger.propertyIndex = coreIdx; + instr.storeInteger.propertyIndex = prop.propertyIndex(); instr.storeInteger.value = value; return true; } @@ -255,21 +266,21 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, case -1: { instr.type = QmlInstruction::StoreVariant; - instr.storeString.propertyIndex = coreIdx; + instr.storeString.propertyIndex = prop.propertyIndex(); instr.storeString.value = output->indexForString(string); } break; case QVariant::String: { instr.type = QmlInstruction::StoreString; - instr.storeString.propertyIndex = coreIdx; + instr.storeString.propertyIndex = prop.propertyIndex(); instr.storeString.value = output->indexForString(string); } break; case QVariant::UInt: { instr.type = QmlInstruction::StoreInteger; - instr.storeInteger.propertyIndex = coreIdx; + instr.storeInteger.propertyIndex = prop.propertyIndex(); bool ok; int value = string.toUInt(&ok); if (!ok) @@ -280,7 +291,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, case QVariant::Int: { instr.type = QmlInstruction::StoreInteger; - instr.storeInteger.propertyIndex = coreIdx; + instr.storeInteger.propertyIndex = prop.propertyIndex(); bool ok; int value = string.toInt(&ok); if (!ok) @@ -292,7 +303,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, case QVariant::Double: { instr.type = QmlInstruction::StoreReal; - instr.storeReal.propertyIndex = coreIdx; + instr.storeReal.propertyIndex = prop.propertyIndex(); bool ok; float value = string.toFloat(&ok); if (!ok) @@ -306,7 +317,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, if (!c.isValid()) COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to color"); instr.type = QmlInstruction::StoreColor; - instr.storeColor.propertyIndex = coreIdx; + instr.storeColor.propertyIndex = prop.propertyIndex(); instr.storeColor.value = c.rgba(); } break; @@ -316,7 +327,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, if (!d.isValid()) COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date"); instr.type = QmlInstruction::StoreDate; - instr.storeDate.propertyIndex = coreIdx; + instr.storeDate.propertyIndex = prop.propertyIndex(); instr.storeDate.value = d.toJulianDay(); } break; @@ -328,7 +339,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; int index = output->indexForInt(data, 4); instr.type = QmlInstruction::StoreTime; - instr.storeTime.propertyIndex = coreIdx; + instr.storeTime.propertyIndex = prop.propertyIndex(); instr.storeTime.valueIndex = index; } break; @@ -344,7 +355,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, dateTime.time().msec() }; int index = output->indexForInt(data, 5); instr.type = QmlInstruction::StoreDateTime; - instr.storeDateTime.propertyIndex = coreIdx; + instr.storeDateTime.propertyIndex = prop.propertyIndex(); instr.storeDateTime.valueIndex = index; } break; @@ -361,7 +372,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, instr.type = QmlInstruction::StorePointF; else instr.type = QmlInstruction::StorePoint; - instr.storeRealPair.propertyIndex = coreIdx; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); instr.storeRealPair.valueIndex = index; } break; @@ -378,7 +389,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, instr.type = QmlInstruction::StoreSizeF; else instr.type = QmlInstruction::StoreSize; - instr.storeRealPair.propertyIndex = coreIdx; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); instr.storeRealPair.valueIndex = index; } break; @@ -396,7 +407,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, instr.type = QmlInstruction::StoreRectF; else instr.type = QmlInstruction::StoreRect; - instr.storeRect.propertyIndex = coreIdx; + instr.storeRect.propertyIndex = prop.propertyIndex(); instr.storeRect.valueIndex = index; } break; @@ -407,7 +418,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, if (!ok) COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to boolean"); instr.type = QmlInstruction::StoreBool; - instr.storeBool.propertyIndex = coreIdx; + instr.storeBool.propertyIndex = prop.propertyIndex(); instr.storeBool.value = b; } break; @@ -421,7 +432,7 @@ bool QmlCompiler::generateStoreInstruction(QmlInstruction &instr, if (converter) { int index = output->customTypeData.count(); instr.type = QmlInstruction::AssignCustomType; - instr.assignCustomType.propertyIndex = coreIdx; + instr.assignCustomType.propertyIndex = prop.propertyIndex(); instr.assignCustomType.valueIndex = index; QmlCompiledData::CustomTypeData data; @@ -536,8 +547,8 @@ void QmlCompiler::compileTree(Object *tree) bool QmlCompiler::compileObject(Object *obj, int ctxt) { - if (obj->type != -1) - obj->metatype = output->types.at(obj->type).metaObject(); + Q_ASSERT (obj->type != -1); + obj->metatype = output->types.at(obj->type).metaObject(); if (output->types.at(obj->type).className == "Component") { COMPILE_CHECK(compileComponent(obj, ctxt)); @@ -555,23 +566,22 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) create.create.type = obj->type; output->bytecode << create; + // Create the synthesized meta object COMPILE_CHECK(compileDynamicMeta(obj)); - int parserStatusCast = -1; - if (obj->type != -1) { - // ### Optimize - const QMetaObject *mo = obj->metatype; - QmlType *type = 0; - while (!type && mo) { - type = QmlMetaType::qmlType(mo); - mo = mo->superClass(); - } - - Q_ASSERT(type); - - parserStatusCast = type->parserStatusCast(); + // 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(); } + 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; @@ -580,35 +590,50 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) output->bytecode << begin; } + // Check if this is a custom parser type. Custom parser types allow + // assignments to non-existant properties. These assignments are then + // compiled by the type. bool isCustomParser = output->types.at(obj->type).type && output->types.at(obj->type).type->customParser() != 0; QList<QmlCustomParserProperty> customProps; + // Compile all explicit properties specified foreach(Property *prop, obj->properties) { - if (prop->name.length() >= 3 && prop->name.startsWith("on") && - ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { - if (!isCustomParser) { - COMPILE_CHECK(compileSignal(prop, obj)); + + if (isCustomParser) { + // Custom parser types don't support signal properties + if (testProperty(prop, obj)) { + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - if (!isCustomParser || (isCustomParser && testProperty(prop, obj))) { - COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(compileSignal(prop,obj)); } else { - customProps << QmlCustomParserNodePrivate::fromProperty(prop); + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); } } + } + // Compile the default property if (obj->defaultProperty) { - if(!isCustomParser || (isCustomParser && testProperty(obj->defaultProperty, obj))) { - COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + Property *prop = obj->defaultProperty; + + if (isCustomParser) { + if (testProperty(prop, obj)) { + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + } else { + customProps << QmlCustomParserNodePrivate::fromProperty(prop); + } } else { - customProps << QmlCustomParserNodePrivate::fromProperty(obj->defaultProperty); + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); } + } + // Compile custom parser parts if (isCustomParser && !customProps.isEmpty()) { // ### Check for failure bool ok = false; @@ -621,6 +646,8 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) output->indexForByteArray(customData); } + // If the type support the QmlParserStatusInterface we need to invoke + // classComplete() if (parserStatusCast != -1) { QmlInstruction complete; complete.type = QmlInstruction::CompleteObject; @@ -713,12 +740,13 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) bool QmlCompiler::compileFetchedObject(Object *obj, int ctxt) { + Q_ASSERT(obj->metatype); + if (obj->defaultProperty) COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); foreach(Property *prop, obj->properties) { - if (prop->name.length() >= 3 && prop->name.startsWith("on") && - ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { + if (isSignalPropertyName(prop->name)) { COMPILE_CHECK(compileSignal(prop, obj)); } else { COMPILE_CHECK(compileProperty(prop, obj, ctxt)); @@ -811,7 +839,7 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) bool QmlCompiler::testProperty(QmlParser::Property *prop, QmlParser::Object *obj) { - if(isAttachedProperty(prop->name) || prop->name == "id") + if(isAttachedPropertyName(prop->name) || prop->name == "id") return true; const QMetaObject *mo = obj->metaObject(); @@ -831,54 +859,71 @@ bool QmlCompiler::testProperty(QmlParser::Property *prop, bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt) { if (prop->values.isEmpty() && !prop->value) - return true; + COMPILE_EXCEPTION2(prop, "Empty property assignment"); - // First we're going to need a reference to this property - const QMetaObject *mo = obj->metaObject(); - if (mo && !isAttachedProperty(prop->name)) { - if (prop->isDefault) { - QMetaProperty p = QmlMetaType::defaultProperty(mo); - // XXX - // Currently we don't handle enums in the static analysis - // so we let them drop through to generateStoreInstruction() - if (p.name() && !p.isEnumType()) { - prop->index = mo->indexOfProperty(p.name()); - prop->name = p.name(); + const QMetaObject *metaObject = obj->metaObject(); + Q_ASSERT(metaObject); - int t = p.type(); - if (t == QVariant::UserType) - t = p.userType(); + if (isAttachedPropertyName(prop->name)) { + // Setup attached property data + 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"); + + prop->value->metatype = type->attachedPropertiesType(); + } else { + // Setup regular property data + QMetaProperty p; - prop->type = t; + if (prop->isDefault) { + p = QmlMetaType::defaultProperty(metaObject); + + if (p.name()) { + prop->index = p.propertyIndex(); + prop->name = p.name(); } + } else { - prop->index = mo->indexOfProperty(prop->name.constData()); - QMetaProperty p = mo->property(prop->index); - // XXX - // Currently we don't handle enums in the static analysis - // so we let them drop through to generateStoreInstruction() - if (p.name() && !p.isEnumType()) { - int t = p.type(); - if (t == QVariant::UserType) - t = p.userType(); + prop->index = metaObject->indexOfProperty(prop->name.constData()); - prop->type = t; + if (prop->index != -1) { + p = metaObject->property(prop->index); + Q_ASSERT(p.name()); } } - } else if(isAttachedProperty(prop->name) && prop->value) { - QmlType *type = QmlMetaType::qmlType(prop->name); - if (type && type->attachedPropertiesType()) - prop->value->metatype = type->attachedPropertiesType(); + + // We can't error here as the "id" property does not require a + // successful index resolution + if (p.name()) { + int t = p.type(); + + if (t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } } - if (prop->name == "id") { + if (!prop->isDefault && prop->name == "id") { COMPILE_CHECK(compileIdProperty(prop, obj)); - } else if (isAttachedProperty(prop->name)) { + } else if (isAttachedPropertyName(prop->name)) { COMPILE_CHECK(compileAttachedProperty(prop, obj, ctxt)); + } else if (prop->index == -1) { + + if (prop->isDefault) { + COMPILE_EXCEPTION2(prop, "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)); @@ -944,19 +989,22 @@ bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, return true; } +// Compile attached property object. In this example, +// Text { +// GridView.row: 10 +// } +// GridView is an attached property object. bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, QmlParser::Object *obj, int ctxt) { - if (!prop->value) - COMPILE_EXCEPTION("Incorrect usage of an attached property"); + 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; - int id = QmlMetaType::attachedPropertiesFuncId(prop->name); - if (id == -1) - COMPILE_EXCEPTION("Non-existant attached property object" << prop->name); fetch.fetchAttached.id = id; output->bytecode << fetch; @@ -970,16 +1018,20 @@ bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, return true; } +// Compile "nested" properties. In this example: +// Text { +// font.size: 12 +// } +// font is a nested property. size is not. bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, int ctxt) { - if (prop->type != 0) - prop->value->metatype = QmlMetaType::metaObjectForType(prop->type); - - if (prop->index == -1) - COMPILE_EXCEPTION2(prop, "Cannot access non-existant property" << prop->name); + Q_ASSERT(prop->type != 0); + Q_ASSERT(prop->index != -1); - if (!QmlMetaType::isObject(prop->value->metatype)) + // Load the nested property's meta type + prop->value->metatype = QmlMetaType::metaObjectForType(prop->type); + if (!prop->value->metatype) COMPILE_EXCEPTION2(prop, "Cannot nest non-QObject property" << prop->name); QmlInstruction fetch; @@ -999,11 +1051,20 @@ bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, return true; } +// Compile 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, int ctxt) { + Q_ASSERT(QmlMetaType::isList(prop->type) || + QmlMetaType::isQmlList(prop->type)); + int t = prop->type; + if (QmlMetaType::isQmlList(t)) { QmlInstruction fetch; fetch.line = prop->location.start.line; @@ -1033,8 +1094,6 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, pop.line = prop->location.start.line; output->bytecode << pop; } else { - Q_ASSERT(QmlMetaType::isList(t)); - QmlInstruction fetch; fetch.type = QmlInstruction::FetchQList; fetch.line = prop->location.start.line; @@ -1072,9 +1131,25 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, pop.type = QmlInstruction::PopQList; output->bytecode << pop; } + return true; } +// Compile regular property assignments of the form property: <value> +// +// ### The following problems exist +// +// There is no distinction between how "lists" of values are specified. This +// Item { +// children: Item {} +// children: Item {} +// } +// is identical to +// Item { +// children: [ Item {}, Item {} ] +// } +// +// We allow assignming multiple values to single value properties bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, QmlParser::Object *obj, int ctxt) @@ -1095,97 +1170,98 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, return true; } +// Compile assigning a single object instance to a regular property bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, QmlParser::Object *obj, QmlParser::Value *v, int ctxt) { - if (v->object->type != -1) - v->object->metatype = output->types.at(v->object->type).metaObject(); - Q_ASSERT(v->object->metaObject()); - - if (prop->index == -1) - COMPILE_EXCEPTION2(prop, "Cannot assign object to non-existant property" << prop->name); - + Q_ASSERT(prop->index != -1); + Q_ASSERT(v->object->type != -1); 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; - assign.storeObject.cast = 0; output->bytecode << assign; v->type = Value::CreatedObject; } else if (prop->type == -1) { - // Variant - // ### Is it always? + // 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; - assign.storeObject.cast = 0; output->bytecode << assign; v->type = Value::CreatedObject; } else { + // Normally compileObject() 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 + v->object->metatype = output->types.at(v->object->type).metaObject(); + Q_ASSERT(v->object->metaObject()); - const QMetaObject *propmo = + // We want to raw metaObject here as the raw metaobject is the + // actual property type before we applied any extensions that might + // effect the properties on the type, but don't effect assignability + const QMetaObject *propertyMetaObject = QmlMetaType::rawMetaObjectForType(prop->type); - bool isPropertyValue = false; + // Will be true if the assigned type inherits QmlPropertyValueSource + bool isPropertyValue = false; + // Will be true if the assgned type inherits propertyMetaObject bool isAssignable = false; - - if (propmo) { - // We want to raw metaObject here as the raw metaobject is the - // actual property type before we applied any extensions + // Determine isPropertyValue and isAssignable values + if (propertyMetaObject) { const QMetaObject *c = v->object->metatype; - while(propmo && c) { - isPropertyValue = isPropertyValue || (c == &QmlPropertyValueSource::staticMetaObject); - isAssignable = isAssignable || (c == propmo); + while(c) { + isPropertyValue |= (c == &QmlPropertyValueSource::staticMetaObject); + isAssignable |= (c == propertyMetaObject); c = c->superClass(); } } else { const QMetaObject *c = v->object->metatype; while(!isPropertyValue && c) { - isPropertyValue = c == &QmlPropertyValueSource::staticMetaObject; + isPropertyValue |= (c == &QmlPropertyValueSource::staticMetaObject); c = c->superClass(); } } 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; - // XXX - this cast may not be 0 - assign.storeObject.cast = 0; output->bytecode << assign; v->type = Value::CreatedObject; - } else if (propmo == &QmlComponent::staticMetaObject) { - + } 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; - // XXX - this cast may not be 0 - assign.storeObject.cast = 0; output->bytecode << assign; v->type = Value::Component; } else if (isPropertyValue) { + // Assign as a property value source COMPILE_CHECK(compileObject(v->object, ctxt)); QmlInstruction assign; @@ -1203,11 +1279,14 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, return true; } +// Compile assigning a literal or binding to a regular property bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, QmlParser::Object *obj, QmlParser::Value *v, int ctxt) { + Q_ASSERT(prop->index != -1); + if (v->value.isScript()) { COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, @@ -1220,17 +1299,12 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, QmlInstruction assign; assign.line = v->location.start.line; - - if (prop->index != -1) { - COMPILE_CHECK(generateStoreInstruction(assign, obj->metaObject()->property(prop->index), prop->index, v)); - } else { - COMPILE_EXCEPTION2(prop, "Cannot assign value to non-existant property" << prop->name); - } - + COMPILE_CHECK(compileStoreInstruction(assign, obj->metaObject()->property(prop->index), v)); output->bytecode << assign; v->type = Value::Literal; } + return true; } @@ -1325,6 +1399,9 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, int ctxt, const QMetaObject *mo, qint64 line) { + Q_ASSERT(mo); + Q_ASSERT(prop->index); + QmlBasicScript bs; bs.compile(bind.toLatin1()); @@ -1335,32 +1412,24 @@ bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, bref = output->indexForString(bind); } - if (prop->index != -1) { + QmlInstruction assign; + assign.assignBinding.context = ctxt; + assign.line = line; - QmlInstruction assign; - assign.assignBinding.context = ctxt; - assign.line = line; - - if (bs.isValid()) - assign.type = QmlInstruction::StoreCompiledBinding; - else - assign.type = QmlInstruction::StoreBinding; - - assign.assignBinding.property = prop->index; - assign.assignBinding.value = bref; - assign.assignBinding.category = QmlMetaProperty::Unknown; - if (mo) { - // ### we should generate an exception if the property is read-only - QMetaProperty mp = mo->property(assign.assignBinding.property); - assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); - } + if (bs.isValid()) + assign.type = QmlInstruction::StoreCompiledBinding; + else + assign.type = QmlInstruction::StoreBinding; - savedTypes.insert(output->bytecode.count(), prop->type); - output->bytecode << assign; + assign.assignBinding.property = prop->index; + assign.assignBinding.value = bref; + QMetaProperty mp = mo->property(assign.assignBinding.property); + if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) + COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); + assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); - } else { - COMPILE_EXCEPTION2(prop, "Cannot assign binding to non-existant property" << prop->name); - } + savedTypes.insert(output->bytecode.count(), prop->type); + output->bytecode << assign; return true; } |