aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-17 17:27:07 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-20 14:27:10 +0200
commit8d441936d2e8ab8c39a66831a658c192b80ca597 (patch)
tree61d71c983c685551d403c5b9b91b0e9075c40fc1
parentc5a8d5b331352e9a1a0a4be7571add641b22238c (diff)
[new compiler] Initial support for components
We use a dedicated pass through the objects in QV4::CompiledData::QmlUnit to determine which objects are QQmlComponents. We remember their object indices as well as to which component other objects belong to (if any). Change-Id: I97929c57e2ccb2fd380d612002d128359c4bc253 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp3
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h1
-rw-r--r--src/qml/compiler/qv4compileddata_p.h1
-rw-r--r--src/qml/qml/qqmlcompiler_p.h7
-rw-r--r--src/qml/qml/qqmlcomponent.cpp20
-rw-r--r--src/qml/qml/qqmlcomponent.h1
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp229
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h38
-rw-r--r--src/qml/qml/qqmltypeloader.cpp28
9 files changed, 266 insertions, 62 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index f3a9b0213d..0802358d93 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -827,6 +827,8 @@ bool QQmlCodeGenerator::setId(AST::Statement *value)
#endif
_object->idIndex = registerString(str.toString());
+ _object->locationOfIdProperty.line = loc.startLine;
+ _object->locationOfIdProperty.column = loc.startColumn;
return true;
}
@@ -993,6 +995,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
objectToWrite->indexOfDefaultProperty = o->indexOfDefaultProperty;
objectToWrite->idIndex = o->idIndex;
objectToWrite->location = o->location;
+ objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
quint32 nextOffset = sizeof(QV4::CompiledData::Object);
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 0fecd84684..981ac0a9a7 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -143,6 +143,7 @@ struct QmlObject
int indexOfDefaultProperty;
QV4::CompiledData::Location location;
+ QV4::CompiledData::Location locationOfIdProperty;
PoolList<QmlProperty> *properties;
PoolList<Signal> *qmlSignals;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 5f67d0c215..6d4a3b7548 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -351,6 +351,7 @@ struct Object
quint32 nBindings;
quint32 offsetToBindings;
Location location;
+ Location locationOfIdProperty;
// Function[]
// Property[]
// Signal[]
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 52d6fe210c..9e63ecb22c 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -140,8 +140,11 @@ public:
// --- new compiler
QV4::CompiledData::CompilationUnit *compilationUnit;
QV4::CompiledData::QmlUnit *qmlUnit;
- // ### sub-context support
- QHash<int, int> objectIndexToId;
+ // index in first hash is component index, hash inside maps from object index in that scope to integer id
+ QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
+ QHash<int, int> objectIndexToIdForRoot;
+
+ bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
// ---
struct Instruction {
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index a30d8becdb..3c8a50ad4f 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -900,24 +900,8 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
if (cc->compilationUnit && !cc->compilationUnit->engine)
cc->compilationUnit->linkToEngine(v4);
- // ### sub-contexts
- QVector<QQmlContextData::ObjectIdMapping> mapping(cc->objectIndexToId.count());
- for (QHash<int, int>::ConstIterator it = cc->objectIndexToId.constBegin(), end = cc->objectIndexToId.constEnd();
- it != end; ++it) {
- const QV4::CompiledData::Object *obj = cc->qmlUnit->objectAt(it.key());
-
- QQmlContextData::ObjectIdMapping m;
- m.id = it.value();
- m.name = cc->qmlUnit->header.stringAt(obj->idIndex);
- mapping[m.id] = m;
- }
- context->setIdPropertyData(mapping);
-
- context->url = cc->url;
-
- state.creator = new QmlObjectCreator(context, cc->qmlUnit, cc->compilationUnit, cc->resolvedTypes,
- cc->propertyCaches, cc->datas, cc->objectIndexToId);
- rv = state.creator->create();
+ state.creator = new QmlObjectCreator(context, cc);
+ rv = state.creator->create(start);
if (!rv)
state.errors = state.creator->errors;
} else {
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 9877f59fb6..fe376d0e4a 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -129,6 +129,7 @@ private:
Q_DISABLE_COPY(QQmlComponent)
friend class QQmlVME;
friend class QQmlTypeData;
+ friend class QmlObjectCreator;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index be96d473fa..03dfdb0e19 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -52,6 +52,8 @@
#include <private/qqmlboundsignal_p.h>
#include <private/qqmltrace_p.h>
#include <private/qqmlcomponentattached_p.h>
+#include <QQmlComponent>
+#include <private/qqmlcomponent_p.h>
QT_USE_NAMESPACE
@@ -462,20 +464,17 @@ static void removeBindingOnProperty(QObject *o, int index)
if (binding) binding->destroy();
}
-QmlObjectCreator::QmlObjectCreator(QQmlContextData *contextData, const QV4::CompiledData::QmlUnit *qmlUnit,
- const QV4::CompiledData::CompilationUnit *jsUnit,
- const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
- const QList<QQmlPropertyCache*> &propertyCaches,
- const QList<QByteArray> &vmeMetaObjectData, const QHash<int, int> &objectIndexToId)
- : QQmlCompilePass(contextData->url, qmlUnit)
+QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData)
+ : QQmlCompilePass(compiledData->url, compiledData->qmlUnit)
, componentAttached(0)
- , engine(contextData->engine)
- , jsUnit(jsUnit)
- , context(contextData)
- , resolvedTypes(resolvedTypes)
- , propertyCaches(propertyCaches)
- , vmeMetaObjectData(vmeMetaObjectData)
- , objectIndexToId(objectIndexToId)
+ , engine(parentContext->engine)
+ , jsUnit(compiledData->compilationUnit)
+ , parentContext(parentContext)
+ , context(0)
+ , resolvedTypes(compiledData->resolvedTypes)
+ , propertyCaches(compiledData->propertyCaches)
+ , vmeMetaObjectData(compiledData->datas)
+ , compiledData(compiledData)
, _qobject(0)
, _compiledObject(0)
, _ddata(0)
@@ -485,6 +484,49 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *contextData, const QV4::Comp
{
}
+QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
+{
+ int objectToCreate;
+
+ if (subComponentIndex == -1) {
+ objectIndexToId = compiledData->objectIndexToIdForRoot;
+ objectToCreate = qmlUnit->indexOfRootObject;
+ } else {
+ objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex];
+ const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
+ objectToCreate = compObj->bindingTable()->value.objectIndex;
+ }
+
+ context = new QQmlContextData;
+ context->isInternal = true;
+ context->url = compiledData->url;
+ context->urlString = compiledData->name;
+ context->imports = compiledData->importCache;
+ context->imports->addref();
+ context->setParent(parentContext);
+
+ QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count());
+ for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
+ it != end; ++it) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(it.key());
+
+ QQmlContextData::ObjectIdMapping m;
+ m.id = it.value();
+ m.name = stringAt(obj->idIndex);
+ mapping[m.id] = m;
+ }
+ context->setIdPropertyData(mapping);
+
+ QObject *instance = createInstance(objectToCreate, parent);
+
+ QQmlData *ddata = QQmlData::get(instance);
+ Q_ASSERT(ddata);
+ ddata->compiledData = compiledData;
+ ddata->compiledData->addref();
+
+ return instance;
+}
+
void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
@@ -932,7 +974,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
QObject *createdSubObject = 0;
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- createdSubObject = create(binding->value.objectIndex, _qobject);
+ createdSubObject = createInstance(binding->value.objectIndex, _qobject);
if (!createdSubObject)
return false;
}
@@ -1084,31 +1126,58 @@ void QmlObjectCreator::setupFunctions()
}
}
-QObject *QmlObjectCreator::create(int index, QObject *parent)
+QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
{
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+ bool isComponent = false;
+ QObject *instance = 0;
- QQmlType *type = resolvedTypes.value(obj->inheritedTypeNameIndex).type;
- Q_ASSERT(type);
+ if (compiledData->isComponent(index)) {
+ isComponent = true;
+ QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
+ QQmlComponentPrivate::get(component)->creationContext = context;
+ instance = component;
+ } else {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
- QObject *instance = type->create();
- // ### use no-event variant
- if (parent)
- instance->setParent(parent);
+ QQmlType *type = resolvedTypes.value(obj->inheritedTypeNameIndex).type;
+ Q_ASSERT(type);
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
- Q_ASSERT(!cache.isNull());
+ instance = type->create();
+ // ### use no-event variant
+ if (parent)
+ instance->setParent(parent);
+ }
- context->addObject(instance);
+ QQmlData *ddata = QQmlData::get(instance, /*create*/true);
+ if (index == qmlUnit->indexOfRootObject) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != context);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != context);
+ QQmlContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = context;
+ } else
+ context->addObject(instance);
+ ddata->ownContext = true;
+ } else if (!ddata->context)
+ context->addObject(instance);
+
+ ddata->outerContext = context;
QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
if (idEntry != objectIndexToId.constEnd())
context->setIdProperty(idEntry.value(), instance);
- if (!populateInstance(index, instance, cache))
- return 0;
+ if (!isComponent) {
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
+ Q_ASSERT(!cache.isNull());
+
+ if (!populateInstance(index, instance, cache))
+ return 0;
+ }
return instance;
}
@@ -1119,7 +1188,7 @@ void QmlObjectCreator::finalize()
QQmlTrace trace("VME Binding Enable");
trace.event("begin binding eval");
- Q_ASSERT(allCreatedBindings.isDetached());
+ Q_ASSERT(allCreatedBindings.isEmpty() || allCreatedBindings.isDetached());
for (QLinkedList<QVector<QQmlAbstractBinding*> >::Iterator it = allCreatedBindings.begin(), end = allCreatedBindings.end();
it != end; ++it) {
@@ -1182,6 +1251,9 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
}
+ _ddata->lineNumber = _compiledObject->location.line;
+ _ddata->columnNumber = _compiledObject->location.column;
+
qSwap(_vmeMetaObject, vmeMetaObject);
QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
@@ -1212,3 +1284,104 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
return errors.isEmpty();
}
+
+
+QQmlAnonymousComponentResolver::QQmlAnonymousComponentResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
+ const QList<QQmlPropertyCache *> &propertyCaches)
+ : QQmlCompilePass(url, qmlUnit)
+ , _componentIndex(-1)
+ , resolvedTypes(resolvedTypes)
+ , propertyCaches(propertyCaches)
+{
+}
+
+bool QQmlAnonymousComponentResolver::resolve()
+{
+ Q_ASSERT(componentRoots.isEmpty());
+
+ // Find objects that are Components. This is missing an extra pass
+ // that finds implicitly defined components, i.e.
+ // someProperty: Item { ... }
+ // when someProperty _is_ a QQmlComponent. In that case the Item {}
+ // should be implicitly surrounded by Component {}
+
+ for (int i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ continue;
+
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(i);
+ if (!cache || cache->metaObject() != &QQmlComponent::staticMetaObject)
+ continue;
+
+ componentRoots.append(i);
+ // Sanity checks: There can be only an (optional) id property and
+ // a default property, that defines the component tree.
+ }
+
+ std::sort(componentRoots.begin(), componentRoots.end());
+
+ // For each component's tree, remember to which component the children
+ // belong to
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ const QV4::CompiledData::Object *component = qmlUnit->objectAt(componentRoots.at(i));
+
+ if (component->nFunctions > 0)
+ COMPILE_EXCEPTION(component, tr("Component objects cannot declare new functions."));
+ if (component->nProperties > 0)
+ COMPILE_EXCEPTION(component, tr("Component objects cannot declare new properties."));
+ if (component->nSignals > 0)
+ COMPILE_EXCEPTION(component, tr("Component objects cannot declare new signals."));
+
+ if (component->nBindings == 0)
+ COMPILE_EXCEPTION(component, tr("Cannot create empty component specification"));
+
+ const QV4::CompiledData::Binding *rootBinding = component->bindingTable();
+ if (component->nBindings > 1 || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
+ COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
+
+ _componentIndex = i;
+ _ids.clear();
+ if (!recordComponentSubTree(rootBinding->value.objectIndex))
+ break;
+ }
+
+ return errors.isEmpty();
+}
+
+bool QQmlAnonymousComponentResolver::recordComponentSubTree(int objectIndex)
+{
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
+
+ // Only include creatable types. Everything else is synthetic, such as group property
+ // objects.
+ if (!stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ objectIndexToComponentIndex.insert(objectIndex, _componentIndex);
+
+ QString id = stringAt(obj->idIndex);
+ if (!id.isEmpty()) {
+ if (_ids.contains(obj->idIndex)) {
+ recordError(obj->locationOfIdProperty, tr("id is not unique"));
+ return false;
+ }
+ _ids.insert(obj->idIndex);
+ }
+
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (int i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Object
+ && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
+ && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ continue;
+
+ // Stop at Component boundary
+ if (std::binary_search(componentRoots.constBegin(), componentRoots.constEnd(), binding->value.objectIndex))
+ continue;
+
+ if (!recordComponentSubTree(binding->value.objectIndex))
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index eb7a6233c5..e0aefaf81d 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -80,24 +80,44 @@ protected:
QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
};
+class QQmlAnonymousComponentResolver : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
+public:
+ QQmlAnonymousComponentResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
+ const QList<QQmlPropertyCache *> &propertyCaches);
+
+ bool resolve();
+
+ QVector<int> componentRoots;
+ QHash<int, int> objectIndexToComponentIndex;
+
+protected:
+ bool recordComponentSubTree(int objectIndex);
+
+ int _componentIndex;
+ QSet<int> _ids;
+
+ const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
+ const QList<QQmlPropertyCache *> propertyCaches;
+};
+
class QmlObjectCreator : public QQmlCompilePass
{
Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
public:
- QmlObjectCreator(QQmlContextData *contextData, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::CompilationUnit *jsUnit,
- const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes, const QList<QQmlPropertyCache *> &propertyCaches, const QList<QByteArray> &vmeMetaObjectData,
- const QHash<int, int> &objectIndexToId);
-
- QObject *create(QObject *parent = 0)
- { return create(qmlUnit->indexOfRootObject, parent); }
- QObject *create(int index, QObject *parent = 0);
+ QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData);
+ QObject *create(int subComponentIndex, QObject *parent = 0);
void finalize();
QQmlComponentAttached *componentAttached;
QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
private:
+ QObject *createInstance(int index, QObject *parent = 0);
+
bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache);
void setupBindings();
@@ -107,12 +127,14 @@ private:
QQmlEngine *engine;
const QV4::CompiledData::CompilationUnit *jsUnit;
+ QQmlContextData *parentContext;
QQmlContextData *context;
const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
const QList<QQmlPropertyCache *> propertyCaches;
const QList<QByteArray> vmeMetaObjectData;
- const QHash<int, int> &objectIndexToId;
+ QHash<int, int> objectIndexToId;
QLinkedList<QVector<QQmlAbstractBinding*> > allCreatedBindings;
+ QQmlCompiledData *compiledData;
QObject *_qobject;
const QV4::CompiledData::Object *_compiledObject;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 8c8f8c9c25..7a54cab0f2 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2250,12 +2250,28 @@ void QQmlTypeData::compile()
m_compiledData->propertyCaches << propertyCache;
}
- // ### support sub-contexts
- for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
- const QString &id = qmlUnit->header.stringAt(obj->idIndex);
- if (!id.isEmpty())
- m_compiledData->objectIndexToId.insert(i, m_compiledData->objectIndexToId.count());
+ {
+ // Scan for anonymous components and determine their scopes.
+ QQmlAnonymousComponentResolver resolver(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, m_compiledData->propertyCaches);
+ if (!resolver.resolve())
+ errors << resolver.errors;
+
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+
+ QHash<int, int> *objectIndexToId = 0;
+ QHash<int, int>::ConstIterator componentIt = resolver.objectIndexToComponentIndex.find(i);
+ if (componentIt != resolver.objectIndexToComponentIndex.constEnd()) {
+ int indexOfComponent = resolver.componentRoots[*componentIt];
+ objectIndexToId = &m_compiledData->objectIndexToIdPerComponent[indexOfComponent];
+ } else
+ objectIndexToId = &m_compiledData->objectIndexToIdForRoot;
+
+ const QString &id = qmlUnit->header.stringAt(obj->idIndex);
+ if (id.isEmpty())
+ continue;
+ objectIndexToId->insert(i, objectIndexToId->count());
+ }
}
if (!errors.isEmpty()) {