summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qmlcompiler.cpp
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-05-27 03:41:53 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-05-27 03:41:53 (GMT)
commite4e735ea8c5ae8e65668938d7af2fb11e1cb6c0e (patch)
tree5073fa9433a31baa06df3fbce781eeeb4a2ba942 /src/declarative/qml/qmlcompiler.cpp
parent65ba2e6f8a57058305e4ca3bdf77c4e8fed3c243 (diff)
downloadQt-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.cpp373
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;
}