diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-12 14:43:56 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-20 14:26:01 +0200 |
commit | 6042327dee1f8dd912a86be16f4044d259c9b3e4 (patch) | |
tree | 48091ee06fc657dcbdd090a27b3ed0eec88bc55b /src/qml/compiler | |
parent | bbb78a92a910d32b2886af62c218db87325eb6ce (diff) |
[new compiler] Initial support for group properties
This implements support for "font.pixelSize: 24" for example. The representation
in the compile data structure is so that font.pixelSize is short-hand for
font {
pixelSize: 24
}
which means that inside the braces is a complete object initializer. For that
initializer we create a dedicated CompiledData::Object, which however has its
type name empty. When populating the outer instance then, the "font" property
is read as QQmlValueType (a QObject) and instead of creating a new QObject we
use that value type as instance to run the rest of the QML object initializer
(everything in braces).
Change-Id: Ic0a37ac77ab88f582546b9c09a3d06a07726420b
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 74 | ||||
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator_p.h | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 3 |
3 files changed, 78 insertions, 7 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 6ca7078e69..b875067620 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -152,21 +152,38 @@ bool QQmlCodeGenerator::visit(AST::UiProgram *) bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node) { - int idx = defineQMLObject(node); - appendBinding(AST::SourceLocation(), registerString(QString()), idx); + // The grammar can't distinguish between two different definitions here: + // Item { ... } + // versus + // font { ... } + // The former is a new binding with no property name and "Item" as type name, + // and the latter is a binding to the font property with no type name but + // only initializer. + + AST::UiQualifiedId *lastId = node->qualifiedTypeNameId; + while (lastId->next) + lastId = lastId->next; + bool isType = lastId->name.unicode()->isUpper(); + if (isType) { + int idx = defineQMLObject(node); + appendBinding(AST::SourceLocation(), registerString(QString()), idx); + } else { + int idx = defineQMLObject(/*qualfied type name id*/0, node->initializer); + appendBinding(node->qualifiedTypeNameId, idx); + } return false; } bool QQmlCodeGenerator::visit(AST::UiObjectBinding *node) { int idx = defineQMLObject(node->qualifiedTypeNameId, node->initializer); - appendBinding(node->qualifiedId->identifierToken, registerString(asString(node->qualifiedId)), idx); + appendBinding(node->qualifiedId, idx); return false; } bool QQmlCodeGenerator::visit(AST::UiScriptBinding *node) { - appendBinding(node->qualifiedId->identifierToken, registerString(asString(node->qualifiedId)), node->statement); + appendBinding(node->qualifiedId, node->statement); return false; } @@ -237,7 +254,9 @@ int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, _object->inheritedTypeNameIndex = registerString(asString(qualifiedTypeNameId)); - AST::SourceLocation loc = qualifiedTypeNameId->firstSourceLocation(); + AST::SourceLocation loc; + if (qualifiedTypeNameId) + loc = qualifiedTypeNameId->firstSourceLocation(); _object->location.line = loc.startLine; _object->location.column = loc.startColumn; @@ -664,6 +683,24 @@ void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, AST } } +void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, AST::Statement *value) +{ + QmlObject *object = 0; + name = resolveQualifiedId(name, &object); + qSwap(_object, object); + appendBinding(name->identifierToken, registerString(name->name.toString()), value); + qSwap(_object, object); +} + +void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, int objectIndex) +{ + QmlObject *object = 0; + name = resolveQualifiedId(name, &object); + qSwap(_object, object); + appendBinding(name->identifierToken, registerString(name->name.toString()), objectIndex); + qSwap(_object, object); +} + void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value) { if (!sanityCheckPropertyName(nameLocation, propertyNameIndex)) @@ -685,9 +722,31 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i _object->bindings->append(binding); } +AST::UiQualifiedId *QQmlCodeGenerator::resolveQualifiedId(AST::UiQualifiedId *name, QmlObject **object) +{ + *object = _object; + while (name->next) { + Binding *binding = New<Binding>(); + binding->propertyNameIndex = registerString(name->name.toString()); + binding->value.type = QV4::CompiledData::Value::Type_Object; + + int objIndex = defineQMLObject(0, 0); + binding->value.objectIndex = objIndex; + + (*object)->bindings->append(binding); + *object = _objects[objIndex]; + + name = name->next; + } + return name; +} + bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex) { - QString name = jsGenerator->strings.at(nameIndex); + const QString &name = jsGenerator->strings.at(nameIndex); + if (name.isEmpty()) + return true; + if (_propertyNames.contains(name)) COMPILE_EXCEPTION(nameLocation, tr("Duplicate property name")); @@ -720,7 +779,8 @@ void QQmlCodeGenerator::recordError(const AST::SourceLocation &location, const Q void QQmlCodeGenerator::collectTypeReferences() { foreach (QmlObject *obj, _objects) { - _typeReferences.add(obj->inheritedTypeNameIndex, obj->location); + if (!stringAt(obj->inheritedTypeNameIndex).isEmpty()) + _typeReferences.add(obj->inheritedTypeNameIndex, obj->location); for (QmlProperty *prop = obj->properties->first; prop; prop = prop->next) { if (prop->type >= QV4::CompiledData::Property::Custom) diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 97ba3ef075..5344dc1535 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -215,9 +215,15 @@ public: void setBindingValue(QV4::CompiledData::Binding *binding, AST::Statement *statement); + void appendBinding(AST::UiQualifiedId *name, AST::Statement *value); + void appendBinding(AST::UiQualifiedId *name, int objectIndex); void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value); void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex); + // resolves qualified name (font.pixelSize for example) and returns the last name along + // with the object any right-hand-side of a binding should apply to. + AST::UiQualifiedId *resolveQualifiedId(AST::UiQualifiedId *name, QmlObject **object); + bool sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex); void recordError(const AST::SourceLocation &location, const QString &description); @@ -229,6 +235,8 @@ public: int registerString(const QString &str) const { return jsGenerator->registerString(str); } template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); } + QString stringAt(int index) const { return jsGenerator->strings.at(index); } + QList<QQmlError> errors; QList<QV4::CompiledData::Import*> _imports; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index c98d53a1fa..9f8bd80f4d 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -315,6 +315,9 @@ struct Property struct Object { + // An empty inherited type name suggests that this object doesn't require to be instantiated + // by itself but is merely used for grouped properties. It can therefore only have bindings, + // so nProperties, nFunctions and nSignals must be zero. quint32 inheritedTypeNameIndex; quint32 idIndex; quint32 indexOfDefaultProperty; |