X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdeclarative%2Fqml%2Fqdeclarativecompiler.cpp;h=6c018c78417c1a49824f0a7ce2ee411a8eb53dfc;hb=45b14259fc0cf704692df1c00da511527d1fba1d;hp=581a538b4b6d5f925c45da45206158bc8b3f4eb4;hpb=9cb3889b33a4a92db40a3a72c3ee4fa25770d539;p=profile%2Fivi%2Fqtdeclarative.git diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 581a538..6c018c7 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -1,8 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** @@ -35,35 +34,34 @@ ** ** ** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "private/qdeclarativecompiler_p.h" +#include "qdeclarativecompiler_p.h" -#include "private/qdeclarativeparser_p.h" -#include "private/qdeclarativescriptparser_p.h" #include "qdeclarativepropertyvaluesource.h" #include "qdeclarativecomponent.h" -#include "private/qmetaobjectbuilder_p.h" -#include "private/qdeclarativestringconverters_p.h" -#include "private/qdeclarativeengine_p.h" +#include +#include +#include "qdeclarativestringconverters_p.h" +#include "qdeclarativeengine_p.h" #include "qdeclarativeengine.h" #include "qdeclarativecontext.h" -#include "private/qdeclarativemetatype_p.h" -#include "private/qdeclarativecustomparser_p_p.h" -#include "private/qdeclarativecontext_p.h" -#include "private/qdeclarativecomponent_p.h" -#include "parser/qdeclarativejsast_p.h" -#include "private/qdeclarativevmemetaobject_p.h" -#include "private/qdeclarativeexpression_p.h" -#include "private/qdeclarativeproperty_p.h" -#include "private/qdeclarativerewrite_p.h" +#include "qdeclarativemetatype_p.h" +#include "qdeclarativecustomparser_p_p.h" +#include "qdeclarativecontext_p.h" +#include "qdeclarativecomponent_p.h" +#include +#include "qdeclarativevmemetaobject_p.h" +#include "qdeclarativeexpression_p.h" +#include "qdeclarativeproperty_p.h" +#include "qdeclarativerewrite_p.h" #include "qdeclarativescriptstring.h" -#include "private/qdeclarativeglobal_p.h" -#include "private/qdeclarativescriptparser_p.h" -#include "private/qdeclarativebinding_p.h" -#include "private/qdeclarativev4compiler_p.h" +#include "qdeclarativeglobal_p.h" +#include "qdeclarativebinding_p.h" +#include #include #include @@ -74,19 +72,38 @@ #include #include +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) + QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS); -using namespace QDeclarativeParser; +using namespace QDeclarativeJS; +using namespace QDeclarativeScript; +using namespace QDeclarativeCompilerTypes; + +static QString id_string(QLatin1String("id")); +static QString on_string(QLatin1String("on")); +static QString Changed_string(QLatin1String("Changed")); +static QString Component_string(QLatin1String("Component")); +static QString Component_import_string(QLatin1String("QML/Component")); +static QString qsTr_string(QLatin1String("qsTr")); +static QString qsTrId_string(QLatin1String("qsTrId")); /*! Instantiate a new QDeclarativeCompiler. */ -QDeclarativeCompiler::QDeclarativeCompiler() -: output(0), engine(0), unitRoot(0), unit(0) +QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool) +: pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1), + cachedTranslationContextIndex(-1), componentStats(0) { + if (compilerStatDump()) + componentStats = pool->New(); } /*! @@ -113,9 +130,14 @@ QList QDeclarativeCompiler::errors() const Attached property names are those that start with a capital letter. */ -bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name) +bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name) { - return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; + return isAttachedPropertyName(QHashedStringRef(&name)); +} + +bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &name) +{ + return !name.isEmpty() && name.at(0).isUpper(); } /*! @@ -129,15 +151,20 @@ bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name) character codes in property names, for simplicity and performance reasons QML only supports letters, numbers and underscores. */ -bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name) +bool QDeclarativeCompiler::isSignalPropertyName(const QString &name) +{ + return isSignalPropertyName(QStringRef(&name)); +} + +bool QDeclarativeCompiler::isSignalPropertyName(const QHashedStringRef &name) { if (name.length() < 3) return false; - if (!name.startsWith("on")) return false; - int ns = name.size(); + if (!name.startsWith(on_string)) return false; + int ns = name.length(); for (int i = 2; i < ns; ++i) { - char curr = name.at(i); - if (curr == '_') continue; - if (curr >= 'A' && curr <= 'Z') return true; + const QChar curr = name.at(i); + if (curr.unicode() == '_') continue; + if (curr.isUpper()) return true; return false; } return false; // consists solely of underscores - invalid. @@ -155,21 +182,23 @@ bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name) For example: \code - COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name))); + COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name)); \endcode */ -#define COMPILE_EXCEPTION(token, desc) \ +#define COMPILE_EXCEPTION_LOCATION(line, column, desc) \ { \ - QString exceptionDescription; \ QDeclarativeError error; \ error.setUrl(output->url); \ - error.setLine((token)->location.start.line); \ - error.setColumn((token)->location.start.column); \ + error.setLine(line); \ + error.setColumn(column); \ error.setDescription(desc.trimmed()); \ exceptions << error; \ return false; \ } +#define COMPILE_EXCEPTION(token, desc) \ + COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc) + /*! \macro COMPILE_CHECK \internal @@ -187,37 +216,50 @@ bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name) This test corresponds to action taken by genLiteralAssignment(). Any change made here, must have a corresponding action in genLiteralAssigment(). */ -bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, - QDeclarativeParser::Value *v) +bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Value *v) { - QString string = v->value.asString(); + const QDeclarativeScript::Variant &value = v->value; - if (!prop.isWritable()) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); - if (prop.isEnumType()) { - int value; - if (prop.isFlagType()) { - value = prop.enumerator().keysToValue(string.toUtf8().constData()); + if (prop->core.isEnum()) { + QMetaProperty p = prop->parent->metaObject()->property(prop->index); + int enumValue; + bool ok; + if (p.isFlagType()) { + enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok); } else - value = prop.enumerator().keyToValue(string.toUtf8().constData()); - if (value == -1) + enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok); + + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration")); + + v->value = QDeclarativeScript::Variant((double)enumValue); return true; } - int type = prop.userType(); + + int type = prop->type; + switch(type) { - case -1: + case QMetaType::QVariant: break; case QVariant::String: if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected")); break; + case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment. + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected")); + break; case QVariant::ByteArray: if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected")); break; case QVariant::Url: if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected")); break; + case QVariant::RegExp: + COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); + break; case QVariant::UInt: { bool ok = v->value.isNumber(); @@ -249,7 +291,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::Color: { bool ok; - QDeclarativeStringConverters::colorFromString(string, &ok); + QDeclarativeStringConverters::colorFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected")); } break; @@ -257,21 +299,21 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::Date: { bool ok; - QDeclarativeStringConverters::dateFromString(string, &ok); + QDeclarativeStringConverters::dateFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected")); } break; case QVariant::Time: { bool ok; - QDeclarativeStringConverters::timeFromString(string, &ok); + QDeclarativeStringConverters::timeFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected")); } break; case QVariant::DateTime: { bool ok; - QDeclarativeStringConverters::dateTimeFromString(string, &ok); + QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected")); } break; @@ -280,7 +322,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::PointF: { bool ok; - QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok); + QDeclarativeStringConverters::pointFFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected")); } break; @@ -288,7 +330,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::SizeF: { bool ok; - QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok); + QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected")); } break; @@ -296,7 +338,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::RectF: { bool ok; - QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok); + QDeclarativeStringConverters::rectFFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected")); } break; @@ -308,261 +350,409 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::Vector3D: { bool ok; - QDeclarativeStringConverters::vector3DFromString(string, &ok); + QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected")); } break; + case QVariant::Vector4D: + { + bool ok; + QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected")); + } + break; default: { - int t = prop.userType(); - QDeclarativeMetaType::StringConverter converter = - QDeclarativeMetaType::customStringConverter(t); + // check if assigning a literal value to a list property. + // in each case, check the singular, since an Array of the specified type + // will not go via this literal assignment codepath. + if (type == qMetaTypeId >()) { + if (!v->value.isNumber()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected")); + } + break; + } else if (type == qMetaTypeId >()) { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(int(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected")); + break; + } else if (type == qMetaTypeId >()) { + if (!v->value.isBoolean()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected")); + } + break; + } else if (type == qMetaTypeId >()) { // we expect a string literal. A string list is not a literal assignment. + if (!v->value.isString()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected")); + } + break; + } else if (type == qMetaTypeId >()) { + if (!v->value.isString()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected")); + } + break; + } + + // otherwise, check for existence of string converter to custom type + QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type); if (!converter) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type())))); + COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type)))); } break; } return true; } +static QUrl urlFromUserString(const QString &data) +{ + QUrl u; + // Preserve any valid percent-encoded octets supplied by the source + u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode); + return u; +} + /*! 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 QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop, - QDeclarativeParser::Value *v) -{ - QDeclarativeInstruction instr; - if (prop.isEnumType()) { - int value; - if (v->value.isNumber()) { - // Preresolved enum - value = (int)v->value.asNumber(); - } else { - // Must be a string - if (prop.isFlagType()) { - value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData()); - } else - value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData()); - } - - instr.setType(QDeclarativeInstruction::StoreInteger); - instr.storeInteger.propertyIndex = prop.propertyIndex(); - instr.storeInteger.value = value; +void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Value *v) +{ + if (prop->core.isEnum()) { + Q_ASSERT(v->value.isNumber()); + // Preresolved value + int value = (int)v->value.asNumber(); + + Instruction::StoreInteger instr; + instr.propertyIndex = prop->index; + instr.value = value; output->addInstruction(instr); return; } - QString string = v->value.asString(); - - int type = prop.userType(); + int type = prop->type; switch(type) { - case -1: + case QMetaType::QVariant: { if (v->value.isNumber()) { double n = v->value.asNumber(); if (double(int(n)) == n) { - instr.setType(QDeclarativeInstruction::StoreVariantInteger); - instr.storeInteger.propertyIndex = prop.propertyIndex(); - instr.storeInteger.value = int(n); + if (prop->core.isVMEProperty()) { + Instruction::StoreVarInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(n); + output->addInstruction(instr); + } else { + Instruction::StoreVariantInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(n); + output->addInstruction(instr); + } + } else { + if (prop->core.isVMEProperty()) { + Instruction::StoreVarDouble instr; + instr.propertyIndex = prop->index; + instr.value = n; + output->addInstruction(instr); + } else { + Instruction::StoreVariantDouble instr; + instr.propertyIndex = prop->index; + instr.value = n; + output->addInstruction(instr); + } + } + } else if (v->value.isBoolean()) { + if (prop->core.isVMEProperty()) { + Instruction::StoreVarBool instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asBoolean(); + output->addInstruction(instr); } else { - instr.setType(QDeclarativeInstruction::StoreVariantDouble); - instr.storeDouble.propertyIndex = prop.propertyIndex(); - instr.storeDouble.value = n; + Instruction::StoreVariantBool instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asBoolean(); + output->addInstruction(instr); } - } else if(v->value.isBoolean()) { - instr.setType(QDeclarativeInstruction::StoreVariantBool); - instr.storeBool.propertyIndex = prop.propertyIndex(); - instr.storeBool.value = v->value.asBoolean(); } else { - instr.setType(QDeclarativeInstruction::StoreVariant); - instr.storeString.propertyIndex = prop.propertyIndex(); - instr.storeString.value = output->indexForString(string); + if (prop->core.isVMEProperty()) { + Instruction::StoreVar instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } else { + Instruction::StoreVariant instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } } } break; case QVariant::String: { - instr.setType(QDeclarativeInstruction::StoreString); - instr.storeString.propertyIndex = prop.propertyIndex(); - instr.storeString.value = output->indexForString(string); + Instruction::StoreString instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } + break; + case QVariant::StringList: + { + Instruction::StoreStringList instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); } break; case QVariant::ByteArray: { - instr.setType(QDeclarativeInstruction::StoreByteArray); - instr.storeByteArray.propertyIndex = prop.propertyIndex(); - instr.storeByteArray.value = output->indexForByteArray(string.toLatin1()); + Instruction::StoreByteArray instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForByteArray(v->value.asString().toLatin1()); + output->addInstruction(instr); } break; case QVariant::Url: { - instr.setType(QDeclarativeInstruction::StoreUrl); - QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); - instr.storeUrl.propertyIndex = prop.propertyIndex(); - instr.storeUrl.value = output->indexForUrl(u); + Instruction::StoreUrl instr; + QString string = v->value.asString(); + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string)); + instr.propertyIndex = prop->index; + instr.value = output->indexForUrl(u); + output->addInstruction(instr); } break; case QVariant::UInt: { - instr.setType(QDeclarativeInstruction::StoreInteger); - instr.storeInteger.propertyIndex = prop.propertyIndex(); - instr.storeInteger.value = uint(v->value.asNumber()); + Instruction::StoreInteger instr; + instr.propertyIndex = prop->index; + instr.value = uint(v->value.asNumber()); + output->addInstruction(instr); } break; case QVariant::Int: { - instr.setType(QDeclarativeInstruction::StoreInteger); - instr.storeInteger.propertyIndex = prop.propertyIndex(); - instr.storeInteger.value = int(v->value.asNumber()); + Instruction::StoreInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(v->value.asNumber()); + output->addInstruction(instr); } break; case QMetaType::Float: { - instr.setType(QDeclarativeInstruction::StoreFloat); - instr.storeFloat.propertyIndex = prop.propertyIndex(); - instr.storeFloat.value = float(v->value.asNumber()); + Instruction::StoreFloat instr; + instr.propertyIndex = prop->index; + instr.value = float(v->value.asNumber()); + output->addInstruction(instr); } break; case QVariant::Double: { - instr.setType(QDeclarativeInstruction::StoreDouble); - instr.storeDouble.propertyIndex = prop.propertyIndex(); - instr.storeDouble.value = v->value.asNumber(); + Instruction::StoreDouble instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asNumber(); + output->addInstruction(instr); } break; case QVariant::Color: { - QColor c = QDeclarativeStringConverters::colorFromString(string); - instr.setType(QDeclarativeInstruction::StoreColor); - instr.storeColor.propertyIndex = prop.propertyIndex(); - instr.storeColor.value = c.rgba(); + Instruction::StoreColor instr; + QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString()); + instr.propertyIndex = prop->index; + instr.value = c.rgba(); + output->addInstruction(instr); } break; #ifndef QT_NO_DATESTRING case QVariant::Date: { - QDate d = QDeclarativeStringConverters::dateFromString(string); - instr.setType(QDeclarativeInstruction::StoreDate); - instr.storeDate.propertyIndex = prop.propertyIndex(); - instr.storeDate.value = d.toJulianDay(); + Instruction::StoreDate instr; + QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString()); + instr.propertyIndex = prop->index; + instr.value = d.toJulianDay(); + output->addInstruction(instr); } break; case QVariant::Time: { - QTime time = QDeclarativeStringConverters::timeFromString(string); - instr.setType(QDeclarativeInstruction::StoreTime); - instr.storeTime.propertyIndex = prop.propertyIndex(); - instr.storeTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time; + Instruction::StoreTime instr; + QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString()); + instr.propertyIndex = prop->index; + Q_ASSERT(sizeof(instr.time) == sizeof(QTime)); + ::memcpy(&instr.time, &time, sizeof(QTime)); + output->addInstruction(instr); } break; case QVariant::DateTime: { - QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string); + Instruction::StoreDateTime instr; + QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString()); QTime time = dateTime.time(); - instr.setType(QDeclarativeInstruction::StoreDateTime); - instr.storeDateTime.propertyIndex = prop.propertyIndex(); - instr.storeDateTime.date = dateTime.date().toJulianDay(); - instr.storeDateTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time; + instr.propertyIndex = prop->index; + instr.date = dateTime.date().toJulianDay(); + Q_ASSERT(sizeof(instr.time) == sizeof(QTime)); + ::memcpy(&instr.time, &time, sizeof(QTime)); + output->addInstruction(instr); } break; #endif // QT_NO_DATESTRING case QVariant::Point: { + Instruction::StorePoint instr; bool ok; - QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint(); - instr.setType(QDeclarativeInstruction::StorePoint); - instr.storePoint.propertyIndex = prop.propertyIndex(); - instr.storePoint.point.xp = point.x(); - instr.storePoint.point.yp = point.y(); + QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint(); + instr.propertyIndex = prop->index; + instr.point.xp = point.x(); + instr.point.yp = point.y(); + output->addInstruction(instr); } break; case QVariant::PointF: { + Instruction::StorePointF instr; bool ok; - QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok); - instr.setType(QDeclarativeInstruction::StorePointF); - instr.storePointF.propertyIndex = prop.propertyIndex(); - instr.storePointF.point.xp = point.x(); - instr.storePointF.point.yp = point.y(); + QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.point.xp = point.x(); + instr.point.yp = point.y(); + output->addInstruction(instr); } break; case QVariant::Size: { + Instruction::StoreSize instr; bool ok; - QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize(); - instr.setType(QDeclarativeInstruction::StoreSize); - instr.storeSize.propertyIndex = prop.propertyIndex(); - instr.storeSize.size.wd = size.width(); - instr.storeSize.size.ht = size.height(); + QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize(); + instr.propertyIndex = prop->index; + instr.size.wd = size.width(); + instr.size.ht = size.height(); + output->addInstruction(instr); } break; case QVariant::SizeF: { + Instruction::StoreSizeF instr; bool ok; - QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok); - instr.setType(QDeclarativeInstruction::StoreSizeF); - instr.storeSizeF.propertyIndex = prop.propertyIndex(); - instr.storeSizeF.size.wd = size.width(); - instr.storeSizeF.size.ht = size.height(); + QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.size.wd = size.width(); + instr.size.ht = size.height(); + output->addInstruction(instr); } break; case QVariant::Rect: { + Instruction::StoreRect instr; bool ok; - QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect(); - instr.setType(QDeclarativeInstruction::StoreRect); - instr.storeRect.propertyIndex = prop.propertyIndex(); - instr.storeRect.rect.x1 = rect.left(); - instr.storeRect.rect.y1 = rect.top(); - instr.storeRect.rect.x2 = rect.right(); - instr.storeRect.rect.y2 = rect.bottom(); + QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect(); + instr.propertyIndex = prop->index; + instr.rect.x1 = rect.left(); + instr.rect.y1 = rect.top(); + instr.rect.x2 = rect.right(); + instr.rect.y2 = rect.bottom(); + output->addInstruction(instr); } break; case QVariant::RectF: { + Instruction::StoreRectF instr; bool ok; - QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok); - instr.setType(QDeclarativeInstruction::StoreRectF); - instr.storeRectF.propertyIndex = prop.propertyIndex(); - instr.storeRectF.rect.xp = rect.left(); - instr.storeRectF.rect.yp = rect.top(); - instr.storeRectF.rect.w = rect.width(); - instr.storeRectF.rect.h = rect.height(); + QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.rect.xp = rect.left(); + instr.rect.yp = rect.top(); + instr.rect.w = rect.width(); + instr.rect.h = rect.height(); + output->addInstruction(instr); } break; case QVariant::Bool: { + Instruction::StoreBool instr; bool b = v->value.asBoolean(); - instr.setType(QDeclarativeInstruction::StoreBool); - instr.storeBool.propertyIndex = prop.propertyIndex(); - instr.storeBool.value = b; + instr.propertyIndex = prop->index; + instr.value = b; + output->addInstruction(instr); } break; case QVariant::Vector3D: { + Instruction::StoreVector3D instr; + bool ok; + QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.vector.xp = vector.x(); + instr.vector.yp = vector.y(); + instr.vector.zp = vector.z(); + output->addInstruction(instr); + } + break; + case QVariant::Vector4D: + { + Instruction::StoreVector4D instr; bool ok; - QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok); - instr.setType(QDeclarativeInstruction::StoreVector3D); - instr.storeVector3D.propertyIndex = prop.propertyIndex(); - instr.storeVector3D.vector.xp = vector.x(); - instr.storeVector3D.vector.yp = vector.y(); - instr.storeVector3D.vector.zp = vector.z(); + QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok); + instr.propertyIndex = prop->index; + instr.vector.xp = vector.x(); + instr.vector.yp = vector.y(); + instr.vector.zp = vector.z(); + instr.vector.wp = vector.w(); + output->addInstruction(instr); } break; default: { - int t = prop.userType(); - instr.setType(QDeclarativeInstruction::AssignCustomType); - instr.assignCustomType.propertyIndex = prop.propertyIndex(); - instr.assignCustomType.primitive = output->indexForString(string); - instr.assignCustomType.type = t; + // generate single literal value assignment to a list property if required + if (type == qMetaTypeId >()) { + Instruction::StoreDoubleQList instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asNumber(); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreIntegerQList instr; + instr.propertyIndex = prop->index; + instr.value = int(v->value.asNumber()); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreBoolQList instr; + bool b = v->value.asBoolean(); + instr.propertyIndex = prop->index; + instr.value = b; + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreUrlQList instr; + QString string = v->value.asString(); + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string)); + instr.propertyIndex = prop->index; + instr.value = output->indexForUrl(u); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreStringQList instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + break; + } + + // otherwise, generate custom type literal assignment + Instruction::AssignCustomType instr; + instr.propertyIndex = prop->index; + instr.primitive = output->indexForString(v->value.asString()); + instr.type = type; + output->addInstruction(instr); } break; } - output->addInstruction(instr); } /*! @@ -573,7 +763,7 @@ void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data) data->types.clear(); data->primitives.clear(); data->datas.clear(); - data->bytecode.clear(); + data->bytecode.resize(0); } /*! @@ -596,17 +786,24 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, Q_ASSERT(out); reset(out); - output = out; + QDeclarativeScript::Object *root = unit->parser().tree(); + Q_ASSERT(root); + + this->engine = engine; + this->enginePrivate = QDeclarativeEnginePrivate::get(engine); + this->unit = unit; + this->unitRoot = root; + this->output = out; // Compile types const QList &resolvedTypes = unit->resolvedTypes(); - QList referencedTypes = unit->parser().referencedTypes(); + QList referencedTypes = unit->parser().referencedTypes(); for (int ii = 0; ii < resolvedTypes.count(); ++ii) { QDeclarativeCompiledData::TypeReference ref; const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii); - QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii); + QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii); if (tref.type) { ref.type = tref.type; @@ -619,112 +816,115 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, if (ref.type->containsRevisionedAttributes()) { QDeclarativeError cacheError; - ref.typePropertyCache = - QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError); - - if (!ref.typePropertyCache) { + ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion, + cacheError); + if (!ref.typePropertyCache) COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description()); - } ref.typePropertyCache->addref(); } } else if (tref.typeData) { ref.component = tref.typeData->compiledData(); } - ref.className = parserRef->name.toUtf8(); + ref.className = parserRef->name; out->types << ref; } - QDeclarativeParser::Object *root = unit->parser().tree(); - Q_ASSERT(root); - - this->engine = engine; - this->enginePrivate = QDeclarativeEnginePrivate::get(engine); - this->unit = unit; - this->unitRoot = root; compileTree(root); if (!isError()) { if (compilerDump()) out->dumpInstructions(); - if (compilerStatDump()) + if (componentStats) dumpStats(); Q_ASSERT(out->rootPropertyCache); } else { reset(out); } - compileState = ComponentCompileState(); - savedCompileStates.clear(); + compileState = 0; output = 0; this->engine = 0; this->enginePrivate = 0; this->unit = 0; + this->cachedComponentTypeRef = -1; + this->cachedTranslationContextIndex = -1; this->unitRoot = 0; return !isError(); } -void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree) +void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree) { - compileState.root = tree; - componentStat.lineNumber = tree->location.start.line; + compileState = pool->New(); + + compileState->root = tree; + if (componentStats) + componentStats->componentStat.lineNumber = tree->location.start.line; - // Build global import scripts - QStringList importedScriptIndexes; + // We generate the importCache before we build the tree so that + // it can be used in the binding compiler. Given we "expect" the + // QML compilation to succeed, this isn't a waste. + output->importCache = new QDeclarativeTypeNameCache(); + foreach (const QString &ns, unit->namespaces()) { + output->importCache->add(ns); + } + int scriptIndex = 0; foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) { - importedScriptIndexes.append(script.qualifier); + QString qualifier = script.qualifier; + QString enclosingNamespace; - QDeclarativeInstruction import; - import.setType(QDeclarativeInstruction::StoreImportedScript); - import.storeScript.value = output->scripts.count(); + const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); + if (lastDotIndex != -1) { + enclosingNamespace = qualifier.left(lastDotIndex); + qualifier = qualifier.mid(lastDotIndex+1); + } - QDeclarativeScriptData *scriptData = script.script->scriptData(); - scriptData->addref(); - output->scripts << scriptData; - output->addInstruction(import); + output->importCache->add(qualifier, scriptIndex++, enclosingNamespace); } - // We generate the importCache before we build the tree so that - // it can be used in the binding compiler. Given we "expect" the - // QML compilation to succeed, this isn't a waste. - output->importCache = new QDeclarativeTypeNameCache(engine); - for (int ii = 0; ii < importedScriptIndexes.count(); ++ii) - output->importCache->add(importedScriptIndexes.at(ii), ii); unit->imports().populateCache(output->importCache, engine); if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) return; - QDeclarativeInstruction init; - init.setType(QDeclarativeInstruction::Init); - init.init.bindingsSize = compileState.bindings.count(); - init.init.parserStatusSize = compileState.parserStatusCount; - init.init.contextCache = genContextCache(); - if (compileState.compiledBindingData.isEmpty()) - init.init.compiledBinding = -1; + Instruction::Init init; + init.bindingsSize = compileState->totalBindingsCount; + init.parserStatusSize = compileState->parserStatusCount; + init.contextCache = genContextCache(); + init.objectStackSize = compileState->objectDepth.maxDepth(); + init.listStackSize = compileState->listDepth.maxDepth(); + if (compileState->compiledBindingData.isEmpty()) + init.compiledBinding = -1; else - init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); + init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData); output->addInstruction(init); - if (!compileState.v8BindingProgram.isEmpty()) { - QDeclarativeInstruction bindings; - bindings.setType(QDeclarativeInstruction::InitV8Bindings); - bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram); - bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex; - bindings.initV8Bindings.line = compileState.v8BindingProgramLine; + foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) { + Instruction::StoreImportedScript import; + import.value = output->scripts.count(); + + QDeclarativeScriptData *scriptData = script.script->scriptData(); + scriptData->addref(); + output->scripts << scriptData; + output->addInstruction(import); + } + + if (!compileState->v8BindingProgram.isEmpty()) { + Instruction::InitV8Bindings bindings; + bindings.program = output->indexForString(compileState->v8BindingProgram); + bindings.programIndex = compileState->v8BindingProgramIndex; + bindings.line = compileState->v8BindingProgramLine; output->addInstruction(bindings); } genObject(tree); - QDeclarativeInstruction def; - def.setType(QDeclarativeInstruction::SetDefault); + Instruction::SetDefault def; output->addInstruction(def); - QDeclarativeInstruction done; - done.setType(QDeclarativeInstruction::Done); + Instruction::Done done; output->addInstruction(done); Q_ASSERT(tree->metatype); @@ -739,25 +939,26 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree) enginePrivate->registerCompositeType(output); } -static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2) +static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string) { - return t1->location.start.line < t2->location.start.line || - (t1->location.start.line == t2->location.start.line && - t1->location.start.column < t2->location.start.column); + for (int ii = 0; ii < list.count(); ++ii) + if (string == list.at(ii)) + return true; + + return false; } -bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt) +bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt) { - componentStat.objects++; + if (componentStats) + componentStats->componentStat.objects++; Q_ASSERT (obj->type != -1); - const QDeclarativeCompiledData::TypeReference &tr = - output->types.at(obj->type); + const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type); obj->metatype = tr.metaObject(); - if (tr.type) + if (tr.type) obj->typeName = tr.type->qmlTypeName(); - obj->className = tr.className; // This object is a "Component" element if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { @@ -765,6 +966,20 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi return true; } + if (tr.component) { + typedef QDeclarativeInstruction I; + const I *init = ((const I *)tr.component->bytecode.constData()); + Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init); + + // Adjust stack depths to include nested components + compileState->objectDepth.pushPop(init->init.objectStackSize); + compileState->listDepth.pushPop(init->init.listStackSize); + compileState->parserStatusCount += init->init.parserStatusSize; + compileState->totalBindingsCount += init->init.bindingsSize; + } + + compileState->objectDepth.push(); + // Object instantiations reset the binding context BindingContext objCtxt(obj); @@ -778,7 +993,7 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi Q_ASSERT(type); obj->parserStatusCast = type->parserStatusCast(); if (obj->parserStatusCast != -1) - compileState.parserStatusCount++; + compileState->parserStatusCount++; // Check if this is a custom parser type. Custom parser types allow // assignments to non-existent properties. These assignments are then @@ -793,8 +1008,8 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi // Must do id property first. This is to ensure that the id given to any // id reference created matches the order in which the objects are // instantiated - foreach(Property *prop, obj->properties) { - if (prop->name == "id") { + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + if (prop->name() == id_string) { COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); break; } @@ -804,34 +1019,75 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi Property *defaultProperty = 0; Property *skipProperty = 0; if (obj->defaultProperty) { - const QMetaObject *metaObject = obj->metaObject(); - Q_ASSERT(metaObject); - QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject); - if (p.name()) { - Property *explicitProperty = obj->getProperty(p.name(), false); - if (explicitProperty && !explicitProperty->value) { - skipProperty = explicitProperty; - - defaultProperty = new Property; - defaultProperty->parent = obj; - defaultProperty->isDefault = true; - defaultProperty->location = obj->defaultProperty->location; - defaultProperty->listValueRange = obj->defaultProperty->listValueRange; - - defaultProperty->values = obj->defaultProperty->values; - defaultProperty->values += explicitProperty->values; - foreach(QDeclarativeParser::Value *value, defaultProperty->values) - value->addref(); - qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan); + defaultProperty = obj->defaultProperty; + + Property *explicitProperty = 0; + + const QMetaObject *mo = obj->metatype; + int idx = mo->indexOfClassInfo("DefaultProperty"); + if (idx != -1) { + QMetaClassInfo info = mo->classInfo(idx); + const char *p = info.value(); + if (p) { + int plen = 0; + char ord = 0; + while (char c = p[plen++]) { ord |= c; }; + --plen; + + if (ord & 0x80) { + // Utf8 - unoptimal, but seldom hit + QString *s = pool->NewString(QString::fromUtf8(p, plen)); + QHashedStringRef r(*s); + + if (obj->propertiesHashField.test(r.hash())) { + for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { + if (ep->name() == r) { + explicitProperty = ep; + break; + } + } + } + + if (!explicitProperty) + defaultProperty->setName(r); - } else { - defaultProperty = obj->defaultProperty; - defaultProperty->addref(); + } else { + QHashedCStringRef r(p, plen); + + if (obj->propertiesHashField.test(r.hash())) { + for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { + if (ep->name() == r) { + explicitProperty = ep; + break; + } + } + } + + if (!explicitProperty) { + // Set the default property name + QChar *buffer = pool->NewRawArray(r.length()); + r.writeUtf16(buffer); + defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash())); + } + } } - } else { - defaultProperty = obj->defaultProperty; - defaultProperty->addref(); } + + if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) { + + skipProperty = explicitProperty; // We merge the values into defaultProperty + + // Find the correct insertion point + Value *insertPos = 0; + + for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) { + if (!(v->location.start < explicitProperty->values.first()->location.start)) + break; + insertPos = v; + } + + defaultProperty->values.insertAfter(insertPos, explicitProperty->values); + } } QDeclarativeCustomParser *cp = 0; @@ -839,36 +1095,38 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi cp = output->types.at(obj->type).type->customParser(); // Build all explicit properties specified - foreach(Property *prop, obj->properties) { + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { if (prop == skipProperty) continue; - if (prop->name == "id") + if (prop->name() == id_string) continue; bool canDefer = false; if (isCustomParser) { - if (doesPropertyExist(prop, obj) && + if (doesPropertyExist(prop, obj) && (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) || - !isAttachedPropertyName(prop->name))) { - int ids = compileState.ids.count(); + !isAttachedPropertyName(prop->name()))) { + int ids = compileState->ids.count(); COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState.ids.count(); + canDefer = ids == compileState->ids.count(); + } else if (isSignalPropertyName(prop->name()) && + (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); } else { customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop); } } else { - if (isSignalPropertyName(prop->name)) { + if (isSignalPropertyName(prop->name())) { COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); } else { - int ids = compileState.ids.count(); + int ids = compileState->ids.count(); COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState.ids.count(); + canDefer = ids == compileState->ids.count(); } } - if (canDefer && !deferredList.isEmpty() && - deferredList.contains(QString::fromUtf8(prop->name))) + if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name())) prop->isDeferred = true; } @@ -880,26 +1138,22 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi bool canDefer = false; if (isCustomParser) { if (doesPropertyExist(prop, obj)) { - int ids = compileState.ids.count(); + int ids = compileState->ids.count(); COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState.ids.count(); + canDefer = ids == compileState->ids.count(); } else { customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop); } } else { - int ids = compileState.ids.count(); + int ids = compileState->ids.count(); COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState.ids.count(); + canDefer = ids == compileState->ids.count(); } - if (canDefer && !deferredList.isEmpty() && - deferredList.contains(QString::fromUtf8(prop->name))) + if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name())) prop->isDeferred = true; } - if (defaultProperty) - defaultProperty->release(); - // Compile custom parser parts if (isCustomParser && !customProps.isEmpty()) { cp->clearErrors(); @@ -914,10 +1168,12 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi } } + compileState->objectDepth.pop(); + return true; } -void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) +void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj) { QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type]; if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { @@ -927,46 +1183,55 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) // Create the object if (obj->custom.isEmpty() && output->types.at(obj->type).type && - !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) { - - QDeclarativeInstruction create; - create.setType(QDeclarativeInstruction::CreateSimpleObject); - create.createSimple.create = output->types.at(obj->type).type->createFunction(); - create.createSimple.typeSize = output->types.at(obj->type).type->createSize(); - create.createSimple.type = obj->type; - create.createSimple.line = obj->location.start.line; - create.createSimple.column = obj->location.start.column; + !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) { + + Instruction::CreateSimpleObject create; + create.create = output->types.at(obj->type).type->createFunction(); + create.typeSize = output->types.at(obj->type).type->createSize(); + create.type = obj->type; + create.line = obj->location.start.line; + create.column = obj->location.start.column; output->addInstruction(create); } else { - QDeclarativeInstruction create; - create.setType(QDeclarativeInstruction::CreateObject); - create.create.line = obj->location.start.line; - create.create.column = obj->location.start.column; - create.create.data = -1; - if (!obj->custom.isEmpty()) - create.create.data = output->indexForByteArray(obj->custom); - create.create.type = obj->type; - if (!output->types.at(create.create.type).type && - !obj->bindingBitmask.isEmpty()) { - Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); - create.create.bindingBits = - output->indexForByteArray(obj->bindingBitmask); + if (output->types.at(obj->type).type) { + Instruction::CreateCppObject create; + create.line = obj->location.start.line; + create.column = obj->location.start.column; + create.data = -1; + if (!obj->custom.isEmpty()) + create.data = output->indexForByteArray(obj->custom); + create.type = obj->type; + create.isRoot = (compileState->root == obj); + output->addInstruction(create); } else { - create.create.bindingBits = -1; - } - output->addInstruction(create); + Instruction::CreateQMLObject create; + create.type = obj->type; + create.isRoot = (compileState->root == obj); + + if (!obj->bindingBitmask.isEmpty()) { + Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); + create.bindingBits = output->indexForByteArray(obj->bindingBitmask); + } else { + create.bindingBits = -1; + } + output->addInstruction(create); + Instruction::CompleteQMLObject complete; + complete.line = obj->location.start.line; + complete.column = obj->location.start.column; + complete.isRoot = (compileState->root == obj); + output->addInstruction(complete); + } } // Setup the synthesized meta object if necessary if (!obj->metadata.isEmpty()) { - QDeclarativeInstruction meta; - meta.setType(QDeclarativeInstruction::StoreMetaObject); - meta.storeMeta.data = output->indexForByteArray(obj->metadata); - meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); - meta.storeMeta.propertyCache = output->propertyCaches.count(); + Instruction::StoreMetaObject meta; + meta.data = output->indexForByteArray(obj->metadata); + meta.aliasData = output->indexForByteArray(obj->synthdata); + meta.propertyCache = output->propertyCaches.count(); QDeclarativePropertyCache *propertyCache = obj->synthCache; Q_ASSERT(propertyCache); @@ -978,8 +1243,8 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) reinterpret_cast(obj->synthdata.constData()); for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; - QDeclarativePropertyCache::Data *data = propertyCache->property(index); - data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias); + QDeclarativePropertyData *data = propertyCache->property(index); + data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias); } } @@ -997,41 +1262,40 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) // Set the object id if (!obj->id.isEmpty()) { - QDeclarativeInstruction id; - id.setType(QDeclarativeInstruction::SetId); - id.setId.value = output->indexForString(obj->id); - id.setId.index = obj->idIndex; + Instruction::SetId id; + id.value = output->indexForString(obj->id); + id.index = obj->idIndex; output->addInstruction(id); } // Begin the class if (tr.type && obj->parserStatusCast != -1) { - QDeclarativeInstruction begin; - begin.setType(QDeclarativeInstruction::BeginObject); - begin.begin.castValue = obj->parserStatusCast; + Instruction::BeginObject begin; + begin.castValue = obj->parserStatusCast; output->addInstruction(begin); } genObjectBody(obj); } -void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj) +void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj) { - typedef QPair PropPair; - foreach(const PropPair &prop, obj->scriptStringProperties) { - const QString &script = prop.first->values.at(0)->value.asScript(); - QDeclarativeInstruction ss; - ss.setType(QDeclarativeInstruction::StoreScriptString); - ss.storeScriptString.propertyIndex = prop.first->index; - ss.storeScriptString.value = output->indexForString(script); - ss.storeScriptString.scope = prop.second; - ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name); - ss.storeScriptString.line = prop.first->location.start.line; + for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + Q_ASSERT(prop->scriptStringScope != -1); + const QString &script = prop->values.first()->value.asScript(); + Instruction::StoreScriptString ss; + ss.propertyIndex = prop->index; + ss.value = output->indexForString(script); + ss.scope = prop->scriptStringScope; +// ss.bindingId = rewriteBinding(script, prop->name()); + ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX + ss.line = prop->location.start.line; + ss.column = prop->location.start.column; output->addInstruction(ss); } bool seenDefer = false; - foreach(Property *prop, obj->valueProperties) { + for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) { if (prop->isDeferred) { seenDefer = true; continue; @@ -1040,198 +1304,184 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj) genValueProperty(prop, obj); } if (seenDefer) { - QDeclarativeInstruction defer; - defer.setType(QDeclarativeInstruction::Defer); - defer.defer.deferCount = 0; + Instruction::Defer defer; + defer.deferCount = 0; int deferIdx = output->addInstruction(defer); int nextInstructionIndex = output->nextInstructionIndex(); - QDeclarativeInstruction init; - init.setType(QDeclarativeInstruction::Init); - init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary - init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary - init.init.contextCache = -1; - init.init.compiledBinding = -1; - output->addInstruction(init); + Instruction::DeferInit dinit; + // XXX - these are now massive over allocations + dinit.bindingsSize = compileState->totalBindingsCount; + dinit.parserStatusSize = compileState->parserStatusCount; + dinit.objectStackSize = compileState->objectDepth.maxDepth(); + dinit.listStackSize = compileState->listDepth.maxDepth(); + output->addInstruction(dinit); - foreach(Property *prop, obj->valueProperties) { + for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) { if (!prop->isDeferred) continue; genValueProperty(prop, obj); } - QDeclarativeInstruction done; - done.setType(QDeclarativeInstruction::Done); + Instruction::Done done; output->addInstruction(done); output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex; } - foreach(Property *prop, obj->signalProperties) { + for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) { - QDeclarativeParser::Value *v = prop->values.at(0); + QDeclarativeScript::Value *v = prop->values.first(); if (v->type == Value::SignalObject) { genObject(v->object); - QDeclarativeInstruction assign; - assign.setType(QDeclarativeInstruction::AssignSignalObject); - assign.assignSignalObject.line = v->location.start.line; - assign.assignSignalObject.signal = - output->indexForByteArray(prop->name); + Instruction::AssignSignalObject assign; + assign.line = v->location.start.line; + assign.signal = output->indexForString(prop->name().toString()); output->addInstruction(assign); } else if (v->type == Value::SignalExpression) { - BindingContext ctxt = compileState.signalExpressions.value(v); - - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreSignal); - store.storeSignal.signalIndex = prop->index; - store.storeSignal.value = - output->indexForString(v->value.asScript().trimmed()); - store.storeSignal.context = ctxt.stack; - store.storeSignal.name = output->indexForByteArray(prop->name); - store.storeSignal.line = v->location.start.line; + Instruction::StoreSignal store; + store.signalIndex = prop->index; + QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler; + const QString &rewrite = + rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString()); + store.value = output->indexForString(rewrite); + store.context = v->signalExpressionContextStack; + store.line = v->location.start.line; + store.column = v->location.start.column; output->addInstruction(store); } } - foreach(Property *prop, obj->attachedProperties) { - QDeclarativeInstruction fetch; - fetch.setType(QDeclarativeInstruction::FetchAttached); - fetch.fetchAttached.id = prop->index; - fetch.fetchAttached.line = prop->location.start.line; + for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + Instruction::FetchAttached fetch; + fetch.id = prop->index; + fetch.line = prop->location.start.line; output->addInstruction(fetch); genObjectBody(prop->value); - QDeclarativeInstruction pop; - pop.setType(QDeclarativeInstruction::PopFetchedObject); + Instruction::PopFetchedObject pop; output->addInstruction(pop); } - foreach(Property *prop, obj->groupedProperties) { - QDeclarativeInstruction fetch; - fetch.setType(QDeclarativeInstruction::FetchObject); - fetch.fetch.property = prop->index; - fetch.fetch.line = prop->location.start.line; + for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) { + Instruction::FetchObject fetch; + fetch.property = prop->index; + fetch.line = prop->location.start.line; output->addInstruction(fetch); if (!prop->value->metadata.isEmpty()) { - QDeclarativeInstruction meta; - meta.setType(QDeclarativeInstruction::StoreMetaObject); - meta.storeMeta.data = output->indexForByteArray(prop->value->metadata); - meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata); - meta.storeMeta.propertyCache = -1; + Instruction::StoreMetaObject meta; + meta.data = output->indexForByteArray(prop->value->metadata); + meta.aliasData = output->indexForByteArray(prop->value->synthdata); + meta.propertyCache = -1; output->addInstruction(meta); } genObjectBody(prop->value); - QDeclarativeInstruction pop; - pop.setType(QDeclarativeInstruction::PopFetchedObject); + Instruction::PopFetchedObject pop; output->addInstruction(pop); } - foreach(Property *prop, obj->valueTypeProperties) { + for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) { if (!prop->isAlias) genValueTypeProperty(obj, prop); } - foreach(Property *prop, obj->valueProperties) { + for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) { if (prop->isDeferred) continue; if (prop->isAlias) genValueProperty(prop, obj); } - foreach(Property *prop, obj->valueTypeProperties) { + for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) { if (prop->isAlias) genValueTypeProperty(obj, prop); } } -void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop) +void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop) { - QDeclarativeInstruction fetch; - fetch.setType(QDeclarativeInstruction::FetchValueType); - fetch.fetchValue.property = prop->index; - fetch.fetchValue.type = prop->type; - fetch.fetchValue.bindingSkipList = 0; + Instruction::FetchValueType fetch; + fetch.property = prop->index; + fetch.type = prop->type; + fetch.bindingSkipList = 0; if (obj->type == -1 || output->types.at(obj->type).component) { // We only have to do this if this is a composite type. If it is a builtin // type it can't possibly already have bindings that need to be cleared. - foreach(Property *vprop, prop->value->valueProperties) { + for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) { if (!vprop->values.isEmpty()) { Q_ASSERT(vprop->index >= 0 && vprop->index < 32); - fetch.fetchValue.bindingSkipList |= (1 << vprop->index); + fetch.bindingSkipList |= (1 << vprop->index); } } } output->addInstruction(fetch); - foreach(Property *vprop, prop->value->valueProperties) { + for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) { genPropertyAssignment(vprop, prop->value, prop); } - QDeclarativeInstruction pop; - pop.setType(QDeclarativeInstruction::PopValueType); - pop.fetchValue.property = prop->index; - pop.fetchValue.type = prop->type; - pop.fetchValue.bindingSkipList = 0; + Instruction::PopValueType pop; + pop.property = prop->index; + pop.type = prop->type; + pop.bindingSkipList = 0; output->addInstruction(pop); } -void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj) +void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj) { - QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object; + QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object; Q_ASSERT(root); - QDeclarativeInstruction create; - create.setType(QDeclarativeInstruction::CreateComponent); - create.createComponent.line = root->location.start.line; - create.createComponent.column = root->location.start.column; - create.createComponent.endLine = root->location.end.line; + Instruction::CreateComponent create; + create.line = root->location.start.line; + create.column = root->location.start.column; + create.endLine = root->location.end.line; + create.isRoot = (compileState->root == obj); int createInstruction = output->addInstruction(create); int nextInstructionIndex = output->nextInstructionIndex(); - ComponentCompileState oldCompileState = compileState; + ComponentCompileState *oldCompileState = compileState; compileState = componentState(root); - QDeclarativeInstruction init; - init.setType(QDeclarativeInstruction::Init); - init.init.bindingsSize = compileState.bindings.count(); - init.init.parserStatusSize = compileState.parserStatusCount; - init.init.contextCache = genContextCache(); - if (compileState.compiledBindingData.isEmpty()) - init.init.compiledBinding = -1; + Instruction::Init init; + init.bindingsSize = compileState->totalBindingsCount; + init.parserStatusSize = compileState->parserStatusCount; + init.contextCache = genContextCache(); + init.objectStackSize = compileState->objectDepth.maxDepth(); + init.listStackSize = compileState->listDepth.maxDepth(); + if (compileState->compiledBindingData.isEmpty()) + init.compiledBinding = -1; else - init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); + init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData); output->addInstruction(init); - if (!compileState.v8BindingProgram.isEmpty()) { - QDeclarativeInstruction bindings; - bindings.setType(QDeclarativeInstruction::InitV8Bindings); - bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram); - bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex; - bindings.initV8Bindings.line = compileState.v8BindingProgramLine; + if (!compileState->v8BindingProgram.isEmpty()) { + Instruction::InitV8Bindings bindings; + bindings.program = output->indexForString(compileState->v8BindingProgram); + bindings.programIndex = compileState->v8BindingProgramIndex; + bindings.line = compileState->v8BindingProgramLine; output->addInstruction(bindings); } genObject(root); - QDeclarativeInstruction def; - def.setType(QDeclarativeInstruction::SetDefault); + Instruction::SetDefault def; output->addInstruction(def); - QDeclarativeInstruction done; - done.setType(QDeclarativeInstruction::Done); + Instruction::Done done; output->addInstruction(done); output->instruction(createInstruction)->createComponent.count = @@ -1240,10 +1490,9 @@ void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj) compileState = oldCompileState; if (!obj->id.isEmpty()) { - QDeclarativeInstruction id; - id.setType(QDeclarativeInstruction::SetId); - id.setId.value = output->indexForString(obj->id); - id.setId.index = obj->idIndex; + Instruction::SetId id; + id.value = output->indexForString(obj->id); + id.index = obj->idIndex; output->addInstruction(id); } @@ -1253,29 +1502,31 @@ void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj) } } -bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj, const BindingContext &ctxt) { // The special "Component" element can only have the id property and a // default property, that actually defines the component's tree + compileState->objectDepth.push(); + // Find, check and set the "id" property (if any) Property *idProp = 0; - if (obj->properties.count() > 1 || - (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) - COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id")); + if (obj->properties.isMany() || + (obj->properties.isOne() && obj->properties.first()->name() != id_string)) + COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id")); - if (obj->properties.count()) - idProp = *obj->properties.begin(); + if (!obj->properties.isEmpty()) + idProp = obj->properties.first(); if (idProp) { - if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object) + if (idProp->value || idProp->values.isMany() || idProp->values.first()->object) COMPILE_EXCEPTION(idProp, tr("Invalid component id specification")); COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive())) QString idVal = idProp->values.first()->primitive(); - if (compileState.ids.contains(idVal)) + if (compileState->ids.value(idVal)) COMPILE_EXCEPTION(idProp, tr("id is not unique")); obj->id = idVal; @@ -1284,8 +1535,8 @@ bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, // 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))) + (obj->defaultProperty->value || obj->defaultProperty->values.isMany() || + (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object))) COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); if (!obj->dynamicProperties.isEmpty()) @@ -1295,8 +1546,8 @@ bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, if (!obj->dynamicSlots.isEmpty()) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); - QDeclarativeParser::Object *root = 0; - if (obj->defaultProperty && obj->defaultProperty->values.count()) + QDeclarativeScript::Object *root = 0; + if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty()) root = obj->defaultProperty->values.first()->object; if (!root) @@ -1305,29 +1556,39 @@ bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, // Build the component tree COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); + compileState->objectDepth.pop(); + return true; } -bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj, const BindingContext &ctxt) { - ComponentCompileState oldComponentCompileState = compileState; - ComponentStat oldComponentStat = componentStat; + ComponentCompileState *oldComponentCompileState = compileState; + compileState = pool->New(); + compileState->root = obj; + compileState->nested = true; + + if (componentStats) { + ComponentStat oldComponentStat = componentStats->componentStat; - compileState = ComponentCompileState(); - compileState.root = obj; - compileState.nested = true; + componentStats->componentStat = ComponentStat(); + componentStats->componentStat.lineNumber = obj->location.start.line; - componentStat = ComponentStat(); - componentStat.lineNumber = obj->location.start.line; + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); - if (obj) - COMPILE_CHECK(buildObject(obj, ctxt)); + COMPILE_CHECK(completeComponentBuild()); - COMPILE_CHECK(completeComponentBuild()); + componentStats->componentStat = oldComponentStat; + } else { + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); + } compileState = oldComponentCompileState; - componentStat = oldComponentStat; return true; } @@ -1336,15 +1597,15 @@ bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *ob // Build a sub-object. A sub-object is one that was not created directly by // QML - such as a grouped property object, or an attached object. Sub-object's // can't have an id, involve a custom parser, have attached properties etc. -bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt) +bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); Q_ASSERT(!obj->defaultProperty); Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding // sub-context - foreach(Property *prop, obj->properties) { - if (isSignalPropertyName(prop->name)) { + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + if (isSignalPropertyName(prop->name())) { COMPILE_CHECK(buildSignal(prop, obj, ctxt)); } else { COMPILE_CHECK(buildProperty(prop, obj, ctxt)); @@ -1356,49 +1617,70 @@ bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const int QDeclarativeCompiler::componentTypeRef() { - QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0); - for (int ii = output->types.count() - 1; ii >= 0; --ii) { - if (output->types.at(ii).type == t) - return ii; + if (cachedComponentTypeRef == -1) { + QDeclarativeType *t = QDeclarativeMetaType::qmlType(Component_import_string,1,0); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) { + cachedComponentTypeRef = ii; + return ii; + } + } + QDeclarativeCompiledData::TypeReference ref; + ref.className = Component_string; + ref.type = t; + output->types << ref; + cachedComponentTypeRef = output->types.count() - 1; } - QDeclarativeCompiledData::TypeReference ref; - ref.className = "Component"; - ref.type = t; - output->types << ref; - return output->types.count() - 1; + return cachedComponentTypeRef; } -bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj, +int QDeclarativeCompiler::translationContextIndex() +{ + if (cachedTranslationContextIndex == -1) { + // This code must match that in the qsTr() implementation + QString path = output->url.toString(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : + QString(); + QByteArray contextUtf8 = context.toUtf8(); + cachedTranslationContextIndex = output->indexForByteArray(contextUtf8); + } + return cachedTranslationContextIndex; +} + +bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metaObject()); - QByteArray name = prop->name; - Q_ASSERT(name.startsWith("on")); - name = name.mid(2); + const QHashedStringRef &propName = prop->name(); + + Q_ASSERT(propName.startsWith(on_string)); + QString name = propName.mid(2, -1).toString(); // 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 < name.size(); ++firstAlphaIndex) { - if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') { - name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a'; + if (name.at(firstAlphaIndex).isUpper()) { + name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower(); break; } } bool notInRevision = false; - int sigIdx = indexOfSignal(obj, name, ¬InRevision); - if (sigIdx == -1) { + QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision); - if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) { + if (sig == 0) { + + if (notInRevision && 0 == property(obj, propName, 0)) { Q_ASSERT(obj->type != -1); const QList &resolvedTypes = unit->resolvedTypes(); const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); if (type.type) { - COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion)); + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion)); } else { - COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name))); + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString())); } } @@ -1408,26 +1690,28 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl } else { - if (prop->value || prop->values.count() != 1) + if (prop->value || !prop->values.isOne()) COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); - prop->index = sigIdx; + prop->index = sig->coreIndex; + prop->core = *sig; + obj->addSignalProperty(prop); - if (prop->values.at(0)->object) { - COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); - prop->values.at(0)->type = Value::SignalObject; + if (prop->values.first()->object) { + COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt)); + prop->values.first()->type = Value::SignalObject; } else { - prop->values.at(0)->type = Value::SignalExpression; + prop->values.first()->type = Value::SignalExpression; - if (!prop->values.at(0)->value.isScript()) + if (!prop->values.first()->value.isScript()) COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)")); - QString script = prop->values.at(0)->value.asScript().trimmed(); + QString script = prop->values.first()->value.asScript().trimmed(); if (script.isEmpty()) COMPILE_EXCEPTION(prop, tr("Empty signal assignment")); - compileState.signalExpressions.insert(prop->values.at(0), ctxt); + prop->values.first()->signalExpressionContextStack = ctxt.stack; } } @@ -1438,37 +1722,28 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl /*! Returns true if (value) property \a prop exists on obj, false otherwise. */ -bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj) +bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj) { - if(isAttachedPropertyName(prop->name) || prop->name == "id") + if (prop->name().isEmpty()) + return false; + if(isAttachedPropertyName(prop->name()) || prop->name() == id_string) return true; - const QMetaObject *mo = obj->metaObject(); - if (mo) { - if (prop->isDefault) { - QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo); - return p.name() != 0; - } else { - int idx = indexOfProperty(obj, prop->name); - return idx != -1 && mo->property(idx).isScriptable(); - } - } - - return false; + return property(obj, prop->name()) != 0; } -bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, - const BindingContext &ctxt) +bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + const BindingContext &ctxt) { - if (prop->isEmpty()) + if (prop->isEmpty()) COMPILE_EXCEPTION(prop, tr("Empty property assignment")); const QMetaObject *metaObject = obj->metaObject(); Q_ASSERT(metaObject); - if (isAttachedPropertyName(prop->name)) { + if (isAttachedPropertyName(prop->name())) { // Setup attached property data if (ctxt.isSubContext()) { @@ -1480,7 +1755,7 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, QDeclarativeType *type = 0; QDeclarativeImportedNamespace *typeNamespace = 0; - unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace); + unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace); if (typeNamespace) { COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, @@ -1498,44 +1773,35 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, prop->value->metatype = type->attachedPropertiesType(); } else { // Setup regular property data - QMetaProperty p; - - if (prop->isDefault) { - p = QDeclarativeMetaType::defaultProperty(metaObject); - - if (p.name()) { - prop->index = p.propertyIndex(); - prop->name = p.name(); - } - - } else { - bool notInRevision = false; - prop->index = indexOfProperty(obj, prop->name, ¬InRevision); - if (prop->index == -1 && notInRevision) { - const QList &resolvedTypes = unit->resolvedTypes(); - const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); - if (type.type) { - COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion)); - } else { - COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name))); - } - } - - if (prop->index != -1) { - p = metaObject->property(prop->index); - Q_ASSERT(p.name()); + bool notInRevision = false; + QDeclarativePropertyData *d = + prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision); - if (!p.isScriptable()) { - prop->index = -1; - p = QMetaProperty(); - } + if (d == 0 && notInRevision) { + const QList &resolvedTypes = unit->resolvedTypes(); + const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); + if (type.type) { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion)); + } else { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString())); } + } else if (d) { + prop->index = d->coreIndex; + prop->core = *d; + } else if (prop->isDefault) { + QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject); + QDeclarativePropertyData defaultPropertyData; + defaultPropertyData.load(p, engine); + if (p.name()) + prop->setName(QLatin1String(p.name())); + prop->core = defaultPropertyData; + prop->index = prop->core.coreIndex; } // We can't error here as the "id" property does not require a // successful index resolution - if (p.name()) - prop->type = p.userType(); + if (prop->index != -1) + prop->type = prop->core.propType; // Check if this is an alias if (prop->index != -1 && @@ -1552,17 +1818,17 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, prop->parent->setBindingBit(prop->index); } - if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { + if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) { // The magic "id" behavior doesn't apply when "id" is resolved as a // default property or to sub-objects (which are always in binding // sub-contexts) COMPILE_CHECK(buildIdProperty(prop, obj)); if (prop->type == QVariant::String && - prop->values.at(0)->value.isString()) + prop->values.first()->value.isString()) COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); - } else if (isAttachedPropertyName(prop->name)) { + } else if (isAttachedPropertyName(prop->name())) { COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); @@ -1571,14 +1837,14 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, if (prop->isDefault) { COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property")); } else { - COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString())); } } else if (prop->value) { COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); - } else if (enginePrivate->isList(prop->type)) { + } else if (prop->core.isQList()) { COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); @@ -1596,22 +1862,22 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, } bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns, - QDeclarativeParser::Property *nsProp, - QDeclarativeParser::Object *obj, + QDeclarativeScript::Property *nsProp, + QDeclarativeScript::Object *obj, const BindingContext &ctxt) { if (!nsProp->value) COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace")); - foreach (Property *prop, nsProp->value->properties) { + for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) { - if (!isAttachedPropertyName(prop->name)) + if (!isAttachedPropertyName(prop->name())) COMPILE_EXCEPTION(prop, tr("Not an attached property name")); // Setup attached property data QDeclarativeType *type = 0; - unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0); + unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0); if (!type || !type->attachedPropertiesType()) COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); @@ -1629,42 +1895,38 @@ bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespac return true; } -void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj) +void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj) { - if (enginePrivate->isList(prop->type)) { + if (prop->core.isQList()) { genListProperty(prop, obj); } else { genPropertyAssignment(prop, obj); } } -void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj) +void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj) { int listType = enginePrivate->listType(prop->type); - QDeclarativeInstruction fetch; - fetch.setType(QDeclarativeInstruction::FetchQList); - fetch.fetchQmlList.property = prop->index; + Instruction::FetchQList fetch; + fetch.property = prop->index; bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; + fetch.type = listType; output->addInstruction(fetch); - for (int ii = 0; ii < prop->values.count(); ++ii) { - QDeclarativeParser::Value *v = prop->values.at(ii); + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { if (v->type == Value::CreatedObject) { genObject(v->object); if (listTypeIsInterface) { - QDeclarativeInstruction assign; - assign.setType(QDeclarativeInstruction::AssignObjectList); - assign.assignObjectList.line = prop->location.start.line; + Instruction::AssignObjectList assign; + assign.line = prop->location.start.line; output->addInstruction(assign); } else { - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreObjectQList); + Instruction::StoreObjectQList store; output->addInstruction(store); } @@ -1676,17 +1938,15 @@ void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop, } - QDeclarativeInstruction pop; - pop.setType(QDeclarativeInstruction::PopQList); + Instruction::PopQList pop; output->addInstruction(pop); } -void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Property *valueTypeProperty) +void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Property *valueTypeProperty) { - for (int ii = 0; ii < prop->values.count(); ++ii) { - QDeclarativeParser::Value *v = prop->values.at(ii); + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { Q_ASSERT(v->type == Value::CreatedObject || v->type == Value::PropertyBinding || @@ -1698,26 +1958,31 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p if (QDeclarativeMetaType::isInterface(prop->type)) { - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreInterface); - store.storeObject.line = v->object->location.start.line; - store.storeObject.propertyIndex = prop->index; + Instruction::StoreInterface store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; output->addInstruction(store); - } else if (prop->type == -1) { + } else if (prop->type == QMetaType::QVariant) { + + if (prop->core.isVMEProperty()) { + Instruction::StoreVarObject store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; + output->addInstruction(store); + } else { + Instruction::StoreVariantObject store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; + output->addInstruction(store); + } - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreVariantObject); - store.storeObject.line = v->object->location.start.line; - store.storeObject.propertyIndex = prop->index; - output->addInstruction(store); } else { - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreObject); - store.storeObject.line = v->object->location.start.line; - store.storeObject.propertyIndex = prop->index; + Instruction::StoreObject store; + store.line = v->object->location.start.line; + store.propertyIndex = prop->index; output->addInstruction(store); } @@ -1727,16 +1992,13 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p } else if (v->type == Value::Literal) { - QMetaProperty mp = obj->metaObject()->property(prop->index); - genLiteralAssignment(mp, v); + genLiteralAssignment(prop, v); } } - for (int ii = 0; ii < prop->onValues.count(); ++ii) { - - QDeclarativeParser::Value *v = prop->onValues.at(ii); + for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) { Q_ASSERT(v->type == Value::ValueSource || v->type == Value::ValueInterceptor); @@ -1744,56 +2006,54 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p if (v->type == Value::ValueSource) { genObject(v->object); - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreValueSource); + Instruction::StoreValueSource store; if (valueTypeProperty) { - store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty); - store.assignValueSource.owner = 1; + store.property = genValueTypeData(prop, valueTypeProperty); + store.owner = 1; } else { - store.assignValueSource.property = genPropertyData(prop); - store.assignValueSource.owner = 0; + store.property = prop->core; + store.owner = 0; } QDeclarativeType *valueType = toQmlType(v->object); - store.assignValueSource.castValue = valueType->propertyValueSourceCast(); + store.castValue = valueType->propertyValueSourceCast(); output->addInstruction(store); } else if (v->type == Value::ValueInterceptor) { genObject(v->object); - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreValueInterceptor); + Instruction::StoreValueInterceptor store; if (valueTypeProperty) { - store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty); - store.assignValueInterceptor.owner = 1; + store.property = genValueTypeData(prop, valueTypeProperty); + store.owner = 1; } else { - store.assignValueInterceptor.property = genPropertyData(prop); - store.assignValueInterceptor.owner = 0; + store.property = prop->core; + store.owner = 0; } QDeclarativeType *valueType = toQmlType(v->object); - store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast(); + store.castValue = valueType->propertyValueInterceptorCast(); output->addInstruction(store); } } } -bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj) +bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj) { if (prop->value || - prop->values.count() > 1 || - prop->values.at(0)->object) + prop->values.isMany() || + prop->values.first()->object) COMPILE_EXCEPTION(prop, tr("Invalid use of id property")); - QDeclarativeParser::Value *idValue = prop->values.at(0); + QDeclarativeScript::Value *idValue = prop->values.first(); QString val = idValue->primitive(); COMPILE_CHECK(checkValidId(idValue, val)); - if (compileState.ids.contains(val)) + if (compileState->ids.value(val)) COMPILE_EXCEPTION(prop, tr("id is not unique")); - prop->values.at(0)->type = Value::Id; + prop->values.first()->type = Value::Id; obj->id = val; addId(val, obj); @@ -1801,35 +2061,39 @@ bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop, return true; } -void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj) +void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj) { - Q_ASSERT(!compileState.ids.contains(id)); + Q_UNUSED(id); + Q_ASSERT(!compileState->ids.value(id)); Q_ASSERT(obj->id == id); - obj->idIndex = compileState.ids.count(); - compileState.ids.insert(id, obj); - compileState.idIndexes.insert(obj->idIndex, obj); + obj->idIndex = compileState->ids.count(); + compileState->ids.append(obj); } -void QDeclarativeCompiler::addBindingReference(const BindingReference &ref) +void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref) { - Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value)); - compileState.bindings.insert(ref.value, ref); + Q_ASSERT(ref->value && !ref->value->bindingReference); + ref->value->bindingReference = ref; + compileState->totalBindingsCount++; + compileState->bindings.prepend(ref); } void QDeclarativeCompiler::saveComponentState() { - Q_ASSERT(compileState.root); - Q_ASSERT(!savedCompileStates.contains(compileState.root)); + Q_ASSERT(compileState->root); + Q_ASSERT(compileState->root->componentCompileState == 0); - savedCompileStates.insert(compileState.root, compileState); - savedComponentStats.append(componentStat); + compileState->root->componentCompileState = compileState; + + if (componentStats) + componentStats->savedComponentStats.append(componentStats->componentStat); } -QDeclarativeCompiler::ComponentCompileState -QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj) +QDeclarativeCompilerTypes::ComponentCompileState * +QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj) { - Q_ASSERT(savedCompileStates.contains(obj)); - return savedCompileStates.value(obj); + Q_ASSERT(obj->componentCompileState); + return obj->componentCompileState; } // Build attached property object. In this example, @@ -1837,17 +2101,21 @@ QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj) // GridView.row: 10 // } // GridView is an attached property object. -bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, const BindingContext &ctxt) { Q_ASSERT(prop->value); Q_ASSERT(prop->index != -1); // This is set in buildProperty() + compileState->objectDepth.push(); + obj->addAttachedProperty(prop); COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + compileState->objectDepth.pop(); + return true; } @@ -1858,32 +2126,33 @@ bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *p // font.family: "Helvetica" // } // font is a nested property. pointSize and family are not. -bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, const BindingContext &ctxt) { Q_ASSERT(prop->type != 0); Q_ASSERT(prop->index != -1); if (QDeclarativeValueTypeFactory::isValueType(prop->type)) { - if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) { + if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) { - if (prop->values.count()) { - if (prop->values.at(0)->location < prop->value->location) { + if (!prop->values.isEmpty()) { + if (prop->values.first()->location < prop->value->location) { COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value")); } else { - COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value")); + COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value")); } } - if (!obj->metaObject()->property(prop->index).isWritable()) { - COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) { + COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); } if (prop->isAlias) { - foreach (Property *vtProp, prop->value->properties) + for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) { vtProp->isAlias = true; + } } COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type], @@ -1899,44 +2168,50 @@ bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *pr if (!prop->value->metatype) COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); - if (prop->values.count()) - COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property")); + if (!prop->values.isEmpty()) + COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property")); obj->addGroupedProperty(prop); + compileState->objectDepth.push(); + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + + compileState->objectDepth.pop(); } return true; } bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Object *baseObj, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Object *baseObj, const BindingContext &ctxt) { + compileState->objectDepth.push(); + if (obj->defaultProperty) COMPILE_EXCEPTION(obj, tr("Invalid property use")); obj->metatype = type->metaObject(); - foreach (Property *prop, obj->properties) { - int idx = type->metaObject()->indexOfProperty(prop->name.constData()); - if (idx == -1) - COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); - QMetaProperty p = type->metaObject()->property(idx); - if (!p.isScriptable()) - COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); - prop->index = idx; - prop->type = p.userType(); + for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { + + QDeclarativePropertyData *d = property(obj, prop->name()); + if (d == 0) + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString())); + + prop->index = d->coreIndex; + prop->type = d->propType; + prop->core = *d; prop->isValueTypeSubProperty = true; if (prop->value) COMPILE_EXCEPTION(prop, tr("Property assignment expected")); - if (prop->values.count() > 1) { + if (prop->values.isMany()) { COMPILE_EXCEPTION(prop, tr("Single property assignment expected")); - } else if (prop->values.count()) { - QDeclarativeParser::Value *value = prop->values.at(0); + } else if (!prop->values.isEmpty()) { + QDeclarativeScript::Value *value = prop->values.first(); if (value->object) { COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); @@ -1945,27 +2220,29 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, //optimization for . enum assignments bool isEnumAssignment = false; - COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment)); + + if (prop->core.isEnum()) + COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment)); + if (isEnumAssignment) { value->type = Value::Literal; } else { - BindingReference reference; - reference.expression = value->value; - reference.property = prop; - reference.value = value; - reference.bindingContext = ctxt; - reference.bindingContext.owner++; + JSBindingReference *reference = pool->New(); + reference->expression = value->value; + reference->property = prop; + reference->value = value; + reference->bindingContext = ctxt; + reference->bindingContext.owner++; addBindingReference(reference); value->type = Value::PropertyBinding; } } else { - COMPILE_CHECK(testLiteralAssignment(p, value)); + COMPILE_CHECK(testLiteralAssignment(prop, value)); value->type = Value::Literal; } } - for (int ii = 0; ii < prop->onValues.count(); ++ii) { - QDeclarativeParser::Value *v = prop->onValues.at(ii); + for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) { Q_ASSERT(v->object); COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); @@ -1974,17 +2251,21 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, obj->addValueProperty(prop); } + compileState->objectDepth.pop(); + return true; } // Build assignments to QML lists. QML lists are properties of type // QDeclarativeListProperty. List properties can accept a list of // objects, or a single binding. -bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, const BindingContext &ctxt) { - Q_ASSERT(enginePrivate->isList(prop->type)); + Q_ASSERT(prop->core.isQList()); + + compileState->listDepth.push(); int t = prop->type; @@ -1994,8 +2275,7 @@ bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop, bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType); bool assignedBinding = false; - for (int ii = 0; ii < prop->values.count(); ++ii) { - QDeclarativeParser::Value *v = prop->values.at(ii); + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { if (v->object) { v->type = Value::CreatedObject; COMPILE_CHECK(buildObject(v->object, ctxt)); @@ -2020,37 +2300,39 @@ bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop, } } + compileState->listDepth.pop(); + return true; } // Compiles an assignment to a QDeclarativeScriptString property -bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, const BindingContext &ctxt) { - if (prop->values.count() > 1) - COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property")); + if (prop->values.isMany()) + COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property")); - if (prop->values.at(0)->object) - COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected")); + if (prop->values.first()->object) + COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected")); - obj->addScriptStringProperty(prop, ctxt.stack); + prop->scriptStringScope = ctxt.stack; + obj->addScriptStringProperty(prop); return true; } // Compile regular property assignments of the form "property: " -bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, +bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, const BindingContext &ctxt) { obj->addValueProperty(prop); - if (prop->values.count() > 1) - COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") ); + if (prop->values.isMany()) + COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") ); - for (int ii = 0; ii < prop->values.count(); ++ii) { - QDeclarativeParser::Value *v = prop->values.at(ii); + for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) { if (v->object) { COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); @@ -2062,9 +2344,7 @@ bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property } } - for (int ii = 0; ii < prop->onValues.count(); ++ii) { - QDeclarativeParser::Value *v = prop->onValues.at(ii); - + for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) { Q_ASSERT(v->object); COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); } @@ -2073,16 +2353,16 @@ bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property } // Compile assigning a single object instance to a regular property -bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Value *v, +bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Value *v, const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); - if (!obj->metaObject()->property(prop->index).isWritable()) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); if (QDeclarativeMetaType::isInterface(prop->type)) { @@ -2091,7 +2371,7 @@ bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Pro v->type = Value::CreatedObject; - } else if (prop->type == -1) { + } else if (prop->type == QMetaType::QVariant) { // Assigning an object to a QVariant COMPILE_CHECK(buildObject(v->object, ctxt)); @@ -2128,13 +2408,13 @@ bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Pro v->type = Value::CreatedObject; } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) { // Automatic "Component" insertion - QDeclarativeParser::Object *root = v->object; - QDeclarativeParser::Object *component = new QDeclarativeParser::Object; + QDeclarativeScript::Object *root = v->object; + QDeclarativeScript::Object *component = pool->New(); component->type = componentTypeRef(); - component->typeName = "Qt/Component"; + component->typeName = QStringLiteral("Qt/Component"); component->metatype = &QDeclarativeComponent::staticMetaObject; component->location = root->location; - QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value; + QDeclarativeScript::Value *componentValue = pool->New(); componentValue->object = root; component->getDefaultProperty()->addValue(componentValue); v->object = component; @@ -2153,17 +2433,19 @@ bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Pro // Item { // NumberAnimation on x { } // } -bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Object *baseObj, - QDeclarativeParser::Value *v, +bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Object *baseObj, + QDeclarativeScript::Value *v, const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); - if (!obj->metaObject()->property(prop->index).isWritable()) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + Q_UNUSED(obj); + + if (!prop->core.isWritable()) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); // Normally buildObject() will set this up, but we need the static @@ -2190,37 +2472,41 @@ bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Propert buildDynamicMeta(baseObj, ForceCreation); v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; } else { - COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData()))); + COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString())); } return true; } // Compile assigning a literal or binding to a regular property -bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Value *v, - const BindingContext &ctxt) +bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); if (v->value.isScript()) { //optimization for . enum assignments - bool isEnumAssignment = false; - COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment)); - if (isEnumAssignment) { - v->type = Value::Literal; - return true; + if (prop->core.isEnum()) { + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment)); + if (isEnumAssignment) { + v->type = Value::Literal; + return true; + } } - COMPILE_CHECK(buildBinding(v, prop, ctxt)); + // Test for other binding optimizations + if (!buildLiteralBinding(v, prop, ctxt)) + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { - COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); + COMPILE_CHECK(testLiteralAssignment(prop, v)); v->type = Value::Literal; } @@ -2228,17 +2514,19 @@ bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Pr return true; } -bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Value *v, - bool *isAssignment) +bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Value *v, + bool *isAssignment) { *isAssignment = false; - if (!prop.isEnumType()) + if (!prop->core.isEnum()) return true; - if (!prop.isWritable()) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + QMetaProperty mprop = obj->metaObject()->property(prop->index); + + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); QString string = v->value.asString(); if (!string.at(0).isUpper()) @@ -2250,10 +2538,10 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop QString typeName = parts.at(0); QDeclarativeType *type = 0; - unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0); + unit->imports().resolveType(typeName, &type, 0, 0, 0, 0); //handle enums on value types (where obj->typeName is empty) - QByteArray objTypeName = obj->typeName; + QString objTypeName = obj->typeName; if (objTypeName.isEmpty()) { QDeclarativeType *objType = toQmlType(obj); if (objType) @@ -2264,61 +2552,71 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop return true; QString enumValue = parts.at(1); - int value = -1; + int value; + bool ok; if (objTypeName == type->qmlTypeName()) { // When these two match, we can short cut the search - if (prop.isFlagType()) { - value = prop.enumerator().keysToValue(enumValue.toUtf8().constData()); + if (mprop.isFlagType()) { + value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); } else { - value = prop.enumerator().keyToValue(enumValue.toUtf8().constData()); + value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); } } else { // Otherwise we have to search the whole type // This matches the logic in QV8TypeWrapper QByteArray enumName = enumValue.toUtf8(); const QMetaObject *metaObject = type->baseMetaObject(); - for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) { + ok = false; + for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) { QMetaEnum e = metaObject->enumerator(ii); - value = e.keyToValue(enumName.constData()); + value = e.keyToValue(enumName.constData(), &ok); } } - if (value == -1) + if (!ok) return true; v->type = Value::Literal; - v->value = QDeclarativeParser::Variant((double)value); + v->value = QDeclarativeScript::Variant((double)value); *isAssignment = true; return true; } +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast (0)->staticQtMetaObject; } +}; + // Similar logic to above, but not knowing target property. int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const { int dot = script.indexOf('.'); if (dot > 0) { + const QByteArray &scope = script.left(dot); QDeclarativeType *type = 0; - unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0); - if (!type) + unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0); + if (!type && scope != "Qt") return -1; - const QMetaObject *mo = type->metaObject(); + const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get(); const char *key = script.constData() + dot+1; int i = mo->enumeratorCount(); while (i--) { - int v = mo->enumerator(i).keyToValue(key); - if (v >= 0) + bool ok; + int v = mo->enumerator(i).keyToValue(key, &ok); + if (ok) return v; } } return -1; } -const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const +const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const { QDeclarativeType *qmltype = 0; - if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0)) + if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0)) return 0; if (!qmltype) return 0; @@ -2327,27 +2625,36 @@ const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) con // similar to logic of completeComponentBuild, but also sticks data // into primitives at the end -int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name) +int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name) { QDeclarativeRewrite::RewriteBinding rewriteBinding; - rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1)); + rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1)); - QString rewrite = rewriteBinding(expression, 0, 0); + QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0); return output->indexForString(rewrite); } +QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name) +{ + QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler; + return rewriteSignalHandler(handler, name); +} + // Ensures that the dynamic meta specification on obj is valid -bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) +bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj) { - QSet propNames; - QSet methodNames; bool seenDefaultProperty = false; + // We use a coarse grain, 31 bit hash to check if there are duplicates. + // Calculating the hash for the names is not a waste as we have to test + // them against the illegalNames set anyway. + QHashField propNames; + QHashField methodNames; + // Check properties - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const QDeclarativeParser::Object::DynamicProperty &prop = - obj->dynamicProperties.at(ii); + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + const QDeclarativeScript::Object::DynamicProperty &prop = *p; if (prop.isDefaultProperty) { if (seenDefaultProperty) @@ -2355,77 +2662,103 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) seenDefaultProperty = true; } - if (propNames.contains(prop.name)) - COMPILE_EXCEPTION(&prop, tr("Duplicate property name")); - - QString propName = QString::fromUtf8(prop.name); - if (propName.at(0).isUpper()) - COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter")); + if (propNames.testAndSet(prop.name.hash())) { + for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p; + p2 = obj->dynamicProperties.next(p2)) { + if (p2->name == prop.name) { + COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, + prop.nameLocation.column, + tr("Duplicate property name")); + } + } + } - if (enginePrivate->v8engine.illegalNames().contains(propName)) - COMPILE_EXCEPTION(&prop, tr("Illegal property name")); + if (prop.name.at(0).isUpper()) { + COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, + prop.nameLocation.column, + tr("Property names cannot begin with an upper case letter")); + } - propNames.insert(prop.name); + if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) { + COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, + prop.nameLocation.column, + tr("Illegal property name")); + } } - for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { - QByteArray name = obj->dynamicSignals.at(ii).name; - if (methodNames.contains(name)) - COMPILE_EXCEPTION(obj, tr("Duplicate signal name")); - QString nameStr = QString::fromUtf8(name); - if (nameStr.at(0).isUpper()) - COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter")); - if (enginePrivate->v8engine.illegalNames().contains(nameStr)) - COMPILE_EXCEPTION(obj, tr("Illegal signal name")); - methodNames.insert(name); + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + const QDeclarativeScript::Object::DynamicSignal &currSig = *s; + + if (methodNames.testAndSet(currSig.name.hash())) { + for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s; + s2 = obj->dynamicSignals.next(s2)) { + if (s2->name == currSig.name) + COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name")); + } + } + + if (currSig.name.at(0).isUpper()) + COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter")); + if (enginePrivate->v8engine()->illegalNames().contains(currSig.name)) + COMPILE_EXCEPTION(&currSig, tr("Illegal signal name")); } - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { - QByteArray name = obj->dynamicSlots.at(ii).name; - if (methodNames.contains(name)) - COMPILE_EXCEPTION(obj, tr("Duplicate method name")); - QString nameStr = QString::fromUtf8(name); - if (nameStr.at(0).isUpper()) - COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter")); - if (enginePrivate->v8engine.illegalNames().contains(nameStr)) - COMPILE_EXCEPTION(obj, tr("Illegal method name")); - methodNames.insert(name); + + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + const QDeclarativeScript::Object::DynamicSlot &currSlot = *s; + + if (methodNames.testAndSet(currSlot.name.hash())) { + for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2; + s2 = obj->dynamicSignals.next(s2)) { + if (s2->name == currSlot.name) + COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name")); + } + for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s; + s2 = obj->dynamicSlots.next(s2)) { + if (s2->name == currSlot.name) + COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name")); + } + } + + if (currSlot.name.at(0).isUpper()) + COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter")); + if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name)) + COMPILE_EXCEPTION(&currSlot, tr("Illegal method name")); } return true; } -bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj) +bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj) { - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) + if (!p->defaultValue || p->type == Object::DynamicProperty::Alias) continue; Property *property = 0; - if (p.isDefaultProperty) { + if (p->isDefaultProperty) { property = obj->getDefaultProperty(); } else { - property = obj->getProperty(p.name); + property = obj->getProperty(p->name); if (!property->values.isEmpty()) COMPILE_EXCEPTION(property, tr("Property value set multiple times")); } + if (p->isReadOnly) + property->isReadOnlyDeclaration = true; + if (property->value) COMPILE_EXCEPTION(property, tr("Invalid property nesting")); - for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { - QDeclarativeParser::Value *v = p.defaultValue->values.at(ii); - v->addref(); - property->values.append(v); - } + property->values.append(p->defaultValue->values); } return true; } Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) -bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode) +bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode) { Q_ASSERT(obj); Q_ASSERT(obj->metatype); @@ -2436,61 +2769,125 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn obj->dynamicSlots.isEmpty()) return true; - QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0); + bool resolveAlias = (mode == ResolveAliases); + + const Object::DynamicProperty *defaultProperty = 0; + int aliasCount = 0; + int varPropCount = 0; + int totalPropCount = 0; + int firstPropertyVarIndex = 0; + + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + + if (p->type == Object::DynamicProperty::Alias) + aliasCount++; + if (p->type == Object::DynamicProperty::Var) + varPropCount++; + + if (p->isDefaultProperty && + (resolveAlias || p->type != Object::DynamicProperty::Alias)) + defaultProperty = p; + + if (!resolveAlias) { + // No point doing this for both the alias and non alias cases + QDeclarativePropertyData *d = property(obj, p->name); + if (d && d->isFinal()) + COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); + } + } + + bool buildData = resolveAlias || aliasCount == 0; + + QByteArray dynamicData; + if (buildData) { + typedef QDeclarativeVMEMetaData VMD; + + dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) + + (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) + + obj->dynamicSlots.count() * sizeof(VMD::MethodData) + + aliasCount * sizeof(VMD::AliasData), 0); + } + + int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1); QByteArray newClassName = obj->metatype->className(); newClassName.append("_QML_"); - int idx = classIndexCounter()->fetchAndAddRelaxed(1); - newClassName.append(QByteArray::number(idx)); - if (compileState.root == obj && !compileState.nested) { + newClassName.append(QByteArray::number(uniqueClassId)); + + if (compileState->root == obj && !compileState->nested) { QString path = output->url.path(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash > -1) { QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) - newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx); - } - } - - QMetaObjectBuilder builder; - builder.setClassName(newClassName); - builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); - - bool hasAlias = false; - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId); + } + } + + QFastMetaBuilder builder; + QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(), + obj->dynamicProperties.count() - (resolveAlias?0:aliasCount), + obj->dynamicSlots.count(), + obj->dynamicSignals.count() + obj->dynamicProperties.count(), + defaultProperty?1:0); + + struct TypeData { + Object::DynamicProperty::Type dtype; + int metaType; + const char *cppType; + } builtinTypes[] = { + { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" }, + { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" }, + { Object::DynamicProperty::Int, QMetaType::Int, "int" }, + { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" }, + { Object::DynamicProperty::Real, QMetaType::Double, "double" }, + { Object::DynamicProperty::String, QMetaType::QString, "QString" }, + { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" }, + { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" }, + { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" }, + { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" }, + { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" }, + }; + static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); + QFastMetaBuilder::StringRef typeRefs[builtinTypeCount]; + + // Reserve dynamic properties + if (obj->dynamicProperties.count()) { + typedef QDeclarativeVMEMetaData VMD; + + int effectivePropertyIndex = 0; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + + // Reserve space for name + p->nameRef = builder.newString(p->name.utf8length()); + + int propertyType = 0; + bool readonly = false; + QFastMetaBuilder::StringRef typeRef; + + if (p->type == Object::DynamicProperty::Alias) { + continue; + } else if (p->type < builtinTypeCount) { + Q_ASSERT(builtinTypes[p->type].dtype == p->type); + propertyType = builtinTypes[p->type].metaType; + if (typeRefs[p->type].isEmpty()) + typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType)); + typeRef = typeRefs[p->type]; - int propIdx = obj->metaObject()->indexOfProperty(p.name.constData()); - if (-1 != propIdx) { - QMetaProperty prop = obj->metaObject()->property(propIdx); - if (prop.isFinal()) - COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property")); - } + } else { + Q_ASSERT(p->type == Object::DynamicProperty::CustomList || + p->type == Object::DynamicProperty::Custom); - if (p.isDefaultProperty && - (p.type != Object::DynamicProperty::Alias || - mode == ResolveAliases)) - builder.addClassInfo("DefaultProperty", p.name); + // XXX don't double resolve this in the case of an alias run - QByteArray type; - int propertyType = 0; - bool readonly = false; - switch(p.type) { - case Object::DynamicProperty::Alias: - hasAlias = true; - continue; - break; - case Object::DynamicProperty::CustomList: - case Object::DynamicProperty::Custom: - { QByteArray customTypeName; QDeclarativeType *qmltype = 0; - QUrl url; - if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0)) - COMPILE_EXCEPTION(&p, tr("Invalid property type")); + QString url; + if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0)) + COMPILE_EXCEPTION(p, tr("Invalid property type")); if (!qmltype) { - QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url); + QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url)); Q_ASSERT(tdata); Q_ASSERT(tdata->isComplete()); @@ -2502,146 +2899,250 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn customTypeName = qmltype->typeName(); } - if (p.type == Object::DynamicProperty::Custom) { - type = customTypeName + '*'; + if (p->type == Object::DynamicProperty::Custom) { + customTypeName += '*'; propertyType = QMetaType::QObjectStar; } else { readonly = true; - type = "QDeclarativeListProperty<"; - type.append(customTypeName); - type.append(">"); + customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">"); propertyType = qMetaTypeId >(); } + + p->resolvedCustomTypeName = pool->NewByteArray(customTypeName); + p->typeRef = builder.newString(customTypeName.length()); + typeRef = p->typeRef; + } + + if (p->type == Object::DynamicProperty::Var) + continue; + + if (p->isReadOnly) + readonly = true; + + if (buildData) { + VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data(); + vmd->propertyCount++; + (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType; + } + + if (p->type < builtinTypeCount) + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + else + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + + p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + + effectivePropertyIndex++; + } + + if (varPropCount) { + VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data(); + if (buildData) + vmd->varPropertyCount = varPropCount; + firstPropertyVarIndex = effectivePropertyIndex; + totalPropCount = varPropCount + effectivePropertyIndex; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (p->type == Object::DynamicProperty::Var) { + QFastMetaBuilder::StringRef typeRef = typeRefs[p->type]; + if (buildData) { + vmd->propertyCount++; + (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant; + } + + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, + QMetaType::QVariant, + p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + + p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + + effectivePropertyIndex++; + } + } + } + + if (aliasCount) { + int aliasIndex = 0; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (p->type == Object::DynamicProperty::Alias) { + if (resolveAlias) { + Q_ASSERT(buildData); + ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++; + COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, + aliasIndex, *p)); + } + // Even if we aren't resolving the alias, we need a fake signal so that the + // metaobject remains consistent across the resolve and non-resolve alias runs + p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + effectivePropertyIndex++; + aliasIndex++; + } } - break; - case Object::DynamicProperty::Variant: - propertyType = -1; - type = "QVariant"; - break; - case Object::DynamicProperty::Int: - propertyType = QVariant::Int; - type = "int"; - break; - case Object::DynamicProperty::Bool: - propertyType = QVariant::Bool; - type = "bool"; - break; - case Object::DynamicProperty::Real: - propertyType = QVariant::Double; - type = "double"; - break; - case Object::DynamicProperty::String: - propertyType = QVariant::String; - type = "QString"; - break; - case Object::DynamicProperty::Url: - propertyType = QVariant::Url; - type = "QUrl"; - break; - case Object::DynamicProperty::Color: - propertyType = QVariant::Color; - type = "QColor"; - break; - case Object::DynamicProperty::Time: - propertyType = QVariant::Time; - type = "QTime"; - break; - case Object::DynamicProperty::Date: - propertyType = QVariant::Date; - type = "QDate"; - break; - case Object::DynamicProperty::DateTime: - propertyType = QVariant::DateTime; - type = "QDateTime"; - break; } + } + + // Reserve default property + QFastMetaBuilder::StringRef defPropRef; + if (defaultProperty) { + defPropRef = builder.newString(strlen("DefaultProperty")); + builder.setClassInfo(0, defPropRef, defaultProperty->nameRef); + } + + // Reserve dynamic signals + int signalIndex = 0; + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + + int paramCount = s->parameterNames.count(); + + int signatureSize = s->name.utf8length() + 2 /* paren */; + int namesSize = 0; + if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */; + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */; - ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++; - QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType }; - dynamicData.append((char *)&propertyData, sizeof(propertyData)); + s->signatureRef = builder.newString(signatureSize); + if (namesSize) s->parameterNamesRef = builder.newString(namesSize); - builder.addSignal(p.name + "Changed()"); - QMetaPropertyBuilder propBuilder = - builder.addProperty(p.name, type, builder.methodCount() - 1); - propBuilder.setWritable(!readonly); + if (buildData) + ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++; + + builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef); + ++signalIndex; } - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + // Reserve dynamic slots + if (obj->dynamicSlots.count()) { - if (p.type == Object::DynamicProperty::Alias) { - if (mode == ResolveAliases) { - ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++; - COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p)); - } else { - // Need a fake signal so that the metaobject remains consistent across - // the resolve and non-resolve alias runs - builder.addSignal(p.name + "Changed()"); + // Allocate QVariant string + if (typeRefs[0].isEmpty()) + typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType)); + + typedef QDeclarativeVMEMetaData VMD; + + int methodIndex = 0; + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + int paramCount = s->parameterNames.count(); + + int signatureSize = s->name.utf8length() + 2 /* paren */; + int namesSize = 0; + if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1)); + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); + + s->signatureRef = builder.newString(signatureSize); + if (namesSize) s->parameterNamesRef = builder.newString(namesSize); + + builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]); + + if (buildData) { + QString funcScript; + funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + + namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); + funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('('); + for (int jj = 0; jj < paramCount; ++jj) { + if (jj) funcScript.append(QLatin1Char(',')); + funcScript.append(QLatin1String(s->parameterNames.at(jj))); + } + funcScript += QLatin1Char(')') + s->body + QLatin1Char(')'); + + VMD::MethodData methodData = { s->parameterNames.count(), 0, + funcScript.length(), + s->location.start.line }; + + VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data(); + vmd->methodCount++; + + VMD::MethodData &md = *(vmd->methodData() + methodIndex); + md = methodData; + md.bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)funcScript.constData(), + (funcScript.length() * sizeof(QChar))); } - } - } - for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { - const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); - QByteArray sig(s.name + '('); - for (int jj = 0; jj < s.parameterTypes.count(); ++jj) { - if (jj) sig.append(','); - sig.append(s.parameterTypes.at(jj)); + methodIndex++; } - sig.append(')'); - QMetaMethodBuilder b = builder.addSignal(sig); - b.setParameterNames(s.parameterNames); - ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++; } - QStringList funcScripts; + // Now allocate used builtin types + for (int ii = 0; ii < builtinTypeCount; ++ii) { + if (!typeRefs[ii].isEmpty()) + typeRefs[ii].load(builtinTypes[ii].cppType); + } - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { - Object::DynamicSlot &s = obj->dynamicSlots[ii]; - QByteArray sig(s.name + '('); - QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('(')); + // Now allocate properties + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - for (int jj = 0; jj < s.parameterNames.count(); ++jj) { - if (jj) { - sig.append(','); - funcScript.append(QLatin1Char(',')); - } - funcScript.append(QLatin1String(s.parameterNames.at(jj))); - sig.append("QVariant"); - } - sig.append(')'); - funcScript.append(QLatin1Char(')')); - funcScript.append(s.body); - funcScript.append(QLatin1Char(')')); - funcScripts << funcScript; + char *d = p->changedSignatureRef.data(); + p->name.writeUtf8(d); + strcpy(d + p->name.utf8length(), "Changed()"); - QMetaMethodBuilder b = builder.addSlot(sig); - b.setReturnType("QVariant"); - b.setParameterNames(s.parameterNames); + if (p->type == Object::DynamicProperty::Alias && !resolveAlias) + continue; - ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++; - QDeclarativeVMEMetaData::MethodData methodData = - { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line }; + p->nameRef.load(p->name); - dynamicData.append((char *)&methodData, sizeof(methodData)); + if (p->type >= builtinTypeCount) { + Q_ASSERT(p->resolvedCustomTypeName); + p->typeRef.load(*p->resolvedCustomTypeName); + } } - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { - const QString &funcScript = funcScripts.at(ii); - QDeclarativeVMEMetaData::MethodData *data = - ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii; + // Allocate default property if necessary + if (defaultProperty) + strcpy(defPropRef.data(), "DefaultProperty"); + + // Now allocate signals + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { - data->bodyOffset = dynamicData.size(); + char *d = s->signatureRef.data(); + char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data(); + s->name.writeUtf8(d); d += s->name.utf8length(); + *d++ = '('; + + for (int jj = 0; jj < s->parameterNames.count(); ++jj) { + if (jj != 0) { *d++ = ','; *d2++ = ','; } + strcpy(d, s->parameterTypes.at(jj).constData()); + d += s->parameterTypes.at(jj).length(); + s->parameterNames.at(jj).writeUtf8(d2); + d2 += s->parameterNames.at(jj).utf8length(); + } + *d++ = ')'; + *d = 0; + if (d2) *d2 = 0; + } - dynamicData.append((const char *)funcScript.constData(), - (funcScript.length() * sizeof(QChar))); + // Now allocate methods + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + char *d = s->signatureRef.data(); + char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data(); + s->name.writeUtf8(d); d += s->name.utf8length(); + *d++ = '('; + for (int jj = 0; jj < s->parameterNames.count(); ++jj) { + if (jj != 0) { *d++ = ','; *d2++ = ','; } + strcpy(d, "QVariant"); + d += strlen("QVariant"); + strcpy(d2, s->parameterNames.at(jj).constData()); + d2 += s->parameterNames.at(jj).length(); + } + *d++ = ')'; + *d = 0; + if (d2) *d2 = 0; } - obj->metadata = builder.toRelocatableData(); - builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); + // Now allocate class name + classNameRef.load(newClassName); + + obj->metadata = builder.toData(); + builder.fromData(&obj->extObject, obj->metatype, obj->metadata); - if (mode == IgnoreAliases && hasAlias) - compileState.aliasingObjects << obj; + if (mode == IgnoreAliases && aliasCount) + compileState->aliasingObjects.append(obj); obj->synthdata = dynamicData; @@ -2651,48 +3152,59 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn } if (obj->type != -1) { - QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy(); - cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags, - QDeclarativePropertyCache::Data::IsVMEFunction, - QDeclarativePropertyCache::Data::IsVMESignal); + QDeclarativePropertyCache *superCache = output->types[obj->type].createPropertyCache(engine); + QDeclarativePropertyCache *cache = + superCache->copyAndAppend(engine, &obj->extObject, + QDeclarativePropertyData::NoFlags, + QDeclarativePropertyData::IsVMEFunction, + QDeclarativePropertyData::IsVMESignal); + + // now we modify the flags appropriately for var properties. + int propertyOffset = obj->extObject.propertyOffset(); + QDeclarativePropertyData *currPropData = 0; + for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) { + currPropData = cache->property(pvi + propertyOffset); + currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty); + } + obj->synthCache = cache; } return true; } -bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val) +bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val) { if (val.isEmpty()) COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); - if (val.at(0).isLetter() && !val.at(0).isLower()) + QChar ch = val.at(0); + if (ch.isLetter() && !ch.isLower()) COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); QChar u(QLatin1Char('_')); - for (int ii = 0; ii < val.count(); ++ii) { + if (!ch.isLetter() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); - if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) { - COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); - } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) { + for (int ii = 1; ii < val.count(); ++ii) { + ch = val.at(ii); + if (!ch.isLetterOrNumber() && ch != u) COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); - } - } - if (enginePrivate->v8engine.illegalNames().contains(val)) + if (enginePrivate->v8engine()->illegalNames().contains(val)) COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); return true; } -#include +#include static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) { if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) { QString name = - static_cast(node)->name->asString(); + static_cast(node)->name.toString(); return QStringList() << name; } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) { QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast(node); @@ -2700,26 +3212,27 @@ static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) QStringList rv = astNodeToStringList(expr->base); if (rv.isEmpty()) return rv; - rv.append(expr->name->asString()); + rv.append(expr->name.toString()); return rv; } return QStringList(); } -bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, +bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder, QByteArray &data, - QDeclarativeParser::Object *obj, - const Object::DynamicProperty &prop) + QDeclarativeScript::Object *obj, + int propIndex, int aliasIndex, + Object::DynamicProperty &prop) { if (!prop.defaultValue) COMPILE_EXCEPTION(obj, tr("No property alias location")); - if (prop.defaultValue->values.count() != 1 || - prop.defaultValue->values.at(0)->object || - !prop.defaultValue->values.at(0)->value.isScript()) + if (!prop.defaultValue->values.isOne() || + prop.defaultValue->values.first()->object || + !prop.defaultValue->values.first()->value.isScript()) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); + QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST(); if (!node) COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen? @@ -2728,18 +3241,19 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, if (alias.count() < 1 || alias.count() > 3) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as , . or ..")); - if (!compileState.ids.contains(alias.at(0))) + QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0)); + if (!idObject) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); - QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)]; - QByteArray typeName; int propIdx = -1; int flags = 0; + int type = 0; bool writable = false; + bool resettable = false; if (alias.count() == 2 || alias.count() == 3) { - propIdx = indexOfProperty(idObject, alias.at(1).toUtf8()); + propIdx = indexOfProperty(idObject, alias.at(1)); if (-1 == propIdx) { COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); @@ -2751,7 +3265,12 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, if (!aliasProperty.isScriptable()) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - writable = aliasProperty.isWritable(); + writable = aliasProperty.isWritable() && !prop.isReadOnly; + resettable = aliasProperty.isResettable() && !prop.isReadOnly; + + if (aliasProperty.type() < QVariant::UserType + || uint(aliasProperty.type()) == QMetaType::QVariant) + type = aliasProperty.type(); if (alias.count() == 3) { QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; @@ -2767,6 +3286,11 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, aliasProperty = valueType->metaObject()->property(valueTypeIndex); propIdx |= (valueTypeIndex << 16); + + // update the property type + type = aliasProperty.type(); + if (type >= (int)QVariant::UserType) + type = 0; } if (aliasProperty.isEnumType()) @@ -2774,21 +3298,13 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, else typeName = aliasProperty.typeName(); } else { - typeName = idObject->metaObject()->className(); + Q_ASSERT(idObject->type != -1); // How else did it get an id? - //use the base type since it has been registered with metatype system - int index = typeName.indexOf("_QML_"); - if (index != -1) { - typeName = typeName.left(index); - } else { - index = typeName.indexOf("_QMLTYPE_"); - const QMetaObject *mo = idObject->metaObject(); - while (index != -1 && mo) { - typeName = mo->superClass()->className(); - index = typeName.indexOf("_QMLTYPE_"); - mo = mo->superClass(); - } - } + const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type); + if (ref.type) + typeName = ref.type->typeName(); + else + typeName = ref.component->root->className(); typeName += '*'; } @@ -2796,159 +3312,270 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, if (typeName.endsWith('*')) flags |= QML_ALIAS_FLAG_PTR; - data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); - data.append((const char *)&propIdx, sizeof(propIdx)); - data.append((const char *)&flags, sizeof(flags)); + QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags }; + + typedef QDeclarativeVMEMetaData VMD; + VMD *vmd = (QDeclarativeVMEMetaData *)data.data(); + *(vmd->aliasData() + aliasIndex) = aliasData; + + prop.nameRef = builder.newString(prop.name.utf8length()); + prop.resolvedCustomTypeName = pool->NewByteArray(typeName); + prop.typeRef = builder.newString(typeName.length()); + + int propertyFlags = 0; + if (writable) + propertyFlags |= QFastMetaBuilder::Writable; + if (resettable) + propertyFlags |= QFastMetaBuilder::Resettable; + + builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type, + (QFastMetaBuilder::PropertyFlag)propertyFlags, + propIndex); - builder.addSignal(prop.name + "Changed()"); - QMetaPropertyBuilder propBuilder = - builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1); - propBuilder.setWritable(writable); return true; } -bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value, - QDeclarativeParser::Property *prop, - const BindingContext &ctxt) +bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value, + QDeclarativeScript::Property *prop, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); Q_ASSERT(prop->parent); Q_ASSERT(prop->parent->metaObject()); - QMetaProperty mp = prop->parent->metaObject()->property(prop->index); - if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type)) - COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); - BindingReference reference; - reference.expression = value->value; - reference.property = prop; - reference.value = value; - reference.bindingContext = ctxt; + JSBindingReference *reference = pool->New(); + reference->expression = value->value; + reference->property = prop; + reference->value = value; + reference->bindingContext = ctxt; addBindingReference(reference); return true; } -void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding, - QDeclarativeParser::Property *prop, - QDeclarativeParser::Object *obj, - QDeclarativeParser::Property *valueTypeProperty) +bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v, + QDeclarativeScript::Property *prop, + const QDeclarativeCompilerTypes::BindingContext &) +{ + Q_ASSERT(v->value.isScript()); + + if (!prop->core.isWritable()) + return false; + + AST::Node *binding = v->value.asAST(); + + if (prop->type == QVariant::String) { + if (AST::CallExpression *e = AST::cast(binding)) { + if (AST::IdentifierExpression *i = AST::cast(e->base)) { + if (i->name == qsTrId_string) { + AST::ArgumentList *arg1 = e->arguments?e->arguments:0; + AST::ArgumentList *arg2 = arg1?arg1->next:0; + + if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral && + (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) && + (!arg2 || !arg2->next)) { + + QStringRef text; + int n = -1; + + text = AST::cast(arg1->expression)->value; + if (arg2) n = (int)AST::cast(arg2->expression)->value; + + TrBindingReference *reference = pool->New(); + reference->dataType = BindingReference::TrId; + reference->text = text; + reference->n = n; + v->bindingReference = reference; + return true; + } + + } else if (i->name == qsTr_string) { + + AST::ArgumentList *arg1 = e->arguments?e->arguments:0; + AST::ArgumentList *arg2 = arg1?arg1->next:0; + AST::ArgumentList *arg3 = arg2?arg2->next:0; + + if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral && + (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) && + (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) && + (!arg3 || !arg3->next)) { + + QStringRef text; + QStringRef comment; + int n = -1; + + text = AST::cast(arg1->expression)->value; + if (arg2) comment = AST::cast(arg2->expression)->value; + if (arg3) n = (int)AST::cast(arg3->expression)->value; + + TrBindingReference *reference = pool->New(); + reference->dataType = BindingReference::Tr; + reference->text = text; + reference->comment = comment; + reference->n = n; + v->bindingReference = reference; + return true; + } + + } + } + } + + } + + return false; +} + +void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding, + QDeclarativeScript::Property *prop, + QDeclarativeScript::Object *obj, + QDeclarativeScript::Property *valueTypeProperty) { Q_UNUSED(obj); - Q_ASSERT(compileState.bindings.contains(binding)); + Q_ASSERT(binding->bindingReference); - const BindingReference &ref = compileState.bindings.value(binding); - if (ref.dataType == BindingReference::V4) { - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreV4Binding); - store.assignBinding.value = ref.compiledIndex; - store.assignBinding.context = ref.bindingContext.stack; - store.assignBinding.owner = ref.bindingContext.owner; - if (valueTypeProperty) - store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) | - ((valueTypeProperty->type & 0xFF)) << 16 | - ((prop->index & 0xFF) << 24); - else - store.assignBinding.property = prop->index; - store.assignBinding.line = binding->location.start.line; + const BindingReference &ref = *binding->bindingReference; + if (ref.dataType == BindingReference::TrId) { + const TrBindingReference &tr = static_cast(ref); + + Instruction::StoreTrIdString store; + store.propertyIndex = prop->core.coreIndex; + store.text = output->indexForByteArray(tr.text.toUtf8()); + store.n = tr.n; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::Tr) { + const TrBindingReference &tr = static_cast(ref); + + Instruction::StoreTrString store; + store.propertyIndex = prop->core.coreIndex; + store.context = translationContextIndex(); + store.text = output->indexForByteArray(tr.text.toUtf8()); + store.comment = output->indexForByteArray(tr.comment.toUtf8()); + store.n = tr.n; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::V4) { + const JSBindingReference &js = static_cast(ref); + + Instruction::StoreV4Binding store; + store.value = js.compiledIndex; + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; + if (valueTypeProperty) { + store.property = (valueTypeProperty->index & 0xFFFF) | + ((valueTypeProperty->type & 0xFF)) << 16 | + ((prop->index & 0xFF) << 24); + store.isRoot = (compileState->root == valueTypeProperty->parent); + } else { + store.property = prop->index; + store.isRoot = (compileState->root == obj); + } + store.line = binding->location.start.line; + store.column = binding->location.start.column; output->addInstruction(store); } else if (ref.dataType == BindingReference::V8) { - QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreV8Binding); - store.assignBinding.value = ref.compiledIndex; - store.assignBinding.context = ref.bindingContext.stack; - store.assignBinding.owner = ref.bindingContext.owner; - store.assignBinding.line = binding->location.start.line; + const JSBindingReference &js = static_cast(ref); + + Instruction::StoreV8Binding store; + store.value = js.compiledIndex; + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; + if (valueTypeProperty) { + store.isRoot = (compileState->root == valueTypeProperty->parent); + } else { + store.isRoot = (compileState->root == obj); + } + store.line = binding->location.start.line; + store.column = binding->location.start.column; - Q_ASSERT(ref.bindingContext.owner == 0 || - (ref.bindingContext.owner != 0 && valueTypeProperty)); - if (ref.bindingContext.owner) { - store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + Q_ASSERT(js.bindingContext.owner == 0 || + (js.bindingContext.owner != 0 && valueTypeProperty)); + if (js.bindingContext.owner) { + store.property = genValueTypeData(prop, valueTypeProperty); } else { - store.assignBinding.property = genPropertyData(prop); + store.property = prop->core; } output->addInstruction(store); - } else { + } else if (ref.dataType == BindingReference::QtScript) { + const JSBindingReference &js = static_cast(ref); + QDeclarativeInstruction store; - if (!prop->isAlias) - store.setType(QDeclarativeInstruction::StoreBinding); - else - store.setType(QDeclarativeInstruction::StoreBindingOnAlias); - store.assignBinding.value = output->indexForString(ref.rewrittenExpression); - store.assignBinding.context = ref.bindingContext.stack; - store.assignBinding.owner = ref.bindingContext.owner; + store.assignBinding.value = output->indexForString(js.rewrittenExpression); + store.assignBinding.context = js.bindingContext.stack; + store.assignBinding.owner = js.bindingContext.owner; store.assignBinding.line = binding->location.start.line; + store.assignBinding.column = binding->location.start.column; - Q_ASSERT(ref.bindingContext.owner == 0 || - (ref.bindingContext.owner != 0 && valueTypeProperty)); - if (ref.bindingContext.owner) { + if (valueTypeProperty) { + store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent); + } else { + store.assignBinding.isRoot = (compileState->root == obj); + } + + Q_ASSERT(js.bindingContext.owner == 0 || + (js.bindingContext.owner != 0 && valueTypeProperty)); + if (js.bindingContext.owner) { store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); } else { - store.assignBinding.property = genPropertyData(prop); + store.assignBinding.property = prop->core; } - output->addInstruction(store); + output->addInstructionHelper( + !prop->isAlias ? QDeclarativeInstruction::StoreBinding + : QDeclarativeInstruction::StoreBindingOnAlias + , store); + } else { + Q_ASSERT(!"Unhandled BindingReference::DataType type"); } } int QDeclarativeCompiler::genContextCache() { - if (compileState.ids.count() == 0) + if (compileState->ids.count() == 0) return -1; QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(); - - for (QHash::ConstIterator iter = compileState.ids.begin(); - iter != compileState.ids.end(); - ++iter) - cache->add(iter.key(), (*iter)->idIndex); + cache->reserve(compileState->ids.count()); + for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) + cache->add(o->id, o->idIndex); output->contextCaches.append(cache); return output->contextCaches.count() - 1; } -int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp, - QDeclarativeParser::Property *prop) +QDeclarativePropertyData +QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp, + QDeclarativeScript::Property *prop) { typedef QDeclarativePropertyPrivate QDPP; - QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index, - enginePrivate->valueTypes[prop->type]->metaObject(), - valueTypeProp->index, engine); - - return output->indexForByteArray(data); -} - -int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop) -{ - typedef QDeclarativePropertyPrivate QDPP; - QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine); - - return output->indexForByteArray(data); + return QDPP::saveValueType(prop->parent->metaObject(), prop->index, + enginePrivate->valueTypes[prop->type]->metaObject(), + valueTypeProp->index, engine); } bool QDeclarativeCompiler::completeComponentBuild() { - componentStat.ids = compileState.ids.count(); + if (componentStats) + componentStats->componentStat.ids = compileState->ids.count(); - for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { - QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii); + for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; + aliasObject = compileState->aliasingObjects.next(aliasObject)) COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); - } - QDeclarativeV4Compiler::Expression expr; - expr.component = compileState.root; - expr.ids = compileState.ids; + QV4Compiler::Expression expr(unit->imports()); + expr.component = compileState->root; + expr.ids = &compileState->ids; expr.importCache = output->importCache; - expr.imports = unit->imports(); - QDeclarativeV4Compiler bindingCompiler; + QV4Compiler bindingCompiler; - QList sharedBindings; + QList sharedBindings; - for (QHash::Iterator iter = compileState.bindings.begin(); - iter != compileState.bindings.end(); ++iter) { + for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { - BindingReference &binding = *iter; + JSBindingReference &binding = *b; // ### We don't currently optimize for bindings on alias's - because // of the solution to QTBUG-13719 @@ -2961,7 +3588,8 @@ bool QDeclarativeCompiler::completeComponentBuild() if (index != -1) { binding.dataType = BindingReference::V4; binding.compiledIndex = index; - componentStat.optimizedBindings.append(iter.key()->location); + if (componentStats) + componentStats->componentStat.optimizedBindings.append(b->value->location); continue; } } @@ -2970,24 +3598,25 @@ bool QDeclarativeCompiler::completeComponentBuild() QString expression = binding.expression.asScript(); QDeclarativeRewrite::RewriteBinding rewriteBinding; - rewriteBinding.setName('$'+binding.property->name); + rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString()); bool isSharable = false; binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); if (isSharable && !binding.property->isAlias /* See above re alias */ && binding.property->type != qMetaTypeId()) { binding.dataType = BindingReference::V8; - sharedBindings.append(&iter.value()); + sharedBindings.append(b); } else { binding.dataType = BindingReference::QtScript; } - componentStat.scriptBindings.append(iter.key()->location); + if (componentStats) + componentStats->componentStat.scriptBindings.append(b->value->location); } if (!sharedBindings.isEmpty()) { struct Sort { - static bool lt(const BindingReference *lhs, const BindingReference *rhs) + static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs) { return lhs->value->location.start.line < rhs->value->location.start.line; } @@ -3000,8 +3629,8 @@ bool QDeclarativeCompiler::completeComponentBuild() QString functionArray(QLatin1String("[")); for (int ii = 0; ii < sharedBindings.count(); ++ii) { - BindingReference *reference = sharedBindings.at(ii); - QDeclarativeParser::Value *value = reference->value; + JSBindingReference *reference = sharedBindings.at(ii); + QDeclarativeScript::Value *value = reference->value; const QString &expression = reference->rewrittenExpression; if (ii != 0) functionArray += QLatin1String(","); @@ -3012,18 +3641,23 @@ bool QDeclarativeCompiler::completeComponentBuild() } functionArray += expression; + lineNumber += expression.count(QLatin1Char('\n')); reference->compiledIndex = ii; } functionArray += QLatin1String("]"); - compileState.v8BindingProgram = functionArray; - compileState.v8BindingProgramLine = startLineNumber; - compileState.v8BindingProgramIndex = output->v8bindings.count(); + compileState->v8BindingProgram = functionArray; + compileState->v8BindingProgramLine = startLineNumber; + compileState->v8BindingProgramIndex = output->v8bindings.count(); output->v8bindings.append(v8::Persistent()); } if (bindingCompiler.isValid()) - compileState.compiledBindingData = bindingCompiler.program(); + compileState->compiledBindingData = bindingCompiler.program(); + + // Check pop()'s matched push()'s + Q_ASSERT(compileState->objectDepth.depth() == 0); + Q_ASSERT(compileState->listDepth.depth() == 0); saveComponentState(); @@ -3032,9 +3666,10 @@ bool QDeclarativeCompiler::completeComponentBuild() void QDeclarativeCompiler::dumpStats() { + Q_ASSERT(componentStats); qWarning().nospace() << "QML Document: " << output->url.toString(); - for (int ii = 0; ii < savedComponentStats.count(); ++ii) { - const ComponentStat &stat = savedComponentStats.at(ii); + for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) { + const ComponentStat &stat = componentStats->savedComponentStats.at(ii); qWarning().nospace() << " Component Line " << stat.lineNumber; qWarning().nospace() << " Total Objects: " << stat.objects; qWarning().nospace() << " IDs Used: " << stat.ids; @@ -3083,10 +3718,9 @@ void QDeclarativeCompiler::dumpStats() Returns true if from can be assigned to a (QObject) property of type to. */ -bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from) +bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from) { - const QMetaObject *toMo = - enginePrivate->rawMetaObjectForType(to); + const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to); const QMetaObject *fromMo = from->metaObject(); while (fromMo) { @@ -3097,7 +3731,20 @@ bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from) return false; } -QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from) +/*! + Returns the element name, as written in the QML file, for o. +*/ +QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o) +{ + Q_ASSERT(o); + if (o->type != -1) { + return output->types.at(o->type).className; + } else { + return QString(); + } +} + +QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from) { // ### Optimize const QMetaObject *mo = from->metatype; @@ -3109,7 +3756,7 @@ QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *fr return type; } -QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj) +QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj) { const QMetaObject *mo = obj->metatype; @@ -3122,74 +3769,108 @@ QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object return rv; } -// This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName -int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name, - bool *notInRevision) +QDeclarativePropertyData * +QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index) { - if (notInRevision) *notInRevision = false; + QDeclarativePropertyCache *cache = 0; - if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) { - // XXX fromUtf8 - QString strName(QString::fromUtf8(name)); - QDeclarativePropertyCache *cache = - object->synthCache?object->synthCache:output->types.at(object->type).propertyCache(); + if (object->synthCache) + cache = object->synthCache; + else if (object->type != -1) + cache = output->types[object->type].createPropertyCache(engine); + else + cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject()); - QDeclarativePropertyCache::Data *d = cache->property(strName); - if (notInRevision) *notInRevision = false; + return cache->property(index); +} - while (d && !(d->isFunction())) - d = cache->overrideData(d); +QDeclarativePropertyData * +QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; - if (d && !cache->isAllowedInRevision(d)) { - if (notInRevision) *notInRevision = true; - return -1; - } else if (d) { - return d->coreIndex; - } + QDeclarativePropertyCache *cache = 0; - if (name.endsWith("Changed")) { - QByteArray propName = name.mid(0, name.length() - 7); + if (object->synthCache) + cache = object->synthCache; + else if (object->type != -1) + cache = output->types[object->type].createPropertyCache(engine); + else + cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject()); - int propIndex = indexOfProperty(object, propName, notInRevision); - if (propIndex != -1) { - d = cache->property(propIndex); - return d->notifyIndex; - } - } + QDeclarativePropertyData *d = cache->property(name); - return -1; + // Find the first property + while (d && d->isFunction()) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return 0; } else { - return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex(); + return d; } - } -int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name, - bool *notInRevision) +// This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName +QDeclarativePropertyData * +QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision) { if (notInRevision) *notInRevision = false; - if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) { - // XXX fromUtf8 - QString strName(QString::fromUtf8(name)); - QDeclarativePropertyCache *cache = - object->synthCache?object->synthCache:output->types.at(object->type).propertyCache(); + QDeclarativePropertyCache *cache = 0; - QDeclarativePropertyCache::Data *d = cache->property(strName); - // Find the first property - while (d && d->isFunction()) - d = cache->overrideData(d); + if (object->synthCache) + cache = object->synthCache; + else if (object->type != -1) + cache = output->types[object->type].createPropertyCache(engine); + else + cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject()); - if (d && !cache->isAllowedInRevision(d)) { - if (notInRevision) *notInRevision = true; - return -1; - } else { - return d?d->coreIndex:-1; - } - } else { - const QMetaObject *mo = object->metaObject(); - return mo->indexOfProperty(name.constData()); + + QDeclarativePropertyData *d = cache->property(name); + if (notInRevision) *notInRevision = false; + + while (d && !(d->isFunction())) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return 0; + } else if (d) { + return d; + } + + if (name.endsWith(Changed_string)) { + QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length()); + + d = property(object, propName, notInRevision); + if (d) + return cache->method(d->notifyIndex); } + + return 0; +} + +// This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName +int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name, + bool *notInRevision) +{ + QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision); + return d?d->coreIndex:-1; +} + +int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name, + bool *notInRevision) +{ + return indexOfProperty(object, QStringRef(&name), notInRevision); +} + +int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name, + bool *notInRevision) +{ + QDeclarativePropertyData *d = property(object, name, notInRevision); + return d?d->coreIndex:-1; } QT_END_NAMESPACE