From 99efe4309379482fce5c231885883e359bf85290 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 6 Mar 2014 16:55:09 +0100 Subject: Remove old compiler and VME This removes the bulk of the code. A few smaller cleanups remain, to be done in smaller changes as they move code around. Additionally the "optimize" option of qqmlbundle was removed. It called QQmlScript::Parser::preparseData, which however was not implemented and always returned an empty QByteArray. Therefore "optimize" would not do anything and the class is gone now :) Change-Id: I0c265e756704cb53c5250be1f69e4a3e1b6e64d5 Reviewed-by: Lars Knoll --- src/qml/qml/qml.pri | 4 - src/qml/qml/qqmlcompileddata.cpp | 102 - src/qml/qml/qqmlcompiler.cpp | 3922 ---------------------------------- src/qml/qml/qqmlcompiler_p.h | 348 --- src/qml/qml/qqmlcomponent.cpp | 51 +- src/qml/qml/qqmlcomponent_p.h | 4 - src/qml/qml/qqmlcustomparser.cpp | 189 -- src/qml/qml/qqmlcustomparser_p.h | 60 +- src/qml/qml/qqmlcustomparser_p_p.h | 89 - src/qml/qml/qqmlengine.cpp | 6 +- src/qml/qml/qqmlengine_p.h | 5 - src/qml/qml/qqmlincubator.cpp | 28 +- src/qml/qml/qqmlincubator_p.h | 4 - src/qml/qml/qqmlinstruction.cpp | 283 --- src/qml/qml/qqmlinstruction_p.h | 560 ----- src/qml/qml/qqmlscript.cpp | 1415 +----------- src/qml/qml/qqmlscript_p.h | 365 ---- src/qml/qml/qqmlstringconverters.cpp | 1 - src/qml/qml/qqmltypeloader.cpp | 113 +- src/qml/qml/qqmltypeloader_p.h | 15 - src/qml/qml/qqmlvme.cpp | 1217 ----------- src/qml/qml/qqmlvme_p.h | 57 - src/qml/types/qqmlconnections.cpp | 48 - src/qml/types/qqmlconnections_p.h | 1 - src/qml/types/qqmldelegatemodel.cpp | 12 +- src/qml/types/qqmllistmodel.cpp | 191 +- src/qml/types/qqmllistmodel_p.h | 11 +- 27 files changed, 83 insertions(+), 9018 deletions(-) delete mode 100644 src/qml/qml/qqmlcompiler.cpp delete mode 100644 src/qml/qml/qqmlcustomparser_p_p.h delete mode 100644 src/qml/qml/qqmlinstruction.cpp delete mode 100644 src/qml/qml/qqmlinstruction_p.h (limited to 'src/qml') diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 3bba6f8e83..33d8be37d1 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -1,5 +1,4 @@ SOURCES += \ - $$PWD/qqmlinstruction.cpp \ $$PWD/qqmlopenmetaobject.cpp \ $$PWD/qqmlvmemetaobject.cpp \ $$PWD/qqmlengine.cpp \ @@ -13,7 +12,6 @@ SOURCES += \ $$PWD/qqmlpropertyvalueinterceptor.cpp \ $$PWD/qqmlproxymetaobject.cpp \ $$PWD/qqmlvme.cpp \ - $$PWD/qqmlcompiler.cpp \ $$PWD/qqmlcompileddata.cpp \ $$PWD/qqmlboundsignal.cpp \ $$PWD/qqmlmetatype.cpp \ @@ -60,7 +58,6 @@ SOURCES += \ HEADERS += \ $$PWD/qqmlglobal_p.h \ - $$PWD/qqmlinstruction_p.h \ $$PWD/qqmlopenmetaobject_p.h \ $$PWD/qqmlvmemetaobject_p.h \ $$PWD/qqml.h \ @@ -70,7 +67,6 @@ HEADERS += \ $$PWD/qqmlincubator.h \ $$PWD/qqmlincubator_p.h \ $$PWD/qqmlcustomparser_p.h \ - $$PWD/qqmlcustomparser_p_p.h \ $$PWD/qqmlpropertyvaluesource.h \ $$PWD/qqmlpropertyvalueinterceptor_p.h \ $$PWD/qqmlboundsignal_p.h \ diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp index d20215c78a..59c56bf513 100644 --- a/src/qml/qml/qqmlcompileddata.cpp +++ b/src/qml/qml/qqmlcompileddata.cpp @@ -56,36 +56,6 @@ QT_BEGIN_NAMESPACE -int QQmlCompiledData::indexForString(const QString &data) -{ - int idx = primitives.indexOf(data); - if (idx == -1) { - idx = primitives.count(); - primitives << data; - } - return idx; -} - -int QQmlCompiledData::indexForByteArray(const QByteArray &data) -{ - int idx = datas.indexOf(data); - if (idx == -1) { - idx = datas.count(); - datas << data; - } - return idx; -} - -int QQmlCompiledData::indexForUrl(const QUrl &data) -{ - int idx = urls.indexOf(data); - if (idx == -1) { - idx = urls.count(); - urls << data; - } - return idx; -} - QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) : engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false), rootPropertyCache(0), compilationUnit(0), qmlUnit(0), totalBindingsCount(0), totalParserStatusCount(0) @@ -110,13 +80,6 @@ QQmlCompiledData::~QQmlCompiledData() clear(); - for (int ii = 0; ii < types.count(); ++ii) { - if (types.at(ii).component) - types.at(ii).component->release(); - if (types.at(ii).typePropertyCache) - types.at(ii).typePropertyCache->release(); - } - for (QHash::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end(); resolvedType != end; ++resolvedType) { if ((*resolvedType)->component) @@ -199,71 +162,6 @@ void QQmlCompiledData::TypeReference::doDynamicTypeCheck() isFullyDynamicType = qtTypeInherits(mo); } -void QQmlCompiledData::dumpInstructions() -{ - if (!name.isEmpty()) - qWarning() << name; - qWarning().nospace() << "Index\tOperation\t\tData1\tData2\tData3\tComments"; - qWarning().nospace() << "-------------------------------------------------------------------------------"; - - const char *instructionStream = bytecode.constData(); - const char *endInstructionStream = bytecode.constData() + bytecode.size(); - - int instructionCount = 0; - while (instructionStream < endInstructionStream) { - QQmlInstruction *instr = (QQmlInstruction *)instructionStream; - dump(instr, instructionCount); - instructionStream += QQmlInstruction::size(instructionType(instr)); - instructionCount++; - } - - qWarning().nospace() << "-------------------------------------------------------------------------------"; -} - -int QQmlCompiledData::addInstructionHelper(QQmlInstruction::Type type, QQmlInstruction &instr) -{ -#ifdef QML_THREADED_VME_INTERPRETER - instr.common.code = QQmlVME::instructionJumpTable()[static_cast(type)]; -#else - instr.common.instructionType = type; -#endif - int ptrOffset = bytecode.size(); - int size = QQmlInstruction::size(type); - if (bytecode.capacity() <= bytecode.size() + size) - bytecode.reserve(bytecode.size() + size + 512); - bytecode.append(reinterpret_cast(&instr), size); - return ptrOffset; -} - -int QQmlCompiledData::nextInstructionIndex() -{ - return bytecode.size(); -} - -QQmlInstruction *QQmlCompiledData::instruction(int index) -{ - return (QQmlInstruction *)(bytecode.constData() + index); -} - -QQmlInstruction::Type QQmlCompiledData::instructionType(const QQmlInstruction *instr) -{ -#ifdef QML_THREADED_VME_INTERPRETER - void *const *jumpTable = QQmlVME::instructionJumpTable(); - void *code = instr->common.code; - -# define QML_CHECK_INSTR_CODE(I, FMT) \ - if (jumpTable[static_cast(QQmlInstruction::I)] == code) \ - return QQmlInstruction::I; - - FOR_EACH_QML_INSTR(QML_CHECK_INSTR_CODE) - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid instruction address"); - return static_cast(0); -# undef QML_CHECK_INSTR_CODE -#else - return static_cast(instr->common.instructionType); -#endif -} - void QQmlCompiledData::initialize(QQmlEngine *engine) { Q_ASSERT(!hasEngine()); diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp deleted file mode 100644 index aefd3018c9..0000000000 --- a/src/qml/qml/qqmlcompiler.cpp +++ /dev/null @@ -1,3922 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlcompiler_p.h" - -#include "qqmlpropertyvaluesource.h" -#include "qqmlcomponent.h" -#include -#include "qqmlstringconverters_p.h" -#include "qqmlengine_p.h" -#include "qqmlengine.h" -#include "qqmlcontext.h" -#include "qqmlmetatype_p.h" -#include "qqmlcustomparser_p_p.h" -#include "qqmlcontext_p.h" -#include "qqmlcomponent_p.h" -#include -#include -#include -#include "qqmlvmemetaobject_p.h" -#include "qqmlexpression_p.h" -#include "qqmlproperty_p.h" -#include "qqmlscriptstring.h" -#include "qqmlglobal_p.h" -#include "qqmlbinding_p.h" -#include "qqmlabstracturlinterceptor.h" - -#include -#include -#include -#include -#include -#include -#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 QQmlJS; -using namespace QQmlScript; -using namespace QQmlCompilerTypes; - -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_module_string(QLatin1String("QML")); -static QString qsTr_string(QLatin1String("qsTr")); -static QString qsTrId_string(QLatin1String("qsTrId")); - -/*! - Instantiate a new QQmlCompiler. -*/ -QQmlCompiler::QQmlCompiler(QQmlPool *pool) -: compileState(0), pool(pool), output(0), engine(0), enginePrivate(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1), - cachedTranslationContextIndex(-1), componentStats(0) -{ - if (compilerStatDump()) - componentStats = pool->New(); -} - -/*! - Returns true if the last call to compile() caused errors. - - \sa errors() -*/ -bool QQmlCompiler::isError() const -{ - return !exceptions.isEmpty(); -} - -/*! - Return the list of errors from the last call to compile(), or an empty list - if there were no errors. -*/ -QList QQmlCompiler::errors() const -{ - return exceptions; -} - -/*! - Returns true if \a name refers to an attached property, false otherwise. - - Attached property names are those that start with a capital letter. -*/ -bool QQmlCompiler::isAttachedPropertyName(const QString &name) -{ - return isAttachedPropertyName(QHashedStringRef(&name)); -} - -bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name) -{ - return !name.isEmpty() && name.at(0).isUpper(); -} - -/*! - Returns true if \a name refers to a signal property, false otherwise. - - Signal property names are those that start with "on", followed by a first - character which is either a capital letter or one or more underscores followed - by a capital letter, which is then followed by other allowed characters. - - Note that although ECMA-262r3 supports dollarsigns and escaped unicode - character codes in property names, for simplicity and performance reasons - QML only supports letters, numbers and underscores. -*/ -bool QQmlCompiler::isSignalPropertyName(const QString &name) -{ - return isSignalPropertyName(QStringRef(&name)); -} - -bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name) -{ - if (name.length() < 3) return false; - if (!name.startsWith(on_string)) return false; - int ns = name.length(); - for (int i = 2; i < ns; ++i) { - const QChar curr = name.at(i); - if (curr.unicode() == '_') continue; - if (curr.isUpper()) return true; - return false; - } - return false; // consists solely of underscores - invalid. -} - -/*! - \macro COMPILE_EXCEPTION - \internal - Inserts an error into the QQmlCompiler error list, and returns false - (failure). - - \a token is used to source the error line and column, and \a desc is the - error itself. \a desc can be an expression that can be piped into QDebug. - - For example: - - \code - COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name)); - \endcode -*/ -#define COMPILE_EXCEPTION_LOCATION(line, column, desc) \ - { \ - QQmlError error; \ - error.setUrl(output->url); \ - 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 - Returns false if \a is false, otherwise does nothing. -*/ -#define COMPILE_CHECK(a) \ - { \ - if (!a) return false; \ - } - -/*! - Returns true if literal \a v can be assigned to property \a prop, otherwise - false. - - This test corresponds to action taken by genLiteralAssignment(). Any change - made here, must have a corresponding action in genLiteralAssigment(). -*/ -bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, QQmlScript::Value *v) -{ - const QQmlScript::Variant &value = v->value; - - 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->core.isEnum()) { - QMetaProperty p = prop->parent->metatype->firstCppMetaObject()->property(prop->index); - int enumValue; - bool ok; - if (p.isFlagType()) { - enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok); - } else - enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok); - - if (!ok) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration")); - - v->value = QQmlScript::Variant((double)enumValue); - return true; - } - - int type = prop->type; - - switch(type) { - 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(); - if (ok) { - double n = v->value.asNumber(); - if (double(uint(n)) != n) - ok = false; - } - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected")); - } - break; - case QVariant::Int: - { - 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 expected")); - } - break; - case QMetaType::Float: - if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected")); - break; - case QVariant::Double: - if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected")); - break; - case QVariant::Color: - { - bool ok; - QQmlStringConverters::colorFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected")); - } - break; -#ifndef QT_NO_DATESTRING - case QVariant::Date: - { - bool ok; - QQmlStringConverters::dateFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected")); - } - break; - case QVariant::Time: - { - bool ok; - QQmlStringConverters::timeFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected")); - } - break; - case QVariant::DateTime: - { - bool ok; - QQmlStringConverters::dateTimeFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected")); - } - break; -#endif // QT_NO_DATESTRING - case QVariant::Point: - case QVariant::PointF: - { - bool ok; - QQmlStringConverters::pointFFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected")); - } - break; - case QVariant::Size: - case QVariant::SizeF: - { - bool ok; - QQmlStringConverters::sizeFFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected")); - } - break; - case QVariant::Rect: - case QVariant::RectF: - { - bool ok; - QQmlStringConverters::rectFFromString(value.asString(), &ok); - if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected")); - } - break; - case QVariant::Bool: - { - if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected")); - } - break; - case QVariant::Vector3D: - { - QQmlInstruction::instr_storeVector3D::QVector3D v3; - if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3))) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected")); - } - break; - case QVariant::Vector4D: - { - QQmlInstruction::instr_storeVector4D::QVector4D v4; - if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4))) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected")); - } - break; - default: - { - // 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; - } else if (type == qMetaTypeId()) { - break; - } - - // otherwise, check for existence of string converter to custom type - QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type); - if (!converter) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(type)))); - } - break; - } - return true; -} - -/*! - 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 QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::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; - } - - int type = prop->type; - switch(type) { - case QMetaType::QVariant: - { - if (v->value.isNumber()) { - double n = v->value.asNumber(); - if (double(int(n)) == n) { - if (prop->core.isVarProperty()) { - 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.isVarProperty()) { - 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.isVarProperty()) { - Instruction::StoreVarBool instr; - instr.propertyIndex = prop->index; - instr.value = v->value.asBoolean(); - output->addInstruction(instr); - } else { - Instruction::StoreVariantBool instr; - instr.propertyIndex = prop->index; - instr.value = v->value.asBoolean(); - output->addInstruction(instr); - } - } else { - if (prop->core.isVarProperty()) { - 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: - { - 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: - { - Instruction::StoreByteArray instr; - instr.propertyIndex = prop->index; - instr.value = output->indexForByteArray(v->value.asString().toLatin1()); - output->addInstruction(instr); - } - break; - case QVariant::Url: - { - Instruction::StoreUrl instr; - QString string = v->value.asString(); - // Encoded dir-separators defeat QUrl processing - decode them first - string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); - QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); - // Apply URL interceptor - if (engine->urlInterceptor()) - u = engine->urlInterceptor()->intercept(u, - QQmlAbstractUrlInterceptor::UrlString); - instr.propertyIndex = prop->index; - instr.value = output->indexForUrl(u); - output->addInstruction(instr); - } - break; - case QVariant::UInt: - { - Instruction::StoreInteger instr; - instr.propertyIndex = prop->index; - instr.value = uint(v->value.asNumber()); - output->addInstruction(instr); - } - break; - case QVariant::Int: - { - Instruction::StoreInteger instr; - instr.propertyIndex = prop->index; - instr.value = int(v->value.asNumber()); - output->addInstruction(instr); - } - break; - case QMetaType::Float: - { - Instruction::StoreFloat instr; - instr.propertyIndex = prop->index; - instr.value = float(v->value.asNumber()); - output->addInstruction(instr); - } - break; - case QVariant::Double: - { - Instruction::StoreDouble instr; - instr.propertyIndex = prop->index; - instr.value = v->value.asNumber(); - output->addInstruction(instr); - } - break; - case QVariant::Color: - { - Instruction::StoreColor instr; - instr.propertyIndex = prop->index; - instr.value = QQmlStringConverters::rgbaFromString(v->value.asString()); - output->addInstruction(instr); - } - break; -#ifndef QT_NO_DATESTRING - case QVariant::Date: - { - Instruction::StoreDate instr; - QDate d = QQmlStringConverters::dateFromString(v->value.asString()); - instr.propertyIndex = prop->index; - instr.value = d.toJulianDay(); - output->addInstruction(instr); - } - break; - case QVariant::Time: - { - Instruction::StoreTime instr; - QTime time = QQmlStringConverters::timeFromString(v->value.asString()); - instr.propertyIndex = prop->index; - instr.time = time.msecsSinceStartOfDay(); - output->addInstruction(instr); - } - break; - case QVariant::DateTime: - { - Instruction::StoreDateTime instr; - QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString()); - QTime time = dateTime.time(); - instr.propertyIndex = prop->index; - instr.date = dateTime.date().toJulianDay(); - instr.time = time.msecsSinceStartOfDay(); - output->addInstruction(instr); - } - break; -#endif // QT_NO_DATESTRING - case QVariant::Point: - { - Instruction::StorePoint instr; - bool ok; - QPoint point = QQmlStringConverters::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 = QQmlStringConverters::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 = QQmlStringConverters::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 = QQmlStringConverters::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 = QQmlStringConverters::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 = QQmlStringConverters::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.propertyIndex = prop->index; - instr.value = b; - output->addInstruction(instr); - } - break; - case QVariant::Vector3D: - { - Instruction::StoreVector3D instr; - instr.propertyIndex = prop->index; - QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector)); - output->addInstruction(instr); - } - break; - case QVariant::Vector4D: - { - Instruction::StoreVector4D instr; - instr.propertyIndex = prop->index; - QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector)); - output->addInstruction(instr); - } - break; - default: - { - // 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(QUrl(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; - } else if (type == qMetaTypeId()) { - if (v->value.isBoolean()) { - Instruction::StoreJSValueBool instr; - instr.propertyIndex = prop->index; - instr.value = v->value.asBoolean(); - output->addInstruction(instr); - } else if (v->value.isNumber()) { - double n = v->value.asNumber(); - if (double(int(n)) == n) { - Instruction::StoreJSValueInteger instr; - instr.propertyIndex = prop->index; - instr.value = int(n); - output->addInstruction(instr); - } else { - Instruction::StoreJSValueDouble instr; - instr.propertyIndex = prop->index; - instr.value = n; - output->addInstruction(instr); - } - } else { - Instruction::StoreJSValueString 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; - } -} - -/*! - Resets data by clearing the lists that the QQmlCompiler modifies. -*/ -void QQmlCompiler::reset(QQmlCompiledData *data) -{ - data->types.clear(); - data->primitives.clear(); - data->datas.clear(); - data->bytecode.resize(0); -} - -/*! - Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine - with which the QQmlCompiledData will be associated. - - Returns true on success, false on failure. On failure, the compile errors - are available from errors(). - - If the environment variant QML_COMPILER_DUMP is set - (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr - on a successful compiler. -*/ -bool QQmlCompiler::compile(QQmlEngine *engine, - QQmlTypeData *unit, - QQmlCompiledData *out) -{ - exceptions.clear(); - - Q_ASSERT(out); - reset(out); - - QQmlScript::Object *root = unit->parser().tree(); - Q_ASSERT(root); - - this->engine = engine; - this->enginePrivate = QQmlEnginePrivate::get(engine); - this->unit = unit; - this->unitRoot = root; - this->output = out; - this->jsModule.reset(new IR::Module(enginePrivate->v4engine()->debugger)); - this->jsModule->isQmlModule = true; - - // Compile types - const QList &resolvedTypes = unit->resolvedTypes(); - QList referencedTypes = unit->parser().referencedTypes(); - - for (int ii = 0; ii < resolvedTypes.count(); ++ii) { - QQmlCompiledData::TypeReference ref; - - const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii); - QQmlScript::TypeReference *parserRef = referencedTypes.at(ii); - - if (tref.typeData) { //QML-based type - if (tref.type->isCompositeSingleton()) { - QString err = tr( "Composite Singleton Type %1 is not creatable.").arg(tref.type->qmlTypeName()); - COMPILE_EXCEPTION(parserRef->firstUse, err); - } - ref.component = tref.typeData->compiledData(); - ref.component->addref(); - } else if (tref.type) {//C++-based type - ref.type = tref.type; - if (!ref.type->isCreatable()) { - QString err = ref.type->noCreationReason(); - if (err.isEmpty()) - err = tr( "Element is not creatable."); - COMPILE_EXCEPTION(parserRef->firstUse, err); - } - - if (ref.type->containsRevisionedAttributes()) { - QQmlError cacheError; - ref.typePropertyCache = enginePrivate->cache(ref.type, - resolvedTypes.at(ii).minorVersion, - cacheError); - if (!ref.typePropertyCache) - COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description()); - ref.typePropertyCache->addref(); - } - } - - ref.doDynamicTypeCheck(); - - out->types << ref; - } - - compileTree(root); - - if (!isError()) { - if (compilerDump()) - out->dumpInstructions(); - if (componentStats) - dumpStats(); - Q_ASSERT(out->rootPropertyCache); - - // Any QQmlPropertyMap instances for example need to have their property cache removed, - // because the class is too dynamic and allows adding properties at any point at run-time. - for (int i = 0; i < output->types.count(); ++i) { - QQmlCompiledData::TypeReference &tr = output->types[i]; - if (!tr.typePropertyCache) - continue; - - if (tr.isFullyDynamicType) { - tr.typePropertyCache->release(); - tr.typePropertyCache = 0; - } - } - } else { - reset(out); - } - - 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 QQmlCompiler::compileTree(QQmlScript::Object *tree) -{ - compileState = pool->New(); - - compileState->root = tree; - if (componentStats) - componentStats->componentStat.lineNumber = tree->location.start.line; - - // 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 QQmlTypeNameCache(); - foreach (const QString &ns, unit->namespaces()) { - output->importCache->add(ns); - } - - // Add any Composite Singletons that were used to the import cache - for (int i = 0; i < unit->compositeSingletons().count(); ++i) { - output->importCache->add(unit->compositeSingletons().at(i).type->qmlTypeName(), - unit->compositeSingletons().at(i).type->sourceUrl(), unit->compositeSingletons().at(i).prefix); - } - - int scriptIndex = 0; - foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) { - QString qualifier = script.qualifier; - QString enclosingNamespace; - - const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); - if (lastDotIndex != -1) { - enclosingNamespace = qualifier.left(lastDotIndex); - qualifier = qualifier.mid(lastDotIndex+1); - } - - output->importCache->add(qualifier, scriptIndex++, enclosingNamespace); - } - - unit->imports().populateCache(output->importCache); - - if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) - return; - - if (!jsModule->functions.isEmpty()) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - QV4::Compiler::JSUnitGenerator jsUnitGenerator(jsModule.data()); - QScopedPointer isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, jsModule.data(), &jsUnitGenerator)); - isel->setUseFastLookups(false); - QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/true); - output->compilationUnit = jsUnit; - output->compilationUnit->ref(); - } - - 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.compiledBinding = output->indexForByteArray(compileState->compiledBindingData); - output->addInstruction(init); - - foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) { - Instruction::StoreImportedScript import; - import.value = output->scripts.count(); - - QQmlScriptData *scriptData = script.script->scriptData(); - scriptData->addref(); - output->scripts << scriptData; - output->addInstruction(import); - } - - genObject(tree); - - Instruction::SetDefault def; - output->addInstruction(def); - - Instruction::Done done; - output->addInstruction(done); - - Q_ASSERT(tree->metatype); - if (!tree->synthdata.isEmpty()) { - enginePrivate->registerInternalCompositeType(output); - } else if (output->types.at(tree->type).component) { - output->metaTypeId = output->types.at(tree->type).component->metaTypeId; - output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId; - } else { - Q_ASSERT(output->types.at(tree->type).type); - output->metaTypeId = output->types.at(tree->type).type->typeId(); - output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId(); - } - if (!tree->synthdata.isEmpty()) - enginePrivate->registerInternalCompositeType(output); -} - -static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string) -{ - for (int ii = 0; ii < list.count(); ++ii) - if (string == list.at(ii)) - return true; - - return false; -} - -bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt) -{ - if (componentStats) - componentStats->componentStat.objects++; - - Q_ASSERT (obj->type != -1); - QQmlCompiledData::TypeReference &tr = output->types[obj->type]; - obj->metatype = tr.createPropertyCache(engine); - - // This object is a "Component" element. - if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) { - COMPILE_CHECK(buildComponent(obj, ctxt)); - return true; - } - - if (tr.component) { - typedef QQmlInstruction I; - const I *init = ((const I *)tr.component->bytecode.constData()); - Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::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); - - // Create the synthesized meta object, ignoring aliases - COMPILE_CHECK(checkDynamicMeta(obj)); - COMPILE_CHECK(mergeDynamicMetaProperties(obj)); - COMPILE_CHECK(buildDynamicMeta(obj, Normal)); - - // Find the native type and check for the QQmlParserStatus interface - QQmlType *type = toQmlType(obj); - Q_ASSERT(type); - obj->parserStatusCast = type->parserStatusCast(); - if (obj->parserStatusCast != -1) - compileState->parserStatusCount++; - - // Check if this is a custom parser type. Custom parser types allow - // assignments to non-existent properties. These assignments are then - // compiled by the type. - bool isCustomParser = output->types.at(obj->type).type && - output->types.at(obj->type).type->customParser() != 0; - QList customProps; - - // Fetch the list of deferred properties - QStringList deferredList = deferredProperties(obj); - - // 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 - for (QQmlScript::Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { - if (prop->name() == id_string) { - COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - break; - } - } - - // Merge - QQmlScript::Property *defaultProperty = 0; - QQmlScript::Property *skipProperty = 0; - if (obj->defaultProperty) { - defaultProperty = obj->defaultProperty; - - QQmlScript::Property *explicitProperty = 0; - - QString defaultPropertyName = obj->metatype->defaultPropertyName(); - if (!defaultPropertyName.isEmpty()) { - QString *s = pool->NewString(defaultPropertyName); - QHashedStringRef r(*s); - - if (obj->propertiesHashField.test(r.hash())) { - for (QQmlScript::Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { - if (ep->name() == r) { - explicitProperty = ep; - break; - } - } - } - - if (!explicitProperty) - defaultProperty->setName(r); - } - - if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) { - - skipProperty = explicitProperty; // We merge the values into defaultProperty - - // Find the correct insertion point - QQmlScript::Value *insertPos = 0; - - for (QQmlScript::Value *v = defaultProperty->values.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - if (!(v->location.start < explicitProperty->values.first()->location.start)) - break; - insertPos = v; - } - - defaultProperty->values.insertAfter(insertPos, explicitProperty->values); - } - } - - QQmlCustomParser *cp = 0; - if (isCustomParser) - cp = output->types.at(obj->type).type->customParser(); - - // Build all explicit properties specified - for (QQmlScript::Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { - - if (prop == skipProperty) - continue; - if (prop->name() == id_string) - continue; - - bool canDefer = false; - if (isCustomParser) { - if (doesPropertyExist(prop, obj) && - (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) || - !isAttachedPropertyName(prop->name()))) { - int ids = compileState->ids.count(); - COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState->ids.count(); - } else if (isSignalPropertyName(prop->name()) && - (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) { - COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); - } else { - customProps << QQmlCustomParserNodePrivate::fromProperty(prop); - } - } else { - if (isSignalPropertyName(prop->name())) { - COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); - } else { - int ids = compileState->ids.count(); - COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState->ids.count(); - } - } - - if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name())) - prop->isDeferred = true; - - } - - // Build the default property - if (defaultProperty) { - QQmlScript::Property *prop = defaultProperty; - - bool canDefer = false; - if (isCustomParser) { - if (doesPropertyExist(prop, obj)) { - int ids = compileState->ids.count(); - COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState->ids.count(); - } else { - customProps << QQmlCustomParserNodePrivate::fromProperty(prop); - } - } else { - int ids = compileState->ids.count(); - COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); - canDefer = ids == compileState->ids.count(); - } - - if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name())) - prop->isDeferred = true; - } - - // Compile custom parser parts - if (isCustomParser && !customProps.isEmpty()) { - cp->clearErrors(); - cp->compiler = this; - cp->object = obj; - obj->custom = cp->compile(customProps); - cp->compiler = 0; - cp->object = 0; - foreach (QQmlError err, cp->errors()) { - err.setUrl(output->url); - exceptions << err; - } - } - - compileState->objectDepth.pop(); - - return true; -} - -void QQmlCompiler::genObject(QQmlScript::Object *obj, bool parentToSuper) -{ - QQmlCompiledData::TypeReference &tr = output->types[obj->type]; - if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) { - genComponent(obj); - return; - } - - // Create the object - if (obj->custom.isEmpty() && output->types.at(obj->type).type && - !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; - create.parentToSuper = parentToSuper; - output->addInstruction(create); - - } else { - - 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); - create.parentToSuper = parentToSuper; - output->addInstruction(create); - } else { - 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->synthdata.isEmpty()) { - Q_ASSERT(!output->types.at(obj->type).isFullyDynamicType); - Instruction::StoreMetaObject meta; - meta.aliasData = output->indexForByteArray(obj->synthdata); - meta.propertyCache = output->propertyCaches.count(); - - QQmlPropertyCache *propertyCache = obj->synthCache; - Q_ASSERT(propertyCache); - propertyCache->addref(); - - if (obj == unitRoot) { - propertyCache->addref(); - output->rootPropertyCache = propertyCache; - } - - output->propertyCaches << propertyCache; - output->addInstruction(meta); - } else if (obj == unitRoot) { - output->rootPropertyCache = tr.createPropertyCache(engine); - output->rootPropertyCache->addref(); - } - - // Set the object id - if (!obj->id.isEmpty()) { - 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) { - Instruction::BeginObject begin; - begin.castValue = obj->parserStatusCast; - output->addInstruction(begin); - } - - genObjectBody(obj); -} - -void QQmlCompiler::genObjectBody(QQmlScript::Object *obj) -{ - for (QQmlScript::Property *prop = obj->scriptStringProperties.first(); prop; prop = QQmlScript::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 = output->indexForString(prop->values.first()->value.asScript()); - ss.line = prop->location.start.line; - ss.column = prop->location.start.column; - ss.isStringLiteral = prop->values.first()->value.isString(); - ss.isNumberLiteral = prop->values.first()->value.isNumber(); - ss.numberValue = prop->values.first()->value.asNumber(); - output->addInstruction(ss); - } - - bool seenDefer = false; - for (QQmlScript::Property *prop = obj->valueProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - if (prop->isDeferred) { - seenDefer = true; - continue; - } - if (!prop->isAlias) - genValueProperty(prop, obj); - } - if (seenDefer) { - Instruction::Defer defer; - defer.deferCount = 0; - int deferIdx = output->addInstruction(defer); - int nextInstructionIndex = output->nextInstructionIndex(); - - 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); - - for (QQmlScript::Property *prop = obj->valueProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - if (!prop->isDeferred) - continue; - genValueProperty(prop, obj); - } - - Instruction::Done done; - output->addInstruction(done); - - output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex; - } - - for (QQmlScript::Property *prop = obj->signalProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - - QQmlScript::Value *v = prop->values.first(); - - if (v->type == QQmlScript::Value::SignalObject) { - - genObject(v->object); - - Instruction::AssignSignalObject assign; - assign.line = v->location.start.line; - assign.column = v->location.start.column; - assign.signal = output->indexForString(prop->name().toString()); - output->addInstruction(assign); - - } else if (v->type == QQmlScript::Value::SignalExpression) { - - Instruction::StoreSignal store; - store.runtimeFunctionIndex = compileState->jsCompileData[v->signalData.signalScopeObject].runtimeFunctionIndices.at(v->signalData.functionIndex); - store.handlerName = output->indexForString(prop->name().toString()); - store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index)); - store.signalIndex = prop->index; - store.value = output->indexForString(v->value.asScript()); - store.context = v->signalData.signalExpressionContextStack; - store.line = v->location.start.line; - store.column = v->location.start.column; - output->addInstruction(store); - - } - - } - - for (QQmlScript::Property *prop = obj->attachedProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - Instruction::FetchAttached fetch; - fetch.id = prop->index; - fetch.line = prop->location.start.line; - output->addInstruction(fetch); - - genObjectBody(prop->value); - - Instruction::PopFetchedObject pop; - output->addInstruction(pop); - } - - for (QQmlScript::Property *prop = obj->groupedProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - Instruction::FetchObject fetch; - fetch.property = prop->index; - fetch.line = prop->location.start.line; - fetch.column = prop->location.start.column; - output->addInstruction(fetch); - - if (!prop->value->synthdata.isEmpty()) { - Instruction::StoreMetaObject meta; - meta.aliasData = output->indexForByteArray(prop->value->synthdata); - meta.propertyCache = output->propertyCaches.count(); - QQmlPropertyCache *propertyCache = prop->value->synthCache; - Q_ASSERT(propertyCache); - propertyCache->addref(); - output->propertyCaches << propertyCache; - output->addInstruction(meta); - } - - genObjectBody(prop->value); - - Instruction::PopFetchedObject pop; - output->addInstruction(pop); - } - - for (QQmlScript::Property *prop = obj->valueTypeProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - if (!prop->isAlias) - genValueTypeProperty(obj, prop); - } - - for (QQmlScript::Property *prop = obj->valueProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - if (prop->isDeferred) - continue; - if (prop->isAlias) - genValueProperty(prop, obj); - } - - for (QQmlScript::Property *prop = obj->valueTypeProperties.first(); prop; prop = QQmlScript::Object::PropertyList::next(prop)) { - if (prop->isAlias) - genValueTypeProperty(obj, prop); - } -} - -void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj, QQmlScript::Property *prop) -{ - 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. - for (QQmlScript::Property *vprop = prop->value->valueProperties.first(); vprop; vprop = QQmlScript::Object::PropertyList::next(vprop)) { - if (!vprop->values.isEmpty()) { - Q_ASSERT(vprop->index >= 0 && vprop->index < 32); - fetch.bindingSkipList |= (1 << vprop->index); - } - } - } - - output->addInstruction(fetch); - - for (QQmlScript::Property *vprop = prop->value->valueProperties.first(); vprop; vprop = QQmlScript::Object::PropertyList::next(vprop)) { - genPropertyAssignment(vprop, prop->value, prop); - } - - Instruction::PopValueType pop; - pop.property = prop->index; - pop.type = prop->type; - pop.bindingSkipList = 0; - output->addInstruction(pop); - - genPropertyAssignment(prop, obj); -} - -void QQmlCompiler::genComponent(QQmlScript::Object *obj) -{ - QQmlScript::Object *root = obj->defaultProperty->values.first()->object; - Q_ASSERT(root); - - 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; - compileState = componentState(root); - - 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.compiledBinding = output->indexForByteArray(compileState->compiledBindingData); - output->addInstruction(init); - - genObject(root); - - Instruction::SetDefault def; - output->addInstruction(def); - - Instruction::Done done; - output->addInstruction(done); - - output->instruction(createInstruction)->createComponent.count = - output->nextInstructionIndex() - nextInstructionIndex; - - compileState = oldCompileState; - - if (!obj->id.isEmpty()) { - Instruction::SetId id; - id.value = output->indexForString(obj->id); - id.index = obj->idIndex; - output->addInstruction(id); - } - - if (obj == unitRoot) { - output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine); - output->rootPropertyCache->addref(); - } -} - -bool QQmlCompiler::buildComponent(QQmlScript::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) - QQmlScript::Property *idProp = 0; - 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.isEmpty()) - idProp = obj->properties.first(); - - if (idProp) { - 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.value(idVal)) - COMPILE_EXCEPTION(idProp, tr("id is not unique")); - - obj->id = idVal; - addId(idVal, obj); - } - - // Check the Component tree is well formed - if (obj->defaultProperty && - (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()) - COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); - if (!obj->dynamicSignals.isEmpty()) - COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); - if (!obj->dynamicSlots.isEmpty()) - COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); - - QQmlScript::Object *root = 0; - if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty()) - root = obj->defaultProperty->values.first()->object; - - if (!root) - COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification")); - - // Build the component tree - COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); - - compileState->objectDepth.pop(); - - return true; -} - -bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - ComponentCompileState *oldComponentCompileState = compileState; - compileState = pool->New(); - compileState->root = obj; - compileState->nested = true; - - if (componentStats) { - ComponentStat oldComponentStat = componentStats->componentStat; - - componentStats->componentStat = ComponentStat(); - componentStats->componentStat.lineNumber = obj->location.start.line; - - if (obj) - COMPILE_CHECK(buildObject(obj, ctxt)); - - COMPILE_CHECK(completeComponentBuild()); - - componentStats->componentStat = oldComponentStat; - } else { - if (obj) - COMPILE_CHECK(buildObject(obj, ctxt)); - - COMPILE_CHECK(completeComponentBuild()); - } - - compileState = oldComponentCompileState; - - return true; -} - - -// 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 QQmlCompiler::buildSubObject(QQmlScript::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 - - for (QQmlScript::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)); - } - } - - return true; -} - -int QQmlCompiler::componentTypeRef() -{ - if (cachedComponentTypeRef == -1) { - QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0); - for (int ii = output->types.count() - 1; ii >= 0; --ii) { - if (output->types.at(ii).type == t) { - cachedComponentTypeRef = ii; - return ii; - } - } - QQmlCompiledData::TypeReference ref; - ref.type = t; - output->types << ref; - cachedComponentTypeRef = output->types.count() - 1; - } - return cachedComponentTypeRef; -} - -int QQmlCompiler::translationContextIndex() -{ - if (cachedTranslationContextIndex == -1) { - // This code must match that in the qsTr() implementation - const QString &path = output->name; - 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; -} - -static AST::FunctionDeclaration *convertSignalHandlerExpressionToFunctionDeclaration(QQmlJS::Engine *jsEngine, - AST::Node *node, - const QString &signalName, - const QList ¶meters) -{ - QQmlJS::MemoryPool *pool = jsEngine->pool(); - - AST::FormalParameterList *paramList = 0; - foreach (const QByteArray ¶m, parameters) { - QStringRef paramNameRef = jsEngine->newStringRef(QString::fromUtf8(param)); - - if (paramList) - paramList = new (pool) AST::FormalParameterList(paramList, paramNameRef); - else - paramList = new (pool) AST::FormalParameterList(paramNameRef); - } - - if (paramList) - paramList = paramList->finish(); - - AST::Statement *statement = node->statementCast(); - if (!statement) { - AST::ExpressionNode *expr = node->expressionCast(); - Q_ASSERT(expr); - statement = new (pool) AST::ExpressionStatement(expr); - } - AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement); - AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement); - elements = elements->finish(); - - AST::FunctionBody *body = new (pool) AST::FunctionBody(elements); - - AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine->newStringRef(signalName), paramList, body); - functionDeclaration->functionToken = statement->firstSourceLocation(); - return functionDeclaration; -} - -bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - Q_ASSERT(obj->metatype); - - 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.at(firstAlphaIndex).isUpper()) { - name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower(); - break; - } - } - - bool notInRevision = false; - - QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision); - - if (sig == 0) { - - if (notInRevision && 0 == property(obj, propName, 0)) { - Q_ASSERT(obj->type != -1); - const QList &resolvedTypes = unit->resolvedTypes(); - const QQmlTypeData::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())); - } - } - - // If the "on" name doesn't resolve into a signal, try it as a - // property. - COMPILE_CHECK(buildProperty(prop, obj, ctxt)); - - } else { - - if (prop->value || !prop->values.isOne()) - COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); - - prop->index = propertyCacheForObject(obj)->methodIndexToSignalIndex(sig->coreIndex); - prop->core = *sig; - - obj->addSignalProperty(prop); - - if (prop->values.first()->object) { - COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt)); - prop->values.first()->type = QQmlScript::Value::SignalObject; - } else { - prop->values.first()->type = QQmlScript::Value::SignalExpression; - - 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.first()->value.asScript().trimmed(); - if (script.isEmpty()) - COMPILE_EXCEPTION(prop, tr("Empty signal assignment")); - - //all handlers should be on the original, rather than cloned signals in order - //to ensure all parameters are available (see qqmlboundsignal constructor for more details) - prop->index = obj->metatype->originalClone(prop->index); - prop->values.first()->signalData.signalExpressionContextStack = ctxt.stack; - prop->values.first()->signalData.signalScopeObject = ctxt.object; - - QList parameters = obj->metatype->signalParameterNames(prop->index); - - AST::FunctionDeclaration *funcDecl = convertSignalHandlerExpressionToFunctionDeclaration(unit->parser().jsEngine(), prop->values.first()->value.asAST(), propName.toString(), parameters); - - ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[ctxt.object]; - cd->functionsToCompile.append(funcDecl); - prop->values.first()->signalData.functionIndex = cd->functionsToCompile.count() - 1; - - QString errorString; - obj->metatype->signalParameterStringForJS(prop->index, &errorString); - if (!errorString.isEmpty()) - COMPILE_EXCEPTION(prop, errorString); - } - } - - return true; -} - - -/*! - Returns true if (value) property \a prop exists on obj, false otherwise. -*/ -bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop, - QQmlScript::Object *obj) -{ - if (prop->name().isEmpty()) - return false; - if(isAttachedPropertyName(prop->name()) || prop->name() == id_string) - return true; - - return property(obj, prop->name()) != 0; -} - -bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - if (prop->isEmpty()) - COMPILE_EXCEPTION(prop, tr("Empty property assignment")); - - if (isAttachedPropertyName(prop->name())) { - // Setup attached property data - - if (ctxt.isSubContext()) { - // Attached properties cannot be used on sub-objects. Sub-objects - // always exist in a binding sub-context, which is what we test - // for here. - COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here")); - } - - QQmlType *type = 0; - QQmlImportNamespace *typeNamespace = 0; - unit->imports().resolveType(prop->name(), &type, 0, 0, &typeNamespace); - - if (typeNamespace) { - COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, - ctxt)); - return true; - } else if (!type || !type->attachedPropertiesType()) { - COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); - } - - if (!prop->value) - COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); - - Q_ASSERT(type->attachedPropertiesFunction()); - prop->index = type->attachedPropertiesId(); - prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType()); - } else { - // Setup regular property data - bool notInRevision = false; - QQmlPropertyData *d = - prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision); - - if (d == 0 && notInRevision) { - const QList &resolvedTypes = unit->resolvedTypes(); - QQmlTypeData::TypeReference type; - if (obj->type != -1) - 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) { - QString defaultPropertyName = obj->metatype->defaultPropertyName(); - - if (!defaultPropertyName.isEmpty()) { - prop->setName(defaultPropertyName); - prop->core = *obj->metatype->defaultProperty(); - prop->index = prop->core.coreIndex; - } - } - - // We can't error here as the "id" property does not require a - // successful index resolution - if (prop->index != -1) - prop->type = prop->core.propType; - - // Check if this is an alias - if (prop->index != -1 && - prop->parent && - prop->parent->type != -1 && - output->types.at(prop->parent->type).component) { - - QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache; - if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias()) - prop->isAlias = true; - } - - if (prop->index != -1 && !prop->values.isEmpty()) - prop->parent->setBindingBit(prop->index); - } - - 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.first()->value.isString()) - COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); - - } else if (isAttachedPropertyName(prop->name())) { - - COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); - - } else if (prop->index == -1) { - - 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(prop->name().toString())); - } - - } else if (prop->value) { - - COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); - - } else if (prop->core.isQList()) { - - COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); - - } else if (prop->type == qMetaTypeId()) { - - COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); - - } else { - - COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); - - } - - return true; -} - -bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns, - QQmlScript::Property *nsProp, - QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - if (!nsProp->value) - COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace")); - - for (QQmlScript::Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) { - - if (!isAttachedPropertyName(prop->name())) - COMPILE_EXCEPTION(prop, tr("Expected type name")); - - // Setup attached property data - - QQmlType *type = 0; - unit->imports().resolveType(ns, prop->name(), &type, 0, 0); - - if (!type || !type->attachedPropertiesType()) - COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); - - if (!prop->value) - COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); - - Q_ASSERT(type->attachedPropertiesFunction()); - prop->index = type->index(); - prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType()); - - COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); - } - - return true; -} - -void QQmlCompiler::genValueProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj) -{ - if (prop->core.isQList()) { - genListProperty(prop, obj); - } else { - genPropertyAssignment(prop, obj); - } -} - -void QQmlCompiler::genListProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj) -{ - int listType = enginePrivate->listType(prop->type); - - Instruction::FetchQList fetch; - fetch.property = prop->index; - bool listTypeIsInterface = QQmlMetaType::isInterface(listType); - fetch.type = listType; - output->addInstruction(fetch); - - for (QQmlScript::Value *v = prop->values.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - - if (v->type == QQmlScript::Value::CreatedObject) { - - genObject(v->object); - if (listTypeIsInterface) { - Instruction::AssignObjectList assign; - assign.line = prop->location.start.line; - output->addInstruction(assign); - } else { - Instruction::StoreObjectQList store; - output->addInstruction(store); - } - - } else if (v->type == QQmlScript::Value::PropertyBinding) { - - genBindingAssignment(v, prop, obj); - - } - - } - - Instruction::PopQList pop; - output->addInstruction(pop); -} - -void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Property *valueTypeProperty) -{ - for (QQmlScript::Value *v = prop->values.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - - Q_ASSERT(v->type == QQmlScript::Value::CreatedObject || - v->type == QQmlScript::Value::PropertyBinding || - v->type == QQmlScript::Value::Literal); - - if (v->type == QQmlScript::Value::CreatedObject) { - - genObject(v->object); - - if (QQmlMetaType::isInterface(prop->type)) { - - Instruction::StoreInterface store; - store.line = v->object->location.start.line; - store.propertyIndex = prop->index; - output->addInstruction(store); - - } else if (prop->type == QMetaType::QVariant) { - - if (prop->core.isVarProperty()) { - 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); - } - - - } else { - - Instruction::StoreObject store; - store.line = v->object->location.start.line; - store.propertyIndex = prop->index; - output->addInstruction(store); - - } - } else if (v->type == QQmlScript::Value::PropertyBinding) { - - genBindingAssignment(v, prop, obj, valueTypeProperty); - - } else if (v->type == QQmlScript::Value::Literal) { - - genLiteralAssignment(prop, v); - - } - - } - - for (QQmlScript::Value *v = prop->onValues.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - - Q_ASSERT(v->type == QQmlScript::Value::ValueSource || - v->type == QQmlScript::Value::ValueInterceptor); - - if (v->type == QQmlScript::Value::ValueSource) { - genObject(v->object, valueTypeProperty?true:false); - - Instruction::StoreValueSource store; - if (valueTypeProperty) - store.property = genValueTypeData(prop, valueTypeProperty); - else - store.property = prop->core; - QQmlType *valueType = toQmlType(v->object); - store.castValue = valueType->propertyValueSourceCast(); - output->addInstruction(store); - - } else if (v->type == QQmlScript::Value::ValueInterceptor) { - genObject(v->object, valueTypeProperty?true:false); - - Instruction::StoreValueInterceptor store; - if (valueTypeProperty) - store.property = genValueTypeData(prop, valueTypeProperty); - else - store.property = prop->core; - QQmlType *valueType = toQmlType(v->object); - store.castValue = valueType->propertyValueInterceptorCast(); - output->addInstruction(store); - } - - } -} - -bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj) -{ - if (prop->value || - prop->values.isMany() || - prop->values.first()->object) - COMPILE_EXCEPTION(prop, tr("Invalid use of id property")); - - QQmlScript::Value *idValue = prop->values.first(); - QString val = idValue->primitive(); - - COMPILE_CHECK(checkValidId(idValue, val)); - - if (compileState->ids.value(val)) - COMPILE_EXCEPTION(prop, tr("id is not unique")); - - prop->values.first()->type = QQmlScript::Value::Id; - - obj->id = val; - addId(val, obj); - - return true; -} - -void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj) -{ - Q_UNUSED(id); - Q_ASSERT(!compileState->ids.value(id)); - Q_ASSERT(obj->id == id); - obj->idIndex = compileState->ids.count(); - compileState->ids.append(obj); -} - -void QQmlCompiler::addBindingReference(JSBindingReference *ref) -{ - Q_ASSERT(ref->value && !ref->value->bindingReference); - ref->value->bindingReference = ref; - compileState->totalBindingsCount++; - compileState->bindings.prepend(ref); -} - -void QQmlCompiler::saveComponentState() -{ - Q_ASSERT(compileState->root); - Q_ASSERT(compileState->root->componentCompileState == 0); - - compileState->root->componentCompileState = compileState; - - if (componentStats) - componentStats->savedComponentStats.append(componentStats->componentStat); -} - -QQmlCompilerTypes::ComponentCompileState * -QQmlCompiler::componentState(QQmlScript::Object *obj) -{ - Q_ASSERT(obj->componentCompileState); - return obj->componentCompileState; -} - -// Build attached property object. In this example, -// Text { -// GridView.row: 10 -// } -// GridView is an attached property object. -bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop, - QQmlScript::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; -} - - -// Build "grouped" properties. In this example: -// Text { -// font.pointSize: 12 -// font.family: "Helvetica" -// } -// font is a nested property. pointSize and family are not. -bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - Q_ASSERT(prop->type != 0); - Q_ASSERT(prop->index != -1); - - if (QQmlValueTypeFactory::isValueType(prop->type)) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(prop->type); - if (prop->type >= 0 && valueType) { - if (!prop->values.isEmpty()) { - // Only error if we are assigning values, and not e.g. a property interceptor - for (QQmlScript::Property *dotProp = prop->value->properties.first(); dotProp; dotProp = prop->value->properties.next(dotProp)) { - if (!dotProp->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.first(), tr( "Property has already been assigned a value")); - } - } - } - } - - 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) { - for (QQmlScript::Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) { - vtProp->isAlias = true; - } - } - - COMPILE_CHECK(buildValueTypeProperty(valueType, prop->value, obj, ctxt.incr())); - - // When building a value type where sub components are declared, this - // code path is followed from buildProperty, even if there is a previous - // assignment to the value type as a whole. Therefore we need to look - // for (and build) assignments to the entire value type before looking - // for any onValue assignments. - for (QQmlScript::Value *v = prop->values.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - if (v->object) { - COMPILE_EXCEPTION(v->object, tr("Objects cannot be assigned to value types")); - } - COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); - } - - for (QQmlScript::Value *v = prop->onValues.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - Q_ASSERT(v->object); - COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); - } - - obj->addValueTypeProperty(prop); - } else { - COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); - } - } else { - // Load the nested property's meta type - prop->value->metatype = enginePrivate->propertyCacheForType(prop->type); - if (!prop->value->metatype) - COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); - - 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 QQmlCompiler::buildValueTypeProperty(QObject *type, - QQmlScript::Object *obj, - QQmlScript::Object *baseObj, - const BindingContext &ctxt) -{ - compileState->objectDepth.push(); - - if (obj->defaultProperty) - COMPILE_EXCEPTION(obj, tr("Invalid property use")); - obj->metatype = enginePrivate->cache(type); - - for (QQmlScript::Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { - - QQmlPropertyData *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.isMany()) { - COMPILE_EXCEPTION(prop, tr("Single property assignment expected")); - } else if (!prop->values.isEmpty()) { - QQmlScript::Value *value = prop->values.first(); - - if (value->object) { - COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); - } else if (value->value.isScript()) { - // ### Check for writability - - //optimization for . enum assignments - bool isEnumAssignment = false; - - if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) - COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment)); - - if (isEnumAssignment) { - value->type = QQmlScript::Value::Literal; - } else { - JSBindingReference *reference = pool->New(); - reference->expression = value->value; - reference->property = prop; - reference->value = value; - reference->bindingContext = ctxt; - reference->bindingContext.owner++; - addBindingReference(reference); - value->type = QQmlScript::Value::PropertyBinding; - } - } else { - COMPILE_CHECK(testLiteralAssignment(prop, value)); - value->type = QQmlScript::Value::Literal; - } - } - - for (QQmlScript::Value *v = prop->onValues.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - Q_ASSERT(v->object); - - COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); - } - - obj->addValueProperty(prop); - } - - compileState->objectDepth.pop(); - - return true; -} - -// Build assignments to QML lists. QML lists are properties of type -// QQmlListProperty. List properties can accept a list of -// objects, or a single binding. -bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - Q_ASSERT(prop->core.isQList()); - - compileState->listDepth.push(); - - int t = prop->type; - - obj->addValueProperty(prop); - - int listType = enginePrivate->listType(t); - bool listTypeIsInterface = QQmlMetaType::isInterface(listType); - - bool assignedBinding = false; - for (QQmlScript::Value *v = prop->values.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - if (v->object) { - v->type = QQmlScript::Value::CreatedObject; - COMPILE_CHECK(buildObject(v->object, ctxt)); - - // We check object coercian here. We check interface assignment - // at runtime. - if (!listTypeIsInterface) { - if (!canCoerce(listType, v->object)) { - COMPILE_EXCEPTION(v, tr("Cannot assign object to list")); - } - } - - } else if (v->value.isScript()) { - if (assignedBinding) - COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists")); - - assignedBinding = true; - COMPILE_CHECK(buildBinding(v, prop, ctxt)); - } else { - COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists")); - } - } - - compileState->listDepth.pop(); - - return true; -} - -// Compiles an assignment to a QQmlScriptString property -bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - if (prop->values.isMany()) - COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a script property")); - - if (prop->values.first()->object) - COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected")); - - prop->scriptStringScope = ctxt.stack; - obj->addScriptStringProperty(prop); - - return true; -} - -// Compile regular property assignments of the form "property: " -bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const BindingContext &ctxt) -{ - obj->addValueProperty(prop); - - if (prop->values.isMany()) - COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") ); - - for (QQmlScript::Value *v = prop->values.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - if (v->object) { - - COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); - - } else { - - COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); - - } - } - - for (QQmlScript::Value *v = prop->onValues.first(); v; v = QQmlScript::Property::ValueList::next(v)) { - Q_ASSERT(v->object); - COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); - } - - return true; -} - -// Compile assigning a single object instance to a regular property -bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Value *v, - const BindingContext &ctxt) -{ - Q_ASSERT(prop->index != -1); - Q_ASSERT(v->object->type != -1); - - if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); - - if (QQmlMetaType::isInterface(prop->type)) { - - // Assigning an object to an interface ptr property - COMPILE_CHECK(buildObject(v->object, ctxt)); - - v->type = QQmlScript::Value::CreatedObject; - - } else if (prop->type == QMetaType::QVariant) { - - // Assigning an object to a QVariant - COMPILE_CHECK(buildObject(v->object, ctxt)); - - v->type = QQmlScript::Value::CreatedObject; - } else { - // Normally buildObject() will set this up, but we need the static - // meta object earlier to test for assignability. It doesn't matter - // that there may still be outstanding synthesized meta object changes - // on this type, as they are not relevant for assignability testing - v->object->metatype = output->types[v->object->type].createPropertyCache(engine); - Q_ASSERT(v->object->metatype); - - // We want to raw metaObject here as the raw metaobject is the - // actual property type before we applied any extensions that might - // effect the properties on the type, but don't effect assignability - QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type); - - // Will be true if the assgned type inherits propertyMetaObject - bool isAssignable = false; - // Determine isAssignable value - if (propertyMetaObject) { - QQmlPropertyCache *c = v->object->metatype; - while (c && !isAssignable) { - isAssignable |= c == propertyMetaObject; - c = c->parent(); - } - } - - if (isAssignable) { - // Simple assignment - COMPILE_CHECK(buildObject(v->object, ctxt)); - - v->type = QQmlScript::Value::CreatedObject; - } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) { - // Automatic "Component" insertion - QQmlScript::Object *root = v->object; - QQmlScript::Object *component = pool->New(); - component->type = componentTypeRef(); - component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject); - component->location = root->location; - QQmlScript::Value *componentValue = pool->New(); - componentValue->object = root; - component->getDefaultProperty()->addValue(componentValue); - v->object = component; - COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); - } else { - COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property")); - } - } - - return true; -} - -// Compile assigning a single object instance to a regular property using the "on" syntax. -// -// For example: -// Item { -// NumberAnimation on x { } -// } -bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Object *baseObj, - QQmlScript::Value *v, - const BindingContext &ctxt) -{ - Q_ASSERT(prop->index != -1); - Q_ASSERT(v->object->type != -1); - - 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 - // meta object earlier to test for assignability. It doesn't matter - // that there may still be outstanding synthesized meta object changes - // on this type, as they are not relevant for assignability testing - v->object->metatype = output->types[v->object->type].createPropertyCache(engine); - Q_ASSERT(v->object->metatype); - - // Will be true if the assigned type inherits QQmlPropertyValueSource - bool isPropertyValue = false; - // Will be true if the assigned type inherits QQmlPropertyValueInterceptor - bool isPropertyInterceptor = false; - if (QQmlType *valueType = toQmlType(v->object)) { - isPropertyValue = valueType->propertyValueSourceCast() != -1; - isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1; - } - - if (isPropertyValue || isPropertyInterceptor) { - // Assign as a property value source - COMPILE_CHECK(buildObject(v->object, ctxt)); - - if (isPropertyInterceptor && baseObj->synthdata.isEmpty()) - buildDynamicMeta(baseObj, ForceCreation); - v->type = isPropertyValue ? QQmlScript::Value::ValueSource : QQmlScript::Value::ValueInterceptor; - } else { - COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString())); - } - - return true; -} - -// Compile assigning a literal or binding to a regular property -bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Value *v, - const BindingContext &ctxt) -{ - Q_ASSERT(prop->index != -1); - - if (v->value.isScript()) { - - //optimization for . enum assignments - if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) { - bool isEnumAssignment = false; - COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment)); - if (isEnumAssignment) { - v->type = QQmlScript::Value::Literal; - return true; - } - } - - // Test for other binding optimizations - if (!buildLiteralBinding(v, prop, ctxt)) - COMPILE_CHECK(buildBinding(v, prop, ctxt)); - - } else { - - COMPILE_CHECK(testLiteralAssignment(prop, v)); - - v->type = QQmlScript::Value::Literal; - } - - return true; -} - -struct StaticQtMetaObject : public QObject -{ - static const QMetaObject *get() - { return &staticQtMetaObject; } -}; - -bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Value *v, - bool *isAssignment) -{ - bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum(); - *isAssignment = false; - if (!prop->core.isEnum() && !isIntProp) - return true; - - QMetaProperty mprop = obj->metatype->firstCppMetaObject()->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()) - return true; - - int dot = string.indexOf(QLatin1Char('.')); - if (dot == -1 || dot == string.length()-1) - return true; - - if (string.indexOf(QLatin1Char('.'), dot+1) != -1) - return true; - - QHashedStringRef typeName(string.constData(), dot); - QString enumValue = string.mid(dot+1); - - if (isIntProp) { - // Allow enum assignment to ints. - bool ok; - int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok); - if (ok) { - v->type = QQmlScript::Value::Literal; - v->value = QQmlScript::Variant((double)enumval); - *isAssignment = true; - } - return true; - } - - QQmlType *type = 0; - unit->imports().resolveType(typeName, &type, 0, 0, 0); - - if (!type && typeName != QLatin1String("Qt")) - return true; - if (type && type->isComposite()) //No enums on composite (or composite singleton) types - return true; - - int value = 0; - bool ok = false; - - if (type && toQmlType(obj) == type) { - // When these two match, we can short cut the search - if (mprop.isFlagType()) { - value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); - } else { - value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); - } - } else { - // Otherwise we have to search the whole type - if (type) { - value = type->enumValue(QHashedStringRef(enumValue), &ok); - } else { - QByteArray enumName = enumValue.toUtf8(); - const QMetaObject *metaObject = StaticQtMetaObject::get(); - for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) { - QMetaEnum e = metaObject->enumerator(ii); - value = e.keyToValue(enumName.constData(), &ok); - } - } - } - - if (!ok) - return true; - - v->type = QQmlScript::Value::Literal; - v->value = QQmlScript::Variant((double)value); - *isAssignment = true; - - return true; -} - -QQmlBinding::Identifier QQmlCompiler::bindingIdentifier(const Variant &value, const QString &name, QQmlCustomParser *customParser) -{ - JSBindingReference *reference = pool->New(); - reference->expression = value; - reference->property = pool->New(); - reference->property->setName(name); - reference->value = 0; - reference->bindingContext = QQmlCompilerTypes::BindingContext(customParser->object); - reference->bindingContext.owner++; - // Unfortunately this is required for example for PropertyChanges where the bindings - // will be executed in the dynamic scope of the target, so we can't resolve any lookups - // at run-time. - reference->disableLookupAcceleration = true; - - const int id = output->customParserBindings.count(); - output->customParserBindings.append(0); // Filled in later. - reference->customParserBindingsIndex = id; - - compileState->totalBindingsCount++; - compileState->bindings.prepend(reference); - - return id; -} - -// Ensures that the dynamic meta specification on obj is valid -bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj) -{ - if (output->types[obj->type].isFullyDynamicType) { - if (!obj->dynamicProperties.isEmpty()) - COMPILE_EXCEPTION(obj, tr("Fully dynamic types cannot declare new properties.")); - if (!obj->dynamicSignals.isEmpty()) - COMPILE_EXCEPTION(obj, tr("Fully dynamic types cannot declare new signals.")); - if (!obj->dynamicSlots.isEmpty()) - COMPILE_EXCEPTION(obj, tr("Fully Dynamic types cannot declare new functions.")); - } - - 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 (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - const QQmlScript::Object::DynamicProperty &prop = *p; - - if (prop.isDefaultProperty) { - if (seenDefaultProperty) - COMPILE_EXCEPTION(&prop, tr("Duplicate default property")); - seenDefaultProperty = true; - } - - if (propNames.testAndSet(prop.name.hash())) { - for (QQmlScript::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 (prop.name.at(0).isUpper()) { - COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, - prop.nameLocation.column, - tr("Property names cannot begin with an upper case letter")); - } - - if (enginePrivate->v8engine()->illegalNames().contains(prop.name.toString())) { - COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line, - prop.nameLocation.column, - tr("Illegal property name")); - } - } - - for (QQmlScript::Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { - const QQmlScript::Object::DynamicSignal &currSig = *s; - - if (methodNames.testAndSet(currSig.name.hash())) { - for (QQmlScript::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.toString())) - COMPILE_EXCEPTION(&currSig, tr("Illegal signal name")); - } - - for (QQmlScript::Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - const QQmlScript::Object::DynamicSlot &currSlot = *s; - - if (methodNames.testAndSet(currSlot.name.hash())) { - for (QQmlScript::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 (QQmlScript::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.toString())) - COMPILE_EXCEPTION(&currSlot, tr("Illegal method name")); - } - - return true; -} - -bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj) -{ - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; - p = obj->dynamicProperties.next(p)) { - - if (!p->defaultValue || p->type == QQmlScript::Object::DynamicProperty::Alias) - continue; - - QQmlScript::Property *property = 0; - if (p->isDefaultProperty) { - property = obj->getDefaultProperty(); - } else { - 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")); - - property->values.append(p->defaultValue->values); - } - return true; -} - -static QStringList astNodeToStringList(QQmlJS::AST::Node *node) -{ - if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { - QString name = - static_cast(node)->name.toString(); - return QStringList() << name; - } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { - QQmlJS::AST::FieldMemberExpression *expr = static_cast(node); - - QStringList rv = astNodeToStringList(expr->base); - if (rv.isEmpty()) - return rv; - rv.append(expr->name.toString()); - return rv; - } - return QStringList(); -} - -static QAtomicInt classIndexCounter(0); - -bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode) -{ - Q_ASSERT(obj); - Q_ASSERT(obj->metatype); - - if (mode != ForceCreation && - obj->dynamicProperties.isEmpty() && - obj->dynamicSignals.isEmpty() && - obj->dynamicSlots.isEmpty()) - return true; - - Q_ASSERT(obj->synthCache == 0); - - struct TypeData { - QQmlScript::Object::DynamicProperty::Type dtype; - int metaType; - } builtinTypes[] = { - { QQmlScript::Object::DynamicProperty::Var, qMetaTypeId() }, - { QQmlScript::Object::DynamicProperty::Variant, QMetaType::QVariant }, - { QQmlScript::Object::DynamicProperty::Int, QMetaType::Int }, - { QQmlScript::Object::DynamicProperty::Bool, QMetaType::Bool }, - { QQmlScript::Object::DynamicProperty::Real, QMetaType::Double }, - { QQmlScript::Object::DynamicProperty::String, QMetaType::QString }, - { QQmlScript::Object::DynamicProperty::Url, QMetaType::QUrl }, - { QQmlScript::Object::DynamicProperty::Color, QMetaType::QColor }, - { QQmlScript::Object::DynamicProperty::Font, QMetaType::QFont }, - { QQmlScript::Object::DynamicProperty::Time, QMetaType::QTime }, - { QQmlScript::Object::DynamicProperty::Date, QMetaType::QDate }, - { QQmlScript::Object::DynamicProperty::DateTime, QMetaType::QDateTime }, - { QQmlScript::Object::DynamicProperty::Rect, QMetaType::QRectF }, - { QQmlScript::Object::DynamicProperty::Point, QMetaType::QPointF }, - { QQmlScript::Object::DynamicProperty::Size, QMetaType::QSizeF }, - { QQmlScript::Object::DynamicProperty::Vector2D, QMetaType::QVector2D }, - { QQmlScript::Object::DynamicProperty::Vector3D, QMetaType::QVector3D }, - { QQmlScript::Object::DynamicProperty::Vector4D, QMetaType::QVector4D }, - { QQmlScript::Object::DynamicProperty::Matrix4x4, QMetaType::QMatrix4x4 }, - { QQmlScript::Object::DynamicProperty::Quaternion, QMetaType::QQuaternion } - }; - static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - - QByteArray newClassName; - - 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(classIndexCounter.fetchAndAddRelaxed(1)); - } - } - if (newClassName.isEmpty()) { - newClassName = QQmlMetaObject(obj->metatype).className(); - newClassName.append("_QML_"); - newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); - } - QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(), - obj->dynamicProperties.count() + - obj->dynamicSignals.count() + - obj->dynamicSlots.count(), - obj->dynamicProperties.count() + - obj->dynamicSignals.count()); - - cache->_dynamicClassName = newClassName; - - int cStringNameCount = 0; - - int aliasCount = 0; - int varPropCount = 0; - - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; - p = obj->dynamicProperties.next(p)) { - - if (p->type == QQmlScript::Object::DynamicProperty::Alias) - aliasCount++; - else if (p->type == QQmlScript::Object::DynamicProperty::Var) - varPropCount++; - - if (p->name.isLatin1()) { - p->nameIndex = cStringNameCount; - cStringNameCount += p->name.length() + 7 /* strlen("Changed") */; - } - - // No point doing this for both the alias and non alias cases - QQmlPropertyData *d = property(obj, p->name); - if (d && d->isFinal()) - COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); - } - - for (QQmlScript::Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { - if (s->name.isLatin1()) { - s->nameIndex = cStringNameCount; - cStringNameCount += s->name.length(); - } - } - - for (QQmlScript::Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - if (s->name.isLatin1()) { - s->nameIndex = cStringNameCount; - cStringNameCount += s->name.length(); - } - } - - char *cStringData = 0; - if (cStringNameCount) { - cache->_dynamicStringData.resize(cStringNameCount); - cStringData = cache->_dynamicStringData.data(); - - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; - p = obj->dynamicProperties.next(p)) { - - if (p->nameIndex == -1) continue; - - char *myData = cStringData + p->nameIndex; - for (int ii = 0; ii < p->name.length(); ++ii) - *myData++ = p->name.at(ii).unicode(); - *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n'; - *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd'; - } - - for (QQmlScript::Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - - if (s->nameIndex == -1) continue; - - char *myData = cStringData + s->nameIndex; - for (int ii = 0; ii < s->name.length(); ++ii) - *myData++ = s->name.at(ii).unicode(); - } - - for (QQmlScript::Object::DynamicSignal *s = obj->dynamicSignals.first(); s; - s = obj->dynamicSignals.next(s)) { - - if (s->nameIndex == -1) continue; - - char *myData = cStringData + s->nameIndex; - for (int ii = 0; ii < s->name.length(); ++ii) - *myData++ = s->name.at(ii).unicode(); - } - } - - QByteArray dynamicData; - typedef QQmlVMEMetaData VMD; - - dynamicData = QByteArray(sizeof(QQmlVMEMetaData) + - obj->dynamicProperties.count() * sizeof(VMD::PropertyData) + - obj->dynamicSlots.count() * sizeof(VMD::MethodData) + - aliasCount * sizeof(VMD::AliasData), 0); - - int effectivePropertyIndex = cache->propertyIndexCacheStart; - int effectiveMethodIndex = cache->methodIndexCacheStart; - - // For property change signal override detection. - // We prepopulate a set of signal names which already exist in the object, - // and throw an error if there is a signal/method defined as an override. - QSet seenSignals; - seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged"); - QQmlPropertyCache *parentCache = cache; - while ((parentCache = parentCache->parent())) { - if (int pSigCount = parentCache->signalCount()) { - int pSigOffset = parentCache->signalOffset(); - for (int i = pSigOffset; i < pSigCount; ++i) { - QQmlPropertyData *currPSig = parentCache->signal(i); - // XXX TODO: find a better way to get signal name from the property data :-/ - for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin(); - iter != parentCache->stringCache.end(); ++iter) { - if (currPSig == (*iter).second) { - seenSignals.insert(iter.key()); - break; - } - } - } - } - } - - // First set up notify signals for properties - first normal, then var, then alias - enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; - for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias - - if (ii == NSS_Var && varPropCount == 0) continue; - else if (ii == NSS_Alias && aliasCount == 0) continue; - - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; - p = obj->dynamicProperties.next(p)) { - - if ((ii == NSS_Normal && (p->type == QQmlScript::Object::DynamicProperty::Alias || - p->type == QQmlScript::Object::DynamicProperty::Var)) || - ((ii == NSS_Var) && (p->type != QQmlScript::Object::DynamicProperty::Var)) || - ((ii == NSS_Alias) && (p->type != QQmlScript::Object::DynamicProperty::Alias))) - continue; - - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; - - QString changedSigName = p->name.toString() + QLatin1String("Changed"); - seenSignals.insert(changedSigName); - - if (p->nameIndex != -1) { - QHashedCStringRef changedSignalName(cStringData + p->nameIndex, - p->name.length() + 7 /* strlen("Changed") */); - cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++); - } else { - cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); - } - } - } - - // Dynamic signals - for (QQmlScript::Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { - int paramCount = s->parameterNames.count(); - - QList names; - QVarLengthArray paramTypes(paramCount?(paramCount + 1):0); - - if (paramCount) { - paramTypes[0] = paramCount; - - for (int i = 0; i < paramCount; ++i) { - if (s->parameterTypes.at(i) < builtinTypeCount) { - // built-in type - paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType; - names.append(s->parameterNames.at(i).toString().toUtf8()); - } else { - // lazily resolved type - Q_ASSERT(s->parameterTypes.at(i) == QQmlScript::Object::DynamicProperty::Custom); - QQmlType *qmltype = 0; - if (!unit->imports().resolveType(s->parameterTypeNames.at(i).toString(), &qmltype, 0, 0, 0)) - COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(s->parameterTypeNames.at(i).toString())); - - // We dont mind even if the composite type ends up being composite singleton, here - // we just acquire the metaTypeId. - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - - paramTypes[i + 1] = data->metaTypeId; - - tdata->release(); - } else { - paramTypes[i + 1] = qmltype->typeId(); - } - names.append(s->parameterNames.at(i).toString().toUtf8()); - } - } - } - - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; - if (paramCount) - flags |= QQmlPropertyData::HasArguments; - - QString signalName = s->name.toString(); - if (seenSignals.contains(signalName)) { - const QQmlScript::Object::DynamicSignal &currSig = *s; - COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name: invalid override of property change signal or superclass signal")); - } - seenSignals.insert(signalName); - - if (s->nameIndex != -1) { - QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash()); - cache->appendSignal(name, flags, effectiveMethodIndex++, - paramCount?paramTypes.constData():0, names); - } else { - cache->appendSignal(signalName, flags, effectiveMethodIndex++, - paramCount?paramTypes.constData():0, names); - } - } - - - // Dynamic slots - for (QQmlScript::Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - int paramCount = s->parameterNames.count(); - - quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; - - if (paramCount) - flags |= QQmlPropertyData::HasArguments; - - QString slotName = s->name.toString(); - if (seenSignals.contains(slotName)) { - const QQmlScript::Object::DynamicSlot &currSlot = *s; - COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name: invalid override of property change signal or superclass signal")); - } - // Note: we don't append slotName to the seenSignals list, since we don't - // protect against overriding change signals or methods with properties. - - if (s->nameIndex != -1) { - QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash()); - cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames); - } else { - cache->appendMethod(slotName, flags, effectiveMethodIndex++, s->parameterNames); - } - } - - - // Dynamic properties (except var and aliases) - int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; - p = obj->dynamicProperties.next(p)) { - - if (p->type == QQmlScript::Object::DynamicProperty::Alias || - p->type == QQmlScript::Object::DynamicProperty::Var) - continue; - - int propertyType = 0; - int vmePropertyType = 0; - quint32 propertyFlags = 0; - - if (p->type < builtinTypeCount) { - propertyType = builtinTypes[p->type].metaType; - vmePropertyType = propertyType; - - if (p->type == QQmlScript::Object::DynamicProperty::Variant) - propertyFlags |= QQmlPropertyData::IsQVariant; - } else { - Q_ASSERT(p->type == QQmlScript::Object::DynamicProperty::CustomList || - p->type == QQmlScript::Object::DynamicProperty::Custom); - - QQmlType *qmltype = 0; - if (!unit->imports().resolveType(p->customType.toString(), &qmltype, 0, 0, 0)) - COMPILE_EXCEPTION(p, tr("Invalid property type")); - - Q_ASSERT(qmltype); - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - - if (p->type == QQmlScript::Object::DynamicProperty::Custom) { - propertyType = data->metaTypeId; - vmePropertyType = QMetaType::QObjectStar; - } else { - propertyType = data->listMetaTypeId; - vmePropertyType = qMetaTypeId >(); - } - - tdata->release(); - } else { - if (p->type == QQmlScript::Object::DynamicProperty::Custom) { - propertyType = qmltype->typeId(); - vmePropertyType = QMetaType::QObjectStar; - } else { - propertyType = qmltype->qListTypeId(); - vmePropertyType = qMetaTypeId >(); - } - } - - if (p->type == QQmlScript::Object::DynamicProperty::Custom) - propertyFlags |= QQmlPropertyData::IsQObjectDerived; - else - propertyFlags |= QQmlPropertyData::IsQList; - } - - if (!p->isReadOnly && p->type != QQmlScript::Object::DynamicProperty::CustomList) - propertyFlags |= QQmlPropertyData::IsWritable; - - if (p->nameIndex != -1) { - QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), - p->name.hash()); - if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - propertyType, effectiveSignalIndex); - } else { - QString propertyName = p->name.toString(); - if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - propertyType, effectiveSignalIndex); - } - - effectiveSignalIndex++; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; - vmd->propertyCount++; - } - - // Now do var properties - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount; - p = obj->dynamicProperties.next(p)) { - - if (p->type != QQmlScript::Object::DynamicProperty::Var) - continue; - - quint32 propertyFlags = QQmlPropertyData::IsVarProperty; - if (!p->isReadOnly) - propertyFlags |= QQmlPropertyData::IsWritable; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; - vmd->propertyCount++; - ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; - - if (p->nameIndex != -1) { - QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), - p->name.hash()); - if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - QMetaType::QVariant, effectiveSignalIndex); - } else { - QString propertyName = p->name.toString(); - if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - QMetaType::QVariant, effectiveSignalIndex); - } - - effectiveSignalIndex++; - } - - // Alias property count. Actual data is setup in buildDynamicMetaAliases - ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; - - // Dynamic slot data - comes after the property data - for (QQmlScript::Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - VMD::MethodData methodData = { /*runtimeFunctionIndex*/ 0, // To be filled in later - s->parameterNames.count(), - s->location.start.line }; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); - vmd->methodCount++; - md = methodData; - - ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[obj]; - - ComponentCompileState::CompiledMetaMethod cmm; - cmm.methodIndex = vmd->methodCount - 1; - cd->functionsToCompile.append(s->funcDecl); - cmm.compiledFunctionIndex = cd->functionsToCompile.count() - 1; - cd->compiledMetaMethods.append(cmm); - } - - if (aliasCount) - compileState->aliasingObjects.append(obj); - - obj->synthdata = dynamicData; - obj->synthCache = cache; - obj->metatype = cache; - - return true; -} - -bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj) -{ - Q_ASSERT(obj->synthCache); - - QByteArray &dynamicData = obj->synthdata; - - QQmlPropertyCache *cache = obj->synthCache; - char *cStringData = cache->_dynamicStringData.data(); - - int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count(); - int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count(); - int effectiveAliasIndex = 0; - - for (QQmlScript::Object::DynamicProperty *p = obj->dynamicProperties.first(); p; - p = obj->dynamicProperties.next(p)) { - - if (p->type != QQmlScript::Object::DynamicProperty::Alias) - continue; - - if (!p->defaultValue) - COMPILE_EXCEPTION(p, tr("No property alias location")); - - if (!p->defaultValue->values.isOne() || - p->defaultValue->values.first()->object || - !p->defaultValue->values.first()->value.isScript()) - COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - - QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST(); - Q_ASSERT(node); - - QStringList alias = astNodeToStringList(node); - if (alias.count() < 1 || alias.count() > 3) - COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as , . or ..")); - - QQmlScript::Object *idObject = compileState->ids.value(alias.at(0)); - if (!idObject) - COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); - - int propIdx = -1; - int propType = 0; - int notifySignal = -1; - int flags = 0; - int type = 0; - bool writable = false; - bool resettable = false; - - quint32 propertyFlags = QQmlPropertyData::IsAlias; - - if (alias.count() == 2 || alias.count() == 3) { - QQmlPropertyData *property = this->property(idObject, alias.at(1)); - - if (!property || property->coreIndex > 0x0000FFFF) - COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - - propIdx = property->coreIndex; - type = property->propType; - - writable = property->isWritable(); - resettable = property->isResettable(); - notifySignal = property->notifyIndex; - - if (alias.count() == 3) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); - if (!valueType) - COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - - propType = type; - - int valueTypeIndex = - valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); - if (valueTypeIndex == -1) - COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - Q_ASSERT(valueTypeIndex <= 0x0000FFFF); - - propIdx |= (valueTypeIndex << 16); - if (valueType->metaObject()->property(valueTypeIndex).isEnumType()) - type = QVariant::Int; - else - type = valueType->metaObject()->property(valueTypeIndex).userType(); - - } else { - if (property->isEnum()) { - type = QVariant::Int; - } else { - // Copy type flags - propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask; - - if (property->isVarProperty()) - propertyFlags |= QQmlPropertyData::IsQVariant; - - if (property->isQObject()) - flags |= QML_ALIAS_FLAG_PTR; - } - } - } else { - Q_ASSERT(idObject->type != -1); // How else did it get an id? - - const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type); - if (ref.type) - type = ref.type->typeId(); - else - type = ref.component->metaTypeId; - - flags |= QML_ALIAS_FLAG_PTR; - propertyFlags |= QQmlPropertyData::IsQObjectDerived; - } - - QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, propType, flags, notifySignal }; - - typedef QQmlVMEMetaData VMD; - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; - - if (!p->isReadOnly && writable) - propertyFlags |= QQmlPropertyData::IsWritable; - else - propertyFlags &= ~QQmlPropertyData::IsWritable; - - if (resettable) - propertyFlags |= QQmlPropertyData::IsResettable; - else - propertyFlags &= ~QQmlPropertyData::IsResettable; - - if (p->nameIndex != -1) { - QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), - p->name.hash()); - if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - type, effectiveSignalIndex++); - } else { - QString propertyName = p->name.toString(); - if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - type, effectiveSignalIndex++); - } - } - - return true; -} - -bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val) -{ - if (val.isEmpty()) - COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); - - QChar ch = val.at(0); - if (ch.isLetter() && !ch.isLower()) - COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); - - QChar u(QLatin1Char('_')); - if (!ch.isLetter() && ch != u) - COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); - - 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)) - COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); - - return true; -} - -bool QQmlCompiler::buildBinding(QQmlScript::Value *value, - QQmlScript::Property *prop, - const BindingContext &ctxt) -{ - Q_ASSERT(prop->index != -1); - Q_ASSERT(prop->parent); - Q_ASSERT(prop->parent->metatype); - - if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) - COMPILE_EXCEPTION(value, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); - - JSBindingReference *reference = pool->New(); - reference->expression = value->value; - reference->property = prop; - reference->value = value; - reference->bindingContext = ctxt; - addBindingReference(reference); - value->type = QQmlScript::Value::PropertyBinding; - - return true; -} - -bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v, - QQmlScript::Property *prop, - const QQmlCompilerTypes::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; - v->type = QQmlScript::Value::PropertyBinding; - 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; - v->type = QQmlScript::Value::PropertyBinding; - return true; - } - - } - } - } - - } - - return false; -} - -void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding, - QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Property *valueTypeProperty) -{ - Q_UNUSED(obj); - Q_ASSERT(binding->bindingReference); - - const BindingReference &ref = *binding->bindingReference; -#ifndef QT_NO_TRANSLATION - 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 -#endif - if (ref.dataType == BindingReference::QtScript) { - const JSBindingReference &js = static_cast(ref); - - Instruction::StoreBinding store; - store.functionIndex = js.compiledIndex; - store.context = js.bindingContext.stack; - store.owner = js.bindingContext.owner; - store.line = binding->location.start.line; - store.column = binding->location.start.column; - store.isAlias = prop->isAlias; - - if (valueTypeProperty) { - store.isRoot = (compileState->root == valueTypeProperty->parent); - } else { - store.isRoot = (compileState->root == obj); - } - store.isFallback = false; - - Q_ASSERT(js.bindingContext.owner == 0 || - (js.bindingContext.owner != 0 && valueTypeProperty)); - if (js.bindingContext.owner) { - store.property = genValueTypeData(prop, valueTypeProperty); - } else { - store.property = prop->core; - } - - output->addInstruction(store); - } else { - Q_ASSERT(!"Unhandled BindingReference::DataType type"); - } -} - -int QQmlCompiler::genContextCache() -{ - if (compileState->ids.count() == 0) - return -1; - - QVector cache(compileState->ids.count()); - int i = 0; - for (QQmlScript::Object *o = compileState->ids.first(); o; o = compileState->ids.next(o), ++i) - cache[i] = QQmlContextData::ObjectIdMapping(o->id, o->idIndex); - - output->contextCaches.append(cache); - return output->contextCaches.count() - 1; -} - -QQmlPropertyData -QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, - QQmlScript::Property *prop) -{ - QQmlValueType *vt = QQmlValueTypeFactory::valueType(prop->type); - Q_ASSERT(vt); - return QQmlPropertyPrivate::saveValueType(prop->core, vt->metaObject(), valueTypeProp->index, engine); -} - -bool QQmlCompiler::completeComponentBuild() -{ - if (componentStats) - componentStats->componentStat.ids = compileState->ids.count(); - - for (QQmlScript::Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; - aliasObject = compileState->aliasingObjects.next(aliasObject)) - COMPILE_CHECK(buildDynamicMetaAliases(aliasObject)); - - const QQmlScript::Parser &parser = unit->parser(); - QQmlJS::Engine *jsEngine = parser.jsEngine(); - QQmlJS::MemoryPool *pool = jsEngine->pool(); - QStringList stringPool; - stringPool.append(QString()); - - for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { - - JSBindingReference &binding = *b; - binding.dataType = BindingReference::QtScript; - - QQmlJS::AST::Node *node = binding.expression.asAST(); - // Always wrap this in an ExpressionStatement, to make sure that - // property var foo: function() { ... } results in a closure initialization. - if (!node->statementCast()) { - AST::ExpressionNode *expr = node->expressionCast(); - node = new (pool) AST::ExpressionStatement(expr); - } - - ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object]; - QtQml::CompiledFunctionOrExpression f; - f.node = node; - QString name = binding.property->name().toString().prepend(QStringLiteral("expression for ")); - stringPool.append(name); - f.nameIndex = stringPool.count() - 1; - f.disableAcceleratedLookups = binding.disableLookupAcceleration; - cd->functionsToCompile.append(f); - binding.compiledIndex = cd->functionsToCompile.count() - 1; - - if (componentStats && b->value) - componentStats->componentStat.scriptBindings.append(b->value->location); - } - - if (!compileState->jsCompileData.isEmpty()) { - const QString &sourceCode = jsEngine->code(); - AST::UiProgram *qmlRoot = parser.qmlRoot(); - - JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache, stringPool); - - JSCodeGen::ObjectIdMapping idMapping; - if (compileState->ids.count() > 0) { - idMapping.reserve(compileState->ids.count()); - for (QQmlScript::Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) { - JSCodeGen::IdMapping m; - m.name = o->id; - m.idIndex = o->idIndex; - if (output->types[o->type].isFullyDynamicType) - m.type = 0; - else - m.type = o->metatype; - idMapping << m; - } - } - - jsCodeGen.beginContextScope(idMapping, compileState->root->metatype); - - for (QHash::Iterator it = compileState->jsCompileData.begin(); - it != compileState->jsCompileData.end(); ++it) { - QQmlScript::Object *scopeObject = it.key(); - ComponentCompileState::PerObjectCompileData *cd = &it.value(); - - jsCodeGen.beginObjectScope(scopeObject->metatype); - - cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile); - QList errors = jsCodeGen.errors(); - if (!errors.isEmpty()) { - exceptions << errors; - return false; - } - - foreach (const QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod &cmm, cd->compiledMetaMethods) { - typedef QQmlVMEMetaData VMD; - VMD *vmd = (QQmlVMEMetaData *)scopeObject->synthdata.data(); - VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex); - md.runtimeFunctionIndex = cd->runtimeFunctionIndices.at(cmm.compiledFunctionIndex); - } - } - - for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { - JSBindingReference &binding = *b; - binding.compiledIndex = compileState->jsCompileData[binding.bindingContext.object].runtimeFunctionIndices[binding.compiledIndex]; - if (!binding.value) { // Must be a binding requested from custom parser - Q_ASSERT(binding.customParserBindingsIndex >= 0 && binding.customParserBindingsIndex < output->customParserBindings.count()); - output->customParserBindings[binding.customParserBindingsIndex] = binding.compiledIndex; - } - } - } - - // Check pop()'s matched push()'s - Q_ASSERT(compileState->objectDepth.depth() == 0); - Q_ASSERT(compileState->listDepth.depth() == 0); - - saveComponentState(); - - return true; -} - -void QQmlCompiler::dumpStats() -{ - Q_ASSERT(componentStats); - qWarning().nospace() << "QML Document: " << output->url.toString(); - 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; - - qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count(); - { - QByteArray output; - for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) { - if (0 == (ii % 10)) { - if (ii) output.append('\n'); - output.append(" "); - } - - output.append('('); - output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line)); - output.append(':'); - output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column)); - output.append(") "); - } - if (!output.isEmpty()) - qWarning().nospace() << output.constData(); - } - } -} - -/*! - Returns true if from can be assigned to a (QObject) property of type - to. -*/ -bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from) -{ - QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to); - QQmlPropertyCache *fromMo = from->metatype; - - while (fromMo) { - if (fromMo == toMo) - return true; - fromMo = fromMo->parent(); - } - return false; -} - -/*! - Returns the element name, as written in the QML file, for o. -*/ -QString QQmlCompiler::elementName(QQmlScript::Object *o) -{ - Q_ASSERT(o); - if (o->type != -1) { - return unit->parser().referencedTypes().at(o->type)->name; - } else { - return QString(); - } -} - -QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from) -{ - if (from->type != -1 && output->types.at(from->type).type) - return output->types.at(from->type).type; - - const QMetaObject *mo = from->metatype->firstCppMetaObject(); - QQmlType *type = 0; - while (!type && mo) { - type = QQmlMetaType::qmlType(mo); - mo = mo->superClass(); - } - return type; -} - -QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj) -{ - const QMetaObject *mo = obj->metatype->firstCppMetaObject(); - - int idx = mo->indexOfClassInfo("DeferredPropertyNames"); - if (idx == -1) - return QStringList(); - - QMetaClassInfo classInfo = mo->classInfo(idx); - QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); - return rv; -} - -QQmlPropertyCache * -QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object) - { - if (object->synthCache) - return object->synthCache; - else if (object->type != -1) - return output->types[object->type].createPropertyCache(engine); - else - return object->metatype; -} - -QQmlPropertyData * -QQmlCompiler::property(QQmlScript::Object *object, int index) -{ - QQmlPropertyCache *cache = propertyCacheForObject(object); - - return cache->property(index); -} - -QQmlPropertyData * -QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision) -{ - if (notInRevision) *notInRevision = false; - - QQmlPropertyCache *cache = propertyCacheForObject(object); - - QQmlPropertyData *d = cache->property(name, 0, 0); - - // 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 d; - } -} - -// This code must match the semantics of QQmlPropertyPrivate::findSignalByName -QQmlPropertyData * -QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision) -{ - if (notInRevision) *notInRevision = false; - - QQmlPropertyCache *cache = propertyCacheForObject(object); - - - QQmlPropertyData *d = cache->property(name, 0, 0); - 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 && d->isSignal()) { - 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->signal(d->notifyIndex); - } - - return 0; -} - -// This code must match the semantics of QQmlPropertyPrivate::findSignalByName -int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name, - bool *notInRevision) -{ - QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision); - return d?d->coreIndex:-1; -} - -int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name, - bool *notInRevision) -{ - return indexOfProperty(object, QStringRef(&name), notInRevision); -} - -int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name, - bool *notInRevision) -{ - QQmlPropertyData *d = property(object, name, notInRevision); - return d?d->coreIndex:-1; -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 03134091f0..98d308aa5c 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -55,7 +55,6 @@ #include "qqml.h" #include "qqmlerror.h" -#include "qqmlinstruction_p.h" #include "qqmlscript_p.h" #include "qqmlengine_p.h" #include @@ -126,23 +125,8 @@ public: void doDynamicTypeCheck(); }; - // --- old compiler: - QList types; - // --- new compiler: // map from name index QHash resolvedTypes; - // --- - - struct V8Program { - V8Program(const QByteArray &p, QQmlCompiledData *c) - : program(p), cdata(c) {} - - QByteArray program; - QV4::PersistentValue bindings; - QQmlCompiledData *cdata; - }; - - QList programs; QQmlPropertyCache *rootPropertyCache; QList primitives; @@ -173,28 +157,6 @@ public: bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); } - // --- - - struct Instruction { -#define QML_INSTR_DATA_TYPEDEF(I, FMT) typedef QQmlInstructionData I; - FOR_EACH_QML_INSTR(QML_INSTR_DATA_TYPEDEF) -#undef QML_INSTR_DATA_TYPEDEF - private: - Instruction(); - }; - - void dumpInstructions(); - - template - int addInstruction(const QQmlInstructionData &data) - { - QQmlInstruction genericInstr; - QQmlInstructionMeta::setDataNoCommon(genericInstr, data); - return addInstructionHelper(static_cast(Instr), genericInstr); - } - int nextInstructionIndex(); - QQmlInstruction *instruction(int index); - QQmlInstruction::Type instructionType(const QQmlInstruction *instr); bool isInitialized() const { return hasEngine(); } void initialize(QQmlEngine *); @@ -204,318 +166,8 @@ protected: virtual void clear(); // From QQmlCleanup private: - friend class QQmlCompiler; - - int addInstructionHelper(QQmlInstruction::Type type, QQmlInstruction &instr); - void dump(QQmlInstruction *, int idx = -1); QQmlCompiledData(const QQmlCompiledData &other); QQmlCompiledData &operator=(const QQmlCompiledData &other); - - int indexForString(const QString &); - int indexForByteArray(const QByteArray &); - int indexForUrl(const QUrl &); -}; - -namespace QQmlCompilerTypes { - struct BindingContext - { - BindingContext() - : stack(0), owner(0), object(0) {} - BindingContext(QQmlScript::Object *o) - : stack(0), owner(0), object(o) {} - BindingContext incr() const { - BindingContext rv(object); - rv.stack = stack + 1; - return rv; - } - bool isSubContext() const { return stack != 0; } - int stack; - int owner; - QQmlScript::Object *object; - }; - - struct BindingReference - { - enum DataType { QtScript, - Tr, TrId }; - DataType dataType; - }; - - struct JSBindingReference : public QQmlPool::Class, - public BindingReference - { - JSBindingReference() : disableLookupAcceleration(false), nextReference(0) {} - - QQmlScript::Variant expression; - QQmlScript::Property *property; - QQmlScript::Value *value; - - int compiledIndex : 16; - int customParserBindingsIndex : 15; - int disableLookupAcceleration: 1; - - BindingContext bindingContext; - - JSBindingReference *nextReference; - }; - - struct TrBindingReference : public QQmlPool::POD, - public BindingReference - { - QStringRef text; - QStringRef comment; - int n; - }; - - struct IdList : public QFieldList - { - QQmlScript::Object *value(const QString &id) const { - for (QQmlScript::Object *o = first(); o; o = next(o)) { - if (o->id == id) - return o; - } - return 0; - } - }; - - struct DepthStack { - DepthStack() : _depth(0), _maxDepth(0) {} - DepthStack(const DepthStack &o) : _depth(o._depth), _maxDepth(o._maxDepth) {} - DepthStack &operator=(const DepthStack &o) { _depth = o._depth; _maxDepth = o._maxDepth; return *this; } - - int depth() const { return _depth; } - int maxDepth() const { return _maxDepth; } - - void push() { ++_depth; _maxDepth = qMax(_depth, _maxDepth); } - void pop() { --_depth; Q_ASSERT(_depth >= 0); Q_ASSERT(_maxDepth > _depth); } - - void pushPop(int count) { _maxDepth = qMax(_depth + count, _maxDepth); } - private: - int _depth; - int _maxDepth; - }; - - // Contains all the incremental compiler state about a component. As - // a single QML file can have multiple components defined, there may be - // more than one of these for each compile - struct ComponentCompileState : public QQmlPool::Class - { - ComponentCompileState() - : parserStatusCount(0), totalBindingsCount(0), pushedProperties(0), nested(false), - root(0) {} - - IdList ids; - int parserStatusCount; - int totalBindingsCount; - int pushedProperties; - bool nested; - - QByteArray compiledBindingData; - - DepthStack objectDepth; - DepthStack listDepth; - - typedef QQmlCompilerTypes::JSBindingReference B; - typedef QFieldList JSBindingReferenceList; - JSBindingReferenceList bindings; - typedef QQmlScript::Object O; - typedef QFieldList AliasingObjectsList; - AliasingObjectsList aliasingObjects; - QQmlScript::Object *root; - - struct CompiledMetaMethod - { - int methodIndex; - int compiledFunctionIndex; // index in functionToCompile - }; - - QList compiledMetaMethods; - struct PerObjectCompileData - { - QList functionsToCompile; - QVector runtimeFunctionIndices; - QVector compiledMetaMethods; - }; - QHash jsCompileData; - }; -}; - -class QMetaObjectBuilder; -class Q_AUTOTEST_EXPORT QQmlCompiler : public QQmlCustomParserCompilerBackend -{ - Q_DECLARE_TR_FUNCTIONS(QQmlCompiler) -public: - QQmlCompiler(QQmlPool *); - - bool compile(QQmlEngine *, QQmlTypeData *, QQmlCompiledData *); - - bool isError() const; - QList errors() const; - - static bool isAttachedPropertyName(const QString &); - static bool isSignalPropertyName(const QString &); - static bool isAttachedPropertyName(const QHashedStringRef &); - static bool isSignalPropertyName(const QHashedStringRef &); - - virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&value, const QString&name, QQmlCustomParser *customParser); - - virtual const QQmlImports &imports() const { return unit->imports(); } - -private: - typedef QQmlCompiledData::Instruction Instruction; - - static void reset(QQmlCompiledData *); - - void compileTree(QQmlScript::Object *tree); - - - bool buildObject(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); - bool buildComponent(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); - bool buildSubObject(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); - bool buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &); - bool buildProperty(QQmlScript::Property *prop, QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &); - bool buildPropertyInNamespace(QQmlImportNamespace *ns, - QQmlScript::Property *prop, - QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &); - bool buildIdProperty(QQmlScript::Property *prop, QQmlScript::Object *obj); - bool buildAttachedProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildGroupedProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildValueTypeProperty(QObject *type, - QQmlScript::Object *obj, - QQmlScript::Object *baseObj, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildListProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildScriptStringProperty(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildPropertyAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildPropertyObjectAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Value *value, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildPropertyOnAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Object *baseObj, - QQmlScript::Value *value, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildPropertyLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Value *value, - const QQmlCompilerTypes::BindingContext &ctxt); - bool doesPropertyExist(QQmlScript::Property *prop, QQmlScript::Object *obj); - bool testLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::Value *value); - bool testQualifiedEnumAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Value *value, - bool *isAssignment); - enum DynamicMetaMode { Normal, ForceCreation }; - bool mergeDynamicMetaProperties(QQmlScript::Object *obj); - bool buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode); - bool buildDynamicMetaAliases(QQmlScript::Object *obj); - bool checkDynamicMeta(QQmlScript::Object *obj); - bool buildBinding(QQmlScript::Value *, QQmlScript::Property *prop, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildLiteralBinding(QQmlScript::Value *, QQmlScript::Property *prop, - const QQmlCompilerTypes::BindingContext &ctxt); - bool buildComponentFromRoot(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); - bool completeComponentBuild(); - bool checkValidId(QQmlScript::Value *, const QString &); - - - void genObject(QQmlScript::Object *obj, bool parentToSuper = false); - void genObjectBody(QQmlScript::Object *obj); - void genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *); - void genComponent(QQmlScript::Object *obj); - void genValueProperty(QQmlScript::Property *prop, QQmlScript::Object *obj); - void genListProperty(QQmlScript::Property *prop, QQmlScript::Object *obj); - void genPropertyAssignment(QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Property *valueTypeProperty = 0); - void genLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::Value *value); - void genBindingAssignment(QQmlScript::Value *binding, - QQmlScript::Property *prop, - QQmlScript::Object *obj, - QQmlScript::Property *valueTypeProperty = 0); - int genContextCache(); - - QQmlPropertyData genValueTypeData(QQmlScript::Property *prop, - QQmlScript::Property *valueTypeProp); - - int componentTypeRef(); - int translationContextIndex(); - - QQmlType *toQmlType(QQmlScript::Object *from); - bool canCoerce(int to, QQmlScript::Object *from); - - QString elementName(QQmlScript::Object *); - - QStringList deferredProperties(QQmlScript::Object *); - - QQmlPropertyCache *propertyCacheForObject(QQmlScript::Object *); - QQmlPropertyData *property(QQmlScript::Object *, int); - QQmlPropertyData *property(QQmlScript::Object *, const QHashedStringRef &, - bool *notInRevision = 0); - QQmlPropertyData *signal(QQmlScript::Object *, const QHashedStringRef &, - bool *notInRevision = 0); - int indexOfProperty(QQmlScript::Object *, const QHashedStringRef &, bool *notInRevision = 0); - int indexOfProperty(QQmlScript::Object *, const QString &, bool *notInRevision = 0); - int indexOfSignal(QQmlScript::Object *, const QString &, bool *notInRevision = 0); - - void addId(const QString &, QQmlScript::Object *); - - void dumpStats(); - - void addBindingReference(QQmlCompilerTypes::JSBindingReference *); - - QQmlCompilerTypes::ComponentCompileState *compileState; - - QQmlPool *pool; - - QQmlCompilerTypes::ComponentCompileState *componentState(QQmlScript::Object *); - void saveComponentState(); - - QList exceptions; - QQmlCompiledData *output; - QQmlEngine *engine; - QQmlEnginePrivate *enginePrivate; - QQmlScript::Object *unitRoot; - QQmlTypeData *unit; - int cachedComponentTypeRef; - int cachedTranslationContextIndex; - - QScopedPointer jsModule; - - // Compiler component statistics. Only collected if QML_COMPILER_STATS=1 - struct ComponentStat - { - ComponentStat() : lineNumber(0), ids(0), objects(0) {} - - quint16 lineNumber; - - int ids; - QList scriptBindings; - int objects; - }; - struct ComponentStats : public QQmlPool::Class - { - ComponentStat componentStat; - QList savedComponentStats; - }; - ComponentStats *componentStats; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index feeb42b7ed..77d02e071f 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -881,15 +881,10 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) enginePriv->referenceScarceResources(); QObject *rv = 0; - if (enginePriv->useNewCompiler) { - state.creator = new QQmlObjectCreator(context, cc, creationContext); - rv = state.creator->create(start); - if (!rv) - state.errors = state.creator->errors; - } else { - state.vme.init(context, cc, start, creationContext); - rv = state.vme.execute(&state.errors); - } + state.creator = new QQmlObjectCreator(context, cc, creationContext); + rv = state.creator->create(start); + if (!rv) + state.errors = state.creator->errors; enginePriv->dereferenceScarceResources(); if (rv) { @@ -922,29 +917,20 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv, state->errors.clear(); state->completePending = true; - if (enginePriv->useNewCompiler) { - QQmlData *ddata = QQmlData::get(object); - Q_ASSERT(ddata->deferredData); - QQmlData::DeferredData *deferredData = ddata->deferredData; - QQmlContextData *creationContext = 0; - state->creator = new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext); - if (!state->creator->populateDeferredProperties(object)) - state->errors << state->creator->errors; - } else { - state->vme.initDeferred(object); - state->vme.execute(&state->errors); - } + QQmlData *ddata = QQmlData::get(object); + Q_ASSERT(ddata->deferredData); + QQmlData::DeferredData *deferredData = ddata->deferredData; + QQmlContextData *creationContext = 0; + state->creator = new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext); + if (!state->creator->populateDeferredProperties(object)) + state->errors << state->creator->errors; } void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state) { if (state->completePending) { - if (enginePriv->useNewCompiler) { - QQmlInstantiationInterrupt interrupt; - state->creator->finalize(interrupt); - } else { - state->vme.complete(); - } + QQmlInstantiationInterrupt interrupt; + state->creator->finalize(interrupt); state->completePending = false; @@ -1015,9 +1001,7 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj) return a; QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine); - if (p->activeVME) { // XXX should only be allowed during begin - a->add(&p->activeVME->componentAttached); - } else if (p->activeObjectCreator) { + if (p->activeObjectCreator) { // XXX should only be allowed during begin a->add(p->activeObjectCreator->componentAttachment()); } else { QQmlData *d = QQmlData::get(obj); @@ -1083,11 +1067,8 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, p->compiledData = d->cc; p->compiledData->addref(); - if (enginePriv->useNewCompiler) { - p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext, p.data())); - p->subComponentToCreate = d->start; - } else - p->vme.init(contextData, d->cc, d->start, d->creationContext); + p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext, p.data())); + p->subComponentToCreate = d->start; enginePriv->incubate(incubator, forContextData); } diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 9bccb0be7b..e8ae540148 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -114,11 +114,7 @@ public: delete creator; } - // --- new compiler QQmlObjectCreator *creator; - // --- old compiler - QQmlVME vme; - // --- QList errors; bool completePending; }; diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index f661317794..16e3abf3a0 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include "qqmlcustomparser_p.h" -#include "qqmlcustomparser_p_p.h" #include "qqmlcompiler_p.h" @@ -93,189 +92,11 @@ using namespace QQmlScript; The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE. */ -QQmlCustomParserNode -QQmlCustomParserNodePrivate::fromObject(QQmlScript::Object *root) -{ - QQmlCustomParserNode rootNode; - if (root->typeReference) - rootNode.d->name = root->typeReference->name; - rootNode.d->location = root->location.start; - - for (QQmlScript::Property *p = root->properties.first(); p; p = root->properties.next(p)) { - rootNode.d->properties << fromProperty(p); - } - - if (root->defaultProperty) - rootNode.d->properties << fromProperty(root->defaultProperty); - - return rootNode; -} - -QQmlCustomParserProperty -QQmlCustomParserNodePrivate::fromProperty(QQmlScript::Property *p) -{ - QQmlCustomParserProperty prop; - prop.d->name = p->name().toString(); - prop.d->isList = p->values.isMany(); - prop.d->location = p->location.start; - - if (p->value) { - QQmlCustomParserNode node = fromObject(p->value); - QList props = node.properties(); - for (int ii = 0; ii < props.count(); ++ii) - prop.d->values << QVariant::fromValue(props.at(ii)); - } else { - for (QQmlScript::Value *v = p->values.first(); v; v = p->values.next(v)) { - v->type = QQmlScript::Value::Literal; - - if(v->object) { - QQmlCustomParserNode node = fromObject(v->object); - prop.d->values << QVariant::fromValue(node); - } else { - prop.d->values << QVariant::fromValue(v->value); - } - - } - } - - return prop; -} - -QQmlCustomParserNode::QQmlCustomParserNode() -: d(new QQmlCustomParserNodePrivate) -{ -} - -QQmlCustomParserNode::QQmlCustomParserNode(const QQmlCustomParserNode &other) -: d(new QQmlCustomParserNodePrivate) -{ - *this = other; -} - -QQmlCustomParserNode &QQmlCustomParserNode::operator=(const QQmlCustomParserNode &other) -{ - d->name = other.d->name; - d->properties = other.d->properties; - d->location = other.d->location; - return *this; -} - -QQmlCustomParserNode::~QQmlCustomParserNode() -{ - delete d; d = 0; -} - -QString QQmlCustomParserNode::name() const -{ - return d->name; -} - -QList QQmlCustomParserNode::properties() const -{ - return d->properties; -} - -QQmlScript::Location QQmlCustomParserNode::location() const -{ - return d->location; -} - -QQmlCustomParserProperty::QQmlCustomParserProperty() -: d(new QQmlCustomParserPropertyPrivate) -{ -} - -QQmlCustomParserProperty::QQmlCustomParserProperty(const QQmlCustomParserProperty &other) -: d(new QQmlCustomParserPropertyPrivate) -{ - *this = other; -} - -QQmlCustomParserProperty &QQmlCustomParserProperty::operator=(const QQmlCustomParserProperty &other) -{ - d->name = other.d->name; - d->isList = other.d->isList; - d->values = other.d->values; - d->location = other.d->location; - return *this; -} - -QQmlCustomParserProperty::~QQmlCustomParserProperty() -{ - delete d; d = 0; -} - -QString QQmlCustomParserProperty::name() const -{ - return d->name; -} - -bool QQmlCustomParserProperty::isList() const -{ - return d->isList; -} - -QQmlScript::Location QQmlCustomParserProperty::location() const -{ - return d->location; -} - -QList QQmlCustomParserProperty::assignedValues() const -{ - return d->values; -} - void QQmlCustomParser::clearErrors() { exceptions.clear(); } -/*! - Reports an error with the given \a description. - - This can only be used during the compile() step. For errors during setCustomData(), use qmlInfo(). - - An error is generated referring to the position of the element in the source file. -*/ -void QQmlCustomParser::error(const QString& description) -{ - Q_ASSERT(object); - QQmlError error; - QString exceptionDescription; - error.setLine(object->location.start.line); - error.setColumn(object->location.start.column); - error.setDescription(description); - exceptions << error; -} - -/*! - Reports an error in parsing \a prop, with the given \a description. - - An error is generated referring to the position of \a node in the source file. -*/ -void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString& description) -{ - QQmlError error; - error.setLine(prop.location().line); - error.setColumn(prop.location().column); - error.setDescription(description); - exceptions << error; -} - -/*! - Reports an error in parsing \a node, with the given \a description. - - An error is generated referring to the position of \a node in the source file. -*/ -void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& description) -{ - QQmlError error; - error.setLine(node.location().line); - error.setColumn(node.location().column); - error.setDescription(description); - exceptions << error; -} - /*! Reports an error with the given \a description. @@ -318,16 +139,6 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const return compiler->resolveType(name); } -/*! - Rewrites \a value and returns an identifier that can be - used to construct the binding later. \a name - is used as the name of the rewritten function. -*/ -QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QQmlScript::Variant &value, const QString& name) -{ - return compiler->bindingIdentifier(value, name, this); -} - QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledData::Binding *binding) { return compiler->bindingIdentifier(binding, this); diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index 4861456c3d..8d98cf6423 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -63,51 +63,6 @@ QT_BEGIN_NAMESPACE - -class QQmlCompiler; - -class QQmlCustomParserPropertyPrivate; -class Q_QML_PRIVATE_EXPORT QQmlCustomParserProperty -{ -public: - QQmlCustomParserProperty(); - QQmlCustomParserProperty(const QQmlCustomParserProperty &); - QQmlCustomParserProperty &operator=(const QQmlCustomParserProperty &); - ~QQmlCustomParserProperty(); - - QString name() const; - QQmlScript::Location location() const; - - bool isList() const; - // Will be one of QQmlScript::Variant, QQmlCustomParserProperty or - // QQmlCustomParserNode - QList assignedValues() const; - -private: - friend class QQmlCustomParserNodePrivate; - friend class QQmlCustomParserPropertyPrivate; - QQmlCustomParserPropertyPrivate *d; -}; - -class QQmlCustomParserNodePrivate; -class Q_QML_PRIVATE_EXPORT QQmlCustomParserNode -{ -public: - QQmlCustomParserNode(); - QQmlCustomParserNode(const QQmlCustomParserNode &); - QQmlCustomParserNode &operator=(const QQmlCustomParserNode &); - ~QQmlCustomParserNode(); - - QString name() const; - QQmlScript::Location location() const; - - QList properties() const; - -private: - friend class QQmlCustomParserNodePrivate; - QQmlCustomParserNodePrivate *d; -}; - struct QQmlCustomParserCompilerBackend { virtual ~QQmlCustomParserCompilerBackend() {} @@ -116,7 +71,6 @@ struct QQmlCustomParserCompilerBackend int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const; const QMetaObject *resolveType(const QString& name) const; - virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&, QQmlCustomParser *) { return QQmlBinding::Invalid; } virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; } virtual QQmlJS::AST::Node *astForBinding(int, int) const { return 0; } @@ -132,23 +86,19 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag) - QQmlCustomParser() : compiler(0), object(0), m_flags(NoFlag) {} - QQmlCustomParser(Flags f) : compiler(0), object(0), m_flags(f) {} + QQmlCustomParser() : compiler(0), m_flags(NoFlag) {} + QQmlCustomParser(Flags f) : compiler(0), m_flags(f) {} virtual ~QQmlCustomParser() {} void clearErrors(); Flags flags() const { return m_flags; } - virtual QByteArray compile(const QList &)=0; virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList &bindings) = 0; virtual void setCustomData(QObject *, const QByteArray &)=0; QList errors() const { return exceptions; } protected: - void error(const QString& description); - void error(const QQmlCustomParserProperty&, const QString& description); - void error(const QQmlCustomParserNode&, const QString& description); void error(const QV4::CompiledData::Binding *binding, const QString& description) { error(binding->location, description); } void error(const QV4::CompiledData::Object *object, const QString& description) @@ -159,7 +109,6 @@ protected: const QMetaObject *resolveType(const QString&) const; - QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&); QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding); QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const; @@ -167,9 +116,7 @@ protected: private: QList exceptions; QQmlCustomParserCompilerBackend *compiler; - QQmlScript::Object *object; Flags m_flags; - friend class QQmlCompiler; friend class QQmlPropertyValidator; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags) @@ -181,7 +128,4 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags) QT_END_NAMESPACE -Q_DECLARE_METATYPE(QQmlCustomParserProperty) -Q_DECLARE_METATYPE(QQmlCustomParserNode) - #endif diff --git a/src/qml/qml/qqmlcustomparser_p_p.h b/src/qml/qml/qqmlcustomparser_p_p.h deleted file mode 100644 index a6b64c6505..0000000000 --- a/src/qml/qml/qqmlcustomparser_p_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLCUSTOMPARSER_P_H -#define QQMLCUSTOMPARSER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qqmlcustomparser_p.h" - -#include "qqmlscript_p.h" - -#include - -QT_BEGIN_NAMESPACE - -class QQmlCustomParserNodePrivate -{ -public: - QString name; - QList properties; - QQmlScript::Location location; - - static QQmlCustomParserNode fromObject(QQmlScript::Object *); - static QQmlCustomParserProperty fromProperty(QQmlScript::Property *); -}; - -class QQmlCustomParserPropertyPrivate -{ -public: - QQmlCustomParserPropertyPrivate() - : isList(false) {} - - QString name; - bool isList; - QQmlScript::Location location; - QList values; -}; - -QT_END_NAMESPACE - -#endif // QQMLCUSTOMPARSER_P_H diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index c344c3e069..72de9845c8 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -556,7 +556,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) : propertyCapture(0), rootContext(0), isDebugging(false), profiler(0), outputWarningsToStdErr(true), cleanup(0), erroredBindings(0), inProgressCreations(0), - workerScriptEngine(0), activeVME(0), + workerScriptEngine(0), activeObjectCreator(0), networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), uniqueId(1), @@ -1045,9 +1045,7 @@ QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) { - if (activeVME) { - activeVME->finalizeCallbacks.append(qMakePair(QPointer(obj), index)); - } else if (activeObjectCreator) { + if (activeObjectCreator) { activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer(obj), index)); } else { void *args[] = { 0 }; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index e00e55f157..56c80dc2cd 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -98,7 +98,6 @@ class QQmlComponentAttached; class QQmlCleanup; class QQmlDelayedError; class QQuickWorkerScriptEngine; -class QQmlVME; class QQmlObjectCreator; class QDir; class QQmlIncubator; @@ -170,11 +169,7 @@ public: typedef QPair,int> FinalizeCallback; void registerFinalizeCallback(QObject *obj, int index); - // --- old compiler: - QQmlVME *activeVME; - // --- new compiler: QQmlObjectCreator *activeObjectCreator; - // --- QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index da4de338ee..4c9c99f1f6 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -98,10 +98,7 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext) incubatorList.insert(p.data()); incubatorCount++; - if (useNewCompiler) - p->vmeGuard.guard(p->creator.data()); - else - p->vmeGuard.guard(&p->vme); + p->vmeGuard.guard(p->creator.data()); p->changeStatus(QQmlIncubator::Loading); if (incubationController) @@ -137,7 +134,7 @@ QQmlIncubationController *QQmlEngine::incubationController() const QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m) : q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute), - result(0), compiledData(0), vme(this), waitingOnMe(0) + result(0), compiledData(0), waitingOnMe(0) { } @@ -297,13 +294,9 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (progress == QQmlIncubatorPrivate::Execute) { enginePriv->referenceScarceResources(); QObject *tresult = 0; - if (enginePriv->useNewCompiler) { - tresult = creator->create(subComponentToCreate, /*parent*/0, &i); - if (!tresult) - errors = creator->errors; - } else { - tresult = vme.execute(&errors, i); - } + tresult = creator->create(subComponentToCreate, /*parent*/0, &i); + if (!tresult) + errors = creator->errors; enginePriv->dereferenceScarceResources(); if (watcher.hasRecursed()) @@ -347,10 +340,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) return; QQmlContextData *ctxt = 0; - if (enginePriv->useNewCompiler) - ctxt = creator->finalize(i); - else - ctxt = vme.complete(i); + ctxt = creator->finalize(i); if (ctxt) { rootContext = ctxt; progress = QQmlIncubatorPrivate::Completed; @@ -382,10 +372,7 @@ finishIncubate: } } } else { - if (enginePriv->useNewCompiler) - vmeGuard.guard(creator.data()); - else - vmeGuard.guard(&vme); + vmeGuard.guard(creator.data()); } } @@ -584,7 +571,6 @@ void QQmlIncubator::clear() bool guardOk = d->vmeGuard.isOK(); - d->vme.reset(); d->vmeGuard.clear(); if (d->creator && guardOk) d->creator->clear(); diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h index 80da2910c1..ccb03f2bc4 100644 --- a/src/qml/qml/qqmlincubator_p.h +++ b/src/qml/qml/qqmlincubator_p.h @@ -88,12 +88,8 @@ public: QPointer result; QQmlGuardedContextData rootContext; QQmlCompiledData *compiledData; - // --- old compiler - QQmlVME vme; - // --- new compiler QScopedPointer creator; int subComponentToCreate; - // --- QQmlVMEGuard vmeGuard; QExplicitlySharedDataPointer waitingOnMe; diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp deleted file mode 100644 index 33ea3bb7d9..0000000000 --- a/src/qml/qml/qqmlinstruction.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlinstruction_p.h" - -#include "qqmlcompiler_p.h" - -#include - -QT_BEGIN_NAMESPACE - -void QQmlCompiledData::dump(QQmlInstruction *instr, int idx) -{ -#ifdef QT_NO_DEBUG_STREAM - Q_UNUSED(instr) - Q_UNUSED(idx) -#else - switch (instructionType(instr)) { - case QQmlInstruction::Init: - qWarning().nospace() << idx << "\t\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding; - break; - case QQmlInstruction::DeferInit: - qWarning().nospace() << idx << "\t\t" << "DEFER_INIT\t\t" << instr->deferInit.bindingsSize << "\t" << instr->deferInit.parserStatusSize << "\t" << instr->deferInit.objectStackSize << "\t" << instr->deferInit.listStackSize; - break; - case QQmlInstruction::Done: - qWarning().nospace() << idx << "\t\t" << "DONE"; - break; - case QQmlInstruction::CreateCppObject: - qWarning().nospace() << idx << "\t\t" << "CREATECPP\t\t\t" << instr->create.type; - break; - case QQmlInstruction::CreateQMLObject: - qWarning().nospace() << idx << "\t\t" << "CREATEQML\t\t\t" << instr->createQml.type << "\t" << instr->createQml.bindingBits; - break; - case QQmlInstruction::CompleteQMLObject: - qWarning().nospace() << idx << "\t\t" << "COMPLETEQML"; - break; - case QQmlInstruction::CreateSimpleObject: - qWarning().nospace() << idx << "\t\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize; - break; - case QQmlInstruction::SetId: - qWarning().nospace() << idx << "\t\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value); - break; - case QQmlInstruction::SetDefault: - qWarning().nospace() << idx << "\t\t" << "SET_DEFAULT"; - break; - case QQmlInstruction::CreateComponent: - qWarning().nospace() << idx << "\t\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; - break; - case QQmlInstruction::StoreMetaObject: - qWarning().nospace() << idx << "\t\t" << "STORE_META\t\t"; - break; - case QQmlInstruction::StoreFloat: - qWarning().nospace() << idx << "\t\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; - break; - case QQmlInstruction::StoreDouble: - qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; - break; - case QQmlInstruction::StoreDoubleQList: - qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE_QLIST\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; - break; - case QQmlInstruction::StoreInteger: - qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; - break; - case QQmlInstruction::StoreIntegerQList: - qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER_QLIST\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; - break; - case QQmlInstruction::StoreBool: - qWarning().nospace() << idx << "\t\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; - break; - case QQmlInstruction::StoreBoolQList: - qWarning().nospace() << idx << "\t\t" << "STORE_BOOL_QLIST\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; - break; - case QQmlInstruction::StoreString: - qWarning().nospace() << idx << "\t\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); - break; - case QQmlInstruction::StoreStringList: - qWarning().nospace() << idx << "\t\t" << "STORE_STRINGLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); - break; - case QQmlInstruction::StoreStringQList: - qWarning().nospace() << idx << "\t\t" << "STORE_STRING_QLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); - break; -#ifndef QT_NO_TRANSLATION - case QQmlInstruction::StoreTrString: - qWarning().nospace() << idx << "\t\t" << "STORE_TR_STRING\t" << instr->storeTrString.propertyIndex << "\t" << instr->storeTrString.context << "\t" << instr->storeTrString.text << "\t" << instr->storeTrString.comment << "\t" << instr->storeTrString.n; - break; - case QQmlInstruction::StoreTrIdString: - qWarning().nospace() << idx << "\t\t" << "STORE_TRID_STRING\t" << instr->storeTrIdString.propertyIndex << "\t" << instr->storeTrIdString.text << "\t" << instr->storeTrIdString.n; - break; -#endif - case QQmlInstruction::StoreByteArray: - qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value); - break; - case QQmlInstruction::StoreUrl: - qWarning().nospace() << idx << "\t\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value); - break; - case QQmlInstruction::StoreUrlQList: - qWarning().nospace() << idx << "\t\t" << "STORE_URL_QLIST\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value); - break; - case QQmlInstruction::StoreColor: - qWarning().nospace() << idx << "\t\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16); - break; - case QQmlInstruction::StoreDate: - qWarning().nospace() << idx << "\t\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value; - break; - case QQmlInstruction::StoreTime: - qWarning().nospace() << idx << "\t\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex; - break; - case QQmlInstruction::StoreDateTime: - qWarning().nospace() << idx << "\t\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex; - break; - case QQmlInstruction::StorePoint: - qWarning().nospace() << idx << "\t\t" << "STORE_POINT\t\t" << instr->storePoint.propertyIndex << "\t" << instr->storePoint.point.xp << "\t" << instr->storePoint.point.yp; - break; - case QQmlInstruction::StorePointF: - qWarning().nospace() << idx << "\t\t" << "STORE_POINTF\t\t" << instr->storePointF.propertyIndex << "\t" << instr->storePointF.point.xp << "\t" << instr->storePointF.point.yp; - break; - case QQmlInstruction::StoreSize: - qWarning().nospace() << idx << "\t\t" << "STORE_SIZE\t\t" << instr->storeSize.propertyIndex << "\t" << instr->storeSize.size.wd << "\t" << instr->storeSize.size.ht; - break; - case QQmlInstruction::StoreSizeF: - qWarning().nospace() << idx << "\t\t" << "STORE_SIZEF\t\t" << instr->storeSizeF.propertyIndex << "\t" << instr->storeSizeF.size.wd << "\t" << instr->storeSizeF.size.ht; - break; - case QQmlInstruction::StoreRect: - qWarning().nospace() << idx << "\t\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.rect.x1 << "\t" << instr->storeRect.rect.y1 << "\t" << instr->storeRect.rect.x2 << "\t" << instr->storeRect.rect.y2; - break; - case QQmlInstruction::StoreRectF: - qWarning().nospace() << idx << "\t\t" << "STORE_RECTF\t\t" << instr->storeRectF.propertyIndex << "\t" << instr->storeRectF.rect.xp << "\t" << instr->storeRectF.rect.yp << "\t" << instr->storeRectF.rect.w << "\t" << instr->storeRectF.rect.h; - break; - case QQmlInstruction::StoreVector3D: - qWarning().nospace() << idx << "\t\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.vector.xp << "\t" << instr->storeVector3D.vector.yp << "\t" << instr->storeVector3D.vector.zp; - break; - case QQmlInstruction::StoreVector4D: - qWarning().nospace() << idx << "\t\t" << "STORE_VECTOR4D\t\t" << instr->storeVector4D.propertyIndex << "\t" << instr->storeVector4D.vector.xp << "\t" << instr->storeVector4D.vector.yp << "\t" << instr->storeVector4D.vector.zp << "\t" << instr->storeVector4D.vector.wp; - break; - case QQmlInstruction::StoreVariant: - qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); - break; - case QQmlInstruction::StoreVariantInteger: - qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; - break; - case QQmlInstruction::StoreVariantDouble: - qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; - break; - case QQmlInstruction::StoreVariantBool: - qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; - break; - case QQmlInstruction::StoreVar: - qWarning().nospace() << idx << "\t\t" << "STORE_VAR\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); - break; - case QQmlInstruction::StoreVarInteger: - qWarning().nospace() << idx << "\t\t" << "STORE_VAR_INTEGER\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; - break; - case QQmlInstruction::StoreVarDouble: - qWarning().nospace() << idx << "\t\t" << "STORE_VAR_DOUBLE\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; - break; - case QQmlInstruction::StoreVarBool: - qWarning().nospace() << idx << "\t\t" << "STORE_VAR_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; - break; - case QQmlInstruction::StoreObject: - qWarning().nospace() << idx << "\t\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; - break; - case QQmlInstruction::StoreVariantObject: - qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; - break; - case QQmlInstruction::StoreVarObject: - qWarning().nospace() << idx << "\t\t" << "STORE_VAR_OBJECT\t" << instr->storeObject.propertyIndex; - break; - case QQmlInstruction::StoreInterface: - qWarning().nospace() << idx << "\t\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; - break; - case QQmlInstruction::StoreSignal: - qWarning().nospace() << idx << "\t\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value; - break; - case QQmlInstruction::StoreImportedScript: - qWarning().nospace() << idx << "\t\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value; - break; - case QQmlInstruction::StoreScriptString: - qWarning().nospace() << idx << "\t\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope << "\t" << instr->storeScriptString.bindingId; - break; - case QQmlInstruction::AssignSignalObject: - qWarning().nospace() << idx << "\t\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal; - break; - case QQmlInstruction::AssignCustomType: - qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type; - break; - case QQmlInstruction::StoreBinding: - qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.functionIndex << "\t" << instr->assignBinding.context; - break; - case QQmlInstruction::StoreValueSource: - qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property.coreIndex << "\t" << instr->assignValueSource.castValue; - break; - case QQmlInstruction::StoreValueInterceptor: - qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property.coreIndex << "\t" << instr->assignValueInterceptor.castValue; - break; - case QQmlInstruction::BeginObject: - qWarning().nospace() << idx << "\t\t" << "BEGIN\t\t\t" << instr->begin.castValue; - break; - case QQmlInstruction::StoreObjectQList: - qWarning().nospace() << idx << "\t\t" << "STORE_OBJECT_QLIST"; - break; - case QQmlInstruction::AssignObjectList: - qWarning().nospace() << idx << "\t\t" << "ASSIGN_OBJECT_LIST"; - break; - case QQmlInstruction::FetchAttached: - qWarning().nospace() << idx << "\t\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id; - break; - case QQmlInstruction::FetchQList: - qWarning().nospace() << idx << "\t\t" << "FETCH_QLIST\t\t" << instr->fetch.property; - break; - case QQmlInstruction::FetchObject: - qWarning().nospace() << idx << "\t\t" << "FETCH\t\t\t" << instr->fetch.property; - break; - case QQmlInstruction::FetchValueType: - qWarning().nospace() << idx << "\t\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type << "\t" << instr->fetchValue.bindingSkipList; - break; - case QQmlInstruction::PopFetchedObject: - qWarning().nospace() << idx << "\t\t" << "POP"; - break; - case QQmlInstruction::PopQList: - qWarning().nospace() << idx << "\t\t" << "POP_QLIST"; - break; - case QQmlInstruction::PopValueType: - qWarning().nospace() << idx << "\t\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type; - break; - case QQmlInstruction::Defer: - qWarning().nospace() << idx << "\t\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount; - break; - default: - qWarning().nospace() << idx << "\t\t" << "XXX UNKNOWN INSTRUCTION" << "\t" << instructionType(instr); - break; - } -#endif // QT_NO_DEBUG_STREAM -} - -int QQmlInstruction::size(Type type) -{ -#define QML_RETURN_INSTR_SIZE(I, FMT) case I: return QQmlInstructionMeta<(int)I>::Size; - switch (type) { - FOR_EACH_QML_INSTR(QML_RETURN_INSTR_SIZE) - default: return 0; - } -#undef QML_RETURN_INSTR_SIZE -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h deleted file mode 100644 index 27dc216a92..0000000000 --- a/src/qml/qml/qqmlinstruction_p.h +++ /dev/null @@ -1,560 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLINSTRUCTION_P_H -#define QQMLINSTRUCTION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -#define FOR_EACH_QML_INSTR(F) \ - F(Init, init) \ - F(DeferInit, deferInit) \ - F(Done, common) \ - F(CreateCppObject, create) \ - F(CreateQMLObject, createQml) \ - F(CompleteQMLObject, completeQml) \ - F(CreateSimpleObject, createSimple) \ - F(SetId, setId) \ - F(SetDefault, common) \ - F(CreateComponent, createComponent) \ - F(StoreMetaObject, storeMeta) \ - F(StoreVariant, storeString) \ - F(StoreVariantInteger, storeInteger) \ - F(StoreVariantDouble, storeDouble) \ - F(StoreVariantBool, storeBool) \ - F(StoreVar, storeString) \ - F(StoreVarInteger, storeInteger) \ - F(StoreVarDouble, storeDouble) \ - F(StoreVarBool, storeBool) \ - F(StoreString, storeString) \ - F(StoreJSValueString, storeString) \ - F(StoreJSValueInteger, storeInteger) \ - F(StoreJSValueDouble, storeDouble) \ - F(StoreJSValueBool, storeBool) \ - F(StoreStringList, storeString) \ - F(StoreStringQList, storeString) \ - F_TRANSLATION(F, StoreTrString, storeTrString) \ - F_TRANSLATION(F, StoreTrIdString, storeTrIdString) \ - F(StoreByteArray, storeByteArray) \ - F(StoreUrl, storeUrl) \ - F(StoreUrlQList, storeUrl) \ - F(StoreFloat, storeFloat) \ - F(StoreDouble, storeDouble) \ - F(StoreDoubleQList, storeDouble) \ - F(StoreBool, storeBool) \ - F(StoreBoolQList, storeBool) \ - F(StoreInteger, storeInteger) \ - F(StoreIntegerQList, storeInteger) \ - F(StoreColor, storeColor) \ - F(StoreDate, storeDate) \ - F(StoreTime, storeTime) \ - F(StoreDateTime, storeDateTime) \ - F(StorePoint, storePoint) \ - F(StorePointF, storePointF) \ - F(StoreSize, storeSize) \ - F(StoreSizeF, storeSizeF) \ - F(StoreRect, storeRect) \ - F(StoreRectF, storeRectF) \ - F(StoreVector3D, storeVector3D) \ - F(StoreVector4D, storeVector4D) \ - F(StoreObject, storeObject) \ - F(AssignCustomType, assignCustomType) \ - F(AssignSignalObject, assignSignalObject) \ - F(StoreSignal, storeSignal) \ - F(StoreImportedScript, storeScript) \ - F(StoreScriptString, storeScriptString) \ - F(BeginObject, begin) \ - F(StoreBinding, assignBinding) \ - F(StoreValueSource, assignValueSource) \ - F(StoreValueInterceptor, assignValueInterceptor) \ - F(StoreObjectQList, common) \ - F(AssignObjectList, assignObjectList) \ - F(StoreVariantObject, storeObject) \ - F(StoreVarObject, storeObject) \ - F(StoreInterface, storeObject) \ - F(FetchAttached, fetchAttached) \ - F(FetchQList, fetchQmlList) \ - F(FetchObject, fetch) \ - F(PopQList, common) \ - F(Defer, defer) \ - F(PopFetchedObject, common) \ - F(FetchValueType, fetchValue) \ - F(PopValueType, fetchValue) - -#ifndef QT_NO_TRANSLATION -#define F_TRANSLATION(F, I, FMT) F(I, FMT) -#else -#define F_TRANSLATION(F, I, FMT) -#endif - -#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200) -# define QML_THREADED_VME_INTERPRETER -#endif - -#ifdef Q_ALIGNOF -# define QML_INSTR_ALIGN_MASK (Q_ALIGNOF(QQmlInstruction) - 1) -#else -# define QML_INSTR_ALIGN_MASK (sizeof(void *) - 1) -#endif - -#ifdef QML_THREADED_VME_INTERPRETER -# define QML_INSTR_HEADER void *code; -# define QML_INSTR_HEADER_INIT this->code = 0; -#else -# define QML_INSTR_HEADER quint8 instructionType; -# define QML_INSTR_HEADER_INIT this->instructionType = 0; -#endif - -#define QML_INSTR_ENUM(I, FMT) I, -#define QML_INSTR_SIZE(I, FMT) ((sizeof(QQmlInstruction::instr_##FMT) + QML_INSTR_ALIGN_MASK) & ~QML_INSTR_ALIGN_MASK) - -class QQmlCompiledData; -union QQmlInstruction -{ - enum Type { - FOR_EACH_QML_INSTR(QML_INSTR_ENUM) - }; - - struct instr_common { - QML_INSTR_HEADER - }; - struct instr_init { - QML_INSTR_HEADER - int bindingsSize; - int parserStatusSize; - int contextCache; - int compiledBinding; - int objectStackSize; - int listStackSize; - }; - struct instr_deferInit { - QML_INSTR_HEADER - int bindingsSize; - int parserStatusSize; - int objectStackSize; - int listStackSize; - }; - struct instr_createQml { - QML_INSTR_HEADER - int type; - int bindingBits; - bool isRoot; - }; - struct instr_completeQml { - QML_INSTR_HEADER - ushort column; - ushort line; - bool isRoot; - }; - struct instr_create { - QML_INSTR_HEADER - int type; - int data; - ushort column; - ushort line; - bool isRoot:1; - bool parentToSuper:1; - }; - struct instr_createSimple { - QML_INSTR_HEADER - void (*create)(void *); - int typeSize; - int type; - ushort column; - ushort line; - bool parentToSuper; - }; - struct instr_storeMeta { - QML_INSTR_HEADER - int aliasData; - int propertyCache; - }; - struct instr_setId { - QML_INSTR_HEADER - int value; - int index; - }; - struct instr_assignValueSource { - QML_INSTR_HEADER - QQmlPropertyRawData property; - int castValue; - }; - struct instr_assignValueInterceptor { - QML_INSTR_HEADER - QQmlPropertyRawData property; - int castValue; - }; - struct instr_assignBinding { - QML_INSTR_HEADER - QQmlPropertyRawData property; - int functionIndex; // index in CompiledData::runtimeFunctions - short context; - short owner; - bool isRoot:1; - bool isAlias:1; - bool isFallback:1; - bool isSafe:1; - ushort line; - ushort column; - }; - struct instr_fetch { - QML_INSTR_HEADER - int property; - ushort line; - ushort column; - }; - struct instr_fetchValue { - QML_INSTR_HEADER - int property; - int type; - quint32 bindingSkipList; - }; - struct instr_fetchQmlList { - QML_INSTR_HEADER - int property; - int type; - }; - struct instr_begin { - QML_INSTR_HEADER - int castValue; - }; - struct instr_storeFloat { - QML_INSTR_HEADER - int propertyIndex; - float value; - }; - struct instr_storeDouble { - QML_INSTR_HEADER - int propertyIndex; - double value; - }; - struct instr_storeInteger { - QML_INSTR_HEADER - int propertyIndex; - int value; - }; - struct instr_storeBool { - QML_INSTR_HEADER - int propertyIndex; - bool value; - }; - struct instr_storeString { - QML_INSTR_HEADER - int propertyIndex; - int value; - }; - struct instr_storeTrString { - QML_INSTR_HEADER - int propertyIndex; - int context; - int text; - int comment; - int n; - }; - struct instr_storeTrIdString { - QML_INSTR_HEADER - int propertyIndex; - int text; - int n; - }; - struct instr_storeByteArray { - QML_INSTR_HEADER - int propertyIndex; - int value; - }; - struct instr_storeScriptString { - QML_INSTR_HEADER - int propertyIndex; - int value; - int scope; - int bindingId; - ushort line; - ushort column; - double numberValue; - bool isStringLiteral:1; - bool isNumberLiteral:1; - }; - struct instr_storeScript { - QML_INSTR_HEADER - int value; - }; - struct instr_storeUrl { - QML_INSTR_HEADER - int propertyIndex; - int value; - }; - struct instr_storeColor { - QML_INSTR_HEADER - int propertyIndex; - unsigned int value; - }; - struct instr_storeDate { - QML_INSTR_HEADER - int propertyIndex; - int value; - }; - struct instr_storeTime { - QML_INSTR_HEADER - int propertyIndex; - int time; // QTime::fromMSecsSinceStartOfDay - }; - struct instr_storeDateTime { - QML_INSTR_HEADER - int propertyIndex; - int date; - int time; - }; - struct instr_storeRect { - QML_INSTR_HEADER - int propertyIndex; - struct QRect { - int x1; - int y1; - int x2; - int y2; - } rect; - }; - struct instr_storeRectF { - QML_INSTR_HEADER - int propertyIndex; - struct QRectF { - qreal xp; - qreal yp; - qreal w; - qreal h; - } rect; - }; - struct instr_storeObject { - QML_INSTR_HEADER - int propertyIndex; - ushort line; - }; - struct instr_assignCustomType { - QML_INSTR_HEADER - int propertyIndex; - int primitive; - int type; - ushort line; - }; - struct instr_storeSignal { - QML_INSTR_HEADER - int runtimeFunctionIndex; - int handlerName; - int parameters; - int signalIndex; - int value; - short context; - ushort line; - ushort column; - }; - struct instr_assignSignalObject { - QML_INSTR_HEADER - int signal; - ushort line; - ushort column; - }; - struct instr_createComponent { - QML_INSTR_HEADER - int count; - int endLine; - int metaObject; - ushort column; - ushort line; - bool isRoot; - }; - struct instr_fetchAttached { - QML_INSTR_HEADER - int id; - ushort line; - }; - struct instr_defer { - QML_INSTR_HEADER - int deferCount; - }; - struct instr_assignObjectList { - QML_INSTR_HEADER - ushort line; - }; - struct instr_storePoint { - QML_INSTR_HEADER - int propertyIndex; - struct QPoint { - int xp; - int yp; - } point; - }; - struct instr_storePointF { - QML_INSTR_HEADER - int propertyIndex; - struct QPointF { - qreal xp; - qreal yp; - } point; - }; - struct instr_storeSize { - QML_INSTR_HEADER - int propertyIndex; - struct QSize { - int wd; - int ht; - } size; - }; - struct instr_storeSizeF { - QML_INSTR_HEADER - int propertyIndex; - struct QSizeF { - qreal wd; - qreal ht; - } size; - }; - struct instr_storeVector3D { - QML_INSTR_HEADER - int propertyIndex; - struct QVector3D { - float xp; - float yp; - float zp; - } vector; - }; - struct instr_storeVector4D { - QML_INSTR_HEADER - int propertyIndex; - struct QVector4D { - float xp; - float yp; - float zp; - float wp; - } vector; - }; - - instr_common common; - instr_init init; - instr_deferInit deferInit; - instr_create create; - instr_createQml createQml; - instr_completeQml completeQml; - instr_createSimple createSimple; - instr_storeMeta storeMeta; - instr_setId setId; - instr_assignValueSource assignValueSource; - instr_assignValueInterceptor assignValueInterceptor; - instr_assignBinding assignBinding; - instr_fetch fetch; - instr_fetchValue fetchValue; - instr_fetchQmlList fetchQmlList; - instr_begin begin; - instr_storeFloat storeFloat; - instr_storeDouble storeDouble; - instr_storeInteger storeInteger; - instr_storeBool storeBool; - instr_storeString storeString; - instr_storeTrString storeTrString; - instr_storeTrIdString storeTrIdString; - instr_storeByteArray storeByteArray; - instr_storeScriptString storeScriptString; - instr_storeScript storeScript; - instr_storeUrl storeUrl; - instr_storeColor storeColor; - instr_storeDate storeDate; - instr_storeTime storeTime; - instr_storeDateTime storeDateTime; - instr_storePoint storePoint; - instr_storePointF storePointF; - instr_storeSize storeSize; - instr_storeSizeF storeSizeF; - instr_storeRect storeRect; - instr_storeRectF storeRectF; - instr_storeVector3D storeVector3D; - instr_storeVector4D storeVector4D; - instr_storeObject storeObject; - instr_assignCustomType assignCustomType; - instr_storeSignal storeSignal; - instr_assignSignalObject assignSignalObject; - instr_createComponent createComponent; - instr_fetchAttached fetchAttached; - instr_defer defer; - instr_assignObjectList assignObjectList; - - static int size(Type type); -}; - -template -struct QQmlInstructionMeta { -}; - -#define QML_INSTR_META_TEMPLATE(I, FMT) \ - template<> struct QQmlInstructionMeta<(int)QQmlInstruction::I> { \ - enum { Size = QML_INSTR_SIZE(I, FMT) }; \ - typedef QQmlInstruction::instr_##FMT DataType; \ - static const DataType &data(const QQmlInstruction &instr) { return instr.FMT; } \ - static void setData(QQmlInstruction &instr, const DataType &v) { memcpy(&instr.FMT, &v, Size); } \ - static void setDataNoCommon(QQmlInstruction &instr, const DataType &v) \ - { memcpy(reinterpret_cast(&instr.FMT) + sizeof(QQmlInstruction::instr_common), \ - reinterpret_cast(&v) + sizeof(QQmlInstruction::instr_common), \ - Size - sizeof(QQmlInstruction::instr_common)); } \ - }; -FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE); -#undef QML_INSTR_META_TEMPLATE - -template -class QQmlInstructionData : public QQmlInstructionMeta::DataType -{ -public: - QQmlInstructionData() : QQmlInstructionMeta::DataType() { QML_INSTR_HEADER_INIT } -}; - -QT_END_NAMESPACE - -#endif // QQMLINSTRUCTION_P_H diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index 0618c90fa5..cf56d5701d 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -58,1359 +58,6 @@ QT_BEGIN_NAMESPACE using namespace QQmlJS; using namespace QQmlScript; -// -// Parser IR classes -// -QQmlScript::Object::Object() -: type(-1), typeReference(0), idIndex(-1), metatype(0), synthCache(0), - defaultProperty(0), parserStatusCast(-1), componentCompileState(0), nextAliasingObject(0), - nextIdObject(0) -{ -} - -QQmlScript::Object::~Object() -{ - if (synthCache) synthCache->release(); -} - -void Object::setBindingBit(int b) -{ - while (bindingBitmask.size() < 4 * (1 + b / 32)) - bindingBitmask.append(char(0)); - - quint32 *bits = (quint32 *)bindingBitmask.data(); - bits[b / 32] |= (1 << (b % 32)); -} - -QQmlScript::Property *Object::getDefaultProperty() -{ - if (!defaultProperty) { - defaultProperty = pool()->New(); - defaultProperty->parent = this; - } - return defaultProperty; -} - -void QQmlScript::Object::addValueProperty(Property *p) -{ - valueProperties.append(p); -} - -void QQmlScript::Object::addSignalProperty(Property *p) -{ - signalProperties.append(p); -} - -void QQmlScript::Object::addAttachedProperty(Property *p) -{ - attachedProperties.append(p); -} - -void QQmlScript::Object::addGroupedProperty(Property *p) -{ - groupedProperties.append(p); -} - -void QQmlScript::Object::addValueTypeProperty(Property *p) -{ - valueTypeProperties.append(p); -} - -void QQmlScript::Object::addScriptStringProperty(Property *p) -{ - scriptStringProperties.append(p); -} - -// This lookup is optimized for missing, and having to create a new property. -Property *QQmlScript::Object::getProperty(const QHashedStringRef &name, bool create) -{ - if (create) { - quint32 h = name.hash(); - if (propertiesHashField.testAndSet(h)) { - for (Property *p = properties.first(); p; p = properties.next(p)) { - if (p->name() == name) - return p; - } - } - - Property *property = pool()->New(); - property->parent = this; - property->_name = name; - property->isDefault = false; - properties.prepend(property); - return property; - } else { - for (Property *p = properties.first(); p; p = properties.next(p)) { - if (p->name() == name) - return p; - } - } - - return 0; -} - -Property *QQmlScript::Object::getProperty(const QStringRef &name, bool create) -{ - return getProperty(QHashedStringRef(name), create); -} - -Property *QQmlScript::Object::getProperty(const QString &name, bool create) -{ - for (Property *p = properties.first(); p; p = properties.next(p)) { - if (p->name() == name) - return p; - } - - if (create) { - Property *property = pool()->New(); - property->parent = this; - property->_name = QStringRef(pool()->NewString(name)); - propertiesHashField.testAndSet(property->_name.hash()); - property->isDefault = false; - properties.prepend(property); - return property; - } else { - return 0; - } -} - -int QQmlScript::Object::aggregateDynamicSignalParameterCount() const -{ - int sum = 0; - for (DynamicSignal *s = dynamicSignals.first(); s; s = dynamicSignals.next(s)) - sum += s->parameterTypes.count() + 1; // +1 for return type - return sum; -} - -int QQmlScript::Object::aggregateDynamicSlotParameterCount() const -{ - int sum = 0; - for (DynamicSlot *s = dynamicSlots.first(); s; s = dynamicSlots.next(s)) - sum += s->parameterNames.count() + 1; // +1 for return type - return sum; -} - -QQmlScript::Object::DynamicProperty::DynamicProperty() -: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0), - nameIndex(-1) -{ -} - -QQmlScript::Object::DynamicSignal::DynamicSignal() -: nextSignal(0), nameIndex(-1) -{ -} - -QQmlScript::Object::DynamicSlot::DynamicSlot() -: funcDecl(0), nextSlot(0), nameIndex(-1) -{ -} - -int QQmlScript::Object::DynamicSlot::parameterNamesLength() const -{ - int rv = 0; - for (int ii = 0; ii < parameterNames.count(); ++ii) - rv += parameterNames.at(ii).length(); - return rv; -} - -QQmlScript::Property::Property() -: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false), - isValueTypeSubProperty(false), isAlias(false), isReadOnlyDeclaration(false), - scriptStringScope(-1), nextMainProperty(0), nextProperty(0) -{ -} - -QQmlScript::Object *QQmlScript::Property::getValue(const LocationSpan &l) -{ - if (!value) { value = pool()->New(); value->location = l; } - return value; -} - -void QQmlScript::Property::addValue(Value *v) -{ - values.append(v); -} - -void QQmlScript::Property::addOnValue(Value *v) -{ - onValues.append(v); -} - -bool QQmlScript::Property::isEmpty() const -{ - return !value && values.isEmpty() && onValues.isEmpty(); -} - -QQmlScript::Value::Value() -: type(Unknown), object(0), bindingReference(0), nextValue(0) -{ -} - -QQmlScript::Variant::Variant() -: t(Invalid) -{ -} - -QQmlScript::Variant::Variant(const Variant &o) -: t(o.t), d(o.d), asWritten(o.asWritten) -{ -} - -QQmlScript::Variant::Variant(bool v) -: t(Boolean), b(v) -{ -} - -QQmlScript::Variant::Variant(double v, const QStringRef &asWritten) -: t(Number), d(v), asWritten(asWritten) -{ -} - -QQmlScript::Variant::Variant(QQmlJS::AST::StringLiteral *v) -: t(String), l(v) -{ -} - -QQmlScript::Variant::Variant(const QStringRef &asWritten, QQmlJS::AST::Node *n) -: t(Script), n(n), asWritten(asWritten) -{ -} - -QQmlScript::Variant &QQmlScript::Variant::operator=(const Variant &o) -{ - t = o.t; - d = o.d; - asWritten = o.asWritten; - return *this; -} - -QQmlScript::Variant::Type QQmlScript::Variant::type() const -{ - return t; -} - -bool QQmlScript::Variant::asBoolean() const -{ - return b; -} - -QString QQmlScript::Variant::asString() const -{ - if (t == String) { - return l->value.toString(); - } else { - return asWritten.toString(); - } -} - -double QQmlScript::Variant::asNumber() const -{ - return d; -} - -//reverse of Lexer::singleEscape() -QString escapedString(const QString &string) -{ - QString tmp = QLatin1String("\""); - for (int i = 0; i < string.length(); ++i) { - const QChar &c = string.at(i); - switch(c.unicode()) { - case 0x08: - tmp += QLatin1String("\\b"); - break; - case 0x09: - tmp += QLatin1String("\\t"); - break; - case 0x0A: - tmp += QLatin1String("\\n"); - break; - case 0x0B: - tmp += QLatin1String("\\v"); - break; - case 0x0C: - tmp += QLatin1String("\\f"); - break; - case 0x0D: - tmp += QLatin1String("\\r"); - break; - case 0x22: - tmp += QLatin1String("\\\""); - break; - case 0x27: - tmp += QLatin1String("\\\'"); - break; - case 0x5C: - tmp += QLatin1String("\\\\"); - break; - default: - tmp += c; - break; - } - } - tmp += QLatin1Char('\"'); - return tmp; -} - -QString QQmlScript::Variant::asScript() const -{ - switch (type()) { - default: - case Invalid: - return QString(); - case Boolean: - return b?QLatin1String("true"):QLatin1String("false"); - case Number: - if (asWritten.isEmpty()) - return QString::number(d); - else - return asWritten.toString(); - case String: - return escapedString(asString()); - case Script: - if (AST::IdentifierExpression *i = AST::cast(n)) { - return i->name.toString(); - } else - return asWritten.toString(); - } -} - -QQmlJS::AST::Node *QQmlScript::Variant::asAST() const -{ - if (type() == Script) - return n; - else - return 0; -} - -bool QQmlScript::Variant::isStringList() const -{ - if (isString()) - return true; - - if (type() != Script || !n) - return false; - - AST::ArrayLiteral *array = AST::cast(n); - if (!array) - return false; - - AST::ElementList *elements = array->elements; - - while (elements) { - - if (!AST::cast(elements->expression)) - return false; - - elements = elements->next; - } - - return true; -} - -QStringList QQmlScript::Variant::asStringList() const -{ - QStringList rv; - if (isString()) { - rv << asString(); - return rv; - } - - AST::ArrayLiteral *array = AST::cast(n); - if (!array) - return rv; - - AST::ElementList *elements = array->elements; - while (elements) { - - AST::StringLiteral *string = AST::cast(elements->expression); - if (!string) - return QStringList(); - rv.append(string->value.toString()); - - elements = elements->next; - } - - return rv; -} - -// -// Actual parser classes -// -namespace { - -class ProcessAST: protected AST::Visitor -{ - struct State { - State() : object(0), property(0) {} - State(QQmlScript::Object *o) : object(o), property(0) {} - State(QQmlScript::Object *o, Property *p) : object(o), property(p) {} - - QQmlScript::Object *object; - Property *property; - }; - - struct StateStack : public QStack - { - void pushObject(QQmlScript::Object *obj) - { - push(State(obj)); - } - - void pushProperty(const QString &name, const LocationSpan &location) - { - const State &state = top(); - if (state.property) { - State s(state.property->getValue(location), - state.property->getValue(location)->getProperty(name)); - s.property->location = location; - push(s); - } else { - State s(state.object, state.object->getProperty(name)); - - s.property->location = location; - push(s); - } - } - - void pushProperty(const QStringRef &name, const LocationSpan &location) - { - const State &state = top(); - if (state.property) { - State s(state.property->getValue(location), - state.property->getValue(location)->getProperty(name)); - s.property->location = location; - push(s); - } else { - State s(state.object, state.object->getProperty(name)); - - s.property->location = location; - push(s); - } - } - }; - -public: - ProcessAST(QQmlScript::Parser *parser); - virtual ~ProcessAST(); - - void operator()(const QString &code, AST::Node *node); - - static void extractVersion(QStringRef string, int *maj, int *min); - -protected: - - QQmlScript::Object *defineObjectBinding(AST::Node *node, AST::UiQualifiedId *propertyName, bool onAssignment, - const QString &objectType, - AST::SourceLocation typeLocation, - LocationSpan location, - AST::UiObjectInitializer *initializer = 0); - - QQmlScript::Variant getVariant(AST::Statement *stmt); - QQmlScript::Variant getVariant(AST::ExpressionNode *expr); - - LocationSpan location(AST::SourceLocation start, AST::SourceLocation end); - LocationSpan location(AST::UiQualifiedId *); - - using AST::Visitor::visit; - using AST::Visitor::endVisit; - - virtual bool visit(AST::UiProgram *node); - virtual bool visit(AST::UiImport *node); - virtual bool visit(AST::UiPragma *node); - virtual bool visit(AST::UiObjectDefinition *node); - virtual bool visit(AST::UiPublicMember *node); - virtual bool visit(AST::UiObjectBinding *node); - - virtual bool visit(AST::UiScriptBinding *node); - virtual bool visit(AST::UiArrayBinding *node); - virtual bool visit(AST::UiSourceElement *node); - - void accept(AST::Node *node); - - QString asString(AST::UiQualifiedId *node) const; - - const State state() const; - QQmlScript::Object *currentObject() const; - Property *currentProperty() const; - - QString textAt(const AST::SourceLocation &loc) const - { return _contents->mid(loc.offset, loc.length); } - - QStringRef textRefAt(const AST::SourceLocation &loc) const - { return QStringRef(_contents, loc.offset, loc.length); } - - QString textAt(const AST::SourceLocation &first, - const AST::SourceLocation &last) const - { return _contents->mid(first.offset, last.offset + last.length - first.offset); } - - QStringRef textRefAt(const AST::SourceLocation &first, - const AST::SourceLocation &last) const - { return QStringRef(_contents, first.offset, last.offset + last.length - first.offset); } - - QString asString(AST::ExpressionNode *expr) - { - if (! expr) - return QString(); - - return textAt(expr->firstSourceLocation(), expr->lastSourceLocation()); - } - - QStringRef asStringRef(AST::ExpressionNode *expr) - { - if (! expr) - return QStringRef(); - - return textRefAt(expr->firstSourceLocation(), expr->lastSourceLocation()); - } - - QString asString(AST::Statement *stmt) - { - if (! stmt) - return QString(); - - QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation()); - s += QLatin1Char('\n'); - return s; - } - - QStringRef asStringRef(AST::Statement *stmt) - { - if (! stmt) - return QStringRef(); - - return textRefAt(stmt->firstSourceLocation(), stmt->lastSourceLocation()); - } - -private: - QQmlScript::Parser *_parser; - StateStack _stateStack; - const QString *_contents; -}; - -ProcessAST::ProcessAST(QQmlScript::Parser *parser) - : _parser(parser) -{ -} - -ProcessAST::~ProcessAST() -{ -} - -void ProcessAST::operator()(const QString &code, AST::Node *node) -{ - _contents = &code; - accept(node); -} - -void ProcessAST::accept(AST::Node *node) -{ - AST::Node::acceptChild(node, this); -} - -const ProcessAST::State ProcessAST::state() const -{ - if (_stateStack.isEmpty()) - return State(); - - return _stateStack.back(); -} - -QQmlScript::Object *ProcessAST::currentObject() const -{ - return state().object; -} - -Property *ProcessAST::currentProperty() const -{ - return state().property; -} - -void ProcessAST::extractVersion(QStringRef string, int *maj, int *min) -{ - *maj = -1; *min = -1; - - if (!string.isEmpty()) { - - int dot = string.indexOf(QLatin1Char('.')); - - if (dot < 0) { - *maj = string.toInt(); - *min = 0; - } else { - *maj = string.left(dot).toInt(); - *min = string.mid(dot + 1).toInt(); - } - } -} - -QString ProcessAST::asString(AST::UiQualifiedId *node) const -{ - QString s; - - for (AST::UiQualifiedId *it = node; it; it = it->next) { - s.append(it->name); - - if (it->next) - s.append(QLatin1Char('.')); - } - - return s; -} - -QQmlScript::Object * -ProcessAST::defineObjectBinding(AST::Node *node, - AST::UiQualifiedId *propertyName, - bool onAssignment, - const QString &objectType, - AST::SourceLocation typeLocation, - LocationSpan location, - AST::UiObjectInitializer *initializer) -{ - int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.')); - - // With no preceding qualification, first char is at (-1 + 1) == 0 - bool isType = !objectType.isEmpty() && objectType.at(lastTypeDot+1).isUpper(); - - int propertyCount = 0; - for (AST::UiQualifiedId *name = propertyName; name; name = name->next){ - ++propertyCount; - _stateStack.pushProperty(name->name, - this->location(name)); - } - - if (!onAssignment && propertyCount && currentProperty() && !currentProperty()->values.isEmpty()) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times")); - error.setLine(this->location(propertyName).start.line); - error.setColumn(this->location(propertyName).start.column); - _parser->_errors << error; - return 0; - } - - if (!isType) { - - // Is the identifier qualified by a namespace? - int namespaceLength = 0; - if (lastTypeDot > 0) { - const QString qualifier(objectType.left(lastTypeDot)); - - for (int ii = 0; ii < _parser->_imports.count(); ++ii) { - const QQmlScript::Import &import = _parser->_imports.at(ii); - if (import.qualifier == qualifier) { - // The qualifier is a namespace - expect a type here - namespaceLength = qualifier.length() + 1; - break; - } - } - } - - if (propertyCount || !currentObject() || namespaceLength) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Expected type name")); - error.setLine(typeLocation.startLine); - error.setColumn(typeLocation.startColumn + namespaceLength); - _parser->_errors << error; - return 0; - } - - LocationSpan loc = ProcessAST::location(typeLocation, typeLocation); - if (propertyName) - loc = ProcessAST::location(propertyName); - - _stateStack.pushProperty(objectType, loc); - accept(initializer); - _stateStack.pop(); - - return 0; - - } else { - // Class - - QQmlScript::Object *obj = _parser->_pool.New(); - - obj->type = _parser->findOrCreateTypeId(objectType, obj); - obj->typeReference = _parser->_refTypes.at(obj->type); - obj->location = location; - obj->astNode = node; - - if (propertyCount) { - Property *prop = currentProperty(); - QQmlScript::Value *v = _parser->_pool.New(); - v->object = obj; - v->location = obj->location; - if (onAssignment) - prop->addOnValue(v); - else - prop->addValue(v); - - while (propertyCount--) - _stateStack.pop(); - - } else { - - if (! _parser->tree()) { - _parser->setTree(obj); - } else { - const State state = _stateStack.top(); - QQmlScript::Value *v = _parser->_pool.New(); - v->object = obj; - v->location = obj->location; - if (state.property) { - state.property->addValue(v); - } else { - Property *defaultProp = state.object->getDefaultProperty(); - if (defaultProp->location.start.line == 0) { - defaultProp->location = v->location; - defaultProp->location.end = defaultProp->location.start; - defaultProp->location.range.length = 0; - } - defaultProp->addValue(v); - } - } - } - - _stateStack.pushObject(obj); - accept(initializer); - _stateStack.pop(); - - return obj; - } -} - -LocationSpan ProcessAST::location(AST::UiQualifiedId *id) -{ - return location(id->identifierToken, id->identifierToken); -} - -LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end) -{ - LocationSpan rv; - rv.start.line = start.startLine; - rv.start.column = start.startColumn; - rv.end.line = end.startLine; - rv.end.column = end.startColumn + end.length - 1; - rv.range.offset = start.offset; - rv.range.length = end.offset + end.length - start.offset; - return rv; -} - -// UiProgram: UiHeaderItemListOpt UiObjectMemberList ; -bool ProcessAST::visit(AST::UiProgram *node) -{ - accept(node->headers); - accept(node->members->member); - return false; -} - -// UiImport: T_IMPORT T_STRING_LITERAL ; -bool ProcessAST::visit(AST::UiImport *node) -{ - QString uri; - QQmlScript::Import import; - - if (!node->fileName.isNull()) { - uri = node->fileName.toString(); - - if (uri.endsWith(QLatin1String(".js"))) { - import.type = QQmlScript::Import::Script; - } else { - import.type = QQmlScript::Import::File; - } - } else { - import.type = QQmlScript::Import::Library; - uri = asString(node->importUri); - } - - AST::SourceLocation startLoc = node->importToken; - AST::SourceLocation endLoc = node->semicolonToken; - - // Qualifier - if (!node->importId.isNull()) { - import.qualifier = node->importId.toString(); - if (!import.qualifier.at(0).isUpper()) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier ID")); - error.setLine(node->importIdToken.startLine); - error.setColumn(node->importIdToken.startColumn); - _parser->_errors << error; - return false; - } - if (import.qualifier == QLatin1String("Qt")) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Reserved name \"Qt\" cannot be used as an qualifier")); - error.setLine(node->importIdToken.startLine); - error.setColumn(node->importIdToken.startColumn); - _parser->_errors << error; - return false; - } - - // Check for script qualifier clashes - bool isScript = import.type == QQmlScript::Import::Script; - for (int ii = 0; ii < _parser->_imports.count(); ++ii) { - const QQmlScript::Import &other = _parser->_imports.at(ii); - bool otherIsScript = other.type == QQmlScript::Import::Script; - - if ((isScript || otherIsScript) && import.qualifier == other.qualifier) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique.")); - error.setLine(node->importIdToken.startLine); - error.setColumn(node->importIdToken.startColumn); - _parser->_errors << error; - return false; - } - } - - } else if (import.type == QQmlScript::Import::Script) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Script import requires a qualifier")); - error.setLine(node->fileNameToken.startLine); - error.setColumn(node->fileNameToken.startColumn); - _parser->_errors << error; - return false; - } - - if (node->versionToken.isValid()) { - extractVersion(textRefAt(node->versionToken), &import.majorVersion, &import.minorVersion); - } else if (import.type == QQmlScript::Import::Library) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Library import requires a version")); - error.setLine(node->importIdToken.startLine); - error.setColumn(node->importIdToken.startColumn); - _parser->_errors << error; - return false; - } - - - import.location = location(startLoc, endLoc); - import.uri = uri; - - _parser->_imports << import; - - return false; -} - -bool ProcessAST::visit(AST::UiPragma *node) -{ - QQmlScript::Pragma pragma; - - // For now the only valid pragma is Singleton, so lets validate the input - if (!node->pragmaType->name.isNull()) - { - if (QLatin1String("Singleton") == node->pragmaType->name) - { - pragma.type = QQmlScript::Pragma::Singleton; - } else { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier")); - error.setLine(node->pragmaToken.startLine); - error.setColumn(node->pragmaToken.startColumn); - _parser->_errors << error; - return false; - } - } else { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier")); - error.setLine(node->pragmaToken.startLine); - error.setColumn(node->pragmaToken.startColumn); - _parser->_errors << error; - return false; - } - - AST::SourceLocation startLoc = node->pragmaToken; - AST::SourceLocation endLoc = node->semicolonToken; - pragma.location = location(startLoc, endLoc); - _parser->_pragmas << pragma; - - return false; -} - -bool ProcessAST::visit(AST::UiPublicMember *node) -{ - static const struct TypeNameToType { - const char *name; - size_t nameLength; - Object::DynamicProperty::Type type; - } propTypeNameToTypes[] = { - { "int", strlen("int"), Object::DynamicProperty::Int }, - { "bool", strlen("bool"), Object::DynamicProperty::Bool }, - { "double", strlen("double"), Object::DynamicProperty::Real }, - { "real", strlen("real"), Object::DynamicProperty::Real }, - { "string", strlen("string"), Object::DynamicProperty::String }, - { "url", strlen("url"), Object::DynamicProperty::Url }, - { "color", strlen("color"), Object::DynamicProperty::Color }, - // Internally QTime, QDate and QDateTime are all supported. - // To be more consistent with JavaScript we expose only - // QDateTime as it matches closely with the Date JS type. - // We also call it "date" to match. - // { "time", strlen("time"), Object::DynamicProperty::Time }, - // { "date", strlen("date"), Object::DynamicProperty::Date }, - { "date", strlen("date"), Object::DynamicProperty::DateTime }, - { "rect", strlen("rect"), Object::DynamicProperty::Rect }, - { "point", strlen("point"), Object::DynamicProperty::Point }, - { "size", strlen("size"), Object::DynamicProperty::Size }, - { "font", strlen("font"), Object::DynamicProperty::Font }, - { "vector2d", strlen("vector2d"), Object::DynamicProperty::Vector2D }, - { "vector3d", strlen("vector3d"), Object::DynamicProperty::Vector3D }, - { "vector4d", strlen("vector4d"), Object::DynamicProperty::Vector4D }, - { "quaternion", strlen("quaternion"), Object::DynamicProperty::Quaternion }, - { "matrix4x4", strlen("matrix4x4"), Object::DynamicProperty::Matrix4x4 }, - { "variant", strlen("variant"), Object::DynamicProperty::Variant }, - { "var", strlen("var"), Object::DynamicProperty::Var } - }; - static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / - sizeof(propTypeNameToTypes[0]); - - if(node->type == AST::UiPublicMember::Signal) { - Object::DynamicSignal *signal = _parser->_pool.New(); - signal->name = node->name; - - AST::UiParameterList *p = node->parameters; - int paramLength = 0; - while (p) { paramLength++; p = p->next; } - p = node->parameters; - - if (paramLength) { - signal->parameterTypes = _parser->_pool.NewRawList(paramLength); - signal->parameterTypeNames = _parser->_pool.NewRawList(paramLength); - signal->parameterNames = _parser->_pool.NewRawList(paramLength); - } - - int index = 0; - while (p) { - const QStringRef &memberType = p->type; - - if (memberType.isEmpty()) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Expected parameter type")); - error.setLine(node->typeToken.startLine); - error.setColumn(node->typeToken.startColumn); - _parser->_errors << error; - return false; - } - - const TypeNameToType *type = 0; - for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) { - const TypeNameToType *t = propTypeNameToTypes + typeIndex; - if (t->nameLength == size_t(memberType.length()) && - QHashedString::compare(memberType.constData(), t->name, int(t->nameLength))) { - type = t; - break; - } - } - - if (!type) { - if (memberType.at(0).isUpper()) { - // Must be a QML object type. - // Lazily determine type during compilation. - signal->parameterTypes[index] = Object::DynamicProperty::Custom; - signal->parameterTypeNames[index] = QHashedStringRef(p->type); - } else { - QQmlError error; - QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: "); - errStr.append(memberType.toString()); - error.setDescription(errStr); - error.setLine(node->typeToken.startLine); - error.setColumn(node->typeToken.startColumn); - _parser->_errors << error; - return false; - } - } else { - // the parameter is a known basic type - signal->parameterTypes[index] = type->type; - } - - signal->parameterNames[index] = QHashedStringRef(p->name); - p = p->next; - index++; - } - - signal->location = location(node->typeToken, node->semicolonToken); - _stateStack.top().object->dynamicSignals.append(signal); - } else { - const QStringRef &memberType = node->memberType; - const QStringRef &name = node->name; - - bool typeFound = false; - Object::DynamicProperty::Type type; - - if ((unsigned)memberType.length() == strlen("alias") && - QHashedString::compare(memberType.constData(), "alias", int(strlen("alias")))) { - type = Object::DynamicProperty::Alias; - typeFound = true; - } - - for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { - const TypeNameToType *t = propTypeNameToTypes + ii; - if (t->nameLength == size_t(memberType.length()) && - QHashedString::compare(memberType.constData(), t->name, int(t->nameLength))) { - type = t->type; - typeFound = true; - } - } - - if (!typeFound && memberType.at(0).isUpper()) { - const QStringRef &typeModifier = node->typeModifier; - - if (typeModifier.isEmpty()) { - type = Object::DynamicProperty::Custom; - } else if ((unsigned)typeModifier.length() == strlen("list") && - QHashedString::compare(typeModifier.constData(), "list", int(strlen("list")))) { - type = Object::DynamicProperty::CustomList; - } else { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Invalid property type modifier")); - error.setLine(node->typeModifierToken.startLine); - error.setColumn(node->typeModifierToken.startColumn); - _parser->_errors << error; - return false; - } - typeFound = true; - } else if (!node->typeModifier.isNull()) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Unexpected property type modifier")); - error.setLine(node->typeModifierToken.startLine); - error.setColumn(node->typeModifierToken.startColumn); - _parser->_errors << error; - return false; - } - - if(!typeFound) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Expected property type")); - error.setLine(node->typeToken.startLine); - error.setColumn(node->typeToken.startColumn); - _parser->_errors << error; - return false; - } - - Object::DynamicProperty *property = _parser->_pool.New(); - property->isDefaultProperty = node->isDefaultMember; - property->isReadOnly = node->isReadonlyMember; - property->type = type; - property->nameLocation.line = node->identifierToken.startLine; - property->nameLocation.column = node->identifierToken.startColumn; - if (type >= Object::DynamicProperty::Custom) { - // This forces the type to be added to the resolved types list - _parser->findOrCreateTypeId(memberType.toString(), _stateStack.top().object); - property->customType = memberType; - } - - property->name = QHashedStringRef(name); - property->location = location(node->firstSourceLocation(), - node->lastSourceLocation()); - - if (node->statement) { // default value - property->defaultValue = _parser->_pool.New(); - property->defaultValue->parent = _stateStack.top().object; - property->defaultValue->location = - location(node->statement->firstSourceLocation(), - node->statement->lastSourceLocation()); - QQmlScript::Value *value = _parser->_pool.New(); - value->location = location(node->statement->firstSourceLocation(), - node->statement->lastSourceLocation()); - value->value = getVariant(node->statement); - property->defaultValue->values.append(value); - } - - _stateStack.top().object->dynamicProperties.append(property); - - // process QML-like initializers (e.g. property Object o: Object {}) - accept(node->binding); - } - - return false; -} - - -// UiObjectMember: UiQualifiedId UiObjectInitializer ; -bool ProcessAST::visit(AST::UiObjectDefinition *node) -{ - LocationSpan l = location(node->firstSourceLocation(), - node->lastSourceLocation()); - - const QString objectType = asString(node->qualifiedTypeNameId); - const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken; - - defineObjectBinding(node, /*propertyName = */ 0, false, objectType, - typeLocation, l, node->initializer); - - return false; -} - - -// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; -bool ProcessAST::visit(AST::UiObjectBinding *node) -{ - LocationSpan l = location(node->qualifiedTypeNameId->identifierToken, - node->initializer->rbraceToken); - - const QString objectType = asString(node->qualifiedTypeNameId); - const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken; - - defineObjectBinding(node, node->qualifiedId, node->hasOnToken, objectType, - typeLocation, l, node->initializer); - - return false; -} - -QQmlScript::Variant ProcessAST::getVariant(AST::Statement *stmt) -{ - if (stmt) { - if (AST::ExpressionStatement *exprStmt = AST::cast(stmt)) - return getVariant(exprStmt->expression); - - return QQmlScript::Variant(asStringRef(stmt), stmt); - } - - return QQmlScript::Variant(); -} - -QQmlScript::Variant ProcessAST::getVariant(AST::ExpressionNode *expr) -{ - if (AST::StringLiteral *lit = AST::cast(expr)) { - return QQmlScript::Variant(lit); - } else if (expr->kind == AST::Node::Kind_TrueLiteral) { - return QQmlScript::Variant(true); - } else if (expr->kind == AST::Node::Kind_FalseLiteral) { - return QQmlScript::Variant(false); - } else if (AST::NumericLiteral *lit = AST::cast(expr)) { - return QQmlScript::Variant(lit->value, asStringRef(expr)); - } else { - - if (AST::UnaryMinusExpression *unaryMinus = AST::cast(expr)) { - if (AST::NumericLiteral *lit = AST::cast(unaryMinus->expression)) { - return QQmlScript::Variant(-lit->value, asStringRef(expr)); - } - } - - return QQmlScript::Variant(asStringRef(expr), expr); - } -} - - -// UiObjectMember: UiQualifiedId T_COLON Statement ; -bool ProcessAST::visit(AST::UiScriptBinding *node) -{ - int propertyCount = 0; - AST::UiQualifiedId *propertyName = node->qualifiedId; - for (AST::UiQualifiedId *name = propertyName; name; name = name->next){ - ++propertyCount; - _stateStack.pushProperty(name->name, - location(name)); - } - - Property *prop = currentProperty(); - - if (!prop->values.isEmpty()) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times")); - error.setLine(this->location(propertyName).start.line); - error.setColumn(this->location(propertyName).start.column); - _parser->_errors << error; - return 0; - } - - QQmlScript::Variant primitive; - - if (AST::ExpressionStatement *stmt = AST::cast(node->statement)) { - primitive = getVariant(stmt->expression); - } else { // do binding - primitive = QQmlScript::Variant(asStringRef(node->statement), node->statement); - } - - prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset; - prop->location.range.offset = node->qualifiedId->identifierToken.offset; - QQmlScript::Value *v = _parser->_pool.New(); - v->value = primitive; - v->location = location(node->statement->firstSourceLocation(), - node->statement->lastSourceLocation()); - - prop->addValue(v); - - while (propertyCount--) - _stateStack.pop(); - - return false; -} - -// UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; -bool ProcessAST::visit(AST::UiArrayBinding *node) -{ - int propertyCount = 0; - AST::UiQualifiedId *propertyName = node->qualifiedId; - for (AST::UiQualifiedId *name = propertyName; name; name = name->next){ - ++propertyCount; - _stateStack.pushProperty(name->name, - location(name)); - } - - Property* prop = currentProperty(); - - if (!prop->values.isEmpty()) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times")); - error.setLine(this->location(propertyName).start.line); - error.setColumn(this->location(propertyName).start.column); - _parser->_errors << error; - return false; - } - - accept(node->members); - - // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range: - prop->listValueRange.offset = node->lbracketToken.offset; - prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset; - - while (propertyCount--) - _stateStack.pop(); - - return false; -} - -bool ProcessAST::visit(AST::UiSourceElement *node) -{ - QQmlScript::Object *obj = currentObject(); - - if (AST::FunctionDeclaration *funDecl = AST::cast(node->sourceElement)) { - - Object::DynamicSlot *slot = _parser->_pool.New(); - slot->location = location(funDecl->identifierToken, funDecl->lastSourceLocation()); - - AST::FormalParameterList *f = funDecl->formals; - while (f) { - slot->parameterNames << f->name.toUtf8(); - f = f->next; - } - - AST::SourceLocation loc = funDecl->rparenToken; - loc.offset = loc.end(); - loc.startColumn += 1; - slot->name = funDecl->name; - slot->funcDecl = funDecl; - obj->dynamicSlots.append(slot); - - } else { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element")); - error.setLine(node->firstSourceLocation().startLine); - error.setColumn(node->firstSourceLocation().startColumn); - _parser->_errors << error; - } - return false; -} - -} // end of anonymous namespace - - -QQmlScript::Parser::Parser() -: root(0), _qmlRoot(0), data(0) -{ - -} - -QQmlScript::Parser::~Parser() -{ - clear(); -} - -namespace QQmlScript { -class ParserJsASTData -{ -public: - ParserJsASTData(const QString &filename) - : filename(filename) {} - - QString filename; - Engine engine; -}; -} - -QByteArray QQmlScript::Parser::preparseData() const -{ - return QByteArray(); -} - -bool QQmlScript::Parser::parse(const QString &qmlcode, const QByteArray & /* preparseData */, - const QUrl &url, const QString &urlString) -{ - clear(); - - if (urlString.isEmpty()) { - _scriptFile = url.toString(); - } else { - // Q_ASSERT(urlString == url.toString()); - _scriptFile = urlString; - } - - QString *code = _pool.NewString(qmlcode); - - data = new QQmlScript::ParserJsASTData(_scriptFile); - - Lexer lexer(&data->engine); - lexer.setCode(*code, /*line = */ 1); - - QQmlJS::Parser parser(&data->engine); - - if (! parser.parse() || !parser.diagnosticMessages().isEmpty()) { - - // Extract errors from the parser - foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { - - if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(_scriptFile), m.loc.startLine, qPrintable(m.message)); - continue; - } - - QQmlError error; - error.setUrl(url); - error.setDescription(m.message); - error.setLine(m.loc.startLine); - error.setColumn(m.loc.startColumn); - _errors << error; - - } - } - - if (_errors.isEmpty()) { - ProcessAST process(this); - process(*code, parser.ast()); - - // Set the url for process errors - for(int ii = 0; ii < _errors.count(); ++ii) - _errors[ii].setUrl(url); - } - - _qmlRoot = parser.ast(); - - return _errors.isEmpty(); -} - -QList QQmlScript::Parser::referencedTypes() const -{ - return _refTypes; -} - -QQmlScript::Object *QQmlScript::Parser::tree() const -{ - return root; -} - -QList QQmlScript::Parser::imports() const -{ - return _imports; -} - -QList QQmlScript::Parser::pragmas() const -{ - return _pragmas; -} - -QList QQmlScript::Parser::errors() const -{ - return _errors; -} - static void replaceWithSpace(QString &str, int idx, int n) { QChar *data = str.data() + idx; @@ -1540,6 +187,24 @@ static inline bool isUriToken(int token) return false; } +static void extractVersion(QStringRef string, int *maj, int *min) +{ + *maj = -1; *min = -1; + + if (!string.isEmpty()) { + + int dot = string.indexOf(QLatin1Char('.')); + + if (dot < 0) { + *maj = string.toInt(); + *min = 0; + } else { + *maj = string.left(dot).toInt(); + *min = string.mid(dot + 1).toInt(); + } + } +} + QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QString &script, QQmlError *error) { Q_ASSERT(error); @@ -1670,7 +335,7 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri } int vmaj, vmin; - ProcessAST::extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()), + extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()), &vmaj, &vmin); bool invalidImport = false; @@ -1749,46 +414,4 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri return rv; } -void QQmlScript::Parser::clear() -{ - _pragmas.clear(); - _imports.clear(); - _refTypes.clear(); - _errors.clear(); - - if (data) { - delete data; - data = 0; - } - - _pool.clear(); - _qmlRoot = 0; -} - -int QQmlScript::Parser::findOrCreateTypeId(const QString &name, Object *object) -{ - for (int ii = 0; ii < _refTypes.size(); ++ii) { - if (_refTypes.at(ii)->name == name) - return ii; - } - - TypeReference *type = _pool.New(); - type->name = name; - type->firstUse = object; - _refTypes.append(type); - return _refTypes.size() - 1; -} - -void QQmlScript::Parser::setTree(QQmlScript::Object *tree) -{ - Q_ASSERT(! root); - - root = tree; -} - -Engine *QQmlScript::Parser::jsEngine() const -{ - return data ? &data->engine : 0; -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index 29da97fe83..15446c089f 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -68,7 +68,6 @@ QT_BEGIN_NAMESPACE class QByteArray; class QQmlPropertyCache; namespace QQmlJS { class Engine; namespace AST { class Node; class StringLiteral; class UiProgram; class FunctionDeclaration; } } -namespace QQmlCompilerTypes { struct BindingReference; struct ComponentCompileState; } namespace QQmlScript { @@ -137,241 +136,11 @@ class TypeReference : public QQmlPool::Class public: // type as it has been referenced in Qml QString name; - // The first use of this type in the parse tree. Useful for error locations. - QQmlScript::Object *firstUse; -}; - -class Object; -class Property; - -class Q_QML_PRIVATE_EXPORT Variant -{ -public: - enum Type { - Invalid, - Boolean, - Number, - String, - Script - }; - - Variant(); - Variant(const Variant &); - explicit Variant(bool); - explicit Variant(double, const QStringRef &asWritten = QStringRef()); - explicit Variant(QQmlJS::AST::StringLiteral *); - explicit Variant(const QStringRef &asWritten, QQmlJS::AST::Node *); - Variant &operator=(const Variant &); - - Type type() const; - - bool isBoolean() const { return type() == Boolean; } - bool isNumber() const { return type() == Number; } - bool isString() const { return type() == String; } - bool isScript() const { return type() == Script; } - bool isStringList() const; - - bool asBoolean() const; - QString asString() const; - double asNumber() const; - QString asScript() const; - QQmlJS::AST::Node *asAST() const; - QStringList asStringList() const; - -private: - Type t; - union { - bool b; - double d; - QQmlJS::AST::StringLiteral *l; - QQmlJS::AST::Node *n; - }; - QStringRef asWritten; -}; - -class Value : public QQmlPool::POD -{ -public: - Value(); - - enum Type { - // The type of this value assignment is not yet known - Unknown, - // This is used as a literal property assignment - Literal, - // This is used as a property binding assignment - PropertyBinding, - // This is used as a QQmlPropertyValueSource assignment - ValueSource, - // This is used as a QQmlPropertyValueInterceptor assignment - ValueInterceptor, - // This is used as a property QObject assignment - CreatedObject, - // This is used as a signal object assignment - SignalObject, - // This is used as a signal expression assignment - SignalExpression, - // This is used as an id assignment only - Id - }; - Type type; - - // ### Temporary (for id only) - QString primitive() const { return value.isString() ? value.asString() : value.asScript(); } - - // Primitive value - Variant value; - // Object value - Object *object; - - LocationSpan location; - - // Used by compiler - struct SignalData { - int signalExpressionContextStack; - Object *signalScopeObject; - int functionIndex; // before gen() index in functionsToCompile, then index in runtime functions - }; - union { - QQmlCompilerTypes::BindingReference *bindingReference; - SignalData signalData; - }; - - // Used in Property::ValueList lists - Value *nextValue; -}; - -class Property : public QQmlPool::POD -{ -public: - Property(); - - // The Object to which this property is attached - Object *parent; - - Object *getValue(const LocationSpan &); - void addValue(Value *v); - void addOnValue(Value *v); - - // The QVariant::Type of the property, or 0 (QVariant::Invalid) if - // unknown. - int type; - // The metaobject index of this property, or -1 if unknown. - int index; - // The core data in the case of a regular property. - // XXX This has to be a value now as the synthCache may change during - // compilation which invalidates pointers. We should fix this. - QQmlPropertyData core; - - // Returns true if this is an empty property - both value and values - // are unset. - bool isEmpty() const; - - typedef QFieldList ValueList; - // The list of values assigned to this property. Content in values - // and value are mutually exclusive - ValueList values; - // The list of values assigned to this property using the "on" syntax - ValueList onValues; - // The accessed property. This is used to represent dot properties. - // Content in value and values are mutually exclusive. - Object *value; - // The property name - const QHashedStringRef &name() const { return _name; } - void setName(const QString &n) { _name = QHashedStringRef(pool()->NewString(n)); } - void setName(const QHashedStringRef &n) { _name = n; } - // True if this property was accessed as the default property. - bool isDefault; - // True if the setting of this property will be deferred. Set by the - // QQmlCompiler - bool isDeferred; - // True if this property is a value-type pseudo-property - bool isValueTypeSubProperty; - // True if this property is a property alias. Set by the - // QQmlCompiler - bool isAlias; - // True if this is a readonly property declaration - bool isReadOnlyDeclaration; - - // Used for scriptStringProperties - int scriptStringScope; - - LocationSpan location; - LocationRange listValueRange; - - // Used in Object::MainPropertyList - Property *nextMainProperty; - - // Used in Object::PropertyList lists - Property *nextProperty; - -private: - friend class Object; - QHashedStringRef _name; }; class Object : public QQmlPool::Class { public: - Object(); - virtual ~Object(); - - // Type of the object. The integer is an index into the - // QQmlCompiledData::types array, or -1 if the object is a property - // group. - int type; - // A back pointer to the QQmlScript::TypeReference for this type, if any. - // Set by the parser. - TypeReference *typeReference; - - // The id assigned to the object (if any). Set by the QQmlCompiler - QString id; - // The id index assigned to the object (if any). Set by the QQmlCompiler - int idIndex; - // Custom parsed data - QByteArray custom; - // Bit mask of the properties assigned bindings - QByteArray bindingBitmask; - void setBindingBit(int); - - QQmlPropertyCache *metatype; - - QQmlJS::AST::Node *astNode; // responsible for the creation of this object - - // The synthesized metaobject, if QML added signals or properties to - // this type. Otherwise null - QByteArray synthdata; // Generated by compiler - QQmlPropertyCache *synthCache; // Generated by compiler - - Property *getDefaultProperty(); - // name ptr must be guaranteed to remain valid - Property *getProperty(const QHashedStringRef &name, bool create=true); - Property *getProperty(const QStringRef &name, bool create=true); - Property *getProperty(const QString &name, bool create=true); - - Property *defaultProperty; - - typedef QFieldList MainPropertyList; - MainPropertyList properties; - QHashField propertiesHashField; - - // Output of the compilation phase (these properties continue to exist - // in either the defaultProperty or properties members too) - void addValueProperty(Property *); - void addSignalProperty(Property *); - void addAttachedProperty(Property *); - void addGroupedProperty(Property *); - void addValueTypeProperty(Property *); - void addScriptStringProperty(Property *); - - typedef QFieldList PropertyList; - PropertyList valueProperties; - PropertyList signalProperties; - PropertyList attachedProperties; - PropertyList groupedProperties; - PropertyList valueTypeProperties; - PropertyList scriptStringProperties; - // Script blocks that were nested under this object struct ScriptBlock { enum Pragma { @@ -384,120 +153,11 @@ public: QString file; Pragmas pragmas; }; - - // The bytes to cast instances by to get to the QQmlParserStatus - // interface. -1 indicates the type doesn't support this interface. - // Set by the QQmlCompiler. - int parserStatusCast; - - LocationSpan location; - - struct DynamicProperty : public QQmlPool::POD - { - DynamicProperty(); - - enum Type { Var, Variant, Int, Bool, Real, String, Url, Color, - Font, Time, Date, DateTime, Rect, Point, Size, - Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, - Alias, Custom, CustomList }; - - quint32 isDefaultProperty:1; - quint32 isReadOnly:1; - - Type type; - - QHashedStringRef customType; - QHashedStringRef name; - QQmlScript::Property *defaultValue; - LocationSpan location; - Location nameLocation; - - // Used by Object::DynamicPropertyList - DynamicProperty *nextProperty; - - // Used by the compiler - int nameIndex; // Points at the name and name + "Changed()" strings - }; - - struct DynamicSignal : public QQmlPool::POD - { - DynamicSignal(); - - QHashedStringRef name; - QQmlPool::List parameterTypes; - QQmlPool::List parameterTypeNames; - QQmlPool::List parameterNames; - - // Used by Object::DynamicSignalList - DynamicSignal *nextSignal; - - // Used by the compiler - int nameIndex; - LocationSpan location; - }; - - struct DynamicSlot : public QQmlPool::Class - { - DynamicSlot(); - - QQmlJS::AST::FunctionDeclaration *funcDecl; - QHashedStringRef name; - QList parameterNames; - LocationSpan location; - - int parameterNamesLength() const; - - // Used by Object::DynamicSlotList - DynamicSlot *nextSlot; - - // Used by the compiler - int nameIndex; - }; - - // The list of dynamic properties - typedef QFieldList DynamicPropertyList; - DynamicPropertyList dynamicProperties; - // The list of dynamic signals - typedef QFieldList DynamicSignalList; - DynamicSignalList dynamicSignals; - // The list of dynamic slots - typedef QFieldList DynamicSlotList; - DynamicSlotList dynamicSlots; - - int aggregateDynamicSignalParameterCount() const; - int aggregateDynamicSlotParameterCount() const; - - // Used by compiler - QQmlCompilerTypes::ComponentCompileState *componentCompileState; - - // Used by ComponentCompileState::AliasingObjectsList - Object *nextAliasingObject; - // Used by ComponentComppileState::IdList - Object *nextIdObject; }; -class ParserJsASTData; class Q_QML_PRIVATE_EXPORT Parser { public: - Parser(); - ~Parser(); - - bool parse(const QString &data, const QByteArray &preparseData, - const QUrl &url = QUrl(), const QString &urlString = QString()); - - QByteArray preparseData() const; - - QList referencedTypes() const; - - QQmlScript::Object *tree() const; - QList imports() const; - QList pragmas() const; - - void clear(); - - QList errors() const; - class JavaScriptMetaData { public: JavaScriptMetaData() @@ -509,29 +169,6 @@ public: static QQmlScript::Object::ScriptBlock::Pragmas extractPragmas(QString &); static JavaScriptMetaData extractMetaData(QString &, QQmlError *error); - - -// ### private: - int findOrCreateTypeId(const QString &name, Object *); - void setTree(QQmlScript::Object *tree); - - void setScriptFile(const QString &filename) {_scriptFile = filename; } - QString scriptFile() const { return _scriptFile; } - - QQmlJS::AST::UiProgram *qmlRoot() const { return _qmlRoot; } - QQmlJS::Engine *jsEngine() const; - -// ### private: - QList _errors; - - QQmlPool _pool; - QQmlScript::Object *root; - QList _imports; - QList _pragmas; - QList _refTypes; - QString _scriptFile; - QQmlJS::AST::UiProgram *_qmlRoot; - ParserJsASTData *data; }; } @@ -540,6 +177,4 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlScript::Object::ScriptBlock::Pragmas) QT_END_NAMESPACE -Q_DECLARE_METATYPE(QQmlScript::Variant) - #endif // QQMLSCRIPT_P_H diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp index 79bb1e9394..c0da9b458f 100644 --- a/src/qml/qml/qqmlstringconverters.cpp +++ b/src/qml/qml/qqmlstringconverters.cpp @@ -41,7 +41,6 @@ #include "qqmlstringconverters_p.h" #include -#include #include #include diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index c1074e8a84..258c5c71b3 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1966,15 +1966,12 @@ QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager) : QQmlTypeLoader::Blob(url, QmlFile, manager), m_typesResolved(false), m_compiledData(0), m_implicitImport(0), m_implicitImportLoaded(false) { - m_useNewCompiler = QQmlEnginePrivate::get(manager->engine())->useNewCompiler; } QQmlTypeData::~QQmlTypeData() { for (int ii = 0; ii < m_scripts.count(); ++ii) m_scripts.at(ii).script->release(); - for (int ii = 0; ii < m_types.count(); ++ii) - if (m_types.at(ii).typeData) m_types.at(ii).typeData->release(); for (QHash::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end; ++it) { if (QQmlTypeData *tdata = it->typeData) @@ -1986,16 +1983,6 @@ QQmlTypeData::~QQmlTypeData() delete m_implicitImport; } -const QQmlScript::Parser &QQmlTypeData::parser() const -{ - return scriptParser; -} - -const QList &QQmlTypeData::resolvedTypes() const -{ - return m_types; -} - const QList &QQmlTypeData::resolvedScripts() const { return m_scripts; @@ -2048,24 +2035,6 @@ void QQmlTypeData::done() } // Check all type dependencies for errors - // --- old compiler: - for (int ii = 0; !isError() && ii < m_types.count(); ++ii) { - const TypeReference &type = m_types.at(ii); - Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); - if (type.typeData && type.typeData->isError()) { - QString typeName = scriptParser.referencedTypes().at(ii)->name; - - QList errors = type.typeData->errors(); - QQmlError error; - error.setUrl(finalUrl()); - error.setLine(type.location.line); - error.setColumn(type.location.column); - error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); - errors.prepend(error); - setError(errors); - } - } - // --- new compiler: for (QHash::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); !isError() && it != end; ++it) { const TypeReference &type = *it; @@ -2083,7 +2052,6 @@ void QQmlTypeData::done() setError(errors); } } - // --- // Check all composite singleton type dependencies for errors for (int ii = 0; !isError() && ii < m_compositeSingletons.count(); ++ii) { @@ -2119,7 +2087,6 @@ void QQmlTypeData::done() if (!isError()) compile(); - scriptParser.clear(); parsedQML.reset(); } @@ -2160,19 +2127,12 @@ void QQmlTypeData::dataReceived(const Data &data) if (data.isFile()) preparseData = data.asFile()->metaData(QLatin1String("qml:preparse")); - if (m_useNewCompiler) { - QQmlEngine *qmlEngine = typeLoader()->engine(); - parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(qmlEngine)->debugger != 0)); - QQmlCodeGenerator compiler(QV8Engine::get(qmlEngine)->illegalNames()); - if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) { - setError(compiler.errors); - return; - } - } else { - if (!scriptParser.parse(code, preparseData, finalUrl(), finalUrlString())) { - setError(scriptParser.errors()); - return; - } + QQmlEngine *qmlEngine = typeLoader()->engine(); + parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(qmlEngine)->debugger != 0)); + QQmlCodeGenerator compiler(QV8Engine::get(qmlEngine)->illegalNames()); + if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) { + setError(compiler.errors); + return; } m_imports.setBaseUrl(finalUrl(), finalUrlString()); @@ -2203,7 +2163,7 @@ void QQmlTypeData::dataReceived(const Data &data) QList errors; // ### convert to use new data structure once old compiler is gone. - if (m_useNewCompiler && m_newImports.isEmpty()) { + if (m_newImports.isEmpty()) { m_newImports.reserve(parsedQML->imports.size()); foreach (QV4::CompiledData::Import *i, parsedQML->imports) { QQmlScript::Import import; @@ -2226,7 +2186,7 @@ void QQmlTypeData::dataReceived(const Data &data) } } - foreach (const QQmlScript::Import &import, m_useNewCompiler ? m_newImports : scriptParser.imports()) { + foreach (const QQmlScript::Import &import, m_newImports) { if (!addImport(import, &errors)) { Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); @@ -2240,7 +2200,7 @@ void QQmlTypeData::dataReceived(const Data &data) } // ### convert to use new data structure once old compiler is gone. - if (m_useNewCompiler && m_newPragmas.isEmpty()) { + if (m_newPragmas.isEmpty()) { m_newPragmas.reserve(parsedQML->pragmas.size()); foreach (QtQml::Pragma *p, parsedQML->pragmas) { QQmlScript::Pragma pragma; @@ -2256,7 +2216,7 @@ void QQmlTypeData::dataReceived(const Data &data) } } - foreach (const QQmlScript::Pragma &pragma, m_useNewCompiler ? m_newPragmas : scriptParser.pragmas()) { + foreach (const QQmlScript::Pragma &pragma, m_newPragmas) { if (!addPragma(pragma, &errors)) { Q_ASSERT(errors.size()); setError(errors); @@ -2312,20 +2272,11 @@ void QQmlTypeData::compile() QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, m_compiledData->name); - if (m_useNewCompiler) { - QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, parsedQML.data()); - if (!compiler.compile()) { - setError(compiler.compilationErrors()); - m_compiledData->release(); - m_compiledData = 0; - } - } else { - QQmlCompiler compiler(&scriptParser._pool); - if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) { - setError(compiler.errors()); - m_compiledData->release(); - m_compiledData = 0; - } + QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, parsedQML.data()); + if (!compiler.compile()) { + setError(compiler.compilationErrors()); + m_compiledData->release(); + m_compiledData = 0; } } @@ -2357,9 +2308,6 @@ void QQmlTypeData::resolveTypes() TypeReference ref; QQmlScript::TypeReference parserRef; parserRef.name = csRef.typeName; - // we are basing our type on the information from qmldir and therefore - // do not have a proper location. - parserRef.firstUse = NULL; if (!csRef.prefix.isEmpty()) { parserRef.name.prepend(csRef.prefix + QLatin1Char('.')); @@ -2382,31 +2330,6 @@ void QQmlTypeData::resolveTypes() } } - // --- old compiler: - foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) { - TypeReference ref; - - int majorVersion = -1; - int minorVersion = -1; - - if (!resolveType(parserRef, majorVersion, minorVersion, ref)) - return; - - if (ref.type->isComposite()) { - ref.typeData = typeLoader()->getType(ref.type->sourceUrl()); - addDependency(ref.typeData); - } - - ref.majorVersion = majorVersion; - ref.minorVersion = minorVersion; - - Q_ASSERT(parserRef->firstUse); - ref.location = parserRef->firstUse->location.start; - - m_types << ref; - } - - // --- new compiler: QV4::CompiledData::TypeReferenceMap typeReferences; QStringList names; if (parsedQML) { @@ -2523,12 +2446,6 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int & error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description())); } - if (parserRef->firstUse) - { - error.setLine(parserRef->firstUse->location.start.line); - error.setColumn(parserRef->firstUse->location.start.column); - } - errors.prepend(error); setError(errors); return false; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index ab6f47e8de..a42412754f 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -424,13 +424,7 @@ private: public: ~QQmlTypeData(); - const QQmlScript::Parser &parser() const; - - // old compiler: - const QList &resolvedTypes() const; - // new compiler: const QHash &resolvedTypeRefs() const { return m_resolvedTypes; } - // --- const QList &resolvedScripts() const; const QSet &namespaces() const; @@ -461,27 +455,18 @@ private: virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace); - // --- old compiler - QQmlScript::Parser scriptParser; - // --- new compiler QScopedPointer parsedQML; QList m_newImports; QList m_newPragmas; - // --- QList m_scripts; QSet m_namespaces; QList m_compositeSingletons; - // --- old compiler - QList m_types; - // --- new compiler // map from name index to resolved type QHash m_resolvedTypes; - // --- bool m_typesResolved:1; - bool m_useNewCompiler:1; QQmlCompiledData *m_compiledData; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 15401e269b..56befa4a3e 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -82,1192 +82,8 @@ QT_BEGIN_NAMESPACE using namespace QQmlVMETypes; -#define VME_EXCEPTION(desc, line) \ - { \ - QQmlError error; \ - error.setDescription(desc.trimmed()); \ - error.setLine(line); \ - error.setUrl(COMP->url); \ - *errors << error; \ - goto exceptionExit; \ - } - -#define VME_EXCEPTION_WITH_COLUMN(desc, line, column) \ - { \ - QQmlError error; \ - error.setDescription(desc.trimmed()); \ - error.setLine(line); \ - error.setColumn(column); \ - error.setUrl(COMP->url); \ - *errors << error; \ - goto exceptionExit; \ - } - bool QQmlVME::s_enableComponentComplete = true; -void QQmlVME::init(QQmlContextData *ctxt, QQmlCompiledData *comp, int start, - QQmlContextData *creation) -{ - Q_ASSERT(ctxt); - Q_ASSERT(comp); - - if (start == -1) { - start = 0; - } else { - creationContext = creation; - } - - State initState; - initState.context = ctxt; - initState.compiledData = comp; - initState.instructionStream = comp->bytecode.constData() + start; - states.push(initState); - - typedef QQmlInstruction I; - I *i = (I *)initState.instructionStream; - - Q_ASSERT(comp->instructionType(i) == I::Init); - - objects.allocate(i->init.objectStackSize); - lists.allocate(i->init.listStackSize); - bindValues.allocate(i->init.bindingsSize); - parserStatus.allocate(i->init.parserStatusSize); - -#ifdef QML_ENABLE_TRACE - parserStatusData.allocate(i->init.parserStatusSize); - rootComponent = comp; -#endif - - rootContext = 0; - engine = ctxt->engine; - profiler.profiler = QQmlEnginePrivate::get(engine)->profiler; -} - -bool QQmlVME::initDeferred(QObject *object) -{ - QQmlData *data = QQmlData::get(object); - - if (!data || !data->deferredData) - return false; - - QQmlContextData *ctxt = data->deferredData->context; - QQmlCompiledData *comp = data->deferredData->compiledData; - int start = data->deferredData->deferredIdx; - - State initState; - initState.flags = State::Deferred; - initState.context = ctxt; - initState.compiledData = comp; - initState.instructionStream = comp->bytecode.constData() + start; - states.push(initState); - - typedef QQmlInstruction I; - I *i = (I *)initState.instructionStream; - - Q_ASSERT(comp->instructionType(i) == I::DeferInit); - - objects.allocate(i->deferInit.objectStackSize); - lists.allocate(i->deferInit.listStackSize); - bindValues.allocate(i->deferInit.bindingsSize); - parserStatus.allocate(i->deferInit.parserStatusSize); - - objects.push(object); - -#ifdef QML_ENABLE_TRACE - parserStatusData.allocate(i->deferInit.parserStatusSize); - rootComponent = comp; -#endif - - rootContext = 0; - engine = ctxt->engine; - profiler.profiler = QQmlEnginePrivate::get(engine)->profiler; - - return true; -} - -namespace { -struct ActiveVMERestorer -{ - ActiveVMERestorer(QQmlVME *me, QQmlEnginePrivate *ep) - : ep(ep), oldVME(ep->activeVME) { ep->activeVME = me; } - ~ActiveVMERestorer() { ep->activeVME = oldVME; } - - QQmlEnginePrivate *ep; - QQmlVME *oldVME; -}; -} - -QObject *QQmlVME::execute(QList *errors, const QQmlInstantiationInterrupt &interrupt) -{ - Q_ASSERT(states.count() >= 1); - -#ifdef QML_ENABLE_TRACE - QQmlTrace trace("VME Execute"); - trace.addDetail("URL", rootComponent->url); -#endif - - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(states.at(0).context->engine); - - ActiveVMERestorer restore(this, ep); - - QObject *rv = run(errors, interrupt); - - return rv; -} - -inline bool fastHasBinding(QObject *o, int index) -{ - if (QQmlData *ddata = static_cast(QObjectPrivate::get(o)->declarativeData)) { - int coreIndex = index & 0x0000FFFF; - return ddata->hasBindingBit(coreIndex); - } - - return false; -} - -static void removeBindingOnProperty(QObject *o, int index) -{ - int coreIndex = index & 0x0000FFFF; - int valueTypeIndex = (index & 0xFFFF0000 ? index >> 16 : -1); - - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0); - if (binding) binding->destroy(); -} - -static QVariant variantFromString(const QString &string) -{ - return QQmlStringConverters::variantFromString(string); -} - -static QV4::ExecutionContext *qmlBindingContext(QQmlEngine *engine, QV4::ExecutionEngine *v4, QV4::Value *qmlBindingWrappers, QQmlContextData *context, QObject *scope, int objIdx) -{ - QV4::Scope valueScope(v4); - QV4::Scoped wrapper(valueScope, qmlBindingWrappers[objIdx]); - if (!wrapper) { - QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, scope)); - wrapper = new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject); - qmlBindingWrappers[objIdx] = wrapper; - } - return wrapper->context(); -} - -// XXX we probably need some form of "work count" here to prevent us checking this -// for every instruction. -#define QML_BEGIN_INSTR_COMMON(I) { \ - const QQmlInstructionMeta<(int)QQmlInstruction::I>::DataType &instr = QQmlInstructionMeta<(int)QQmlInstruction::I>::data(*genericInstr); \ - INSTRUCTIONSTREAM += QQmlInstructionMeta<(int)QQmlInstruction::I>::Size; \ - Q_UNUSED(instr); - -#ifdef QML_THREADED_VME_INTERPRETER -# define QML_BEGIN_INSTR(I) op_##I: \ - QML_BEGIN_INSTR_COMMON(I) - -# define QML_NEXT_INSTR(I) { \ - if (watcher.hasRecursed()) return 0; \ - genericInstr = reinterpret_cast(INSTRUCTIONSTREAM); \ - goto *genericInstr->common.code; \ - } - -# define QML_END_INSTR(I) } \ - if (watcher.hasRecursed()) return 0; \ - genericInstr = reinterpret_cast(INSTRUCTIONSTREAM); \ - if (interrupt.shouldInterrupt()) return 0; \ - goto *genericInstr->common.code; - -#else -# define QML_BEGIN_INSTR(I) \ - case QQmlInstruction::I: \ - QML_BEGIN_INSTR_COMMON(I) - -# define QML_NEXT_INSTR(I) { \ - if (watcher.hasRecursed()) return 0; \ - break; \ - } - -# define QML_END_INSTR(I) \ - if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; \ - } break; -#endif - -#define QML_STORE_VALUE(name, cpptype, value) \ - QML_BEGIN_INSTR(name) \ - cpptype v = value; \ - void *a[] = { (void *)&v, 0, &status, &flags }; \ - QObject *target = objects.top(); \ - CLEAN_PROPERTY(target, instr.propertyIndex); \ - QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \ - QML_END_INSTR(name) - -#define QML_STORE_PROVIDER_VALUE(name, type, value) \ - QML_BEGIN_INSTR(name) \ - struct { void *data[4]; } buffer; \ - if (QQml_valueTypeProvider()->storeValueType(type, &value, &buffer, sizeof(buffer))) { \ - void *a[] = { reinterpret_cast(&buffer), 0, &status, &flags }; \ - QObject *target = objects.top(); \ - CLEAN_PROPERTY(target, instr.propertyIndex); \ - QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \ - } \ - QML_END_INSTR(name) - -#define QML_STORE_LIST(name, cpptype, value) \ - QML_BEGIN_INSTR(name) \ - cpptype v; \ - v.append(value); \ - void *a[] = { (void *)&v, 0, &status, &flags }; \ - QObject *target = objects.top(); \ - CLEAN_PROPERTY(target, instr.propertyIndex); \ - QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \ - QML_END_INSTR(name) - -#define QML_STORE_VAR(name, value) \ - QML_BEGIN_INSTR(name) \ - tmpValue = (value); \ - QV4::ValueRef valueref(tmpValue); \ - QObject *target = objects.top(); \ - CLEAN_PROPERTY(target, instr.propertyIndex); \ - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(target); \ - Q_ASSERT(vmemo); \ - vmemo->setVMEProperty(instr.propertyIndex, valueref); \ - QML_END_INSTR(name) - -#define QML_STORE_POINTER(name, value) \ - QML_BEGIN_INSTR(name) \ - void *a[] = { (void *)value, 0, &status, &flags }; \ - QObject *target = objects.top(); \ - CLEAN_PROPERTY(target, instr.propertyIndex); \ - QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \ - QML_END_INSTR(name) - -#define CLEAN_PROPERTY(o, index) \ - if (fastHasBinding(o, index)) \ - removeBindingOnProperty(o, index) - -QObject *QQmlVME::run(QList *errors, - const QQmlInstantiationInterrupt &interrupt -#ifdef QML_THREADED_VME_INTERPRETER - , void * const **storeJumpTable -#endif - ) -{ -#ifdef QML_THREADED_VME_INTERPRETER - if (storeJumpTable) { -#define QML_INSTR_ADDR(I, FMT) &&op_##I, - static void *const jumpTable[] = { - FOR_EACH_QML_INSTR(QML_INSTR_ADDR) - }; -#undef QML_INSTR_ADDR - *storeJumpTable = jumpTable; - return 0; - } -#endif - Q_ASSERT(errors->isEmpty()); - Q_ASSERT(states.count() >= 1); - - QQmlEngine *engine = states.at(0).context->engine; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - QV4::ExecutionEngine *v4 = ep->v4engine(); - QV4::Scope valueScope(v4); - QV4::ScopedValue tmpValue(valueScope); - QV4::Value *qmlBindingWrappers = valueScope.alloc(objects.capacity()); - std::fill(qmlBindingWrappers, qmlBindingWrappers + objects.capacity(), QV4::Primitive::undefinedValue()); - - int status = -1; // needed for dbus - QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::RemoveBindingOnAliasWrite; - - QRecursionWatcher watcher(this); - -#define COMP states.top().compiledData -#define CTXT states.top().context -#define INSTRUCTIONSTREAM states.top().instructionStream -#define BINDINGSKIPLIST states.top().bindingSkipList - -#define TYPES COMP->types -#define PRIMITIVES COMP->primitives -#define DATAS COMP->datas -#define PROGRAMS COMP->programs -#define PROPERTYCACHES COMP->propertyCaches -#define SCRIPTS COMP->scripts -#define URLS COMP->urls - -#ifdef QML_THREADED_VME_INTERPRETER - const QQmlInstruction *genericInstr = reinterpret_cast(INSTRUCTIONSTREAM); - goto *genericInstr->common.code; -#else - for (;;) { - const QQmlInstruction *genericInstr = reinterpret_cast(INSTRUCTIONSTREAM); - - switch (genericInstr->common.instructionType) { -#endif - - // Store a created object in a property. These all pop from the objects stack. - QML_STORE_VALUE(StoreObject, QObject *, objects.pop()); - QML_STORE_VALUE(StoreVariantObject, QVariant, QVariant::fromValue(objects.pop())); - QML_STORE_VAR(StoreVarObject, QV4::QObjectWrapper::wrap(ep->v4engine(), objects.pop())); - - // Store a literal value in a corresponding property - QML_STORE_VALUE(StoreFloat, float, instr.value); - QML_STORE_VALUE(StoreDouble, double, instr.value); - QML_STORE_VALUE(StoreBool, bool, instr.value); - QML_STORE_VALUE(StoreInteger, int, instr.value); - QML_STORE_PROVIDER_VALUE(StoreColor, QMetaType::QColor, instr.value); - QML_STORE_VALUE(StoreDate, QDate, QDate::fromJulianDay(instr.value)); - QML_STORE_VALUE(StoreDateTime, QDateTime, - QDateTime(QDate::fromJulianDay(instr.date), QTime::fromMSecsSinceStartOfDay(instr.time))); - QML_STORE_VALUE(StoreTime, QTime, QTime::fromMSecsSinceStartOfDay(instr.time)); - QML_STORE_POINTER(StorePoint, (QPoint *)&instr.point); - QML_STORE_POINTER(StorePointF, (QPointF *)&instr.point); - QML_STORE_POINTER(StoreSize, (QSize *)&instr.size); - QML_STORE_POINTER(StoreSizeF, (QSizeF *)&instr.size); - QML_STORE_POINTER(StoreRect, (QRect *)&instr.rect); - QML_STORE_POINTER(StoreRectF, (QRectF *)&instr.rect); - QML_STORE_PROVIDER_VALUE(StoreVector3D, QMetaType::QVector3D, instr.vector); - QML_STORE_PROVIDER_VALUE(StoreVector4D, QMetaType::QVector4D, instr.vector); - QML_STORE_POINTER(StoreString, &PRIMITIVES.at(instr.value)); - QML_STORE_POINTER(StoreByteArray, &DATAS.at(instr.value)); - QML_STORE_POINTER(StoreUrl, &URLS.at(instr.value)); -#ifndef QT_NO_TRANSLATION - QML_STORE_VALUE(StoreTrString, QString, - QCoreApplication::translate(DATAS.at(instr.context).constData(), - DATAS.at(instr.text).constData(), - DATAS.at(instr.comment).constData(), - instr.n)); - QML_STORE_VALUE(StoreTrIdString, QString, qtTrId(DATAS.at(instr.text).constData(), instr.n)); -#endif - - // Store a literal value in a QList - QML_STORE_LIST(StoreStringList, QStringList, PRIMITIVES.at(instr.value)); - QML_STORE_LIST(StoreStringQList, QList, PRIMITIVES.at(instr.value)); - QML_STORE_LIST(StoreUrlQList, QList, URLS.at(instr.value)); - QML_STORE_LIST(StoreDoubleQList, QList, instr.value); - QML_STORE_LIST(StoreBoolQList, QList, instr.value); - QML_STORE_LIST(StoreIntegerQList, QList, instr.value); - - // Store a literal value in a QVariant property - QML_STORE_VALUE(StoreVariant, QVariant, variantFromString(PRIMITIVES.at(instr.value))); - QML_STORE_VALUE(StoreVariantInteger, QVariant, QVariant(instr.value)); - QML_STORE_VALUE(StoreVariantDouble, QVariant, QVariant(instr.value)); - QML_STORE_VALUE(StoreVariantBool, QVariant, QVariant(instr.value)); - - // Store a literal value in a var property. - // We deliberately do not use string converters here - QML_STORE_VAR(StoreVar, ep->v8engine()->fromVariant(PRIMITIVES.at(instr.value))); - QML_STORE_VAR(StoreVarInteger, QV4::Primitive::fromInt32(instr.value)); - QML_STORE_VAR(StoreVarDouble, QV4::Primitive::fromDouble(instr.value)); - QML_STORE_VAR(StoreVarBool, QV4::Primitive::fromBoolean(instr.value)); - - // Store a literal value in a QJSValue property. - QML_STORE_VALUE(StoreJSValueString, QJSValue, QJSValue(PRIMITIVES.at(instr.value))); - QML_STORE_VALUE(StoreJSValueInteger, QJSValue, QJSValue(instr.value)); - QML_STORE_VALUE(StoreJSValueDouble, QJSValue, QJSValue(instr.value)); - QML_STORE_VALUE(StoreJSValueBool, QJSValue, QJSValue(instr.value)); - - QML_BEGIN_INSTR(Init) - // Ensure that the compiled data has been initialized - if (!COMP->isInitialized()) COMP->initialize(engine); - - QQmlContextData *parentCtxt = CTXT; - CTXT = new QQmlContextData; - CTXT->isInternal = true; - CTXT->url = COMP->url; - CTXT->urlString = COMP->name; - CTXT->imports = COMP->importCache; - CTXT->imports->addref(); - CTXT->setParent(parentCtxt); - if (instr.contextCache != -1) - CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache)); - if (states.count() == 1) { - rootContext = CTXT; - rootContext->activeVMEData = data; - rootContext->isRootObjectInCreation = true; - } - if (states.count() == 1 && !creationContext.isNull()) { - // A component that is logically created within another component instance shares the - // same instances of script imports. For example: - // - // import QtQuick 2.0 - // import "test.js" as Test - // ListView { - // model: Test.getModel() - // delegate: Component { - // Text { text: Test.getValue(index); } - // } - // } - // - // Has the same "Test" instance. To implement this, we simply copy the v8 handles into - // the inner context. We have to create a fresh persistent handle for each to prevent - // double dispose. It is possible we could do this more efficiently using some form of - // referencing instead. - CTXT->importedScripts = creationContext->importedScripts; - } - QML_END_INSTR(Init) - - QML_BEGIN_INSTR(DeferInit) - QML_END_INSTR(DeferInit) - - QML_BEGIN_INSTR(Done) - states.pop(); - - if (states.isEmpty()) - goto normalExit; - QML_END_INSTR(Done) - - QML_BEGIN_INSTR(CreateQMLObject) - const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type); - Q_ASSERT(type.component); - - Q_QML_VME_PROFILE(profiler, startBackground(type.component->name)); - - states.push(State()); - - State *cState = &states[states.count() - 2]; - State *nState = &states[states.count() - 1]; - - nState->context = cState->context; - nState->compiledData = type.component; - nState->instructionStream = type.component->bytecode.constData(); - - if (instr.bindingBits != -1) { - const QByteArray &bits = cState->compiledData->datas.at(instr.bindingBits); - nState->bindingSkipList = QBitField((const quint32*)bits.constData(), - bits.size() * 8); - } - if (instr.isRoot) - nState->bindingSkipList = nState->bindingSkipList.united(cState->bindingSkipList); - - // As the state in the state stack changed, execution will continue in the new program. - QML_END_INSTR(CreateQMLObject) - - QML_BEGIN_INSTR(CompleteQMLObject) - Q_QML_VME_PROFILE(profiler, foreground(CTXT->url, instr.line, instr.column)); - - QObject *o = objects.top(); - Q_ASSERT(o); - - QQmlData *ddata = QQmlData::get(o); - Q_ASSERT(ddata); - - if (states.count() == 1) { - // Keep a reference to the compiled data we rely on. - // Only the top-level component instance needs to add a reference - higher-level - // components add a reference to the components they depend on, so an instance - // of the top-level component keeps them all referenced. - ddata->compiledData = states[0].compiledData; - ddata->compiledData->addref(); - } - - if (instr.isRoot) { - if (ddata->context) { - Q_ASSERT(ddata->context != CTXT); - Q_ASSERT(ddata->outerContext); - Q_ASSERT(ddata->outerContext != CTXT); - QQmlContextData *c = ddata->context; - while (c->linkedContext) c = c->linkedContext; - c->linkedContext = CTXT; - } else { - CTXT->addObject(o); - } - - ddata->ownContext = true; - } else if (!ddata->context) { - CTXT->addObject(o); - } - - ddata->setImplicitDestructible(); - ddata->outerContext = CTXT; - ddata->lineNumber = instr.line; - ddata->columnNumber = instr.column; - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - QML_END_INSTR(CompleteQMLObject) - - QML_BEGIN_INSTR(CreateCppObject) - const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type); - Q_ASSERT(type.type); - Q_QML_VME_PROFILE(profiler, start(type.type->qmlTypeName(), CTXT->url, instr.line, instr.column)); - - QObject *o = 0; - void *memory = 0; - type.type->create(&o, &memory, sizeof(QQmlData)); - - if (!o) - VME_EXCEPTION(tr("Unable to create object of type %1").arg(type.type->elementName()), - instr.line); - - QQmlData *ddata = new (memory) QQmlData; - ddata->ownMemory = false; - QObjectPrivate::get(o)->declarativeData = ddata; - - if (rootContext && rootContext->isRootObjectInCreation) { - ddata->rootObjectInCreation = true; - rootContext->isRootObjectInCreation = false; - } - - if (type.typePropertyCache && !ddata->propertyCache) { - ddata->propertyCache = type.typePropertyCache; - ddata->propertyCache->addref(); - } - - if (states.count() == 1) { - // Keep a reference to the compiled data we rely on - ddata->compiledData = states[0].compiledData; - ddata->compiledData->addref(); - } - - if (instr.isRoot) { - if (ddata->context) { - Q_ASSERT(ddata->context != CTXT); - Q_ASSERT(ddata->outerContext); - Q_ASSERT(ddata->outerContext != CTXT); - QQmlContextData *c = ddata->context; - while (c->linkedContext) c = c->linkedContext; - c->linkedContext = CTXT; - } else { - CTXT->addObject(o); - } - - ddata->ownContext = true; - } else if (!ddata->context) { - CTXT->addObject(o); - } - - ddata->setImplicitDestructible(); - ddata->outerContext = CTXT; - ddata->lineNumber = instr.line; - ddata->columnNumber = instr.column; - - if (instr.data != -1) { - QQmlCustomParser *customParser = - TYPES.at(instr.type).type->customParser(); - customParser->setCustomData(o, DATAS.at(instr.data)); - } - if (!objects.isEmpty()) { - QObject *parent = objects.at(objects.count() - 1 - (instr.parentToSuper?1:0)); -#if 0 // ### refactor - if (o->isWidgetType() && parent->isWidgetType()) - static_cast(o)->setParent(static_cast(parent)); - else -#endif - QQml_setParent_noEvent(o, parent); - ddata->parentFrozen = true; - } - objects.push(o); - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - QML_END_INSTR(CreateCppObject) - - QML_BEGIN_INSTR(CreateSimpleObject) - const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type); - Q_QML_VME_PROFILE(profiler, start(ref.type->qmlTypeName(), CTXT->url, instr.line, instr.column)); - QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData)); - ::memset(static_cast(o), 0, instr.typeSize + sizeof(QQmlData)); - instr.create(o); - - QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize); - if (!ddata->propertyCache && ref.typePropertyCache) { - ddata->propertyCache = ref.typePropertyCache; - ddata->propertyCache->addref(); - } - ddata->lineNumber = instr.line; - ddata->columnNumber = instr.column; - - QObjectPrivate::get(o)->declarativeData = ddata; - ddata->context = ddata->outerContext = CTXT; - ddata->nextContextObject = CTXT->contextObjects; - if (ddata->nextContextObject) - ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; - ddata->prevContextObject = &CTXT->contextObjects; - CTXT->contextObjects = ddata; - - QObject *parent = objects.at(objects.count() - 1 - (instr.parentToSuper?1:0)); - QQml_setParent_noEvent(o, parent); - - ddata->parentFrozen = true; - objects.push(o); - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - QML_END_INSTR(CreateSimpleObject) - - QML_BEGIN_INSTR(SetId) - QObject *target = objects.top(); - CTXT->setIdProperty(instr.index, target); - QML_END_INSTR(SetId) - - QML_BEGIN_INSTR(SetDefault) - CTXT->contextObject = objects.top(); - QML_END_INSTR(SetDefault) - - QML_BEGIN_INSTR(CreateComponent) - QQmlComponent *qcomp = - new QQmlComponent(CTXT->engine, COMP, INSTRUCTIONSTREAM - COMP->bytecode.constData(), - objects.isEmpty() ? 0 : objects.top()); - - QQmlData *ddata = QQmlData::get(qcomp, true); - Q_ASSERT(ddata); - - CTXT->addObject(qcomp); - - if (states.count() == 1) { - // Keep a reference to the compiled data we rely on - ddata->compiledData = states[0].compiledData; - ddata->compiledData->addref(); - } - - if (instr.isRoot) - ddata->ownContext = true; - - ddata->setImplicitDestructible(); - ddata->outerContext = CTXT; - ddata->lineNumber = instr.line; - ddata->columnNumber = instr.column; - - QQmlComponentPrivate::get(qcomp)->creationContext = CTXT; - - objects.push(qcomp); - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - INSTRUCTIONSTREAM += instr.count; - QML_END_INSTR(CreateComponent) - - QML_BEGIN_INSTR(StoreMetaObject) - QObject *target = objects.top(); - - QQmlPropertyCache *propertyCache = PROPERTYCACHES.at(instr.propertyCache); - - const QQmlVMEMetaData *data = - (const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData(); - - QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, target, objects.count() - 1); - (void)new QQmlVMEMetaObject(target, propertyCache, data, qmlContext, COMP); - - QQmlData *ddata = QQmlData::get(target, true); - if (ddata->propertyCache) ddata->propertyCache->release(); - ddata->propertyCache = propertyCache; - ddata->propertyCache->addref(); - - QML_END_INSTR(StoreMetaObject) - - QML_BEGIN_INSTR(AssignCustomType) - QObject *target = objects.top(); - CLEAN_PROPERTY(target, instr.propertyIndex); - - const QString &primitive = PRIMITIVES.at(instr.primitive); - int type = instr.type; - QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type); - QVariant v = (*converter)(primitive); - - QMetaProperty prop = - target->metaObject()->property(instr.propertyIndex); - if (v.isNull() || ((int)prop.type() != type && prop.userType() != type)) - VME_EXCEPTION(tr("Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line); - - void *a[] = { (void *)v.data(), 0, &status, &flags }; - QMetaObject::metacall(target, QMetaObject::WriteProperty, - instr.propertyIndex, a); - QML_END_INSTR(AssignCustomType) - - QML_BEGIN_INSTR(AssignSignalObject) - // XXX optimize - - QObject *assign = objects.pop(); - QObject *target = objects.top(); - int sigIdx = instr.signal; - const QString &pr = PRIMITIVES.at(sigIdx); - - QQmlProperty prop(target, pr); - if (prop.type() & QQmlProperty::SignalProperty) { - - QMetaMethod method = QQmlMetaType::defaultMethod(assign); - if (!method.isValid()) - VME_EXCEPTION_WITH_COLUMN(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line, instr.column); - - if (!QMetaObject::checkConnectArgs(prop.method(), method)) { - VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2") - .arg(QString::fromLatin1(method.methodSignature().constData())) - .arg(QString::fromLatin1(prop.method().methodSignature().constData())), instr.line); - } - - QQmlPropertyPrivate::connect(target, prop.index(), assign, method.methodIndex()); - - } else { - VME_EXCEPTION(tr("Cannot assign an object to signal property %1").arg(pr), instr.line); - } - - - QML_END_INSTR(AssignSignalObject) - - QML_BEGIN_INSTR(StoreSignal) - QObject *target = objects.top(); - QObject *context = objects.at(objects.count() - 1 - instr.context); - - QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, context, objects.count() - 1 - instr.context); - - QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.runtimeFunctionIndex]; - - tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false); - - QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine); - QQmlBoundSignalExpression *expr = - new QQmlBoundSignalExpression(target, instr.signalIndex, - CTXT, context, tmpValue); - bs->takeExpression(expr); - QML_END_INSTR(StoreSignal) - - QML_BEGIN_INSTR(StoreImportedScript) - QV4::Scope scope(v4); - QV4::ScopedObject scripts(scope, CTXT->importedScripts.value()); - if (!scripts) { - scripts = v4->newArrayObject(); - CTXT->importedScripts = scripts; - } - scripts->putIndexed(instr.value, SCRIPTS.at(instr.value)->scriptValueForContext(CTXT)); - QML_END_INSTR(StoreImportedScript) - - QML_BEGIN_INSTR(StoreScriptString) - QObject *target = objects.top(); - QObject *scope = objects.at(objects.count() - 1 - instr.scope); - QQmlScriptString ss(PRIMITIVES.at(instr.value), CTXT->asQQmlContext(), scope); - ss.d.data()->bindingId = instr.bindingId; - ss.d.data()->lineNumber = qmlSourceCoordinate(instr.line); - ss.d.data()->columnNumber = qmlSourceCoordinate(instr.column); - ss.d.data()->isStringLiteral = instr.isStringLiteral; - ss.d.data()->isNumberLiteral = instr.isNumberLiteral; - ss.d.data()->numberValue = instr.numberValue; - - void *a[] = { &ss, 0, &status, &flags }; - QMetaObject::metacall(target, QMetaObject::WriteProperty, - instr.propertyIndex, a); - QML_END_INSTR(StoreScriptString) - - QML_BEGIN_INSTR(BeginObject) - Q_QML_VME_PROFILE(profiler, push()); - QObject *target = objects.top(); - QQmlParserStatus *status = reinterpret_cast(reinterpret_cast(target) + instr.castValue); - parserStatus.push(status); -#ifdef QML_ENABLE_TRACE - Q_ASSERT(QObjectPrivate::get(target)->declarativeData); - parserStatusData.push(static_cast(QObjectPrivate::get(target)->declarativeData)); -#endif - status->d = &parserStatus.top(); - - status->classBegin(); - QML_END_INSTR(BeginObject) - - QML_BEGIN_INSTR(StoreBinding) - QObject *target = - objects.at(objects.count() - 1 - instr.owner); - QObject *context = - objects.at(objects.count() - 1 - instr.context); - - if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex)) - QML_NEXT_INSTR(StoreBinding); - - QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, context, objects.count() - 1 - instr.context); - - QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.functionIndex]; - - tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false); - - QQmlBinding *bind = new QQmlBinding(tmpValue, context, CTXT, COMP->name, instr.line, instr.column); - bindValues.push(bind); - bind->m_mePtr = &bindValues.top(); - bind->setTarget(target, instr.property, CTXT); - - if (instr.isAlias) { - QQmlAbstractBinding *old = - QQmlPropertyPrivate::setBindingNoEnable(target, - instr.property.coreIndex, - instr.property.getValueTypeCoreIndex(), - bind); - if (old) { old->destroy(); } - } else { - typedef QQmlPropertyPrivate QDPP; - Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property)); - Q_ASSERT(bind->object() == target); - - CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property)); - - bind->addToObject(); - - if (!instr.property.isValueTypeVirtual()) { - QQmlData *data = QQmlData::get(target); - Q_ASSERT(data); - data->setPendingBindingBit(target, instr.property.coreIndex); - } - } - QML_END_INSTR(StoreBinding) - - QML_BEGIN_INSTR(StoreValueSource) - QObject *obj = objects.pop(); - QQmlPropertyValueSource *vs = reinterpret_cast(reinterpret_cast(obj) + instr.castValue); - QObject *target = obj->parent(); - vs->setTarget(QQmlPropertyPrivate::restore(target, instr.property, CTXT)); - QML_END_INSTR(StoreValueSource) - - QML_BEGIN_INSTR(StoreValueInterceptor) - QObject *obj = objects.pop(); - QQmlPropertyValueInterceptor *vi = reinterpret_cast(reinterpret_cast(obj) + instr.castValue); - QObject *target = obj->parent(); - QQmlProperty prop = - QQmlPropertyPrivate::restore(target, instr.property, CTXT); - vi->setTarget(prop); - QQmlVMEMetaObject *mo = QQmlVMEMetaObject::get(target); - Q_ASSERT(mo); - mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi); - QML_END_INSTR(StoreValueInterceptor) - - QML_BEGIN_INSTR(StoreObjectQList) - QObject *assign = objects.pop(); - - const List &list = lists.top(); - if (list.qListProperty.append) - list.qListProperty.append((QQmlListProperty*)&list.qListProperty, assign); - else - VME_EXCEPTION(tr("Cannot assign object to read only list"), -1); - QML_END_INSTR(StoreObjectQList) - - QML_BEGIN_INSTR(AssignObjectList) - // This is only used for assigning interfaces - QObject *assign = objects.pop(); - const List &list = lists.top(); - - int type = list.type; - - void *ptr = 0; - - const char *iid = QQmlMetaType::interfaceIId(type); - if (iid) - ptr = assign->qt_metacast(iid); - if (!ptr) - VME_EXCEPTION(tr("Cannot assign object to list"), instr.line); - - if (list.qListProperty.append) - list.qListProperty.append((QQmlListProperty*)&list.qListProperty, ptr); - else - VME_EXCEPTION(tr("Cannot assign object to read only list"), -1); - QML_END_INSTR(AssignObjectList) - - QML_BEGIN_INSTR(StoreInterface) - QObject *assign = objects.pop(); - QObject *target = objects.top(); - CLEAN_PROPERTY(target, instr.propertyIndex); - - int coreIdx = instr.propertyIndex; - QMetaProperty prop = target->metaObject()->property(coreIdx); - int t = prop.userType(); - const char *iid = QQmlMetaType::interfaceIId(t); - bool ok = false; - if (iid) { - void *ptr = assign->qt_metacast(iid); - if (ptr) { - void *a[] = { &ptr, 0, &status, &flags }; - QMetaObject::metacall(target, - QMetaObject::WriteProperty, - coreIdx, a); - ok = true; - } - } - - if (!ok) - VME_EXCEPTION(tr("Cannot assign object to interface property"), instr.line); - QML_END_INSTR(StoreInterface) - - QML_BEGIN_INSTR(FetchAttached) - QObject *target = objects.top(); - - QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target); - - if (!qmlObject) - VME_EXCEPTION(tr("Unable to create attached object"), instr.line); - - objects.push(qmlObject); - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - QML_END_INSTR(FetchAttached) - - QML_BEGIN_INSTR(FetchQList) - QObject *target = objects.top(); - - lists.push(List(instr.type)); - - void *a[1]; - a[0] = (void *)&(lists.top().qListProperty); - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.property, a); - QML_END_INSTR(FetchQList) - - QML_BEGIN_INSTR(FetchObject) - QObject *target = objects.top(); - - QObject *obj = 0; - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = &obj; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.property, a); - - if (!obj) - VME_EXCEPTION_WITH_COLUMN(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line, instr.column); - - objects.push(obj); - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - QML_END_INSTR(FetchObject) - - QML_BEGIN_INSTR(PopQList) - lists.pop(); - QML_END_INSTR(PopQList) - - QML_BEGIN_INSTR(Defer) - if (instr.deferCount) { - QObject *target = objects.top(); - QQmlData *data = QQmlData::get(target, true); - if (data->deferredData) { - //This rare case still won't always work right - qmlInfo(target) << "Setting deferred property across multiple components may not work"; - delete data->deferredData; - } - data->deferredData = new QQmlData::DeferredData; - //If we're in a CreateQML here, data->compiledData could be reset later - data->deferredData->compiledData = COMP; - data->deferredData->context = CTXT; - // Keep this data referenced until we're initialized - data->deferredData->compiledData->addref(); - data->deferredData->deferredIdx = INSTRUCTIONSTREAM - COMP->bytecode.constData(); - Q_ASSERT(data->deferredData->deferredIdx != 0); - INSTRUCTIONSTREAM += instr.deferCount; - } - QML_END_INSTR(Defer) - - QML_BEGIN_INSTR(PopFetchedObject) - objects.pop(); - QML_END_INSTR(PopFetchedObject) - - QML_BEGIN_INSTR(FetchValueType) - QObject *target = objects.top(); - - if (instr.bindingSkipList != 0) { - // Possibly need to clear bindings - QQmlData *targetData = QQmlData::get(target); - if (targetData) { - QQmlAbstractBinding *binding = - QQmlPropertyPrivate::binding(target, instr.property, -1); - - if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) { - QQmlPropertyPrivate::setBinding(target, instr.property, -1, 0); - binding->destroy(); - } else if (binding) { - QQmlValueTypeProxyBinding *proxy = - static_cast(binding); - proxy->removeBindings(instr.bindingSkipList); - } - } - } - - QQmlValueType *valueHandler = QQmlValueTypeFactory::valueType(instr.type); - Q_ASSERT(valueHandler); - valueHandler->read(target, instr.property); - objects.push(valueHandler); - qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue(); - QML_END_INSTR(FetchValueType) - - QML_BEGIN_INSTR(PopValueType) - QQmlValueType *valueHandler = - static_cast(objects.pop()); - QObject *target = objects.top(); - valueHandler->write(target, instr.property, QQmlPropertyPrivate::BypassInterceptor); - QML_END_INSTR(PopValueType) - -#ifdef QML_THREADED_VME_INTERPRETER - // nothing to do -#else - default: - Q_UNREACHABLE(); - qFatal("QQmlCompiledData: Internal error - unknown instruction %d", genericInstr->common.instructionType); - break; - } - } -#endif - -exceptionExit: - Q_ASSERT(!states.isEmpty()); - Q_ASSERT(!errors->isEmpty()); - - reset(); - - return 0; - -normalExit: - Q_ASSERT(objects.count() == 1); - - QObject *rv = objects.top(); - - objects.deallocate(); - lists.deallocate(); - states.clear(); - Q_QML_VME_PROFILE(profiler, stop()); - - return rv; -} - -void QQmlVME::reset() -{ - Q_ASSERT(!states.isEmpty() || objects.isEmpty()); - - QRecursionWatcher watcher(this); - - if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred)) - delete objects.at(0); - - if (!rootContext.isNull()) - rootContext->activeVMEData = 0; - - // Remove the QQmlParserStatus and QQmlAbstractBinding back pointers - blank(parserStatus); - blank(bindValues); - - while (componentAttached) { - QQmlComponentAttached *a = componentAttached; - a->rem(); - } - - engine = 0; - objects.deallocate(); - lists.deallocate(); - bindValues.deallocate(); - parserStatus.deallocate(); -#ifdef QML_ENABLE_TRACE - parserStatusData.deallocate(); -#endif - finalizeCallbacks.clear(); - states.clear(); - rootContext = 0; - creationContext = 0; - - // If profiling is switched off during a VME run and then switched back on - // before or during the next run background ranges from the first run will - // be reported in the second run because we don't clear() here. We accept - // that as the collected data will be incomplete anyway and because not - // calling clear() here is benefitial for the non-profiling case. - Q_QML_VME_PROFILE(profiler, clear(true)); -} - -#ifdef QML_THREADED_VME_INTERPRETER -void *const *QQmlVME::instructionJumpTable() -{ - static void * const *jumpTable = 0; - if (!jumpTable) { - QQmlVME dummy; - QQmlInstantiationInterrupt i; - dummy.run(0, i, &jumpTable); - } - return jumpTable; -} -#endif - -QQmlContextData *QQmlVME::complete(const QQmlInstantiationInterrupt &interrupt) -{ - Q_ASSERT(engine || - (bindValues.isEmpty() && - parserStatus.isEmpty() && - componentAttached == 0 && - rootContext.isNull() && - finalizeCallbacks.isEmpty())); - - if (!engine) - return 0; - - QQmlTrace trace("VME Complete"); -#ifdef QML_ENABLE_TRACE - trace.addDetail("URL", rootComponent->url); -#endif - - ActiveVMERestorer restore(this, QQmlEnginePrivate::get(engine)); - QRecursionWatcher watcher(this); - - { - QQmlTrace trace("VME Binding Enable"); - trace.event("begin binding eval"); - while (!bindValues.isEmpty()) { - QQmlAbstractBinding *b = bindValues.pop(); - - if (b) { - b->m_mePtr = 0; - QQmlData *data = QQmlData::get(b->object()); - Q_ASSERT(data); - data->clearPendingBindingBit(b->propertyIndex()); - b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::DontRemoveBinding); - } - - if (watcher.hasRecursed() || interrupt.shouldInterrupt()) - return 0; - } - bindValues.deallocate(); - } - - if (componentCompleteEnabled()) { // the qml designer does the component complete later - QQmlTrace trace("VME Component Complete"); - while (!parserStatus.isEmpty()) { - Q_QML_VME_PROFILE(profiler, pop()); - QQmlParserStatus *status = parserStatus.pop(); -#ifdef QML_ENABLE_TRACE - QQmlData *data = parserStatusData.pop(); -#endif - - if (status && status->d) { - status->d = 0; -#ifdef QML_ENABLE_TRACE - QQmlTrace trace("Component complete"); - trace.addDetail("URL", data->outerContext->url); - trace.addDetail("Line", data->lineNumber); -#endif - status->componentComplete(); - } - - if (watcher.hasRecursed() || interrupt.shouldInterrupt()) - return 0; - } - parserStatus.deallocate(); - Q_QML_VME_PROFILE(profiler, clear()); - } - - { - QQmlTrace trace("VME Finalize Callbacks"); - for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) { - QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii); - QObject *obj = callback.first; - if (obj) { - void *args[] = { 0 }; - QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args); - } - if (watcher.hasRecursed()) - return 0; - } - finalizeCallbacks.clear(); - } - - { - QQmlTrace trace("VME Component.onCompleted Callbacks"); - while (componentAttached) { - QQmlComponentAttached *a = componentAttached; - a->rem(); - QQmlData *d = QQmlData::get(a->parent()); - Q_ASSERT(d); - Q_ASSERT(d->context); - a->add(&d->context->componentAttached); - if (componentCompleteEnabled()) - emit a->completed(); - - if (watcher.hasRecursed() || interrupt.shouldInterrupt()) - return 0; - } - } - - QQmlContextData *rv = rootContext; - - reset(); - - if (rv) rv->activeVMEData = data; - - return rv; -} - void QQmlVME::enableComponentComplete() { s_enableComponentComplete = true; @@ -1283,22 +99,6 @@ bool QQmlVME::componentCompleteEnabled() return s_enableComponentComplete; } -void QQmlVME::blank(QFiniteStack &bs) -{ - for (int ii = 0; ii < bs.count(); ++ii) { - QQmlAbstractBinding *b = bs.at(ii); - if (b) b->m_mePtr = 0; - } -} - -void QQmlVME::blank(QFiniteStack &pss) -{ - for (int ii = 0; ii < pss.count(); ++ii) { - QQmlParserStatus *ps = pss.at(ii); - if(ps) ps->d = 0; - } -} - QQmlVMEGuard::QQmlVMEGuard() : m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0) { @@ -1309,23 +109,6 @@ QQmlVMEGuard::~QQmlVMEGuard() clear(); } -void QQmlVMEGuard::guard(QQmlVME *vme) -{ - clear(); - - m_objectCount = vme->objects.count(); - m_objects = new QPointer[m_objectCount]; - for (int ii = 0; ii < m_objectCount; ++ii) - m_objects[ii] = vme->objects[ii]; - - m_contextCount = (vme->rootContext.isNull()?0:1) + vme->states.count(); - m_contexts = new QQmlGuardedContextData[m_contextCount]; - for (int ii = 0; ii < vme->states.count(); ++ii) - m_contexts[ii] = vme->states.at(ii).context; - if (!vme->rootContext.isNull()) - m_contexts[m_contextCount - 1] = vme->rootContext.contextData(); -} - void QQmlVMEGuard::guard(QQmlObjectCreator *creator) { clear(); diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index cde8c0c6c4..f6476d77e0 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -55,7 +55,6 @@ #include "qqmlerror.h" #include -#include "qqmlinstruction_p.h" #include #include @@ -122,67 +121,12 @@ private: class Q_QML_PRIVATE_EXPORT QQmlVME { - Q_DECLARE_TR_FUNCTIONS(QQmlVME) public: - QQmlVME() : data(0), componentAttached(0) {} - QQmlVME(void *data) : data(data), componentAttached(0) {} - - void *data; - QQmlComponentAttached *componentAttached; - QList finalizeCallbacks; - - void init(QQmlContextData *, QQmlCompiledData *, int start, - QQmlContextData * = 0); - bool initDeferred(QObject *); - void reset(); - - QObject *execute(QList *errors, const QQmlInstantiationInterrupt & = QQmlInstantiationInterrupt()); - QQmlContextData *complete(const QQmlInstantiationInterrupt & = QQmlInstantiationInterrupt()); - static void enableComponentComplete(); static void disableComponentComplete(); static bool componentCompleteEnabled(); private: - friend class QQmlVMEGuard; - - QObject *run(QList *errors, const QQmlInstantiationInterrupt & -#ifdef QML_THREADED_VME_INTERPRETER - , void *const**storeJumpTable = 0 -#endif - ); - -#ifdef QML_THREADED_VME_INTERPRETER - static void *const*instructionJumpTable(); - friend class QQmlCompiledData; -#endif - - QQmlEngine *engine; - QRecursionNode recursion; - -#ifdef QML_ENABLE_TRACE - QQmlCompiledData *rootComponent; -#endif - - QFiniteStack objects; - QFiniteStack lists; - - QFiniteStack bindValues; - QFiniteStack parserStatus; -#ifdef QML_ENABLE_TRACE - QFiniteStack parserStatusData; -#endif - QQmlVmeProfiler profiler; - - QQmlGuardedContextData rootContext; - QQmlGuardedContextData creationContext; - - typedef QQmlVMETypes::State State; - QStack states; - - static void blank(QFiniteStack &); - static void blank(QFiniteStack &); - static bool s_enableComponentComplete; }; @@ -195,7 +139,6 @@ public: QQmlVMEGuard(); ~QQmlVMEGuard(); - void guard(QQmlVME *); void guard(QQmlObjectCreator *); void clear(); diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 70f859ffe2..122056e653 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -203,54 +203,6 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore) d->ignoreUnknownSignals = ignore; } - - -QByteArray -QQmlConnectionsParser::compile(const QList &props) -{ - QByteArray rv; - QDataStream ds(&rv, QIODevice::WriteOnly); - - for(int ii = 0; ii < props.count(); ++ii) - { - QString propName = props.at(ii).name(); - int propLine = props.at(ii).location().line; - int propColumn = props.at(ii).location().column; - - if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) { - error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); - return QByteArray(); - } - - QList values = props.at(ii).assignedValues(); - - for (int i = 0; i < values.count(); ++i) { - const QVariant &value = values.at(i); - - if (value.userType() == qMetaTypeId()) { - error(props.at(ii), QQmlConnections::tr("Connections: nested objects not allowed")); - return QByteArray(); - } else if (value.userType() == qMetaTypeId()) { - error(props.at(ii), QQmlConnections::tr("Connections: syntax error")); - return QByteArray(); - } else { - QQmlScript::Variant v = qvariant_cast(value); - if (v.isScript()) { - ds << propName; - ds << v.asScript(); - ds << propLine; - ds << propColumn; - } else { - error(props.at(ii), QQmlConnections::tr("Connections: script expected")); - return QByteArray(); - } - } - } - } - - return rv; -} - QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList &props) { Q_UNUSED(objectIndex) diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h index cb436b1eb4..f9b664cccf 100644 --- a/src/qml/types/qqmlconnections_p.h +++ b/src/qml/types/qqmlconnections_p.h @@ -84,7 +84,6 @@ private: class QQmlConnectionsParser : public QQmlCustomParser { public: - virtual QByteArray compile(const QList &); virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList &props); virtual void setCustomData(QObject *, const QByteArray &); }; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 60c6389d28..e0d9094387 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1872,16 +1872,8 @@ void QQmlDelegateModelItem::incubateObject( incubatorPriv->compiledData = componentPriv->cc; incubatorPriv->compiledData->addref(); - if (enginePriv->useNewCompiler) { - incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->cc, componentPriv->creationContext)); - incubatorPriv->subComponentToCreate = componentPriv->start; - } else { - incubatorPriv->vme.init( - context, - componentPriv->cc, - componentPriv->start, - componentPriv->creationContext); - } + incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->cc, componentPriv->creationContext)); + incubatorPriv->subComponentToCreate = componentPriv->start; enginePriv->incubate(*incubationTask, forContext); } diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index fbf3c091c2..dd52dfc1d4 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -2252,139 +2252,6 @@ void QQmlListModel::sync() qmlInfo(this) << "List sync() can only be called from a WorkerScript"; } -bool QQmlListModelParser::compileProperty(const QQmlCustomParserProperty &prop, QList &instr, QByteArray &data) -{ - QList values = prop.assignedValues(); - for(int ii = 0; ii < values.count(); ++ii) { - const QVariant &value = values.at(ii); - - if(value.userType() == qMetaTypeId()) { - QQmlCustomParserNode node = - qvariant_cast(value); - - if (node.name() != listElementTypeName) { - const QMetaObject *mo = resolveType(node.name()); - if (mo != &QQmlListElement::staticMetaObject) { - error(node, QQmlListModel::tr("ListElement: cannot contain nested elements")); - return false; - } - listElementTypeName = node.name(); // cache right name for next time - } - - { - ListInstruction li; - li.type = ListInstruction::Push; - li.dataIdx = -1; - instr << li; - } - - QList props = node.properties(); - for(int jj = 0; jj < props.count(); ++jj) { - const QQmlCustomParserProperty &nodeProp = props.at(jj); - if (nodeProp.name().isEmpty()) { - error(nodeProp, QQmlListModel::tr("ListElement: cannot contain nested elements")); - return false; - } - if (nodeProp.name() == QStringLiteral("id")) { - error(nodeProp, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property")); - return false; - } - - ListInstruction li; - int ref = data.count(); - data.append(nodeProp.name().toUtf8()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - - if(!compileProperty(nodeProp, instr, data)) - return false; - - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - } - - { - ListInstruction li; - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - } - - } else { - - QQmlScript::Variant variant = - qvariant_cast(value); - - int ref = data.count(); - - QByteArray d; - d += char(variant.type()); // type tag - if (variant.isString()) { - d += variant.asString().toUtf8(); - } else if (variant.isNumber()) { - d += QByteArray::number(variant.asNumber(),'g',20); - } else if (variant.isBoolean()) { - d += char(variant.asBoolean()); - } else if (variant.isScript()) { - if (definesEmptyList(variant.asScript())) { - d[0] = char(QQmlScript::Variant::Invalid); // marks empty list - } else { - QByteArray script = variant.asScript().toUtf8(); - bool ok; - int v = evaluateEnum(script, &ok); - if (!ok) { - using namespace QQmlJS; - AST::Node *node = variant.asAST(); - AST::StringLiteral *literal = 0; - if (AST::CallExpression *callExpr = AST::cast(node)) { - if (AST::IdentifierExpression *idExpr = AST::cast(callExpr->base)) { - if (idExpr->name == QLatin1String("QT_TR_NOOP") || idExpr->name == QLatin1String("QT_TRID_NOOP")) { - if (callExpr->arguments && !callExpr->arguments->next) - literal = AST::cast(callExpr->arguments->expression); - if (!literal) { - error(prop, QQmlListModel::tr("ListElement: improperly specified %1").arg(idExpr->name.toString())); - return false; - } - } else if (idExpr->name == QLatin1String("QT_TRANSLATE_NOOP")) { - if (callExpr->arguments && callExpr->arguments->next && !callExpr->arguments->next->next) - literal = AST::cast(callExpr->arguments->next->expression); - if (!literal) { - error(prop, QQmlListModel::tr("ListElement: improperly specified QT_TRANSLATE_NOOP")); - return false; - } - } - } - } - - if (literal) { - d[0] = char(QQmlScript::Variant::String); - d += literal->value.toUtf8(); - } else { - error(prop, QQmlListModel::tr("ListElement: cannot use script for property value")); - return false; - } - } else { - d[0] = char(QQmlScript::Variant::Number); - d += QByteArray::number(v); - } - } - } - d.append('\0'); - data.append(d); - - ListInstruction li; - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; - } - } - - return true; -} - bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QV4::CompiledData::Binding *binding, QList &instr, QByteArray &data) { if (binding->type >= QV4::CompiledData::Binding::Type_Object) { @@ -2448,18 +2315,18 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU QByteArray d; if (binding->type == QV4::CompiledData::Binding::Type_String) { - d += char(QQmlScript::Variant::String); + d += char(String); d += binding->valueAsString(&qmlUnit->header).toUtf8(); } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { - d += char(QQmlScript::Variant::Number); + d += char(Number); d += QByteArray::number(binding->valueAsNumber(),'g',20); } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { - d += char(QQmlScript::Variant::Boolean); + d += char(Boolean); d += char(binding->valueAsBoolean()); } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { QString scriptStr = binding->valueAsScriptString(&qmlUnit->header); if (definesEmptyList(scriptStr)) { - d[0] = char(QQmlScript::Variant::Invalid); // marks empty list + d[0] = char(Invalid); // marks empty list } else { QByteArray script = scriptStr.toUtf8(); bool ok; @@ -2491,14 +2358,14 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU } if (literal) { - d[0] = char(QQmlScript::Variant::String); + d[0] = char(String); d += literal->value.toUtf8(); } else { error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); return false; } } else { - d[0] = char(QQmlScript::Variant::Number); + d[0] = char(Number); d += QByteArray::number(v); } } @@ -2516,42 +2383,6 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU return true; } -QByteArray QQmlListModelParser::compile(const QList &customProps) -{ - QList instr; - QByteArray data; - listElementTypeName = QString(); // unknown - - for(int ii = 0; ii < customProps.count(); ++ii) { - const QQmlCustomParserProperty &prop = customProps.at(ii); - if(!prop.name().isEmpty()) { // isn't default property - error(prop, QQmlListModel::tr("ListModel: undefined property '%1'").arg(prop.name())); - return QByteArray(); - } - - if(!compileProperty(prop, instr, data)) { - return QByteArray(); - } - } - - int size = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction) + - data.count(); - - QByteArray rv; - rv.resize(size); - - ListModelData *lmd = (ListModelData *)rv.data(); - lmd->dataOffset = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction); - lmd->instrCount = instr.count(); - for (int ii = 0; ii < instr.count(); ++ii) - lmd->instructions()[ii] = instr.at(ii); - ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); - - return rv; -} - QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList &bindings) { QList instr; @@ -2647,21 +2478,21 @@ void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d) QString name = e0.name; QVariant value; - switch (QQmlScript::Variant::Type(data[instr.dataIdx])) { - case QQmlScript::Variant::Invalid: + switch (PropertyType(data[instr.dataIdx])) { + case Invalid: { const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); value = QVariant::fromValue(emptyModel); } break; - case QQmlScript::Variant::Boolean: + case Boolean: value = bool(data[1 + instr.dataIdx]); break; - case QQmlScript::Variant::Number: + case Number: value = QByteArray(data + 1 + instr.dataIdx).toDouble(); break; - case QQmlScript::Variant::String: + case String: value = QString::fromUtf8(data + 1 + instr.dataIdx); break; default: diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index 1fd57f063c..17fbb8a819 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -158,8 +158,16 @@ Q_OBJECT class QQmlListModelParser : public QQmlCustomParser { public: + enum PropertyType { + Invalid, + Boolean, + Number, + String, + Script + }; + + QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {} - QByteArray compile(const QList &); QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList &bindings); void setCustomData(QObject *, const QByteArray &); @@ -175,7 +183,6 @@ private: int instrCount; ListInstruction *instructions() const; }; - bool compileProperty(const QQmlCustomParserProperty &prop, QList &instr, QByteArray &data); bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QV4::CompiledData::Binding *binding, QList &instr, QByteArray &data); bool definesEmptyList(const QString &); -- cgit v1.2.3