From e4e735ea8c5ae8e65668938d7af2fb11e1cb6c0e Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 27 May 2009 13:41:53 +1000 Subject: Simplify and comment compiler --- src/declarative/qml/qmlcompiler.cpp | 373 +++++++++++++++++++-------------- src/declarative/qml/qmlcompiler_p.h | 11 +- src/declarative/qml/qmlinstruction.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 1 - src/declarative/qml/qmlmetatype.cpp | 1 + src/declarative/qml/qmlvme.cpp | 7 +- 6 files changed, 229 insertions(+), 166 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 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 * and QmlList *. +// +// QList * types can accept a list of objects, or a single binding +// QmlList * 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: +// +// ### 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; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 27c4dd2..bc9e06c 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -119,7 +119,8 @@ public: QList errors() const; static bool isValidId(const QString &); - static bool isAttachedProperty(const QByteArray &); + static bool isAttachedPropertyName(const QByteArray &); + static bool isSignalPropertyName(const QByteArray &); private: void reset(QmlCompiledComponent *, bool); @@ -154,11 +155,9 @@ private: QmlParser::Object *obj, QmlParser::Value *value, int ctxt); - - bool generateStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - int index, - QmlParser::Value *value); + bool compileStoreInstruction(QmlInstruction &instr, + const QMetaProperty &prop, + QmlParser::Value *value); bool compileDynamicMeta(QmlParser::Object *obj); bool compileBinding(const QString &, QmlParser::Property *prop, diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index bb40063..0aa860d 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -116,7 +116,7 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) qWarning() << idx << "\t" << line << "\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); break; case QmlInstruction::StoreObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex << "\t" << instr->storeObject.cast; + 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; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index abefd6c..5c6fa5a 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -235,7 +235,6 @@ public: } storeRect; struct { int propertyIndex; - int cast; } storeObject; struct { int propertyIndex; diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index 6d44f7a..3e25ae0 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -771,6 +771,7 @@ const char *QmlMetaType::interfaceIId(int userType) bool QmlMetaType::isObject(const QMetaObject *mo) { + // ### Huh? while(mo) { if (mo == &QObject::staticMetaObject) return true; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 991c7ad..e68afcc 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -546,8 +546,7 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QObject *target = stack.top(); void *a[1]; - void *obj = (void *)(((char *)assignObj) + instr.storeObject.cast); - a[0] = (void *)&obj; + a[0] = (void *)&assignObj; QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.storeObject.propertyIndex, a); @@ -674,8 +673,6 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QmlMetaProperty mp(target, instr.assignBinding.property, (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); - if (!mp.isWritable()) - VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, 0); bindValues.append(bind); @@ -700,8 +697,6 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QmlMetaProperty mp(target, instr.assignBinding.property, (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); - if (!mp.isWritable()) - VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, false); bindValues.append(bind); -- cgit v0.12