summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qmlcompiler.cpp
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2009-07-16 21:36:34 (GMT)
committerMichael Brasser <michael.brasser@nokia.com>2009-07-16 21:36:34 (GMT)
commit6470f646d0815f67bab507c1362cdda775c42a6e (patch)
tree6389ca2728ec8b78294af60e20b918fdccdf88f1 /src/declarative/qml/qmlcompiler.cpp
parent50f400ac20e918db1d0a6496003d953dedaba42a (diff)
parent3bd0062535aaa991fadf739f9362851afacb19eb (diff)
downloadQt-6470f646d0815f67bab507c1362cdda775c42a6e.zip
Qt-6470f646d0815f67bab507c1362cdda775c42a6e.tar.gz
Qt-6470f646d0815f67bab507c1362cdda775c42a6e.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src/declarative/qml/qmlcompiler.cpp')
-rw-r--r--src/declarative/qml/qmlcompiler.cpp287
1 files changed, 167 insertions, 120 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index ed9df03..b0bc6e8 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -68,23 +68,43 @@
QT_BEGIN_NAMESPACE
+DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
+
using namespace QmlParser;
+/*!
+ Instantiate a new QmlCompiler.
+*/
QmlCompiler::QmlCompiler()
: output(0)
{
}
+/*!
+ Returns true if the last call to compile() caused errors.
+
+ \sa errors()
+*/
bool QmlCompiler::isError() const
{
return !exceptions.isEmpty();
}
+/*!
+ Return the list of errors from the last call to compile(), or an empty list
+ if there were no errors.
+*/
QList<QmlError> QmlCompiler::errors() const
{
return exceptions;
}
+/*!
+ Returns true if \a val is a legal object id, false otherwise.
+
+ Legal ids must start with a letter or underscore, and contain only
+ letters, numbers and underscores.
+*/
bool QmlCompiler::isValidId(const QString &val)
{
if (val.isEmpty())
@@ -122,27 +142,26 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name)
'A' <= name.at(2) && 'Z' >= name.at(2);
}
-#define COMPILE_EXCEPTION2(token, desc) \
- { \
- QString exceptionDescription; \
- QmlError error; \
- error.setUrl(output->url); \
- error.setLine(token->location.start.line); \
- error.setColumn(token->location.start.column); \
- QDebug d(&exceptionDescription); \
- d << desc; \
- error.setDescription(exceptionDescription.trimmed()); \
- exceptions << error; \
- return false; \
- }
+/*!
+ Inserts an error into the QmlCompiler error list, and returns false
+ (failure).
-#define COMPILE_EXCEPTION(desc) \
+ \a token is used to source the error line and column, and \a desc is the
+ error itself. \a desc can be an expression that can be piped into QDebug.
+
+ For example:
+
+ \code
+ COMPILE_EXCEPTION(property, "Error for property" << property->name);
+ \endcode
+*/
+#define COMPILE_EXCEPTION(token, desc) \
{ \
QString exceptionDescription; \
QmlError error; \
error.setUrl(output->url); \
- error.setLine(obj->location.start.line); \
- error.setColumn(obj->location.start.column); \
+ error.setLine((token)->location.start.line); \
+ error.setColumn((token)->location.start.column); \
QDebug d(&exceptionDescription); \
d << desc; \
error.setDescription(exceptionDescription.trimmed()); \
@@ -150,19 +169,28 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name)
return false; \
}
+/*!
+ Returns false if \a is false, otherwise does nothing.
+*/
#define COMPILE_CHECK(a) \
{ \
if (!a) return false; \
}
-// Compile a simple assignment of v to prop into instr
+/*!
+ Returns true if literal \a v can be assigned to property \a prop, otherwise
+ false.
+
+ This test corresponds to action taken by genLiteralAssignment(). Any change
+ made here, must have a corresponding action in genLiteralAssigment().
+*/
bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
QmlParser::Value *v)
{
QString string = v->value.asScript();
if (!prop.isWritable())
- COMPILE_EXCEPTION2(v, "Invalid property assignment: read-only property");
+ COMPILE_EXCEPTION(v, "Invalid property assignment: read-only property");
if (prop.isEnumType()) {
int value;
@@ -171,7 +199,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
} else
value = prop.enumerator().keyToValue(string.toLatin1().constData());
if (value == -1)
- COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown enumeration");
+ COMPILE_EXCEPTION(v, "Invalid property assignment: unknown enumeration");
return true;
}
int type = prop.userType();
@@ -179,61 +207,61 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
case -1:
break;
case QVariant::String:
- if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: string expected");
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, "Invalid property assignment: string expected");
break;
case QVariant::Url:
- if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: url expected");
+ if (!v->value.isString()) COMPILE_EXCEPTION(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");
+ if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(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");
+ if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(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");
+ if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(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");
+ if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(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");
+ if (!c.isValid()) COMPILE_EXCEPTION(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");
+ if (!d.isValid()) COMPILE_EXCEPTION(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");
+ if (!time.isValid()) COMPILE_EXCEPTION(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");
+ if (!dateTime.isValid()) COMPILE_EXCEPTION(v, "Invalid property assignment: datetime expected");
}
break;
case QVariant::Point:
@@ -241,7 +269,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
{
bool ok;
QPointF point = QmlStringConverters::pointFFromString(string, &ok);
- if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: point expected");
+ if (!ok) COMPILE_EXCEPTION(v, "Invalid property assignment: point expected");
}
break;
case QVariant::Size:
@@ -249,7 +277,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
{
bool ok;
QSizeF size = QmlStringConverters::sizeFFromString(string, &ok);
- if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: size expected");
+ if (!ok) COMPILE_EXCEPTION(v, "Invalid property assignment: size expected");
}
break;
case QVariant::Rect:
@@ -257,12 +285,12 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
{
bool ok;
QRectF rect = QmlStringConverters::rectFFromString(string, &ok);
- if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: rect expected");
+ if (!ok) COMPILE_EXCEPTION(v, "Invalid property assignment: rect expected");
}
break;
case QVariant::Bool:
{
- if (!v->value.isBoolean()) COMPILE_EXCEPTION2(v, "Invalid property assignment: boolean expected");
+ if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, "Invalid property assignment: boolean expected");
}
break;
default:
@@ -273,13 +301,19 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop,
QmlMetaType::StringConverter converter =
QmlMetaType::customStringConverter(t);
if (!converter)
- COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown type" << prop.type());
+ COMPILE_EXCEPTION(v, "Invalid property assignment: unknown type" << prop.type());
}
break;
}
return true;
}
+/*!
+ Generate a store instruction for assigning literal \a v to property \a prop.
+
+ Any literal assignment that is approved in testLiteralAssignment() must have
+ a corresponding action in this method.
+*/
void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop,
QmlParser::Value *v)
{
@@ -469,17 +503,31 @@ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop,
output->bytecode << instr;
}
-void QmlCompiler::reset(QmlCompiledData *cc)
+/*!
+ Resets data by clearing the lists that the QmlCompiler modifies.
+*/
+void QmlCompiler::reset(QmlCompiledData *data)
{
- cc->types.clear();
- cc->primitives.clear();
- cc->floatData.clear();
- cc->intData.clear();
- cc->customTypeData.clear();
- cc->datas.clear();
- cc->bytecode.clear();
+ data->types.clear();
+ data->primitives.clear();
+ data->floatData.clear();
+ data->intData.clear();
+ data->customTypeData.clear();
+ data->datas.clear();
+ data->bytecode.clear();
}
+/*!
+ Compile \a unit, and store the output in \a out. \a engine is the QmlEngine
+ with which the QmlCompiledData will be associated.
+
+ Returns true on success, false on failure. On failure, the compile errors
+ are available from errors().
+
+ If the environment variant QML_COMPILER_DUMP is set
+ (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
+ on a successful compiler.
+*/
bool QmlCompiler::compile(QmlEngine *engine,
QmlCompositeTypeData *unit,
QmlCompiledData *out)
@@ -526,11 +574,14 @@ bool QmlCompiler::compile(QmlEngine *engine,
compileTree(root);
if (!isError()) {
- out->dumpInstructions();
+ if (compilerDump())
+ out->dumpInstructions();
} else {
reset(out);
}
+ compileState = ComponentCompileState();
+ savedCompileStates.clear();
output = 0;
return !isError();
@@ -622,7 +673,7 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt)
bool canDefer = false;
if (isCustomParser) {
- if (testProperty(prop, obj)) {
+ if (doesPropertyExist(prop, obj)) {
int ids = compileState.ids.count();
COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
canDefer = ids == compileState.ids.count();
@@ -651,7 +702,7 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt)
bool canDefer = false;
if (isCustomParser) {
- if (testProperty(prop, obj)) {
+ if (doesPropertyExist(prop, obj)) {
int ids = compileState.ids.count();
COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
canDefer = ids == compileState.ids.count();
@@ -676,7 +727,7 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt)
QmlCustomParser *cp = output->types.at(obj->type).type->customParser();
obj->custom = cp->compile(customProps, &ok);
if(!ok)
- COMPILE_EXCEPTION("Failure compiling custom type");
+ COMPILE_EXCEPTION(obj, "Failure compiling custom type");
}
return true;
@@ -876,36 +927,36 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj,
Property *idProp = 0;
if (obj->properties.count() > 1 ||
(obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
- COMPILE_EXCEPTION("Invalid component specification");
+ COMPILE_EXCEPTION(obj, "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");
+ COMPILE_EXCEPTION(obj, "Invalid component id specification");
if (idProp) {
QString idVal = idProp->values.first()->primitive().toUtf8();
if (compileState.ids.contains(idVal))
- COMPILE_EXCEPTION("id is not unique");
+ COMPILE_EXCEPTION(obj, "id is not unique");
addId(idVal, obj);
- obj->id = idVal.toUtf8();
+ obj->id = idVal;
}
// 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");
+ COMPILE_EXCEPTION(obj, "Invalid component body specification");
Object *root = 0;
if (obj->defaultProperty && obj->defaultProperty->values.count())
root = obj->defaultProperty->values.first()->object;
if (!root)
- COMPILE_EXCEPTION("Cannot create empty component specification");
+ COMPILE_EXCEPTION(obj, "Cannot create empty component specification");
// Build the component tree
COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
@@ -989,7 +1040,7 @@ bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj,
Q_ASSERT(obj->metaObject());
if (prop->isEmpty())
- COMPILE_EXCEPTION2(prop, "Empty property assignment");
+ COMPILE_EXCEPTION(prop, "Empty property assignment");
QByteArray name = prop->name;
Q_ASSERT(name.startsWith("on"));
@@ -1008,7 +1059,7 @@ bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj,
} else {
if (prop->value || prop->values.count() > 1)
- COMPILE_EXCEPTION("Incorrectly specified signal");
+ COMPILE_EXCEPTION(prop, "Incorrectly specified signal");
prop->index = sigIdx;
obj->addSignalProperty(prop);
@@ -1025,9 +1076,11 @@ bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj,
}
-// Returns true if prop exists on obj, false otherwise
-bool QmlCompiler::testProperty(QmlParser::Property *prop,
- QmlParser::Object *obj)
+/*!
+ Returns true if (value) property \a prop exists on obj, false otherwise.
+*/
+bool QmlCompiler::doesPropertyExist(QmlParser::Property *prop,
+ QmlParser::Object *obj)
{
if(isAttachedPropertyName(prop->name) || prop->name == "id")
return true;
@@ -1051,7 +1104,7 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop,
const BindingContext &ctxt)
{
if (prop->isEmpty())
- COMPILE_EXCEPTION2(prop, "Empty property assignment");
+ COMPILE_EXCEPTION(prop, "Empty property assignment");
const QMetaObject *metaObject = obj->metaObject();
Q_ASSERT(metaObject);
@@ -1063,16 +1116,16 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop,
// 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");
+ COMPILE_EXCEPTION(prop, "Attached properties cannot be used here");
}
QmlType *type = QmlMetaType::qmlType(prop->name);
if (!type || !type->attachedPropertiesType())
- COMPILE_EXCEPTION2(prop, "Non-existant attached object");
+ COMPILE_EXCEPTION(prop, "Non-existant attached object");
if (!prop->value)
- COMPILE_EXCEPTION2(prop, "Invalid attached object assignment");
+ COMPILE_EXCEPTION(prop, "Invalid attached object assignment");
prop->value->metatype = type->attachedPropertiesType();
} else {
@@ -1125,9 +1178,9 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop,
} else if (prop->index == -1) {
if (prop->isDefault) {
- COMPILE_EXCEPTION2(prop->values.first(), "Cannot assign to non-existant default property");
+ COMPILE_EXCEPTION(prop->values.first(), "Cannot assign to non-existant default property");
} else {
- COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant property" << prop->name);
+ COMPILE_EXCEPTION(prop, "Cannot assign to non-existant property" << prop->name);
}
} else if (prop->value) {
@@ -1280,17 +1333,17 @@ bool QmlCompiler::buildIdProperty(QmlParser::Property *prop,
if (prop->value ||
prop->values.count() > 1 ||
prop->values.at(0)->object)
- COMPILE_EXCEPTION2(prop, "Invalid use of id property");
+ COMPILE_EXCEPTION(prop, "Invalid use of id property");
QString val = prop->values.at(0)->primitive();
if (!isValidId(val))
- COMPILE_EXCEPTION2(prop, val << "is not a valid object id");
+ COMPILE_EXCEPTION(prop, val << "is not a valid object id");
if (compileState.ids.contains(val))
- COMPILE_EXCEPTION2(prop, "id is not unique");
+ COMPILE_EXCEPTION(prop, "id is not unique");
- obj->id = val.toUtf8();
+ obj->id = val;
prop->values.at(0)->type = Value::Id;
@@ -1301,18 +1354,16 @@ bool QmlCompiler::buildIdProperty(QmlParser::Property *prop,
void QmlCompiler::addId(const QString &id, QmlParser::Object *obj)
{
- IdReference reference;
- reference.id = id;
- reference.object = obj;
- reference.idx = compileState.ids.count();
- compileState.ids.insert(id, reference);
+ Q_ASSERT(!compileState.ids.contains(id));
+ Q_ASSERT(obj->id == id);
+ obj->idIndex = compileState.ids.count();
+ compileState.ids.insert(id, obj);
}
void QmlCompiler::addBindingReference(const BindingReference &ref)
{
- int id = compileState.bindings.count();
- compileState.bindings << ref;
- compileState.bindingMap.insert(ref.value, id);
+ Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
+ compileState.bindings.insert(ref.value, ref);
}
void QmlCompiler::saveComponentState()
@@ -1368,7 +1419,7 @@ bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop,
// 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);
+ COMPILE_EXCEPTION(prop, "Cannot nest non-QObject property" << prop->name);
obj->addGroupedProperty(prop);
@@ -1408,12 +1459,12 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop,
// at runtime.
if (!listTypeIsInterface) {
if (!canCoerce(listType, v->object)) {
- COMPILE_EXCEPTION("Cannot assign object to list");
+ COMPILE_EXCEPTION(v, "Cannot assign object to list");
}
}
} else {
- COMPILE_EXCEPTION("Cannot assign primitives to lists");
+ COMPILE_EXCEPTION(v, "Cannot assign primitives to lists");
}
}
@@ -1432,19 +1483,19 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop,
// at runtime.
if (!listTypeIsInterface) {
if (!canCoerce(listType, v->object)) {
- COMPILE_EXCEPTION("Cannot assign object to list");
+ COMPILE_EXCEPTION(v, "Cannot assign object to list");
}
}
} else if (v->value.isScript()) {
if (assignedBinding)
- COMPILE_EXCEPTION("Can only assign one binding to lists");
+ COMPILE_EXCEPTION(v, "Can only assign one binding to lists");
assignedBinding = true;
COMPILE_CHECK(buildBinding(v, prop, ctxt));
v->type = Value::PropertyBinding;
} else {
- COMPILE_EXCEPTION("Cannot assign primitives to lists");
+ COMPILE_EXCEPTION(v, "Cannot assign primitives to lists");
}
}
@@ -1570,7 +1621,7 @@ bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop,
v->type = Value::ValueSource;
} else {
- COMPILE_EXCEPTION2(v->object, "Cannot assign object to property");
+ COMPILE_EXCEPTION(v->object, "Cannot assign object to property");
}
}
@@ -1615,12 +1666,12 @@ bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj)
if (prop.isDefaultProperty) {
if (seenDefaultProperty)
- COMPILE_EXCEPTION("Duplicate default property");
+ COMPILE_EXCEPTION(obj, "Duplicate default property");
seenDefaultProperty = true;
}
if (propNames.contains(prop.name))
- COMPILE_EXCEPTION("Duplicate property name");
+ COMPILE_EXCEPTION(obj, "Duplicate property name");
propNames.insert(prop.name);
}
@@ -1628,13 +1679,13 @@ bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj)
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");
+ COMPILE_EXCEPTION(obj, "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");
+ COMPILE_EXCEPTION(obj, "Duplicate method name");
methodNames.insert(name);
}
@@ -1656,7 +1707,7 @@ bool QmlCompiler::mergeDynamicMetaProperties(QmlParser::Object *obj)
property = obj->getProperty(p.name);
if (property->value)
- COMPILE_EXCEPTION2(property, "Invalid property nesting");
+ COMPILE_EXCEPTION(property, "Invalid property nesting");
for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
Value *v = p.defaultValue->values.at(ii);
@@ -1687,6 +1738,14 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode)
for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
+ int propIdx =
+ obj->metaObject()->indexOfProperty(p.name.constData());
+ if (-1 != propIdx) {
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
+ if (prop.isFinal())
+ COMPILE_EXCEPTION(&p, "Cannot override FINAL property");
+ }
+
if (p.isDefaultProperty &&
(p.type != Object::DynamicProperty::Alias ||
mode == ResolveAliases))
@@ -1797,14 +1856,8 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode)
obj->metadata = builder.toRelocatableData();
builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
- // ### Remove me
- obj->extObjectData = &obj->extObject;
-
- if (mode == IgnoreAliases && hasAlias) {
- AliasReference alias;
- alias.object = obj;
- compileState.aliases << alias;
- }
+ if (mode == IgnoreAliases && hasAlias)
+ compileState.aliasingObjects << obj;
obj->synthdata = dynamicData;
@@ -1836,34 +1889,34 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder,
const Object::DynamicProperty &prop)
{
if (!prop.defaultValue)
- COMPILE_EXCEPTION("No property alias location");
+ COMPILE_EXCEPTION(obj, "No property alias location");
if (prop.defaultValue->values.count() != 1 ||
prop.defaultValue->values.at(0)->object ||
!prop.defaultValue->values.at(0)->value.isScript())
- COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+ COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location");
QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
if (!node)
- COMPILE_EXCEPTION("No property alias location"); // ### Can this happen?
+ COMPILE_EXCEPTION(obj, "No property alias location"); // ### Can this happen?
QStringList alias = astNodeToStringList(node);
if (alias.count() != 2)
- COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+ COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location");
if (!compileState.ids.contains(alias.at(0)))
- COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+ COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location");
- const IdReference &id = compileState.ids[alias.at(0)];
- int propIdx = id.object->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData());
+ Object *idObject = compileState.ids[alias.at(0)];
+ int propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData());
if (-1 == propIdx)
- COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location");
+ COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location");
- QMetaProperty aliasProperty = id.object->metaObject()->property(propIdx);
+ QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
- data.append((const char *)&id.idx, sizeof(id.idx));
+ data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
data.append((const char *)&propIdx, sizeof(propIdx));
builder.addSignal(prop.name + "Changed()");
@@ -1881,13 +1934,12 @@ bool QmlCompiler::buildBinding(QmlParser::Value *value,
QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
if (!mp.isWritable() && !QmlMetaType::isList(prop->type))
- COMPILE_EXCEPTION2(prop, "Invalid property assignment: read-only property");
+ COMPILE_EXCEPTION(prop, "Invalid property assignment: read-only property");
BindingReference reference;
reference.expression = value->value;
reference.property = prop;
reference.value = value;
- reference.instructionIdx = output->bytecode.count();
reference.bindingContext = ctxt;
addBindingReference(reference);
@@ -1898,10 +1950,9 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
QmlParser::Property *prop,
QmlParser::Object *obj)
{
- Q_ASSERT(compileState.bindingMap.contains(binding));
+ Q_ASSERT(compileState.bindings.contains(binding));
- const BindingReference &ref =
- compileState.bindings.at(compileState.bindingMap.value(binding));
+ const BindingReference &ref = compileState.bindings.value(binding);
QMetaProperty mp = obj->metaObject()->property(prop->index);
@@ -1927,21 +1978,17 @@ bool QmlCompiler::completeComponentBuild()
{
saveComponentState();
- for (int ii = 0; ii < compileState.aliases.count(); ++ii) {
- const AliasReference &alias = compileState.aliases.at(ii);
- COMPILE_CHECK(buildDynamicMeta(alias.object, ResolveAliases));
+ for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
+ Object *aliasObject = compileState.aliasingObjects.at(ii);
+ COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
}
-
QmlBasicScript::Expression expr;
expr.component = compileState.root;
- foreach (const IdReference &id, compileState.ids) {
- expr.ids.insert(id.id, qMakePair(id.object, id.idx));
- }
-
- for (int ii = 0; ii < compileState.bindings.count(); ++ii) {
- BindingReference &binding = compileState.bindings[ii];
+ expr.ids = compileState.ids;
+ for (QHash<QmlParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) {
+ BindingReference &binding = *iter;
QmlBasicScript bs;
expr.context = binding.bindingContext.object;