1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcompiler_p.h"
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qqmlstringconverters_p.h"
49 #include "qqmlengine_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlcontext.h"
52 #include "qqmlmetatype_p.h"
53 #include "qqmlcustomparser_p_p.h"
54 #include "qqmlcontext_p.h"
55 #include "qqmlcomponent_p.h"
56 #include <private/qqmljsast_p.h>
57 #include "qqmlvmemetaobject_p.h"
58 #include "qqmlexpression_p.h"
59 #include "qqmlproperty_p.h"
60 #include "qqmlrewrite_p.h"
61 #include "qqmlscriptstring.h"
62 #include "qqmlglobal_p.h"
63 #include "qqmlbinding_p.h"
64 #include <private/qv4compiler_p.h>
71 #include <QtCore/qdebug.h>
72 #include <QtCore/qdatetime.h>
73 #include <QtCore/qvarlengtharray.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QQmlJS;
87 using namespace QQmlScript;
88 using namespace QQmlCompilerTypes;
90 static QString id_string(QLatin1String("id"));
91 static QString on_string(QLatin1String("on"));
92 static QString Changed_string(QLatin1String("Changed"));
93 static QString Component_string(QLatin1String("Component"));
94 static QString Component_import_string(QLatin1String("QML/Component"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QQmlCompiler.
101 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
102 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QQmlCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QQmlError> QQmlCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QQmlCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
191 error.setUrl(output->url); \
192 error.setLine(line); \
193 error.setColumn(column); \
194 error.setDescription(desc.trimmed()); \
195 exceptions << error; \
199 #define COMPILE_EXCEPTION(token, desc) \
200 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
205 Returns false if \a is false, otherwise does nothing.
207 #define COMPILE_CHECK(a) \
209 if (!a) return false; \
213 Returns true if literal \a v can be assigned to property \a prop, otherwise
216 This test corresponds to action taken by genLiteralAssignment(). Any change
217 made here, must have a corresponding action in genLiteralAssigment().
219 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
220 QQmlScript::Value *v)
222 const QQmlScript::Variant &value = v->value;
224 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
225 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
227 if (prop->core.isEnum()) {
228 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
231 if (p.isFlagType()) {
232 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
234 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
237 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
239 v->value = QQmlScript::Variant((double)enumValue);
243 int type = prop->type;
246 case QMetaType::QVariant:
248 case QVariant::String:
249 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
251 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
252 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
254 case QVariant::ByteArray:
255 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
258 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
260 case QVariant::RegExp:
261 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
265 bool ok = v->value.isNumber();
267 double n = v->value.asNumber();
268 if (double(uint(n)) != n)
271 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
276 bool ok = v->value.isNumber();
278 double n = v->value.asNumber();
279 if (double(int(n)) != n)
282 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
285 case QMetaType::Float:
286 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
288 case QVariant::Double:
289 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
291 case QVariant::Color:
294 QQmlStringConverters::colorFromString(value.asString(), &ok);
295 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
298 #ifndef QT_NO_DATESTRING
302 QQmlStringConverters::dateFromString(value.asString(), &ok);
303 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
309 QQmlStringConverters::timeFromString(value.asString(), &ok);
310 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
313 case QVariant::DateTime:
316 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
317 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
320 #endif // QT_NO_DATESTRING
321 case QVariant::Point:
322 case QVariant::PointF:
325 QQmlStringConverters::pointFFromString(value.asString(), &ok);
326 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
330 case QVariant::SizeF:
333 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
334 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
338 case QVariant::RectF:
341 QQmlStringConverters::rectFFromString(value.asString(), &ok);
342 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
347 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
350 case QVariant::Vector3D:
352 QQmlInstruction::instr_storeVector3D::QVector3D v3;
353 if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3)))
354 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
357 case QVariant::Vector4D:
359 QQmlInstruction::instr_storeVector4D::QVector4D v4;
360 if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4)))
361 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
366 // check if assigning a literal value to a list property.
367 // in each case, check the singular, since an Array of the specified type
368 // will not go via this literal assignment codepath.
369 if (type == qMetaTypeId<QList<qreal> >()) {
370 if (!v->value.isNumber()) {
371 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
374 } else if (type == qMetaTypeId<QList<int> >()) {
375 bool ok = v->value.isNumber();
377 double n = v->value.asNumber();
378 if (double(int(n)) != n)
381 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
383 } else if (type == qMetaTypeId<QList<bool> >()) {
384 if (!v->value.isBoolean()) {
385 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
388 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
389 if (!v->value.isString()) {
390 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
393 } else if (type == qMetaTypeId<QList<QUrl> >()) {
394 if (!v->value.isString()) {
395 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
400 // otherwise, check for existence of string converter to custom type
401 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
403 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
411 Generate a store instruction for assigning literal \a v to property \a prop.
413 Any literal assignment that is approved in testLiteralAssignment() must have
414 a corresponding action in this method.
416 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
417 QQmlScript::Value *v)
419 if (prop->core.isEnum()) {
420 Q_ASSERT(v->value.isNumber());
422 int value = (int)v->value.asNumber();
424 Instruction::StoreInteger instr;
425 instr.propertyIndex = prop->index;
427 output->addInstruction(instr);
431 int type = prop->type;
433 case QMetaType::QVariant:
435 if (v->value.isNumber()) {
436 double n = v->value.asNumber();
437 if (double(int(n)) == n) {
438 if (prop->core.isVMEProperty()) {
439 Instruction::StoreVarInteger instr;
440 instr.propertyIndex = prop->index;
441 instr.value = int(n);
442 output->addInstruction(instr);
444 Instruction::StoreVariantInteger instr;
445 instr.propertyIndex = prop->index;
446 instr.value = int(n);
447 output->addInstruction(instr);
450 if (prop->core.isVMEProperty()) {
451 Instruction::StoreVarDouble instr;
452 instr.propertyIndex = prop->index;
454 output->addInstruction(instr);
456 Instruction::StoreVariantDouble instr;
457 instr.propertyIndex = prop->index;
459 output->addInstruction(instr);
462 } else if (v->value.isBoolean()) {
463 if (prop->core.isVMEProperty()) {
464 Instruction::StoreVarBool instr;
465 instr.propertyIndex = prop->index;
466 instr.value = v->value.asBoolean();
467 output->addInstruction(instr);
469 Instruction::StoreVariantBool instr;
470 instr.propertyIndex = prop->index;
471 instr.value = v->value.asBoolean();
472 output->addInstruction(instr);
475 if (prop->core.isVMEProperty()) {
476 Instruction::StoreVar instr;
477 instr.propertyIndex = prop->index;
478 instr.value = output->indexForString(v->value.asString());
479 output->addInstruction(instr);
481 Instruction::StoreVariant instr;
482 instr.propertyIndex = prop->index;
483 instr.value = output->indexForString(v->value.asString());
484 output->addInstruction(instr);
489 case QVariant::String:
491 Instruction::StoreString instr;
492 instr.propertyIndex = prop->index;
493 instr.value = output->indexForString(v->value.asString());
494 output->addInstruction(instr);
497 case QVariant::StringList:
499 Instruction::StoreStringList instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForString(v->value.asString());
502 output->addInstruction(instr);
505 case QVariant::ByteArray:
507 Instruction::StoreByteArray instr;
508 instr.propertyIndex = prop->index;
509 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
510 output->addInstruction(instr);
515 Instruction::StoreUrl instr;
516 QString string = v->value.asString();
517 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
518 instr.propertyIndex = prop->index;
519 instr.value = output->indexForUrl(u);
520 output->addInstruction(instr);
525 Instruction::StoreInteger instr;
526 instr.propertyIndex = prop->index;
527 instr.value = uint(v->value.asNumber());
528 output->addInstruction(instr);
533 Instruction::StoreInteger instr;
534 instr.propertyIndex = prop->index;
535 instr.value = int(v->value.asNumber());
536 output->addInstruction(instr);
539 case QMetaType::Float:
541 Instruction::StoreFloat instr;
542 instr.propertyIndex = prop->index;
543 instr.value = float(v->value.asNumber());
544 output->addInstruction(instr);
547 case QVariant::Double:
549 Instruction::StoreDouble instr;
550 instr.propertyIndex = prop->index;
551 instr.value = v->value.asNumber();
552 output->addInstruction(instr);
555 case QVariant::Color:
557 Instruction::StoreColor instr;
558 instr.propertyIndex = prop->index;
559 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
560 output->addInstruction(instr);
563 #ifndef QT_NO_DATESTRING
566 Instruction::StoreDate instr;
567 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
568 instr.propertyIndex = prop->index;
569 instr.value = d.toJulianDay();
570 output->addInstruction(instr);
575 Instruction::StoreTime instr;
576 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
577 instr.propertyIndex = prop->index;
578 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
579 ::memcpy(&instr.time, &time, sizeof(QTime));
580 output->addInstruction(instr);
583 case QVariant::DateTime:
585 Instruction::StoreDateTime instr;
586 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
587 QTime time = dateTime.time();
588 instr.propertyIndex = prop->index;
589 instr.date = dateTime.date().toJulianDay();
590 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
591 ::memcpy(&instr.time, &time, sizeof(QTime));
592 output->addInstruction(instr);
595 #endif // QT_NO_DATESTRING
596 case QVariant::Point:
598 Instruction::StorePoint instr;
600 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
601 instr.propertyIndex = prop->index;
602 instr.point.xp = point.x();
603 instr.point.yp = point.y();
604 output->addInstruction(instr);
607 case QVariant::PointF:
609 Instruction::StorePointF instr;
611 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
612 instr.propertyIndex = prop->index;
613 instr.point.xp = point.x();
614 instr.point.yp = point.y();
615 output->addInstruction(instr);
620 Instruction::StoreSize instr;
622 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
623 instr.propertyIndex = prop->index;
624 instr.size.wd = size.width();
625 instr.size.ht = size.height();
626 output->addInstruction(instr);
629 case QVariant::SizeF:
631 Instruction::StoreSizeF instr;
633 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
634 instr.propertyIndex = prop->index;
635 instr.size.wd = size.width();
636 instr.size.ht = size.height();
637 output->addInstruction(instr);
642 Instruction::StoreRect instr;
644 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
645 instr.propertyIndex = prop->index;
646 instr.rect.x1 = rect.left();
647 instr.rect.y1 = rect.top();
648 instr.rect.x2 = rect.right();
649 instr.rect.y2 = rect.bottom();
650 output->addInstruction(instr);
653 case QVariant::RectF:
655 Instruction::StoreRectF instr;
657 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
658 instr.propertyIndex = prop->index;
659 instr.rect.xp = rect.left();
660 instr.rect.yp = rect.top();
661 instr.rect.w = rect.width();
662 instr.rect.h = rect.height();
663 output->addInstruction(instr);
668 Instruction::StoreBool instr;
669 bool b = v->value.asBoolean();
670 instr.propertyIndex = prop->index;
672 output->addInstruction(instr);
675 case QVariant::Vector3D:
677 Instruction::StoreVector3D instr;
678 instr.propertyIndex = prop->index;
679 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
680 output->addInstruction(instr);
683 case QVariant::Vector4D:
685 Instruction::StoreVector4D instr;
686 instr.propertyIndex = prop->index;
687 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
688 output->addInstruction(instr);
693 // generate single literal value assignment to a list property if required
694 if (type == qMetaTypeId<QList<qreal> >()) {
695 Instruction::StoreDoubleQList instr;
696 instr.propertyIndex = prop->index;
697 instr.value = v->value.asNumber();
698 output->addInstruction(instr);
700 } else if (type == qMetaTypeId<QList<int> >()) {
701 Instruction::StoreIntegerQList instr;
702 instr.propertyIndex = prop->index;
703 instr.value = int(v->value.asNumber());
704 output->addInstruction(instr);
706 } else if (type == qMetaTypeId<QList<bool> >()) {
707 Instruction::StoreBoolQList instr;
708 bool b = v->value.asBoolean();
709 instr.propertyIndex = prop->index;
711 output->addInstruction(instr);
713 } else if (type == qMetaTypeId<QList<QUrl> >()) {
714 Instruction::StoreUrlQList instr;
715 QString string = v->value.asString();
716 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
717 instr.propertyIndex = prop->index;
718 instr.value = output->indexForUrl(u);
719 output->addInstruction(instr);
721 } else if (type == qMetaTypeId<QList<QString> >()) {
722 Instruction::StoreStringQList instr;
723 instr.propertyIndex = prop->index;
724 instr.value = output->indexForString(v->value.asString());
725 output->addInstruction(instr);
729 // otherwise, generate custom type literal assignment
730 Instruction::AssignCustomType instr;
731 instr.propertyIndex = prop->index;
732 instr.primitive = output->indexForString(v->value.asString());
734 output->addInstruction(instr);
741 Resets data by clearing the lists that the QQmlCompiler modifies.
743 void QQmlCompiler::reset(QQmlCompiledData *data)
746 data->primitives.clear();
748 data->bytecode.resize(0);
752 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
753 with which the QQmlCompiledData will be associated.
755 Returns true on success, false on failure. On failure, the compile errors
756 are available from errors().
758 If the environment variant QML_COMPILER_DUMP is set
759 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
760 on a successful compiler.
762 bool QQmlCompiler::compile(QQmlEngine *engine,
764 QQmlCompiledData *out)
771 QQmlScript::Object *root = unit->parser().tree();
774 this->engine = engine;
775 this->enginePrivate = QQmlEnginePrivate::get(engine);
777 this->unitRoot = root;
781 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
782 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
784 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
785 QQmlCompiledData::TypeReference ref;
787 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
788 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
791 ref.type = tref.type;
792 if (!ref.type->isCreatable()) {
793 QString err = ref.type->noCreationReason();
795 err = tr( "Element is not creatable.");
796 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
799 if (ref.type->containsRevisionedAttributes()) {
800 QQmlError cacheError;
801 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
803 if (!ref.typePropertyCache)
804 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
805 ref.typePropertyCache->addref();
808 } else if (tref.typeData) {
809 ref.component = tref.typeData->compiledData();
811 ref.className = parserRef->name;
819 out->dumpInstructions();
822 Q_ASSERT(out->rootPropertyCache);
830 this->enginePrivate = 0;
832 this->cachedComponentTypeRef = -1;
833 this->cachedTranslationContextIndex = -1;
839 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
841 compileState = pool->New<ComponentCompileState>();
843 compileState->root = tree;
845 componentStats->componentStat.lineNumber = tree->location.start.line;
847 // We generate the importCache before we build the tree so that
848 // it can be used in the binding compiler. Given we "expect" the
849 // QML compilation to succeed, this isn't a waste.
850 output->importCache = new QQmlTypeNameCache();
851 foreach (const QString &ns, unit->namespaces()) {
852 output->importCache->add(ns);
856 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
857 QString qualifier = script.qualifier;
858 QString enclosingNamespace;
860 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
861 if (lastDotIndex != -1) {
862 enclosingNamespace = qualifier.left(lastDotIndex);
863 qualifier = qualifier.mid(lastDotIndex+1);
866 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
869 unit->imports().populateCache(output->importCache, engine);
871 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
874 Instruction::Init init;
875 init.bindingsSize = compileState->totalBindingsCount;
876 init.parserStatusSize = compileState->parserStatusCount;
877 init.contextCache = genContextCache();
878 init.objectStackSize = compileState->objectDepth.maxDepth();
879 init.listStackSize = compileState->listDepth.maxDepth();
880 if (compileState->compiledBindingData.isEmpty())
881 init.compiledBinding = -1;
883 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
884 output->addInstruction(init);
886 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
887 Instruction::StoreImportedScript import;
888 import.value = output->scripts.count();
890 QQmlScriptData *scriptData = script.script->scriptData();
891 scriptData->addref();
892 output->scripts << scriptData;
893 output->addInstruction(import);
896 if (!compileState->v8BindingProgram.isEmpty()) {
897 Instruction::InitV8Bindings bindings;
898 int index = output->programs.count();
900 typedef QQmlCompiledData::V8Program V8Program;
901 output->programs.append(V8Program(compileState->v8BindingProgram, output));
903 bindings.programIndex = index;
904 bindings.line = compileState->v8BindingProgramLine;
905 output->addInstruction(bindings);
910 Instruction::SetDefault def;
911 output->addInstruction(def);
913 Instruction::Done done;
914 output->addInstruction(done);
916 Q_ASSERT(tree->metatype);
918 if (tree->metadata.isEmpty()) {
919 output->root = tree->metatype;
921 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
922 output->root = &output->rootData;
924 if (!tree->metadata.isEmpty())
925 enginePrivate->registerCompositeType(output);
928 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
930 for (int ii = 0; ii < list.count(); ++ii)
931 if (string == list.at(ii))
937 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
940 componentStats->componentStat.objects++;
942 Q_ASSERT (obj->type != -1);
943 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
944 obj->metatype = tr.metaObject();
947 obj->typeName = tr.type->qmlTypeName();
949 // This object is a "Component" element
950 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
951 COMPILE_CHECK(buildComponent(obj, ctxt));
956 typedef QQmlInstruction I;
957 const I *init = ((const I *)tr.component->bytecode.constData());
958 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
960 // Adjust stack depths to include nested components
961 compileState->objectDepth.pushPop(init->init.objectStackSize);
962 compileState->listDepth.pushPop(init->init.listStackSize);
963 compileState->parserStatusCount += init->init.parserStatusSize;
964 compileState->totalBindingsCount += init->init.bindingsSize;
967 compileState->objectDepth.push();
969 // Object instantiations reset the binding context
970 BindingContext objCtxt(obj);
972 // Create the synthesized meta object, ignoring aliases
973 COMPILE_CHECK(checkDynamicMeta(obj));
974 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
975 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
977 // Find the native type and check for the QQmlParserStatus interface
978 QQmlType *type = toQmlType(obj);
980 obj->parserStatusCast = type->parserStatusCast();
981 if (obj->parserStatusCast != -1)
982 compileState->parserStatusCount++;
984 // Check if this is a custom parser type. Custom parser types allow
985 // assignments to non-existent properties. These assignments are then
986 // compiled by the type.
987 bool isCustomParser = output->types.at(obj->type).type &&
988 output->types.at(obj->type).type->customParser() != 0;
989 QList<QQmlCustomParserProperty> customProps;
991 // Fetch the list of deferred properties
992 QStringList deferredList = deferredProperties(obj);
994 // Must do id property first. This is to ensure that the id given to any
995 // id reference created matches the order in which the objects are
997 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
998 if (prop->name() == id_string) {
999 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1005 Property *defaultProperty = 0;
1006 Property *skipProperty = 0;
1007 if (obj->defaultProperty) {
1008 defaultProperty = obj->defaultProperty;
1010 Property *explicitProperty = 0;
1012 const QMetaObject *mo = obj->metatype;
1013 int idx = mo->indexOfClassInfo("DefaultProperty");
1015 QMetaClassInfo info = mo->classInfo(idx);
1016 const char *p = info.value();
1020 while (char c = p[plen++]) { ord |= c; };
1024 // Utf8 - unoptimal, but seldom hit
1025 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1026 QHashedStringRef r(*s);
1028 if (obj->propertiesHashField.test(r.hash())) {
1029 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1030 if (ep->name() == r) {
1031 explicitProperty = ep;
1037 if (!explicitProperty)
1038 defaultProperty->setName(r);
1041 QHashedCStringRef r(p, plen);
1043 if (obj->propertiesHashField.test(r.hash())) {
1044 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1045 if (ep->name() == r) {
1046 explicitProperty = ep;
1052 if (!explicitProperty) {
1053 // Set the default property name
1054 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1055 r.writeUtf16(buffer);
1056 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1062 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1064 skipProperty = explicitProperty; // We merge the values into defaultProperty
1066 // Find the correct insertion point
1067 Value *insertPos = 0;
1069 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1070 if (!(v->location.start < explicitProperty->values.first()->location.start))
1075 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1079 QQmlCustomParser *cp = 0;
1081 cp = output->types.at(obj->type).type->customParser();
1083 // Build all explicit properties specified
1084 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1086 if (prop == skipProperty)
1088 if (prop->name() == id_string)
1091 bool canDefer = false;
1092 if (isCustomParser) {
1093 if (doesPropertyExist(prop, obj) &&
1094 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1095 !isAttachedPropertyName(prop->name()))) {
1096 int ids = compileState->ids.count();
1097 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1098 canDefer = ids == compileState->ids.count();
1099 } else if (isSignalPropertyName(prop->name()) &&
1100 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1101 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1103 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1106 if (isSignalPropertyName(prop->name())) {
1107 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1109 int ids = compileState->ids.count();
1110 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1111 canDefer = ids == compileState->ids.count();
1115 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1116 prop->isDeferred = true;
1120 // Build the default property
1121 if (defaultProperty) {
1122 Property *prop = defaultProperty;
1124 bool canDefer = false;
1125 if (isCustomParser) {
1126 if (doesPropertyExist(prop, obj)) {
1127 int ids = compileState->ids.count();
1128 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1129 canDefer = ids == compileState->ids.count();
1131 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1134 int ids = compileState->ids.count();
1135 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1136 canDefer = ids == compileState->ids.count();
1139 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1140 prop->isDeferred = true;
1143 // Compile custom parser parts
1144 if (isCustomParser && !customProps.isEmpty()) {
1146 cp->compiler = this;
1148 obj->custom = cp->compile(customProps);
1151 foreach (QQmlError err, cp->errors()) {
1152 err.setUrl(output->url);
1157 compileState->objectDepth.pop();
1162 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1164 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1165 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1170 // Create the object
1171 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1172 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1174 Instruction::CreateSimpleObject create;
1175 create.create = output->types.at(obj->type).type->createFunction();
1176 create.typeSize = output->types.at(obj->type).type->createSize();
1177 create.type = obj->type;
1178 create.line = obj->location.start.line;
1179 create.column = obj->location.start.column;
1180 output->addInstruction(create);
1184 if (output->types.at(obj->type).type) {
1185 Instruction::CreateCppObject create;
1186 create.line = obj->location.start.line;
1187 create.column = obj->location.start.column;
1189 if (!obj->custom.isEmpty())
1190 create.data = output->indexForByteArray(obj->custom);
1191 create.type = obj->type;
1192 create.isRoot = (compileState->root == obj);
1193 output->addInstruction(create);
1195 Instruction::CreateQMLObject create;
1196 create.type = obj->type;
1197 create.isRoot = (compileState->root == obj);
1199 if (!obj->bindingBitmask.isEmpty()) {
1200 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1201 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1203 create.bindingBits = -1;
1205 output->addInstruction(create);
1207 Instruction::CompleteQMLObject complete;
1208 complete.line = obj->location.start.line;
1209 complete.column = obj->location.start.column;
1210 complete.isRoot = (compileState->root == obj);
1211 output->addInstruction(complete);
1215 // Setup the synthesized meta object if necessary
1216 if (!obj->metadata.isEmpty()) {
1217 Instruction::StoreMetaObject meta;
1218 meta.data = output->indexForByteArray(obj->metadata);
1219 meta.aliasData = output->indexForByteArray(obj->synthdata);
1220 meta.propertyCache = output->propertyCaches.count();
1222 QQmlPropertyCache *propertyCache = obj->synthCache;
1223 Q_ASSERT(propertyCache);
1224 propertyCache->addref();
1226 // Add flag for alias properties
1227 if (!obj->synthdata.isEmpty()) {
1228 const QQmlVMEMetaData *vmeMetaData =
1229 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1230 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1231 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1232 QQmlPropertyData *data = propertyCache->property(index);
1233 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1237 if (obj == unitRoot) {
1238 propertyCache->addref();
1239 output->rootPropertyCache = propertyCache;
1242 output->propertyCaches << propertyCache;
1243 output->addInstruction(meta);
1244 } else if (obj == unitRoot) {
1245 output->rootPropertyCache = tr.createPropertyCache(engine);
1246 output->rootPropertyCache->addref();
1249 // Set the object id
1250 if (!obj->id.isEmpty()) {
1251 Instruction::SetId id;
1252 id.value = output->indexForString(obj->id);
1253 id.index = obj->idIndex;
1254 output->addInstruction(id);
1258 if (tr.type && obj->parserStatusCast != -1) {
1259 Instruction::BeginObject begin;
1260 begin.castValue = obj->parserStatusCast;
1261 output->addInstruction(begin);
1267 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1269 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1270 Q_ASSERT(prop->scriptStringScope != -1);
1271 const QString &script = prop->values.first()->value.asScript();
1272 Instruction::StoreScriptString ss;
1273 ss.propertyIndex = prop->index;
1274 ss.value = output->indexForString(script);
1275 ss.scope = prop->scriptStringScope;
1276 // ss.bindingId = rewriteBinding(script, prop->name());
1277 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1278 ss.line = prop->location.start.line;
1279 ss.column = prop->location.start.column;
1280 output->addInstruction(ss);
1283 bool seenDefer = false;
1284 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1285 if (prop->isDeferred) {
1290 genValueProperty(prop, obj);
1293 Instruction::Defer defer;
1294 defer.deferCount = 0;
1295 int deferIdx = output->addInstruction(defer);
1296 int nextInstructionIndex = output->nextInstructionIndex();
1298 Instruction::DeferInit dinit;
1299 // XXX - these are now massive over allocations
1300 dinit.bindingsSize = compileState->totalBindingsCount;
1301 dinit.parserStatusSize = compileState->parserStatusCount;
1302 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1303 dinit.listStackSize = compileState->listDepth.maxDepth();
1304 output->addInstruction(dinit);
1306 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1307 if (!prop->isDeferred)
1309 genValueProperty(prop, obj);
1312 Instruction::Done done;
1313 output->addInstruction(done);
1315 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1318 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1320 QQmlScript::Value *v = prop->values.first();
1322 if (v->type == Value::SignalObject) {
1324 genObject(v->object);
1326 Instruction::AssignSignalObject assign;
1327 assign.line = v->location.start.line;
1328 assign.signal = output->indexForString(prop->name().toString());
1329 output->addInstruction(assign);
1331 } else if (v->type == Value::SignalExpression) {
1333 Instruction::StoreSignal store;
1334 store.signalIndex = prop->index;
1335 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1336 store.value = output->indexForByteArray(rewrite.toUtf8());
1337 store.context = v->signalExpressionContextStack;
1338 store.line = v->location.start.line;
1339 store.column = v->location.start.column;
1340 output->addInstruction(store);
1346 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1347 Instruction::FetchAttached fetch;
1348 fetch.id = prop->index;
1349 fetch.line = prop->location.start.line;
1350 output->addInstruction(fetch);
1352 genObjectBody(prop->value);
1354 Instruction::PopFetchedObject pop;
1355 output->addInstruction(pop);
1358 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1359 Instruction::FetchObject fetch;
1360 fetch.property = prop->index;
1361 fetch.line = prop->location.start.line;
1362 output->addInstruction(fetch);
1364 if (!prop->value->metadata.isEmpty()) {
1365 Instruction::StoreMetaObject meta;
1366 meta.data = output->indexForByteArray(prop->value->metadata);
1367 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1368 meta.propertyCache = -1;
1369 output->addInstruction(meta);
1372 genObjectBody(prop->value);
1374 Instruction::PopFetchedObject pop;
1375 output->addInstruction(pop);
1378 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1380 genValueTypeProperty(obj, prop);
1383 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1384 if (prop->isDeferred)
1387 genValueProperty(prop, obj);
1390 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1392 genValueTypeProperty(obj, prop);
1396 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1398 Instruction::FetchValueType fetch;
1399 fetch.property = prop->index;
1400 fetch.type = prop->type;
1401 fetch.bindingSkipList = 0;
1403 if (obj->type == -1 || output->types.at(obj->type).component) {
1404 // We only have to do this if this is a composite type. If it is a builtin
1405 // type it can't possibly already have bindings that need to be cleared.
1406 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1407 if (!vprop->values.isEmpty()) {
1408 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1409 fetch.bindingSkipList |= (1 << vprop->index);
1414 output->addInstruction(fetch);
1416 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1417 genPropertyAssignment(vprop, prop->value, prop);
1420 Instruction::PopValueType pop;
1421 pop.property = prop->index;
1422 pop.type = prop->type;
1423 pop.bindingSkipList = 0;
1424 output->addInstruction(pop);
1427 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1429 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1432 Instruction::CreateComponent create;
1433 create.line = root->location.start.line;
1434 create.column = root->location.start.column;
1435 create.endLine = root->location.end.line;
1436 create.isRoot = (compileState->root == obj);
1437 int createInstruction = output->addInstruction(create);
1438 int nextInstructionIndex = output->nextInstructionIndex();
1440 ComponentCompileState *oldCompileState = compileState;
1441 compileState = componentState(root);
1443 Instruction::Init init;
1444 init.bindingsSize = compileState->totalBindingsCount;
1445 init.parserStatusSize = compileState->parserStatusCount;
1446 init.contextCache = genContextCache();
1447 init.objectStackSize = compileState->objectDepth.maxDepth();
1448 init.listStackSize = compileState->listDepth.maxDepth();
1449 if (compileState->compiledBindingData.isEmpty())
1450 init.compiledBinding = -1;
1452 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1453 output->addInstruction(init);
1455 if (!compileState->v8BindingProgram.isEmpty()) {
1456 Instruction::InitV8Bindings bindings;
1457 int index = output->programs.count();
1459 typedef QQmlCompiledData::V8Program V8Program;
1460 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1462 bindings.programIndex = index;
1463 bindings.line = compileState->v8BindingProgramLine;
1464 output->addInstruction(bindings);
1469 Instruction::SetDefault def;
1470 output->addInstruction(def);
1472 Instruction::Done done;
1473 output->addInstruction(done);
1475 output->instruction(createInstruction)->createComponent.count =
1476 output->nextInstructionIndex() - nextInstructionIndex;
1478 compileState = oldCompileState;
1480 if (!obj->id.isEmpty()) {
1481 Instruction::SetId id;
1482 id.value = output->indexForString(obj->id);
1483 id.index = obj->idIndex;
1484 output->addInstruction(id);
1487 if (obj == unitRoot) {
1488 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1489 output->rootPropertyCache->addref();
1493 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1494 const BindingContext &ctxt)
1496 // The special "Component" element can only have the id property and a
1497 // default property, that actually defines the component's tree
1499 compileState->objectDepth.push();
1501 // Find, check and set the "id" property (if any)
1502 Property *idProp = 0;
1503 if (obj->properties.isMany() ||
1504 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1505 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1507 if (!obj->properties.isEmpty())
1508 idProp = obj->properties.first();
1511 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1512 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1513 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1515 QString idVal = idProp->values.first()->primitive();
1517 if (compileState->ids.value(idVal))
1518 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1524 // Check the Component tree is well formed
1525 if (obj->defaultProperty &&
1526 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1527 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1528 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1530 if (!obj->dynamicProperties.isEmpty())
1531 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1532 if (!obj->dynamicSignals.isEmpty())
1533 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1534 if (!obj->dynamicSlots.isEmpty())
1535 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1537 QQmlScript::Object *root = 0;
1538 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1539 root = obj->defaultProperty->values.first()->object;
1542 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1544 // Build the component tree
1545 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1547 compileState->objectDepth.pop();
1552 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1553 const BindingContext &ctxt)
1555 ComponentCompileState *oldComponentCompileState = compileState;
1556 compileState = pool->New<ComponentCompileState>();
1557 compileState->root = obj;
1558 compileState->nested = true;
1560 if (componentStats) {
1561 ComponentStat oldComponentStat = componentStats->componentStat;
1563 componentStats->componentStat = ComponentStat();
1564 componentStats->componentStat.lineNumber = obj->location.start.line;
1567 COMPILE_CHECK(buildObject(obj, ctxt));
1569 COMPILE_CHECK(completeComponentBuild());
1571 componentStats->componentStat = oldComponentStat;
1574 COMPILE_CHECK(buildObject(obj, ctxt));
1576 COMPILE_CHECK(completeComponentBuild());
1579 compileState = oldComponentCompileState;
1585 // Build a sub-object. A sub-object is one that was not created directly by
1586 // QML - such as a grouped property object, or an attached object. Sub-object's
1587 // can't have an id, involve a custom parser, have attached properties etc.
1588 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1590 Q_ASSERT(obj->metatype);
1591 Q_ASSERT(!obj->defaultProperty);
1592 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1595 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1596 if (isSignalPropertyName(prop->name())) {
1597 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1599 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1606 int QQmlCompiler::componentTypeRef()
1608 if (cachedComponentTypeRef == -1) {
1609 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1610 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1611 if (output->types.at(ii).type == t) {
1612 cachedComponentTypeRef = ii;
1616 QQmlCompiledData::TypeReference ref;
1617 ref.className = Component_string;
1619 output->types << ref;
1620 cachedComponentTypeRef = output->types.count() - 1;
1622 return cachedComponentTypeRef;
1625 int QQmlCompiler::translationContextIndex()
1627 if (cachedTranslationContextIndex == -1) {
1628 // This code must match that in the qsTr() implementation
1629 const QString &path = output->name;
1630 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1631 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1633 QByteArray contextUtf8 = context.toUtf8();
1634 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1636 return cachedTranslationContextIndex;
1639 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1640 const BindingContext &ctxt)
1642 Q_ASSERT(obj->metaObject());
1644 const QHashedStringRef &propName = prop->name();
1646 Q_ASSERT(propName.startsWith(on_string));
1647 QString name = propName.mid(2, -1).toString();
1649 // Note that the property name could start with any alpha or '_' or '$' character,
1650 // so we need to do the lower-casing of the first alpha character.
1651 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1652 if (name.at(firstAlphaIndex).isUpper()) {
1653 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1658 bool notInRevision = false;
1660 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1664 if (notInRevision && 0 == property(obj, propName, 0)) {
1665 Q_ASSERT(obj->type != -1);
1666 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1667 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1669 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));
1671 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1675 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1677 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1681 if (prop->value || !prop->values.isOne())
1682 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1684 prop->index = sig->coreIndex;
1687 obj->addSignalProperty(prop);
1689 if (prop->values.first()->object) {
1690 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1691 prop->values.first()->type = Value::SignalObject;
1693 prop->values.first()->type = Value::SignalExpression;
1695 if (!prop->values.first()->value.isScript())
1696 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1698 QString script = prop->values.first()->value.asScript().trimmed();
1699 if (script.isEmpty())
1700 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1702 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1711 Returns true if (value) property \a prop exists on obj, false otherwise.
1713 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1714 QQmlScript::Object *obj)
1716 if (prop->name().isEmpty())
1718 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1721 return property(obj, prop->name()) != 0;
1724 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1725 QQmlScript::Object *obj,
1726 const BindingContext &ctxt)
1728 if (prop->isEmpty())
1729 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1731 const QMetaObject *metaObject = obj->metaObject();
1732 Q_ASSERT(metaObject);
1734 if (isAttachedPropertyName(prop->name())) {
1735 // Setup attached property data
1737 if (ctxt.isSubContext()) {
1738 // Attached properties cannot be used on sub-objects. Sub-objects
1739 // always exist in a binding sub-context, which is what we test
1741 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1745 QQmlImportedNamespace *typeNamespace = 0;
1746 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1748 if (typeNamespace) {
1749 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1752 } else if (!type || !type->attachedPropertiesType()) {
1753 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1757 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1759 Q_ASSERT(type->attachedPropertiesFunction());
1760 prop->index = type->attachedPropertiesId();
1761 prop->value->metatype = type->attachedPropertiesType();
1763 // Setup regular property data
1764 bool notInRevision = false;
1765 QQmlPropertyData *d =
1766 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1768 if (d == 0 && notInRevision) {
1769 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1770 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1772 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));
1774 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1777 prop->index = d->coreIndex;
1779 } else if (prop->isDefault) {
1780 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1781 QQmlPropertyData defaultPropertyData;
1782 defaultPropertyData.load(p, engine);
1784 prop->setName(QLatin1String(p.name()));
1785 prop->core = defaultPropertyData;
1786 prop->index = prop->core.coreIndex;
1789 // We can't error here as the "id" property does not require a
1790 // successful index resolution
1791 if (prop->index != -1)
1792 prop->type = prop->core.propType;
1794 // Check if this is an alias
1795 if (prop->index != -1 &&
1797 prop->parent->type != -1 &&
1798 output->types.at(prop->parent->type).component) {
1800 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1801 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1802 prop->isAlias = true;
1805 if (prop->index != -1 && !prop->values.isEmpty())
1806 prop->parent->setBindingBit(prop->index);
1809 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1811 // The magic "id" behavior doesn't apply when "id" is resolved as a
1812 // default property or to sub-objects (which are always in binding
1814 COMPILE_CHECK(buildIdProperty(prop, obj));
1815 if (prop->type == QVariant::String &&
1816 prop->values.first()->value.isString())
1817 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1819 } else if (isAttachedPropertyName(prop->name())) {
1821 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1823 } else if (prop->index == -1) {
1825 if (prop->isDefault) {
1826 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1828 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1831 } else if (prop->value) {
1833 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1835 } else if (prop->core.isQList()) {
1837 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1839 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1841 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1845 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1852 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
1853 QQmlScript::Property *nsProp,
1854 QQmlScript::Object *obj,
1855 const BindingContext &ctxt)
1858 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1860 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1862 if (!isAttachedPropertyName(prop->name()))
1863 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1865 // Setup attached property data
1868 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1870 if (!type || !type->attachedPropertiesType())
1871 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1874 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1876 Q_ASSERT(type->attachedPropertiesFunction());
1877 prop->index = type->index();
1878 prop->value->metatype = type->attachedPropertiesType();
1880 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1886 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1887 QQmlScript::Object *obj)
1889 if (prop->core.isQList()) {
1890 genListProperty(prop, obj);
1892 genPropertyAssignment(prop, obj);
1896 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1897 QQmlScript::Object *obj)
1899 int listType = enginePrivate->listType(prop->type);
1901 Instruction::FetchQList fetch;
1902 fetch.property = prop->index;
1903 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1904 fetch.type = listType;
1905 output->addInstruction(fetch);
1907 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1909 if (v->type == Value::CreatedObject) {
1911 genObject(v->object);
1912 if (listTypeIsInterface) {
1913 Instruction::AssignObjectList assign;
1914 assign.line = prop->location.start.line;
1915 output->addInstruction(assign);
1917 Instruction::StoreObjectQList store;
1918 output->addInstruction(store);
1921 } else if (v->type == Value::PropertyBinding) {
1923 genBindingAssignment(v, prop, obj);
1929 Instruction::PopQList pop;
1930 output->addInstruction(pop);
1933 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1934 QQmlScript::Object *obj,
1935 QQmlScript::Property *valueTypeProperty)
1937 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1939 Q_ASSERT(v->type == Value::CreatedObject ||
1940 v->type == Value::PropertyBinding ||
1941 v->type == Value::Literal);
1943 if (v->type == Value::CreatedObject) {
1945 genObject(v->object);
1947 if (QQmlMetaType::isInterface(prop->type)) {
1949 Instruction::StoreInterface store;
1950 store.line = v->object->location.start.line;
1951 store.propertyIndex = prop->index;
1952 output->addInstruction(store);
1954 } else if (prop->type == QMetaType::QVariant) {
1956 if (prop->core.isVMEProperty()) {
1957 Instruction::StoreVarObject store;
1958 store.line = v->object->location.start.line;
1959 store.propertyIndex = prop->index;
1960 output->addInstruction(store);
1962 Instruction::StoreVariantObject store;
1963 store.line = v->object->location.start.line;
1964 store.propertyIndex = prop->index;
1965 output->addInstruction(store);
1971 Instruction::StoreObject store;
1972 store.line = v->object->location.start.line;
1973 store.propertyIndex = prop->index;
1974 output->addInstruction(store);
1977 } else if (v->type == Value::PropertyBinding) {
1979 genBindingAssignment(v, prop, obj, valueTypeProperty);
1981 } else if (v->type == Value::Literal) {
1983 genLiteralAssignment(prop, v);
1989 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1991 Q_ASSERT(v->type == Value::ValueSource ||
1992 v->type == Value::ValueInterceptor);
1994 if (v->type == Value::ValueSource) {
1995 genObject(v->object);
1997 Instruction::StoreValueSource store;
1998 if (valueTypeProperty) {
1999 store.property = genValueTypeData(prop, valueTypeProperty);
2002 store.property = prop->core;
2005 QQmlType *valueType = toQmlType(v->object);
2006 store.castValue = valueType->propertyValueSourceCast();
2007 output->addInstruction(store);
2009 } else if (v->type == Value::ValueInterceptor) {
2010 genObject(v->object);
2012 Instruction::StoreValueInterceptor store;
2013 if (valueTypeProperty) {
2014 store.property = genValueTypeData(prop, valueTypeProperty);
2017 store.property = prop->core;
2020 QQmlType *valueType = toQmlType(v->object);
2021 store.castValue = valueType->propertyValueInterceptorCast();
2022 output->addInstruction(store);
2028 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2029 QQmlScript::Object *obj)
2032 prop->values.isMany() ||
2033 prop->values.first()->object)
2034 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2036 QQmlScript::Value *idValue = prop->values.first();
2037 QString val = idValue->primitive();
2039 COMPILE_CHECK(checkValidId(idValue, val));
2041 if (compileState->ids.value(val))
2042 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2044 prop->values.first()->type = Value::Id;
2052 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2055 Q_ASSERT(!compileState->ids.value(id));
2056 Q_ASSERT(obj->id == id);
2057 obj->idIndex = compileState->ids.count();
2058 compileState->ids.append(obj);
2061 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2063 Q_ASSERT(ref->value && !ref->value->bindingReference);
2064 ref->value->bindingReference = ref;
2065 compileState->totalBindingsCount++;
2066 compileState->bindings.prepend(ref);
2069 void QQmlCompiler::saveComponentState()
2071 Q_ASSERT(compileState->root);
2072 Q_ASSERT(compileState->root->componentCompileState == 0);
2074 compileState->root->componentCompileState = compileState;
2077 componentStats->savedComponentStats.append(componentStats->componentStat);
2080 QQmlCompilerTypes::ComponentCompileState *
2081 QQmlCompiler::componentState(QQmlScript::Object *obj)
2083 Q_ASSERT(obj->componentCompileState);
2084 return obj->componentCompileState;
2087 // Build attached property object. In this example,
2091 // GridView is an attached property object.
2092 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2093 QQmlScript::Object *obj,
2094 const BindingContext &ctxt)
2096 Q_ASSERT(prop->value);
2097 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2099 compileState->objectDepth.push();
2101 obj->addAttachedProperty(prop);
2103 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2105 compileState->objectDepth.pop();
2111 // Build "grouped" properties. In this example:
2113 // font.pointSize: 12
2114 // font.family: "Helvetica"
2116 // font is a nested property. pointSize and family are not.
2117 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2118 QQmlScript::Object *obj,
2119 const BindingContext &ctxt)
2121 Q_ASSERT(prop->type != 0);
2122 Q_ASSERT(prop->index != -1);
2124 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2125 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2127 if (!prop->values.isEmpty()) {
2128 if (prop->values.first()->location < prop->value->location) {
2129 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2131 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2135 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2136 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2140 if (prop->isAlias) {
2141 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2142 vtProp->isAlias = true;
2146 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2147 prop->value, obj, ctxt.incr()));
2148 obj->addValueTypeProperty(prop);
2150 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2154 // Load the nested property's meta type
2155 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2156 if (!prop->value->metatype)
2157 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2159 if (!prop->values.isEmpty())
2160 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2162 obj->addGroupedProperty(prop);
2164 compileState->objectDepth.push();
2166 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2168 compileState->objectDepth.pop();
2174 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2175 QQmlScript::Object *obj,
2176 QQmlScript::Object *baseObj,
2177 const BindingContext &ctxt)
2179 compileState->objectDepth.push();
2181 if (obj->defaultProperty)
2182 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2183 obj->metatype = type->metaObject();
2185 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2187 QQmlPropertyData *d = property(obj, prop->name());
2189 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2191 prop->index = d->coreIndex;
2192 prop->type = d->propType;
2194 prop->isValueTypeSubProperty = true;
2197 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2199 if (prop->values.isMany()) {
2200 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2201 } else if (!prop->values.isEmpty()) {
2202 QQmlScript::Value *value = prop->values.first();
2204 if (value->object) {
2205 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2206 } else if (value->value.isScript()) {
2207 // ### Check for writability
2209 //optimization for <Type>.<EnumValue> enum assignments
2210 bool isEnumAssignment = false;
2212 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2213 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2215 if (isEnumAssignment) {
2216 value->type = Value::Literal;
2218 JSBindingReference *reference = pool->New<JSBindingReference>();
2219 reference->expression = value->value;
2220 reference->property = prop;
2221 reference->value = value;
2222 reference->bindingContext = ctxt;
2223 reference->bindingContext.owner++;
2224 addBindingReference(reference);
2225 value->type = Value::PropertyBinding;
2228 COMPILE_CHECK(testLiteralAssignment(prop, value));
2229 value->type = Value::Literal;
2233 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2234 Q_ASSERT(v->object);
2236 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2239 obj->addValueProperty(prop);
2242 compileState->objectDepth.pop();
2247 // Build assignments to QML lists. QML lists are properties of type
2248 // QQmlListProperty<T>. List properties can accept a list of
2249 // objects, or a single binding.
2250 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2251 QQmlScript::Object *obj,
2252 const BindingContext &ctxt)
2254 Q_ASSERT(prop->core.isQList());
2256 compileState->listDepth.push();
2260 obj->addValueProperty(prop);
2262 int listType = enginePrivate->listType(t);
2263 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2265 bool assignedBinding = false;
2266 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2268 v->type = Value::CreatedObject;
2269 COMPILE_CHECK(buildObject(v->object, ctxt));
2271 // We check object coercian here. We check interface assignment
2273 if (!listTypeIsInterface) {
2274 if (!canCoerce(listType, v->object)) {
2275 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2279 } else if (v->value.isScript()) {
2280 if (assignedBinding)
2281 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2283 assignedBinding = true;
2284 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2285 v->type = Value::PropertyBinding;
2287 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2291 compileState->listDepth.pop();
2296 // Compiles an assignment to a QQmlScriptString property
2297 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2298 QQmlScript::Object *obj,
2299 const BindingContext &ctxt)
2301 if (prop->values.isMany())
2302 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2304 if (prop->values.first()->object)
2305 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2307 prop->scriptStringScope = ctxt.stack;
2308 obj->addScriptStringProperty(prop);
2313 // Compile regular property assignments of the form "property: <value>"
2314 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2315 QQmlScript::Object *obj,
2316 const BindingContext &ctxt)
2318 obj->addValueProperty(prop);
2320 if (prop->values.isMany())
2321 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2323 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2326 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2330 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2335 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2336 Q_ASSERT(v->object);
2337 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2343 // Compile assigning a single object instance to a regular property
2344 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2345 QQmlScript::Object *obj,
2346 QQmlScript::Value *v,
2347 const BindingContext &ctxt)
2349 Q_ASSERT(prop->index != -1);
2350 Q_ASSERT(v->object->type != -1);
2352 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2353 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2355 if (QQmlMetaType::isInterface(prop->type)) {
2357 // Assigning an object to an interface ptr property
2358 COMPILE_CHECK(buildObject(v->object, ctxt));
2360 v->type = Value::CreatedObject;
2362 } else if (prop->type == QMetaType::QVariant) {
2364 // Assigning an object to a QVariant
2365 COMPILE_CHECK(buildObject(v->object, ctxt));
2367 v->type = Value::CreatedObject;
2369 // Normally buildObject() will set this up, but we need the static
2370 // meta object earlier to test for assignability. It doesn't matter
2371 // that there may still be outstanding synthesized meta object changes
2372 // on this type, as they are not relevant for assignability testing
2373 v->object->metatype = output->types.at(v->object->type).metaObject();
2374 Q_ASSERT(v->object->metaObject());
2376 // We want to raw metaObject here as the raw metaobject is the
2377 // actual property type before we applied any extensions that might
2378 // effect the properties on the type, but don't effect assignability
2379 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2381 // Will be true if the assgned type inherits propertyMetaObject
2382 bool isAssignable = false;
2383 // Determine isAssignable value
2384 if (propertyMetaObject) {
2385 const QMetaObject *c = v->object->metatype;
2387 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2388 c = c->superClass();
2393 // Simple assignment
2394 COMPILE_CHECK(buildObject(v->object, ctxt));
2396 v->type = Value::CreatedObject;
2397 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2398 // Automatic "Component" insertion
2399 QQmlScript::Object *root = v->object;
2400 QQmlScript::Object *component = pool->New<Object>();
2401 component->type = componentTypeRef();
2402 component->typeName = QStringLiteral("Qt/Component");
2403 component->metatype = &QQmlComponent::staticMetaObject;
2404 component->location = root->location;
2405 QQmlScript::Value *componentValue = pool->New<Value>();
2406 componentValue->object = root;
2407 component->getDefaultProperty()->addValue(componentValue);
2408 v->object = component;
2409 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2411 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2418 // Compile assigning a single object instance to a regular property using the "on" syntax.
2422 // NumberAnimation on x { }
2424 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2425 QQmlScript::Object *obj,
2426 QQmlScript::Object *baseObj,
2427 QQmlScript::Value *v,
2428 const BindingContext &ctxt)
2430 Q_ASSERT(prop->index != -1);
2431 Q_ASSERT(v->object->type != -1);
2435 if (!prop->core.isWritable())
2436 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2439 // Normally buildObject() will set this up, but we need the static
2440 // meta object earlier to test for assignability. It doesn't matter
2441 // that there may still be outstanding synthesized meta object changes
2442 // on this type, as they are not relevant for assignability testing
2443 v->object->metatype = output->types.at(v->object->type).metaObject();
2444 Q_ASSERT(v->object->metaObject());
2446 // Will be true if the assigned type inherits QQmlPropertyValueSource
2447 bool isPropertyValue = false;
2448 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2449 bool isPropertyInterceptor = false;
2450 if (QQmlType *valueType = toQmlType(v->object)) {
2451 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2452 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2455 if (isPropertyValue || isPropertyInterceptor) {
2456 // Assign as a property value source
2457 COMPILE_CHECK(buildObject(v->object, ctxt));
2459 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2460 buildDynamicMeta(baseObj, ForceCreation);
2461 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2463 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2469 // Compile assigning a literal or binding to a regular property
2470 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2471 QQmlScript::Object *obj,
2472 QQmlScript::Value *v,
2473 const BindingContext &ctxt)
2475 Q_ASSERT(prop->index != -1);
2477 if (v->value.isScript()) {
2479 //optimization for <Type>.<EnumValue> enum assignments
2480 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2481 bool isEnumAssignment = false;
2482 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2483 if (isEnumAssignment) {
2484 v->type = Value::Literal;
2489 // Test for other binding optimizations
2490 if (!buildLiteralBinding(v, prop, ctxt))
2491 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2493 v->type = Value::PropertyBinding;
2497 COMPILE_CHECK(testLiteralAssignment(prop, v));
2499 v->type = Value::Literal;
2505 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2506 QQmlScript::Object *obj,
2507 QQmlScript::Value *v,
2510 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2511 *isAssignment = false;
2512 if (!prop->core.isEnum() && !isIntProp)
2515 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2517 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2518 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2520 QString string = v->value.asString();
2521 if (!string.at(0).isUpper())
2525 // Allow enum assignment to ints.
2526 int enumval = evaluateEnum(string.toUtf8());
2527 if (enumval != -1) {
2528 v->type = Value::Literal;
2529 v->value = QQmlScript::Variant((double)enumval);
2530 *isAssignment = true;
2535 QStringList parts = string.split(QLatin1Char('.'));
2536 if (parts.count() != 2)
2539 QString typeName = parts.at(0);
2541 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2543 //handle enums on value types (where obj->typeName is empty)
2544 QString objTypeName = obj->typeName;
2545 if (objTypeName.isEmpty()) {
2546 QQmlType *objType = toQmlType(obj);
2548 objTypeName = objType->qmlTypeName();
2554 QString enumValue = parts.at(1);
2558 if (objTypeName == type->qmlTypeName()) {
2559 // When these two match, we can short cut the search
2560 if (mprop.isFlagType()) {
2561 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2563 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2566 // Otherwise we have to search the whole type
2567 // This matches the logic in QV8TypeWrapper
2568 QByteArray enumName = enumValue.toUtf8();
2569 const QMetaObject *metaObject = type->baseMetaObject();
2571 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2572 QMetaEnum e = metaObject->enumerator(ii);
2573 value = e.keyToValue(enumName.constData(), &ok);
2580 v->type = Value::Literal;
2581 v->value = QQmlScript::Variant((double)value);
2582 *isAssignment = true;
2587 struct StaticQtMetaObject : public QObject
2589 static const QMetaObject *get()
2590 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2593 // Similar logic to above, but not knowing target property.
2594 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2596 int dot = script.indexOf('.');
2598 const QByteArray &scope = script.left(dot);
2600 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2601 if (!type && scope != "Qt")
2603 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2604 const char *key = script.constData() + dot+1;
2605 int i = mo->enumeratorCount();
2608 int v = mo->enumerator(i).keyToValue(key, &ok);
2616 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2618 QQmlType *qmltype = 0;
2619 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2623 return qmltype->metaObject();
2626 // similar to logic of completeComponentBuild, but also sticks data
2627 // into primitives at the end
2628 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2630 QQmlRewrite::RewriteBinding rewriteBinding;
2631 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2633 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2635 return output->indexForString(rewrite);
2638 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2640 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2641 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2644 // Ensures that the dynamic meta specification on obj is valid
2645 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2647 bool seenDefaultProperty = false;
2649 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2650 // Calculating the hash for the names is not a waste as we have to test
2651 // them against the illegalNames set anyway.
2652 QHashField propNames;
2653 QHashField methodNames;
2656 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2657 const QQmlScript::Object::DynamicProperty &prop = *p;
2659 if (prop.isDefaultProperty) {
2660 if (seenDefaultProperty)
2661 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2662 seenDefaultProperty = true;
2665 if (propNames.testAndSet(prop.name.hash())) {
2666 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2667 p2 = obj->dynamicProperties.next(p2)) {
2668 if (p2->name == prop.name) {
2669 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2670 prop.nameLocation.column,
2671 tr("Duplicate property name"));
2676 if (prop.name.at(0).isUpper()) {
2677 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2678 prop.nameLocation.column,
2679 tr("Property names cannot begin with an upper case letter"));
2682 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2683 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2684 prop.nameLocation.column,
2685 tr("Illegal property name"));
2689 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2690 const QQmlScript::Object::DynamicSignal &currSig = *s;
2692 if (methodNames.testAndSet(currSig.name.hash())) {
2693 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2694 s2 = obj->dynamicSignals.next(s2)) {
2695 if (s2->name == currSig.name)
2696 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2700 if (currSig.name.at(0).isUpper())
2701 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2702 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2703 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2706 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2707 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2709 if (methodNames.testAndSet(currSlot.name.hash())) {
2710 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2711 s2 = obj->dynamicSignals.next(s2)) {
2712 if (s2->name == currSlot.name)
2713 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2715 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2716 s2 = obj->dynamicSlots.next(s2)) {
2717 if (s2->name == currSlot.name)
2718 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2722 if (currSlot.name.at(0).isUpper())
2723 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2724 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2725 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2731 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2733 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2734 p = obj->dynamicProperties.next(p)) {
2736 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2739 Property *property = 0;
2740 if (p->isDefaultProperty) {
2741 property = obj->getDefaultProperty();
2743 property = obj->getProperty(p->name);
2744 if (!property->values.isEmpty())
2745 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2749 property->isReadOnlyDeclaration = true;
2751 if (property->value)
2752 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2754 property->values.append(p->defaultValue->values);
2759 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2761 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2764 Q_ASSERT(obj->metatype);
2766 if (mode != ForceCreation &&
2767 obj->dynamicProperties.isEmpty() &&
2768 obj->dynamicSignals.isEmpty() &&
2769 obj->dynamicSlots.isEmpty())
2772 bool resolveAlias = (mode == ResolveAliases);
2774 const Object::DynamicProperty *defaultProperty = 0;
2776 int varPropCount = 0;
2777 int totalPropCount = 0;
2778 int firstPropertyVarIndex = 0;
2780 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2782 if (p->type == Object::DynamicProperty::Alias)
2784 if (p->type == Object::DynamicProperty::Var)
2787 if (p->isDefaultProperty &&
2788 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2789 defaultProperty = p;
2791 if (!resolveAlias) {
2792 // No point doing this for both the alias and non alias cases
2793 QQmlPropertyData *d = property(obj, p->name);
2794 if (d && d->isFinal())
2795 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2799 bool buildData = resolveAlias || aliasCount == 0;
2801 QByteArray dynamicData;
2803 typedef QQmlVMEMetaData VMD;
2805 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2806 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2807 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2808 aliasCount * sizeof(VMD::AliasData), 0);
2811 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2813 QByteArray newClassName = obj->metatype->className();
2814 newClassName.append("_QML_");
2815 newClassName.append(QByteArray::number(uniqueClassId));
2817 if (compileState->root == obj && !compileState->nested) {
2818 QString path = output->url.path();
2819 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2820 if (lastSlash > -1) {
2821 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2822 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2823 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2827 // Size of the array that describes parameter types & names
2828 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2829 + obj->dynamicProperties.count() // for Changed() signals return types
2830 // Return "parameters" don't have names
2831 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2833 QFastMetaBuilder builder;
2835 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2836 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2837 obj->dynamicSlots.count(),
2838 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2839 defaultProperty?1:0, paramDataSize, ¶mIndex);
2842 Object::DynamicProperty::Type dtype;
2844 } builtinTypes[] = {
2845 { Object::DynamicProperty::Var, QMetaType::QVariant },
2846 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2847 { Object::DynamicProperty::Int, QMetaType::Int },
2848 { Object::DynamicProperty::Bool, QMetaType::Bool },
2849 { Object::DynamicProperty::Real, QMetaType::Double },
2850 { Object::DynamicProperty::String, QMetaType::QString },
2851 { Object::DynamicProperty::Url, QMetaType::QUrl },
2852 { Object::DynamicProperty::Color, QMetaType::QColor },
2853 { Object::DynamicProperty::Time, QMetaType::QTime },
2854 { Object::DynamicProperty::Date, QMetaType::QDate },
2855 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2857 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2859 // Reserve dynamic properties
2860 if (obj->dynamicProperties.count()) {
2861 typedef QQmlVMEMetaData VMD;
2863 int effectivePropertyIndex = 0;
2864 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2866 // Reserve space for name
2867 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2868 p->nameRef = builder.newString(p->name.utf8length());
2871 int propertyType = 0; // for VMD
2872 bool readonly = false;
2874 if (p->type == Object::DynamicProperty::Alias) {
2876 } else if (p->type < builtinTypeCount) {
2877 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2878 metaType = builtinTypes[p->type].metaType;
2879 propertyType = metaType;
2882 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2883 p->type == Object::DynamicProperty::Custom);
2885 // XXX don't double resolve this in the case of an alias run
2887 QByteArray customTypeName;
2888 QQmlType *qmltype = 0;
2890 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2891 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2894 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2896 Q_ASSERT(tdata->isComplete());
2898 QQmlCompiledData *data = tdata->compiledData();
2899 customTypeName = data->root->className();
2903 customTypeName = qmltype->typeName();
2906 if (p->type == Object::DynamicProperty::Custom) {
2907 customTypeName += '*';
2908 propertyType = QMetaType::QObjectStar;
2911 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2912 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2915 metaType = QMetaType::type(customTypeName);
2916 Q_ASSERT(metaType != QMetaType::UnknownType);
2917 Q_ASSERT(metaType != QMetaType::Void);
2920 if (p->type == Object::DynamicProperty::Var)
2927 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2928 vmd->propertyCount++;
2929 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2932 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2933 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2934 effectivePropertyIndex);
2936 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2937 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2940 effectivePropertyIndex++;
2944 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2946 vmd->varPropertyCount = varPropCount;
2947 firstPropertyVarIndex = effectivePropertyIndex;
2948 totalPropCount = varPropCount + effectivePropertyIndex;
2949 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2950 if (p->type == Object::DynamicProperty::Var) {
2952 vmd->propertyCount++;
2953 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2956 builder.setProperty(effectivePropertyIndex, p->nameRef,
2957 QMetaType::QVariant,
2958 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2959 effectivePropertyIndex);
2961 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2962 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2965 effectivePropertyIndex++;
2972 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2973 if (p->type == Object::DynamicProperty::Alias) {
2975 Q_ASSERT(buildData);
2976 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2977 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2980 // Even if we aren't resolving the alias, we need a fake signal so that the
2981 // metaobject remains consistent across the resolve and non-resolve alias runs
2982 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2983 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2985 effectivePropertyIndex++;
2992 // Reserve default property
2993 QFastMetaBuilder::StringRef defPropRef;
2994 if (defaultProperty) {
2995 defPropRef = builder.newString(strlen("DefaultProperty"));
2996 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2999 // Reserve dynamic signals
3000 int signalIndex = 0;
3001 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3003 s->nameRef = builder.newString(s->name.utf8length());
3005 int paramCount = s->parameterNames.count();
3006 QVarLengthArray<int, 10> paramTypes(paramCount);
3008 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3009 for (int i = 0; i < paramCount; ++i) {
3010 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3011 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3012 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3017 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3019 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3020 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3021 paramIndex += paramCount*2 + 1;
3025 // Reserve dynamic slots
3026 if (obj->dynamicSlots.count()) {
3028 typedef QQmlVMEMetaData VMD;
3030 int methodIndex = 0;
3031 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3032 s->nameRef = builder.newString(s->name.utf8length());
3033 int paramCount = s->parameterNames.count();
3035 QVarLengthArray<int, 10> paramTypes(paramCount);
3037 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3038 for (int i = 0; i < paramCount; ++i) {
3039 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3040 paramTypes[i] = QMetaType::QVariant;
3044 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3045 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3046 paramIndex += paramCount*2 + 1;
3051 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3052 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3053 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3054 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3055 for (int jj = 0; jj < paramCount; ++jj) {
3056 if (jj) funcScript.append(QLatin1Char(','));
3057 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3059 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3061 QByteArray utf8 = funcScript.toUtf8();
3062 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3064 s->location.start.line };
3066 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3069 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3071 md.bodyOffset = dynamicData.size();
3073 dynamicData.append((const char *)utf8.constData(), utf8.length());
3081 // Now allocate properties
3082 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3084 char *d = p->changedNameRef.data();
3085 p->name.writeUtf8(d);
3086 strcpy(d + p->name.utf8length(), "Changed");
3087 p->changedNameRef.loadByteArrayData();
3089 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3092 p->nameRef.load(p->name);
3095 // Allocate default property if necessary
3096 if (defaultProperty)
3097 defPropRef.load("DefaultProperty");
3099 // Now allocate signals
3100 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3102 s->nameRef.load(s->name);
3104 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3105 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3108 // Now allocate methods
3109 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3110 s->nameRef.load(s->name);
3112 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3113 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3116 // Now allocate class name
3117 classNameRef.load(newClassName);
3119 obj->metadata = builder.toData();
3120 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3122 if (mode == IgnoreAliases && aliasCount)
3123 compileState->aliasingObjects.append(obj);
3125 obj->synthdata = dynamicData;
3127 if (obj->synthCache) {
3128 obj->synthCache->release();
3129 obj->synthCache = 0;
3132 if (obj->type != -1) {
3133 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3134 QQmlPropertyCache *cache =
3135 superCache->copyAndAppend(engine, &obj->extObject,
3136 QQmlPropertyData::NoFlags,
3137 QQmlPropertyData::IsVMEFunction,
3138 QQmlPropertyData::IsVMESignal);
3140 // now we modify the flags appropriately for var properties.
3141 int propertyOffset = obj->extObject.propertyOffset();
3142 QQmlPropertyData *currPropData = 0;
3143 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3144 currPropData = cache->property(pvi + propertyOffset);
3145 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3148 obj->synthCache = cache;
3154 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3157 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3159 QChar ch = val.at(0);
3160 if (ch.isLetter() && !ch.isLower())
3161 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3163 QChar u(QLatin1Char('_'));
3164 if (!ch.isLetter() && ch != u)
3165 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3167 for (int ii = 1; ii < val.count(); ++ii) {
3169 if (!ch.isLetterOrNumber() && ch != u)
3170 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3173 if (enginePrivate->v8engine()->illegalNames().contains(val))
3174 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3179 #include <private/qqmljsparser_p.h>
3181 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3183 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3185 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3186 return QStringList() << name;
3187 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3188 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3190 QStringList rv = astNodeToStringList(expr->base);
3193 rv.append(expr->name.toString());
3196 return QStringList();
3199 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3201 QQmlScript::Object *obj,
3202 int propIndex, int aliasIndex,
3203 Object::DynamicProperty &prop)
3205 Q_ASSERT(!prop.nameRef.isEmpty());
3206 if (!prop.defaultValue)
3207 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3209 if (!prop.defaultValue->values.isOne() ||
3210 prop.defaultValue->values.first()->object ||
3211 !prop.defaultValue->values.first()->value.isScript())
3212 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3214 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3216 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3218 QStringList alias = astNodeToStringList(node);
3220 if (alias.count() < 1 || alias.count() > 3)
3221 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3223 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3225 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3227 QByteArray typeName;
3232 bool writable = false;
3233 bool resettable = false;
3234 if (alias.count() == 2 || alias.count() == 3) {
3235 propIdx = indexOfProperty(idObject, alias.at(1));
3237 if (-1 == propIdx) {
3238 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3239 } else if (propIdx > 0xFFFF) {
3240 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3243 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3244 if (!aliasProperty.isScriptable())
3245 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3247 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3248 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3250 type = aliasProperty.userType();
3252 if (alias.count() == 3) {
3253 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3255 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3257 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3259 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3260 if (valueTypeIndex == -1)
3261 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3262 Q_ASSERT(valueTypeIndex <= 0xFF);
3264 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3265 propIdx |= (valueTypeIndex << 16);
3267 // update the property type
3268 type = aliasProperty.userType();
3271 if (aliasProperty.isEnumType())
3272 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3274 typeName = aliasProperty.typeName();
3276 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3278 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3280 typeName = ref.type->typeName();
3282 typeName = ref.component->root->className();
3287 if (typeName.endsWith('*'))
3288 flags |= QML_ALIAS_FLAG_PTR;
3290 if (type == QMetaType::UnknownType) {
3291 Q_ASSERT(!typeName.isEmpty());
3292 type = QMetaType::type(typeName);
3293 Q_ASSERT(type != QMetaType::UnknownType);
3294 Q_ASSERT(type != QMetaType::Void);
3297 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3299 typedef QQmlVMEMetaData VMD;
3300 VMD *vmd = (QQmlVMEMetaData *)data.data();
3301 *(vmd->aliasData() + aliasIndex) = aliasData;
3303 int propertyFlags = 0;
3305 propertyFlags |= QFastMetaBuilder::Writable;
3307 propertyFlags |= QFastMetaBuilder::Resettable;
3309 builder.setProperty(propIndex, prop.nameRef, type,
3310 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3316 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3317 QQmlScript::Property *prop,
3318 const BindingContext &ctxt)
3320 Q_ASSERT(prop->index != -1);
3321 Q_ASSERT(prop->parent);
3322 Q_ASSERT(prop->parent->metaObject());
3324 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3325 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3327 JSBindingReference *reference = pool->New<JSBindingReference>();
3328 reference->expression = value->value;
3329 reference->property = prop;
3330 reference->value = value;
3331 reference->bindingContext = ctxt;
3332 addBindingReference(reference);
3337 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3338 QQmlScript::Property *prop,
3339 const QQmlCompilerTypes::BindingContext &)
3341 Q_ASSERT(v->value.isScript());
3343 if (!prop->core.isWritable())
3346 AST::Node *binding = v->value.asAST();
3348 if (prop->type == QVariant::String) {
3349 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3350 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3351 if (i->name == qsTrId_string) {
3352 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3353 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3355 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3356 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3357 (!arg2 || !arg2->next)) {
3362 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3363 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3365 TrBindingReference *reference = pool->New<TrBindingReference>();
3366 reference->dataType = BindingReference::TrId;
3367 reference->text = text;
3369 v->bindingReference = reference;
3373 } else if (i->name == qsTr_string) {
3375 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3376 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3377 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3379 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3380 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3381 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3382 (!arg3 || !arg3->next)) {
3388 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3389 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3390 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3392 TrBindingReference *reference = pool->New<TrBindingReference>();
3393 reference->dataType = BindingReference::Tr;
3394 reference->text = text;
3395 reference->comment = comment;
3397 v->bindingReference = reference;
3410 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3411 QQmlScript::Property *prop,
3412 QQmlScript::Object *obj,
3413 QQmlScript::Property *valueTypeProperty)
3416 Q_ASSERT(binding->bindingReference);
3418 const BindingReference &ref = *binding->bindingReference;
3419 if (ref.dataType == BindingReference::TrId) {
3420 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3422 Instruction::StoreTrIdString store;
3423 store.propertyIndex = prop->core.coreIndex;
3424 store.text = output->indexForByteArray(tr.text.toUtf8());
3426 output->addInstruction(store);
3427 } else if (ref.dataType == BindingReference::Tr) {
3428 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3430 Instruction::StoreTrString store;
3431 store.propertyIndex = prop->core.coreIndex;
3432 store.context = translationContextIndex();
3433 store.text = output->indexForByteArray(tr.text.toUtf8());
3434 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3436 output->addInstruction(store);
3437 } else if (ref.dataType == BindingReference::V4) {
3438 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3440 Instruction::StoreV4Binding store;
3441 store.value = js.compiledIndex;
3442 store.context = js.bindingContext.stack;
3443 store.owner = js.bindingContext.owner;
3444 if (valueTypeProperty) {
3445 store.property = (valueTypeProperty->index & 0xFFFF) |
3446 ((valueTypeProperty->type & 0xFF)) << 16 |
3447 ((prop->index & 0xFF) << 24);
3448 store.isRoot = (compileState->root == valueTypeProperty->parent);
3450 store.property = prop->index;
3451 store.isRoot = (compileState->root == obj);
3453 store.line = binding->location.start.line;
3454 store.column = binding->location.start.column;
3455 output->addInstruction(store);
3456 } else if (ref.dataType == BindingReference::V8) {
3457 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3459 Instruction::StoreV8Binding store;
3460 store.value = js.compiledIndex;
3461 store.context = js.bindingContext.stack;
3462 store.owner = js.bindingContext.owner;
3463 store.isAlias = prop->isAlias;
3464 if (valueTypeProperty) {
3465 store.isRoot = (compileState->root == valueTypeProperty->parent);
3467 store.isRoot = (compileState->root == obj);
3469 store.line = binding->location.start.line;
3470 store.column = binding->location.start.column;
3472 Q_ASSERT(js.bindingContext.owner == 0 ||
3473 (js.bindingContext.owner != 0 && valueTypeProperty));
3474 if (js.bindingContext.owner) {
3475 store.property = genValueTypeData(prop, valueTypeProperty);
3477 store.property = prop->core;
3480 output->addInstruction(store);
3481 } else if (ref.dataType == BindingReference::QtScript) {
3482 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3484 Instruction::StoreBinding store;
3485 store.value = output->indexForString(js.rewrittenExpression);
3486 store.context = js.bindingContext.stack;
3487 store.owner = js.bindingContext.owner;
3488 store.line = binding->location.start.line;
3489 store.column = binding->location.start.column;
3490 store.isAlias = prop->isAlias;
3492 if (valueTypeProperty) {
3493 store.isRoot = (compileState->root == valueTypeProperty->parent);
3495 store.isRoot = (compileState->root == obj);
3498 Q_ASSERT(js.bindingContext.owner == 0 ||
3499 (js.bindingContext.owner != 0 && valueTypeProperty));
3500 if (js.bindingContext.owner) {
3501 store.property = genValueTypeData(prop, valueTypeProperty);
3503 store.property = prop->core;
3506 output->addInstruction(store);
3508 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3512 int QQmlCompiler::genContextCache()
3514 if (compileState->ids.count() == 0)
3517 QQmlIntegerCache *cache = new QQmlIntegerCache();
3518 cache->reserve(compileState->ids.count());
3519 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3520 cache->add(o->id, o->idIndex);
3522 output->contextCaches.append(cache);
3523 return output->contextCaches.count() - 1;
3527 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3528 QQmlScript::Property *prop)
3530 typedef QQmlPropertyPrivate QDPP;
3531 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3532 enginePrivate->valueTypes[prop->type]->metaObject(),
3533 valueTypeProp->index, engine);
3536 bool QQmlCompiler::completeComponentBuild()
3539 componentStats->componentStat.ids = compileState->ids.count();
3541 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3542 aliasObject = compileState->aliasingObjects.next(aliasObject))
3543 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3545 QV4Compiler::Expression expr(unit->imports());
3546 expr.component = compileState->root;
3547 expr.ids = &compileState->ids;
3548 expr.importCache = output->importCache;
3550 QV4Compiler bindingCompiler;
3552 QList<JSBindingReference*> sharedBindings;
3554 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3556 JSBindingReference &binding = *b;
3558 // ### We don't currently optimize for bindings on alias's - because
3559 // of the solution to QTBUG-13719
3560 if (!binding.property->isAlias) {
3561 expr.context = binding.bindingContext.object;
3562 expr.property = binding.property;
3563 expr.expression = binding.expression;
3565 int index = bindingCompiler.compile(expr, enginePrivate);
3567 binding.dataType = BindingReference::V4;
3568 binding.compiledIndex = index;
3570 componentStats->componentStat.optimizedBindings.append(b->value->location);
3575 // Pre-rewrite the expression
3576 QString expression = binding.expression.asScript();
3578 QQmlRewrite::RewriteBinding rewriteBinding;
3579 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3580 bool isSharable = false;
3581 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3583 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3584 binding.dataType = BindingReference::V8;
3585 sharedBindings.append(b);
3588 componentStats->componentStat.sharedBindings.append(b->value->location);
3590 binding.dataType = BindingReference::QtScript;
3593 componentStats->componentStat.scriptBindings.append(b->value->location);
3597 if (!sharedBindings.isEmpty()) {
3599 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3601 return lhs->value->location.start.line < rhs->value->location.start.line;
3605 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3607 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3608 int lineNumber = startLineNumber;
3610 QByteArray functionArray("[", 1);
3611 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3613 JSBindingReference *reference = sharedBindings.at(ii);
3614 QQmlScript::Value *value = reference->value;
3615 const QString &expression = reference->rewrittenExpression;
3617 if (ii != 0) functionArray.append(",", 1);
3619 while (lineNumber < value->location.start.line) {
3621 functionArray.append("\n", 1);
3624 functionArray += expression.toUtf8();
3625 lineNumber += expression.count(QLatin1Char('\n'));
3626 reference->compiledIndex = ii;
3628 functionArray.append("]", 1);
3630 compileState->v8BindingProgram = functionArray;
3631 compileState->v8BindingProgramLine = startLineNumber;
3634 if (bindingCompiler.isValid())
3635 compileState->compiledBindingData = bindingCompiler.program();
3637 // Check pop()'s matched push()'s
3638 Q_ASSERT(compileState->objectDepth.depth() == 0);
3639 Q_ASSERT(compileState->listDepth.depth() == 0);
3641 saveComponentState();
3646 void QQmlCompiler::dumpStats()
3648 Q_ASSERT(componentStats);
3649 qWarning().nospace() << "QML Document: " << output->url.toString();
3650 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3651 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3652 qWarning().nospace() << " Component Line " << stat.lineNumber;
3653 qWarning().nospace() << " Total Objects: " << stat.objects;
3654 qWarning().nospace() << " IDs Used: " << stat.ids;
3655 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3659 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3660 if (0 == (ii % 10)) {
3661 if (ii) output.append("\n");
3666 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3668 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3669 output.append(") ");
3671 if (!output.isEmpty())
3672 qWarning().nospace() << output.constData();
3675 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3678 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3679 if (0 == (ii % 10)) {
3680 if (ii) output.append("\n");
3685 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3687 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3688 output.append(") ");
3690 if (!output.isEmpty())
3691 qWarning().nospace() << output.constData();
3694 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3697 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3698 if (0 == (ii % 10)) {
3699 if (ii) output.append("\n");
3704 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3706 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3707 output.append(") ");
3709 if (!output.isEmpty())
3710 qWarning().nospace() << output.constData();
3716 Returns true if from can be assigned to a (QObject) property of type
3719 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3721 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3722 const QMetaObject *fromMo = from->metaObject();
3725 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3727 fromMo = fromMo->superClass();
3733 Returns the element name, as written in the QML file, for o.
3735 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3738 if (o->type != -1) {
3739 return output->types.at(o->type).className;
3745 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3748 const QMetaObject *mo = from->metatype;
3750 while (!type && mo) {
3751 type = QQmlMetaType::qmlType(mo);
3752 mo = mo->superClass();
3757 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3759 const QMetaObject *mo = obj->metatype;
3761 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3763 return QStringList();
3765 QMetaClassInfo classInfo = mo->classInfo(idx);
3766 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3771 QQmlCompiler::property(QQmlScript::Object *object, int index)
3773 QQmlPropertyCache *cache = 0;
3775 if (object->synthCache)
3776 cache = object->synthCache;
3777 else if (object->type != -1)
3778 cache = output->types[object->type].createPropertyCache(engine);
3780 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3782 return cache->property(index);
3786 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3788 if (notInRevision) *notInRevision = false;
3790 QQmlPropertyCache *cache = 0;
3792 if (object->synthCache)
3793 cache = object->synthCache;
3794 else if (object->type != -1)
3795 cache = output->types[object->type].createPropertyCache(engine);
3797 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3799 QQmlPropertyData *d = cache->property(name);
3801 // Find the first property
3802 while (d && d->isFunction())
3803 d = cache->overrideData(d);
3805 if (d && !cache->isAllowedInRevision(d)) {
3806 if (notInRevision) *notInRevision = true;
3813 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3815 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3817 if (notInRevision) *notInRevision = false;
3819 QQmlPropertyCache *cache = 0;
3821 if (object->synthCache)
3822 cache = object->synthCache;
3823 else if (object->type != -1)
3824 cache = output->types[object->type].createPropertyCache(engine);
3826 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3829 QQmlPropertyData *d = cache->property(name);
3830 if (notInRevision) *notInRevision = false;
3832 while (d && !(d->isFunction()))
3833 d = cache->overrideData(d);
3835 if (d && !cache->isAllowedInRevision(d)) {
3836 if (notInRevision) *notInRevision = true;
3842 if (name.endsWith(Changed_string)) {
3843 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3845 d = property(object, propName, notInRevision);
3847 return cache->method(d->notifyIndex);
3853 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3854 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3855 bool *notInRevision)
3857 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3858 return d?d->coreIndex:-1;
3861 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3862 bool *notInRevision)
3864 return indexOfProperty(object, QStringRef(&name), notInRevision);
3867 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3868 bool *notInRevision)
3870 QQmlPropertyData *d = property(object, name, notInRevision);
3871 return d?d->coreIndex:-1;