diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-13 16:39:00 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-20 14:26:23 +0200 |
commit | d071acf7ff4573cdf7dbea801f40375611243551 (patch) | |
tree | ec34f84d8d795b2996da63e74183eba93fff4ee3 /src/qml/compiler/qqmlcodegenerator.cpp | |
parent | 269e29fdf36dd700d8c985dc7f11dbb5c8746c51 (diff) |
[new compiler] Initial support for attached properties
Attached properties are implemented similarly to group properties, except that
the object operated on isn't a QQmlValueType from a property (i.e. font) but the
QObject that implements the attached properties.
Change-Id: If73751162c191c65512ca1bddadd6270e6e33793
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler/qqmlcodegenerator.cpp')
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 193 |
1 files changed, 108 insertions, 85 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 2f76de168b..2e0ea224c2 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -874,6 +874,15 @@ void QQmlCodeGenerator::collectTypeReferences() for (SignalParameter *param = sig->parameters->first; param; param = param->next) if (!stringAt(param->customTypeNameIndex).isEmpty()) _typeReferences.add(param->customTypeNameIndex, param->location); + + for (Binding *binding = obj->bindings->first; binding; binding = binding->next) { + if (binding->type != QV4::CompiledData::Binding::Type_Object) + continue; + const QString &propName = stringAt(binding->propertyNameIndex); + // Attached property? + if (propName.unicode()->isUpper()) + _typeReferences.add(binding->propertyNameIndex, binding->location); + } } } @@ -1070,9 +1079,10 @@ void JSCodeGen::QmlScanner::end() leaveEnvironment(); } -SignalHandlerConverter::SignalHandlerConverter(ParsedQML *parsedQML, const QHash<int, QQmlPropertyCache *> &resolvedPropertyCaches, QQmlCompiledData *unit) - : parsedQML(parsedQML) - , resolvedPropertyCaches(resolvedPropertyCaches) +SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate, ParsedQML *parsedQML, + QQmlCompiledData *unit) + : enginePrivate(enginePrivate) + , parsedQML(parsedQML) , unit(unit) { } @@ -1083,114 +1093,127 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio QString elementName = stringAt(obj->inheritedTypeNameIndex); if (elementName.isEmpty()) continue; - QQmlPropertyCache *propertyCache = 0; - // map from signal name defined in qml itself to list of parameters - QHash<QString, QStringList> customSignals; + QQmlPropertyCache *cache = unit->resolvedTypes[obj->inheritedTypeNameIndex].createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache)) + return false; + } + return true; +} - for (Binding *binding = obj->bindings->first; binding; binding = binding->next) { - if (binding->type != QV4::CompiledData::Binding::Type_Script) - continue; +bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(QmlObject *obj, const QString &typeName, QQmlPropertyCache *propertyCache) +{ + // map from signal name defined in qml itself to list of parameters + QHash<QString, QStringList> customSignals; + + for (Binding *binding = obj->bindings->first; binding; binding = binding->next) { + QString propertyName = stringAt(binding->propertyNameIndex); + // Attached property? + if (propertyName.unicode()->isUpper() && binding->type == QV4::CompiledData::Binding::Type_Object) { + QmlObject *attachedObj = parsedQML->objects[binding->value.objectIndex]; + QQmlType *type = unit->resolvedTypes.value(binding->propertyNameIndex).type; + QQmlPropertyCache *cache = enginePrivate->cache(type->attachedPropertiesType()); + if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache)) + return false; + continue; + } - QString propertyName = stringAt(binding->propertyNameIndex); - if (!QQmlCodeGenerator::isSignalPropertyName(propertyName)) - continue; + if (binding->type != QV4::CompiledData::Binding::Type_Script) + continue; - if (!propertyCache) - propertyCache = resolvedPropertyCaches.value(obj->inheritedTypeNameIndex); - Q_ASSERT(propertyCache); + if (!QQmlCodeGenerator::isSignalPropertyName(propertyName)) + continue; - PropertyResolver resolver(propertyCache); + PropertyResolver resolver(propertyCache); - Q_ASSERT(propertyName.startsWith(QStringLiteral("on"))); - propertyName.remove(0, 2); + Q_ASSERT(propertyName.startsWith(QStringLiteral("on"))); + propertyName.remove(0, 2); - // Note that the property name could start with any alpha or '_' or '$' character, - // so we need to do the lower-casing of the first alpha character. - for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) { - if (propertyName.at(firstAlphaIndex).isUpper()) { - propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower(); - break; - } + // Note that the property name could start with any alpha or '_' or '$' character, + // so we need to do the lower-casing of the first alpha character. + for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) { + if (propertyName.at(firstAlphaIndex).isUpper()) { + propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower(); + break; } + } - QList<QString> parameters; + QList<QString> parameters; - bool notInRevision = false; - QQmlPropertyData *signal = resolver.signal(propertyName, ¬InRevision); - if (signal) { - int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex); - foreach (const QByteArray ¶m, propertyCache->signalParameterNames(sigIndex)) - parameters << QString::fromUtf8(param); - } else { - if (notInRevision) { - // Try assinging it as a property later - if (resolver.property(propertyName, /*notInRevision ptr*/0)) - continue; - - const QString &originalPropertyName = stringAt(binding->propertyNameIndex); - - const QQmlType *type = unit->resolvedTypes.value(obj->inheritedTypeNameIndex).type; - if (type) { - COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion())); - } else { - COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName).arg(originalPropertyName)); - } - } + bool notInRevision = false; + QQmlPropertyData *signal = resolver.signal(propertyName, ¬InRevision); + if (signal) { + int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex); + foreach (const QByteArray ¶m, propertyCache->signalParameterNames(sigIndex)) + parameters << QString::fromUtf8(param); + } else { + if (notInRevision) { + // Try assinging it as a property later + if (resolver.property(propertyName, /*notInRevision ptr*/0)) + continue; - // Try to look up the signal parameter names in the object itself + const QString &originalPropertyName = stringAt(binding->propertyNameIndex); - // build cache if necessary - if (customSignals.isEmpty()) { - for (Signal *signal = obj->qmlSignals->first; signal; signal = signal->next) { - const QString &signalName = stringAt(signal->nameIndex); - customSignals.insert(signalName, signal->parameterStringList(parsedQML->jsGenerator.strings)); - } + const QQmlType *type = unit->resolvedTypes.value(obj->inheritedTypeNameIndex).type; + if (type) { + COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion())); + } else { + COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName)); } + } - QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName); - if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) { - QString alternateName = propertyName.mid(0, propertyName.length() - strlen("Changed")); - entry = customSignals.find(alternateName); - } + // Try to look up the signal parameter names in the object itself - if (entry == customSignals.constEnd()) { - // Can't find even a custom signal, then just don't do anything and try - // keeping the binding as a regular property assignment. - continue; + // build cache if necessary + if (customSignals.isEmpty()) { + for (Signal *signal = obj->qmlSignals->first; signal; signal = signal->next) { + const QString &signalName = stringAt(signal->nameIndex); + customSignals.insert(signalName, signal->parameterStringList(parsedQML->jsGenerator.strings)); } + } - parameters = entry.value(); + QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName); + if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) { + QString alternateName = propertyName.mid(0, propertyName.length() - strlen("Changed")); + entry = customSignals.find(alternateName); } - QQmlJS::Engine &jsEngine = parsedQML->jsParserEngine; - QQmlJS::MemoryPool *pool = jsEngine.pool(); + if (entry == customSignals.constEnd()) { + // Can't find even a custom signal, then just don't do anything and try + // keeping the binding as a regular property assignment. + continue; + } - AST::FormalParameterList *paramList = 0; - foreach (const QString ¶m, parameters) { - QStringRef paramNameRef = jsEngine.newStringRef(param); + parameters = entry.value(); + } - if (paramList) - paramList = new (pool) AST::FormalParameterList(paramList, paramNameRef); - else - paramList = new (pool) AST::FormalParameterList(paramNameRef); - } + QQmlJS::Engine &jsEngine = parsedQML->jsParserEngine; + QQmlJS::MemoryPool *pool = jsEngine.pool(); + + AST::FormalParameterList *paramList = 0; + foreach (const QString ¶m, parameters) { + QStringRef paramNameRef = jsEngine.newStringRef(param); if (paramList) - paramList = paramList->finish(); + paramList = new (pool) AST::FormalParameterList(paramList, paramNameRef); + else + paramList = new (pool) AST::FormalParameterList(paramNameRef); + } - AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex]); - AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement); - AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement); - elements = elements->finish(); + if (paramList) + paramList = paramList->finish(); - AST::FunctionBody *body = new (pool) AST::FunctionBody(elements); + AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex]); + AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement); + AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement); + elements = elements->finish(); - AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine.newStringRef(propertyName), paramList, body); + AST::FunctionBody *body = new (pool) AST::FunctionBody(elements); - parsedQML->functions[binding->value.compiledScriptIndex] = functionDeclaration; - binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression; - binding->propertyNameIndex = parsedQML->jsGenerator.registerString(propertyName); - } + AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine.newStringRef(propertyName), paramList, body); + + parsedQML->functions[binding->value.compiledScriptIndex] = functionDeclaration; + binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression; + binding->propertyNameIndex = parsedQML->jsGenerator.registerString(propertyName); } return true; } |