aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-01 09:04:50 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-08 10:04:38 +0100
commit4a2f09f14a4b79006e661b6d98c03909c4ba9db1 (patch)
treec5397277abe70e03849f17f54d834e7983697ff0
parent4a662c21e669e964f9c3b835a91a38c9decf4ad4 (diff)
[new compiler] Initial support for custom parsers
Enough to support the Connections {} element. What's missing are pre-compiled bindings signal handlers. Change-Id: I3ad1413fa636434d899ae8fb380249aaf40363dc Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp5
-rw-r--r--src/qml/qml/qqmlcompiler_p.h2
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp23
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp49
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h4
-rw-r--r--src/qml/qml/qqmltypeloader.cpp3
-rw-r--r--src/qml/types/qqmlconnections.cpp38
-rw-r--r--src/qml/types/qqmlconnections_p.h1
9 files changed, 117 insertions, 10 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 9d8f16da8e..19ccb6d0fd 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -1620,7 +1620,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
QString elementName = stringAt(obj->inheritedTypeNameIndex);
if (elementName.isEmpty())
continue;
- QQmlPropertyCache *cache = unit->resolvedTypes[obj->inheritedTypeNameIndex].createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ QQmlCompiledData::TypeReference &tr = unit->resolvedTypes[obj->inheritedTypeNameIndex];
+ if (tr.type && tr.type->customParser())
+ continue;
+ QQmlPropertyCache *cache = tr.createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
return false;
}
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 516f6653ca..d410d396e3 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -157,6 +157,8 @@ public:
// 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;
+ // hash key is object index
+ QHash<int, QByteArray> customParserData;
QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 19e49009ce..0cc62fb988 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -230,6 +230,13 @@ void QQmlCustomParser::clearErrors()
exceptions.clear();
}
+QByteArray QQmlCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+{
+ Q_UNUSED(qmlUnit)
+ Q_UNUSED(bindings)
+ return QByteArray();
+}
+
/*!
Reports an error with the given \a description.
@@ -256,7 +263,6 @@ void QQmlCustomParser::error(const QString& description)
void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString& description)
{
QQmlError error;
- QString exceptionDescription;
error.setLine(prop.location().line);
error.setColumn(prop.location().column);
error.setDescription(description);
@@ -271,7 +277,6 @@ void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString
void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& description)
{
QQmlError error;
- QString exceptionDescription;
error.setLine(node.location().line);
error.setColumn(node.location().column);
error.setDescription(description);
@@ -279,6 +284,20 @@ void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& de
}
/*!
+ Reports an error in parsing \a binding, with the given \a description.
+
+ An error is generated referring to the position of \a node in the source file.
+*/
+void QQmlCustomParser::error(const QV4::CompiledData::Binding *binding, const QString &description)
+{
+ QQmlError error;
+ error.setLine(binding->location.line);
+ error.setColumn(binding->location.column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
If \a script is a simple enumeration expression (eg. Text.AlignLeft),
returns the integer equivalent (eg. 1), and sets \a ok to true.
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 27f7e00b31..3004b0f50c 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -126,6 +126,7 @@ public:
Flags flags() const { return m_flags; }
virtual QByteArray compile(const QList<QQmlCustomParserProperty> &)=0;
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); // ### make pure virtual
virtual void setCustomData(QObject *, const QByteArray &)=0;
QList<QQmlError> errors() const { return exceptions; }
@@ -134,6 +135,7 @@ protected:
void error(const QString& description);
void error(const QQmlCustomParserProperty&, const QString& description);
void error(const QQmlCustomParserNode&, const QString& description);
+ void error(const QV4::CompiledData::Binding *binding, const QString& description);
int evaluateEnum(const QByteArray&, bool *ok) const;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 822708a73e..abf978801d 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,6 +55,7 @@
#include <QQmlComponent>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlcodegenerator_p.h>
+#include <private/qqmlcustomparser_p.h>
QT_USE_NAMESPACE
@@ -1237,6 +1238,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
bool isComponent = false;
QObject *instance = 0;
+ QQmlCustomParser *customParser = 0;
if (compiledData->isComponent(index)) {
isComponent = true;
@@ -1254,6 +1256,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
+
const int parserStatusCast = type->parserStatusCast();
if (parserStatusCast != -1) {
QQmlParserStatus *parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
@@ -1261,6 +1264,8 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
_parserStatusCallbacks[index] = parserStatus;
parserStatus->d = &_parserStatusCallbacks[index];
}
+
+ customParser = type->customParser();
} else {
Q_ASSERT(typeRef.component);
if (typeRef.component->qmlUnit->isSingleton())
@@ -1305,6 +1310,11 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
if (idEntry != objectIndexToId.constEnd())
context->setIdProperty(idEntry.value(), instance);
+ if (customParser) {
+ QByteArray data = compiledData->customParserData.value(index);
+ customParser->setCustomData(instance, data);
+ }
+
if (!isComponent) {
QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
Q_ASSERT(!cache.isNull());
@@ -1727,11 +1737,13 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
QQmlPropertyValidator::QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
- const QList<QQmlPropertyCache *> &propertyCaches, const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent)
+ const QList<QQmlPropertyCache *> &propertyCaches, const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent,
+ QHash<int, QByteArray> *customParserData)
: QQmlCompilePass(url, qmlUnit)
, resolvedTypes(resolvedTypes)
, propertyCaches(propertyCaches)
, objectIndexToIdPerComponent(objectIndexToIdPerComponent)
+ , customParserData(customParserData)
{
}
@@ -1756,6 +1768,12 @@ bool QQmlPropertyValidator::validate()
bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache)
{
+ QQmlCustomParser *customParser = 0;
+ QQmlCompiledData::TypeReference objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ if (objectType.type)
+ customParser = objectType.type->customParser();
+ QList<const QV4::CompiledData::Binding*> customBindings;
+
PropertyResolver propertyResolver(propertyCache);
QQmlPropertyData *defaultProperty = propertyCache->defaultProperty();
@@ -1763,8 +1781,11 @@ bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj,
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
- || binding->type == QV4::CompiledData::Binding::Type_GroupProperty)
+ || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ if (customParser)
+ customBindings << binding;
continue;
+ }
const QString name = stringAt(binding->propertyNameIndex);
@@ -1777,9 +1798,8 @@ bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj,
if (notInRevision) {
QString typeName = stringAt(obj->inheritedTypeNameIndex);
- QQmlCompiledData::TypeReference type = resolvedTypes.value(objectIndex);
- if (type.type) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
+ if (objectType.type) {
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType.type->module()).arg(objectType.majorVersion).arg(objectType.minorVersion));
} else {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
}
@@ -1790,6 +1810,10 @@ bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj,
}
if (!pd) {
+ if (customParser) {
+ customBindings << binding;
+ continue;
+ }
if (bindingToDefaultProperty) {
COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
} else {
@@ -1798,5 +1822,20 @@ bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj,
}
}
+ if (customParser && !customBindings.isEmpty()) {
+ customParser->clearErrors();
+ QByteArray data = customParser->compile(qmlUnit, customBindings);
+ customParserData->insert(objectIndex, data);
+ const QList<QQmlError> parserErrors = customParser->errors();
+ if (!parserErrors.isEmpty()) {
+ foreach (QQmlError error, parserErrors) {
+ error.setUrl(url);
+ errors << error;
+ }
+ return false;
+ }
+ }
+
return true;
}
+
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 229a7de198..e33e47edcc 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -122,7 +122,8 @@ public:
QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
const QList<QQmlPropertyCache *> &propertyCaches,
- const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent);
+ const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent,
+ QHash<int, QByteArray> *customParserData);
bool validate();
@@ -134,6 +135,7 @@ private:
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes;
const QList<QQmlPropertyCache *> &propertyCaches;
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
+ QHash<int, QByteArray> *customParserData;
};
class QmlObjectCreator : public QQmlCompilePass
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 60fa00a5c9..1a4c8f015d 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2466,7 +2466,8 @@ void QQmlTypeData::compile()
// Sanity check property bindings
if (errors.isEmpty()) {
QQmlPropertyValidator validator(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes,
- m_compiledData->propertyCaches, m_compiledData->objectIndexToIdPerComponent);
+ m_compiledData->propertyCaches, m_compiledData->objectIndexToIdPerComponent,
+ &m_compiledData->customParserData);
if (!validator.validate())
errors << validator.errors;
}
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 5e6a1a084a..b8920deb21 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -251,6 +251,44 @@ QQmlConnectionsParser::compile(const QList<QQmlCustomParserProperty> &props)
return rv;
}
+QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+{
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ for (int ii = 0; ii < props.count(); ++ii) {
+ const QV4::CompiledData::Binding *binding = props.at(ii);
+ QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
+ int propLine = binding->location.line;
+ int propColumn = binding->location.column;
+
+ if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
+ error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
+ return QByteArray();
+ }
+
+
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
+ if (!qmlUnit->header.stringAt(target->inheritedTypeNameIndex).isEmpty())
+ error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
+ else
+ error(binding, QQmlConnections::tr("Connections: syntax error"));
+ return QByteArray();
+ } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
+ error(binding, QQmlConnections::tr("Connections: script expected"));
+ return QByteArray();
+ } else {
+ ds << propName;
+ ds << binding->valueAsString(&qmlUnit->header);
+ ds << propLine;
+ ds << propColumn;
+ }
+ }
+
+ return rv;
+}
+
void QQmlConnectionsParser::setCustomData(QObject *object,
const QByteArray &data)
{
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index 9bc668e5f4..2579e4c239 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -85,6 +85,7 @@ class QQmlConnectionsParser : public QQmlCustomParser
{
public:
virtual QByteArray compile(const QList<QQmlCustomParserProperty> &);
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
virtual void setCustomData(QObject *, const QByteArray &);
};