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))));
410 static QUrl urlFromUserString(const QString &data)
413 // Preserve any valid percent-encoded octets supplied by the source
414 u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
419 Generate a store instruction for assigning literal \a v to property \a prop.
421 Any literal assignment that is approved in testLiteralAssignment() must have
422 a corresponding action in this method.
424 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
425 QQmlScript::Value *v)
427 if (prop->core.isEnum()) {
428 Q_ASSERT(v->value.isNumber());
430 int value = (int)v->value.asNumber();
432 Instruction::StoreInteger instr;
433 instr.propertyIndex = prop->index;
435 output->addInstruction(instr);
439 int type = prop->type;
441 case QMetaType::QVariant:
443 if (v->value.isNumber()) {
444 double n = v->value.asNumber();
445 if (double(int(n)) == n) {
446 if (prop->core.isVMEProperty()) {
447 Instruction::StoreVarInteger instr;
448 instr.propertyIndex = prop->index;
449 instr.value = int(n);
450 output->addInstruction(instr);
452 Instruction::StoreVariantInteger instr;
453 instr.propertyIndex = prop->index;
454 instr.value = int(n);
455 output->addInstruction(instr);
458 if (prop->core.isVMEProperty()) {
459 Instruction::StoreVarDouble instr;
460 instr.propertyIndex = prop->index;
462 output->addInstruction(instr);
464 Instruction::StoreVariantDouble instr;
465 instr.propertyIndex = prop->index;
467 output->addInstruction(instr);
470 } else if (v->value.isBoolean()) {
471 if (prop->core.isVMEProperty()) {
472 Instruction::StoreVarBool instr;
473 instr.propertyIndex = prop->index;
474 instr.value = v->value.asBoolean();
475 output->addInstruction(instr);
477 Instruction::StoreVariantBool instr;
478 instr.propertyIndex = prop->index;
479 instr.value = v->value.asBoolean();
480 output->addInstruction(instr);
483 if (prop->core.isVMEProperty()) {
484 Instruction::StoreVar instr;
485 instr.propertyIndex = prop->index;
486 instr.value = output->indexForString(v->value.asString());
487 output->addInstruction(instr);
489 Instruction::StoreVariant instr;
490 instr.propertyIndex = prop->index;
491 instr.value = output->indexForString(v->value.asString());
492 output->addInstruction(instr);
497 case QVariant::String:
499 Instruction::StoreString instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForString(v->value.asString());
502 output->addInstruction(instr);
505 case QVariant::StringList:
507 Instruction::StoreStringList instr;
508 instr.propertyIndex = prop->index;
509 instr.value = output->indexForString(v->value.asString());
510 output->addInstruction(instr);
513 case QVariant::ByteArray:
515 Instruction::StoreByteArray instr;
516 instr.propertyIndex = prop->index;
517 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
518 output->addInstruction(instr);
523 Instruction::StoreUrl instr;
524 QString string = v->value.asString();
525 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
526 instr.propertyIndex = prop->index;
527 instr.value = output->indexForUrl(u);
528 output->addInstruction(instr);
533 Instruction::StoreInteger instr;
534 instr.propertyIndex = prop->index;
535 instr.value = uint(v->value.asNumber());
536 output->addInstruction(instr);
541 Instruction::StoreInteger instr;
542 instr.propertyIndex = prop->index;
543 instr.value = int(v->value.asNumber());
544 output->addInstruction(instr);
547 case QMetaType::Float:
549 Instruction::StoreFloat instr;
550 instr.propertyIndex = prop->index;
551 instr.value = float(v->value.asNumber());
552 output->addInstruction(instr);
555 case QVariant::Double:
557 Instruction::StoreDouble instr;
558 instr.propertyIndex = prop->index;
559 instr.value = v->value.asNumber();
560 output->addInstruction(instr);
563 case QVariant::Color:
565 Instruction::StoreColor instr;
566 instr.propertyIndex = prop->index;
567 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
568 output->addInstruction(instr);
571 #ifndef QT_NO_DATESTRING
574 Instruction::StoreDate instr;
575 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
576 instr.propertyIndex = prop->index;
577 instr.value = d.toJulianDay();
578 output->addInstruction(instr);
583 Instruction::StoreTime instr;
584 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
585 instr.propertyIndex = prop->index;
586 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
587 ::memcpy(&instr.time, &time, sizeof(QTime));
588 output->addInstruction(instr);
591 case QVariant::DateTime:
593 Instruction::StoreDateTime instr;
594 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
595 QTime time = dateTime.time();
596 instr.propertyIndex = prop->index;
597 instr.date = dateTime.date().toJulianDay();
598 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
599 ::memcpy(&instr.time, &time, sizeof(QTime));
600 output->addInstruction(instr);
603 #endif // QT_NO_DATESTRING
604 case QVariant::Point:
606 Instruction::StorePoint instr;
608 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
609 instr.propertyIndex = prop->index;
610 instr.point.xp = point.x();
611 instr.point.yp = point.y();
612 output->addInstruction(instr);
615 case QVariant::PointF:
617 Instruction::StorePointF instr;
619 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
620 instr.propertyIndex = prop->index;
621 instr.point.xp = point.x();
622 instr.point.yp = point.y();
623 output->addInstruction(instr);
628 Instruction::StoreSize instr;
630 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
631 instr.propertyIndex = prop->index;
632 instr.size.wd = size.width();
633 instr.size.ht = size.height();
634 output->addInstruction(instr);
637 case QVariant::SizeF:
639 Instruction::StoreSizeF instr;
641 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
642 instr.propertyIndex = prop->index;
643 instr.size.wd = size.width();
644 instr.size.ht = size.height();
645 output->addInstruction(instr);
650 Instruction::StoreRect instr;
652 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
653 instr.propertyIndex = prop->index;
654 instr.rect.x1 = rect.left();
655 instr.rect.y1 = rect.top();
656 instr.rect.x2 = rect.right();
657 instr.rect.y2 = rect.bottom();
658 output->addInstruction(instr);
661 case QVariant::RectF:
663 Instruction::StoreRectF instr;
665 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
666 instr.propertyIndex = prop->index;
667 instr.rect.xp = rect.left();
668 instr.rect.yp = rect.top();
669 instr.rect.w = rect.width();
670 instr.rect.h = rect.height();
671 output->addInstruction(instr);
676 Instruction::StoreBool instr;
677 bool b = v->value.asBoolean();
678 instr.propertyIndex = prop->index;
680 output->addInstruction(instr);
683 case QVariant::Vector3D:
685 Instruction::StoreVector3D instr;
686 instr.propertyIndex = prop->index;
687 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
688 output->addInstruction(instr);
691 case QVariant::Vector4D:
693 Instruction::StoreVector4D instr;
694 instr.propertyIndex = prop->index;
695 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
696 output->addInstruction(instr);
701 // generate single literal value assignment to a list property if required
702 if (type == qMetaTypeId<QList<qreal> >()) {
703 Instruction::StoreDoubleQList instr;
704 instr.propertyIndex = prop->index;
705 instr.value = v->value.asNumber();
706 output->addInstruction(instr);
708 } else if (type == qMetaTypeId<QList<int> >()) {
709 Instruction::StoreIntegerQList instr;
710 instr.propertyIndex = prop->index;
711 instr.value = int(v->value.asNumber());
712 output->addInstruction(instr);
714 } else if (type == qMetaTypeId<QList<bool> >()) {
715 Instruction::StoreBoolQList instr;
716 bool b = v->value.asBoolean();
717 instr.propertyIndex = prop->index;
719 output->addInstruction(instr);
721 } else if (type == qMetaTypeId<QList<QUrl> >()) {
722 Instruction::StoreUrlQList instr;
723 QString string = v->value.asString();
724 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
725 instr.propertyIndex = prop->index;
726 instr.value = output->indexForUrl(u);
727 output->addInstruction(instr);
729 } else if (type == qMetaTypeId<QList<QString> >()) {
730 Instruction::StoreStringQList instr;
731 instr.propertyIndex = prop->index;
732 instr.value = output->indexForString(v->value.asString());
733 output->addInstruction(instr);
737 // otherwise, generate custom type literal assignment
738 Instruction::AssignCustomType instr;
739 instr.propertyIndex = prop->index;
740 instr.primitive = output->indexForString(v->value.asString());
742 output->addInstruction(instr);
749 Resets data by clearing the lists that the QQmlCompiler modifies.
751 void QQmlCompiler::reset(QQmlCompiledData *data)
754 data->primitives.clear();
756 data->bytecode.resize(0);
760 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
761 with which the QQmlCompiledData will be associated.
763 Returns true on success, false on failure. On failure, the compile errors
764 are available from errors().
766 If the environment variant QML_COMPILER_DUMP is set
767 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
768 on a successful compiler.
770 bool QQmlCompiler::compile(QQmlEngine *engine,
772 QQmlCompiledData *out)
779 QQmlScript::Object *root = unit->parser().tree();
782 this->engine = engine;
783 this->enginePrivate = QQmlEnginePrivate::get(engine);
785 this->unitRoot = root;
789 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
790 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
792 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
793 QQmlCompiledData::TypeReference ref;
795 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
796 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
799 ref.type = tref.type;
800 if (!ref.type->isCreatable()) {
801 QString err = ref.type->noCreationReason();
803 err = tr( "Element is not creatable.");
804 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
807 if (ref.type->containsRevisionedAttributes()) {
808 QQmlError cacheError;
809 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
811 if (!ref.typePropertyCache)
812 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
813 ref.typePropertyCache->addref();
816 } else if (tref.typeData) {
817 ref.component = tref.typeData->compiledData();
819 ref.className = parserRef->name;
827 out->dumpInstructions();
830 Q_ASSERT(out->rootPropertyCache);
838 this->enginePrivate = 0;
840 this->cachedComponentTypeRef = -1;
841 this->cachedTranslationContextIndex = -1;
847 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
849 compileState = pool->New<ComponentCompileState>();
851 compileState->root = tree;
853 componentStats->componentStat.lineNumber = tree->location.start.line;
855 // We generate the importCache before we build the tree so that
856 // it can be used in the binding compiler. Given we "expect" the
857 // QML compilation to succeed, this isn't a waste.
858 output->importCache = new QQmlTypeNameCache();
859 foreach (const QString &ns, unit->namespaces()) {
860 output->importCache->add(ns);
864 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
865 QString qualifier = script.qualifier;
866 QString enclosingNamespace;
868 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
869 if (lastDotIndex != -1) {
870 enclosingNamespace = qualifier.left(lastDotIndex);
871 qualifier = qualifier.mid(lastDotIndex+1);
874 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
877 unit->imports().populateCache(output->importCache, engine);
879 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
882 Instruction::Init init;
883 init.bindingsSize = compileState->totalBindingsCount;
884 init.parserStatusSize = compileState->parserStatusCount;
885 init.contextCache = genContextCache();
886 init.objectStackSize = compileState->objectDepth.maxDepth();
887 init.listStackSize = compileState->listDepth.maxDepth();
888 if (compileState->compiledBindingData.isEmpty())
889 init.compiledBinding = -1;
891 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
892 output->addInstruction(init);
894 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
895 Instruction::StoreImportedScript import;
896 import.value = output->scripts.count();
898 QQmlScriptData *scriptData = script.script->scriptData();
899 scriptData->addref();
900 output->scripts << scriptData;
901 output->addInstruction(import);
904 if (!compileState->v8BindingProgram.isEmpty()) {
905 Instruction::InitV8Bindings bindings;
906 int index = output->programs.count();
908 typedef QQmlCompiledData::V8Program V8Program;
909 output->programs.append(V8Program(compileState->v8BindingProgram, output));
911 bindings.programIndex = index;
912 bindings.line = compileState->v8BindingProgramLine;
913 output->addInstruction(bindings);
918 Instruction::SetDefault def;
919 output->addInstruction(def);
921 Instruction::Done done;
922 output->addInstruction(done);
924 Q_ASSERT(tree->metatype);
926 if (tree->metadata.isEmpty()) {
927 output->root = tree->metatype;
929 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
930 output->root = &output->rootData;
932 if (!tree->metadata.isEmpty())
933 enginePrivate->registerCompositeType(output);
936 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
938 for (int ii = 0; ii < list.count(); ++ii)
939 if (string == list.at(ii))
945 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
948 componentStats->componentStat.objects++;
950 Q_ASSERT (obj->type != -1);
951 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
952 obj->metatype = tr.metaObject();
955 obj->typeName = tr.type->qmlTypeName();
957 // This object is a "Component" element
958 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
959 COMPILE_CHECK(buildComponent(obj, ctxt));
964 typedef QQmlInstruction I;
965 const I *init = ((const I *)tr.component->bytecode.constData());
966 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
968 // Adjust stack depths to include nested components
969 compileState->objectDepth.pushPop(init->init.objectStackSize);
970 compileState->listDepth.pushPop(init->init.listStackSize);
971 compileState->parserStatusCount += init->init.parserStatusSize;
972 compileState->totalBindingsCount += init->init.bindingsSize;
975 compileState->objectDepth.push();
977 // Object instantiations reset the binding context
978 BindingContext objCtxt(obj);
980 // Create the synthesized meta object, ignoring aliases
981 COMPILE_CHECK(checkDynamicMeta(obj));
982 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
983 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
985 // Find the native type and check for the QQmlParserStatus interface
986 QQmlType *type = toQmlType(obj);
988 obj->parserStatusCast = type->parserStatusCast();
989 if (obj->parserStatusCast != -1)
990 compileState->parserStatusCount++;
992 // Check if this is a custom parser type. Custom parser types allow
993 // assignments to non-existent properties. These assignments are then
994 // compiled by the type.
995 bool isCustomParser = output->types.at(obj->type).type &&
996 output->types.at(obj->type).type->customParser() != 0;
997 QList<QQmlCustomParserProperty> customProps;
999 // Fetch the list of deferred properties
1000 QStringList deferredList = deferredProperties(obj);
1002 // Must do id property first. This is to ensure that the id given to any
1003 // id reference created matches the order in which the objects are
1005 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1006 if (prop->name() == id_string) {
1007 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1013 Property *defaultProperty = 0;
1014 Property *skipProperty = 0;
1015 if (obj->defaultProperty) {
1016 defaultProperty = obj->defaultProperty;
1018 Property *explicitProperty = 0;
1020 const QMetaObject *mo = obj->metatype;
1021 int idx = mo->indexOfClassInfo("DefaultProperty");
1023 QMetaClassInfo info = mo->classInfo(idx);
1024 const char *p = info.value();
1028 while (char c = p[plen++]) { ord |= c; };
1032 // Utf8 - unoptimal, but seldom hit
1033 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1034 QHashedStringRef r(*s);
1036 if (obj->propertiesHashField.test(r.hash())) {
1037 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1038 if (ep->name() == r) {
1039 explicitProperty = ep;
1045 if (!explicitProperty)
1046 defaultProperty->setName(r);
1049 QHashedCStringRef r(p, plen);
1051 if (obj->propertiesHashField.test(r.hash())) {
1052 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1053 if (ep->name() == r) {
1054 explicitProperty = ep;
1060 if (!explicitProperty) {
1061 // Set the default property name
1062 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1063 r.writeUtf16(buffer);
1064 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1070 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1072 skipProperty = explicitProperty; // We merge the values into defaultProperty
1074 // Find the correct insertion point
1075 Value *insertPos = 0;
1077 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1078 if (!(v->location.start < explicitProperty->values.first()->location.start))
1083 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1087 QQmlCustomParser *cp = 0;
1089 cp = output->types.at(obj->type).type->customParser();
1091 // Build all explicit properties specified
1092 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1094 if (prop == skipProperty)
1096 if (prop->name() == id_string)
1099 bool canDefer = false;
1100 if (isCustomParser) {
1101 if (doesPropertyExist(prop, obj) &&
1102 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1103 !isAttachedPropertyName(prop->name()))) {
1104 int ids = compileState->ids.count();
1105 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1106 canDefer = ids == compileState->ids.count();
1107 } else if (isSignalPropertyName(prop->name()) &&
1108 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1109 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1111 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1114 if (isSignalPropertyName(prop->name())) {
1115 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1117 int ids = compileState->ids.count();
1118 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1119 canDefer = ids == compileState->ids.count();
1123 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1124 prop->isDeferred = true;
1128 // Build the default property
1129 if (defaultProperty) {
1130 Property *prop = defaultProperty;
1132 bool canDefer = false;
1133 if (isCustomParser) {
1134 if (doesPropertyExist(prop, obj)) {
1135 int ids = compileState->ids.count();
1136 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1137 canDefer = ids == compileState->ids.count();
1139 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1142 int ids = compileState->ids.count();
1143 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1144 canDefer = ids == compileState->ids.count();
1147 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1148 prop->isDeferred = true;
1151 // Compile custom parser parts
1152 if (isCustomParser && !customProps.isEmpty()) {
1154 cp->compiler = this;
1156 obj->custom = cp->compile(customProps);
1159 foreach (QQmlError err, cp->errors()) {
1160 err.setUrl(output->url);
1165 compileState->objectDepth.pop();
1170 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1172 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1173 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1178 // Create the object
1179 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1180 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1182 Instruction::CreateSimpleObject create;
1183 create.create = output->types.at(obj->type).type->createFunction();
1184 create.typeSize = output->types.at(obj->type).type->createSize();
1185 create.type = obj->type;
1186 create.line = obj->location.start.line;
1187 create.column = obj->location.start.column;
1188 output->addInstruction(create);
1192 if (output->types.at(obj->type).type) {
1193 Instruction::CreateCppObject create;
1194 create.line = obj->location.start.line;
1195 create.column = obj->location.start.column;
1197 if (!obj->custom.isEmpty())
1198 create.data = output->indexForByteArray(obj->custom);
1199 create.type = obj->type;
1200 create.isRoot = (compileState->root == obj);
1201 output->addInstruction(create);
1203 Instruction::CreateQMLObject create;
1204 create.type = obj->type;
1205 create.isRoot = (compileState->root == obj);
1207 if (!obj->bindingBitmask.isEmpty()) {
1208 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1209 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1211 create.bindingBits = -1;
1213 output->addInstruction(create);
1215 Instruction::CompleteQMLObject complete;
1216 complete.line = obj->location.start.line;
1217 complete.column = obj->location.start.column;
1218 complete.isRoot = (compileState->root == obj);
1219 output->addInstruction(complete);
1223 // Setup the synthesized meta object if necessary
1224 if (!obj->metadata.isEmpty()) {
1225 Instruction::StoreMetaObject meta;
1226 meta.data = output->indexForByteArray(obj->metadata);
1227 meta.aliasData = output->indexForByteArray(obj->synthdata);
1228 meta.propertyCache = output->propertyCaches.count();
1230 QQmlPropertyCache *propertyCache = obj->synthCache;
1231 Q_ASSERT(propertyCache);
1232 propertyCache->addref();
1234 // Add flag for alias properties
1235 if (!obj->synthdata.isEmpty()) {
1236 const QQmlVMEMetaData *vmeMetaData =
1237 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1238 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1239 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1240 QQmlPropertyData *data = propertyCache->property(index);
1241 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1245 if (obj == unitRoot) {
1246 propertyCache->addref();
1247 output->rootPropertyCache = propertyCache;
1250 output->propertyCaches << propertyCache;
1251 output->addInstruction(meta);
1252 } else if (obj == unitRoot) {
1253 output->rootPropertyCache = tr.createPropertyCache(engine);
1254 output->rootPropertyCache->addref();
1257 // Set the object id
1258 if (!obj->id.isEmpty()) {
1259 Instruction::SetId id;
1260 id.value = output->indexForString(obj->id);
1261 id.index = obj->idIndex;
1262 output->addInstruction(id);
1266 if (tr.type && obj->parserStatusCast != -1) {
1267 Instruction::BeginObject begin;
1268 begin.castValue = obj->parserStatusCast;
1269 output->addInstruction(begin);
1275 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1277 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1278 Q_ASSERT(prop->scriptStringScope != -1);
1279 const QString &script = prop->values.first()->value.asScript();
1280 Instruction::StoreScriptString ss;
1281 ss.propertyIndex = prop->index;
1282 ss.value = output->indexForString(script);
1283 ss.scope = prop->scriptStringScope;
1284 // ss.bindingId = rewriteBinding(script, prop->name());
1285 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1286 ss.line = prop->location.start.line;
1287 ss.column = prop->location.start.column;
1288 output->addInstruction(ss);
1291 bool seenDefer = false;
1292 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1293 if (prop->isDeferred) {
1298 genValueProperty(prop, obj);
1301 Instruction::Defer defer;
1302 defer.deferCount = 0;
1303 int deferIdx = output->addInstruction(defer);
1304 int nextInstructionIndex = output->nextInstructionIndex();
1306 Instruction::DeferInit dinit;
1307 // XXX - these are now massive over allocations
1308 dinit.bindingsSize = compileState->totalBindingsCount;
1309 dinit.parserStatusSize = compileState->parserStatusCount;
1310 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1311 dinit.listStackSize = compileState->listDepth.maxDepth();
1312 output->addInstruction(dinit);
1314 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1315 if (!prop->isDeferred)
1317 genValueProperty(prop, obj);
1320 Instruction::Done done;
1321 output->addInstruction(done);
1323 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1326 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1328 QQmlScript::Value *v = prop->values.first();
1330 if (v->type == Value::SignalObject) {
1332 genObject(v->object);
1334 Instruction::AssignSignalObject assign;
1335 assign.line = v->location.start.line;
1336 assign.signal = output->indexForString(prop->name().toString());
1337 output->addInstruction(assign);
1339 } else if (v->type == Value::SignalExpression) {
1341 Instruction::StoreSignal store;
1342 store.signalIndex = prop->index;
1343 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1344 store.value = output->indexForByteArray(rewrite.toUtf8());
1345 store.context = v->signalExpressionContextStack;
1346 store.line = v->location.start.line;
1347 store.column = v->location.start.column;
1348 output->addInstruction(store);
1354 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1355 Instruction::FetchAttached fetch;
1356 fetch.id = prop->index;
1357 fetch.line = prop->location.start.line;
1358 output->addInstruction(fetch);
1360 genObjectBody(prop->value);
1362 Instruction::PopFetchedObject pop;
1363 output->addInstruction(pop);
1366 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1367 Instruction::FetchObject fetch;
1368 fetch.property = prop->index;
1369 fetch.line = prop->location.start.line;
1370 output->addInstruction(fetch);
1372 if (!prop->value->metadata.isEmpty()) {
1373 Instruction::StoreMetaObject meta;
1374 meta.data = output->indexForByteArray(prop->value->metadata);
1375 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1376 meta.propertyCache = -1;
1377 output->addInstruction(meta);
1380 genObjectBody(prop->value);
1382 Instruction::PopFetchedObject pop;
1383 output->addInstruction(pop);
1386 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1388 genValueTypeProperty(obj, prop);
1391 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1392 if (prop->isDeferred)
1395 genValueProperty(prop, obj);
1398 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1400 genValueTypeProperty(obj, prop);
1404 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1406 Instruction::FetchValueType fetch;
1407 fetch.property = prop->index;
1408 fetch.type = prop->type;
1409 fetch.bindingSkipList = 0;
1411 if (obj->type == -1 || output->types.at(obj->type).component) {
1412 // We only have to do this if this is a composite type. If it is a builtin
1413 // type it can't possibly already have bindings that need to be cleared.
1414 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1415 if (!vprop->values.isEmpty()) {
1416 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1417 fetch.bindingSkipList |= (1 << vprop->index);
1422 output->addInstruction(fetch);
1424 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1425 genPropertyAssignment(vprop, prop->value, prop);
1428 Instruction::PopValueType pop;
1429 pop.property = prop->index;
1430 pop.type = prop->type;
1431 pop.bindingSkipList = 0;
1432 output->addInstruction(pop);
1435 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1437 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1440 Instruction::CreateComponent create;
1441 create.line = root->location.start.line;
1442 create.column = root->location.start.column;
1443 create.endLine = root->location.end.line;
1444 create.isRoot = (compileState->root == obj);
1445 int createInstruction = output->addInstruction(create);
1446 int nextInstructionIndex = output->nextInstructionIndex();
1448 ComponentCompileState *oldCompileState = compileState;
1449 compileState = componentState(root);
1451 Instruction::Init init;
1452 init.bindingsSize = compileState->totalBindingsCount;
1453 init.parserStatusSize = compileState->parserStatusCount;
1454 init.contextCache = genContextCache();
1455 init.objectStackSize = compileState->objectDepth.maxDepth();
1456 init.listStackSize = compileState->listDepth.maxDepth();
1457 if (compileState->compiledBindingData.isEmpty())
1458 init.compiledBinding = -1;
1460 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1461 output->addInstruction(init);
1463 if (!compileState->v8BindingProgram.isEmpty()) {
1464 Instruction::InitV8Bindings bindings;
1465 int index = output->programs.count();
1467 typedef QQmlCompiledData::V8Program V8Program;
1468 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1470 bindings.programIndex = index;
1471 bindings.line = compileState->v8BindingProgramLine;
1472 output->addInstruction(bindings);
1477 Instruction::SetDefault def;
1478 output->addInstruction(def);
1480 Instruction::Done done;
1481 output->addInstruction(done);
1483 output->instruction(createInstruction)->createComponent.count =
1484 output->nextInstructionIndex() - nextInstructionIndex;
1486 compileState = oldCompileState;
1488 if (!obj->id.isEmpty()) {
1489 Instruction::SetId id;
1490 id.value = output->indexForString(obj->id);
1491 id.index = obj->idIndex;
1492 output->addInstruction(id);
1495 if (obj == unitRoot) {
1496 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1497 output->rootPropertyCache->addref();
1501 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1502 const BindingContext &ctxt)
1504 // The special "Component" element can only have the id property and a
1505 // default property, that actually defines the component's tree
1507 compileState->objectDepth.push();
1509 // Find, check and set the "id" property (if any)
1510 Property *idProp = 0;
1511 if (obj->properties.isMany() ||
1512 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1513 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1515 if (!obj->properties.isEmpty())
1516 idProp = obj->properties.first();
1519 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1520 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1521 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1523 QString idVal = idProp->values.first()->primitive();
1525 if (compileState->ids.value(idVal))
1526 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1532 // Check the Component tree is well formed
1533 if (obj->defaultProperty &&
1534 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1535 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1536 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1538 if (!obj->dynamicProperties.isEmpty())
1539 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1540 if (!obj->dynamicSignals.isEmpty())
1541 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1542 if (!obj->dynamicSlots.isEmpty())
1543 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1545 QQmlScript::Object *root = 0;
1546 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1547 root = obj->defaultProperty->values.first()->object;
1550 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1552 // Build the component tree
1553 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1555 compileState->objectDepth.pop();
1560 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1561 const BindingContext &ctxt)
1563 ComponentCompileState *oldComponentCompileState = compileState;
1564 compileState = pool->New<ComponentCompileState>();
1565 compileState->root = obj;
1566 compileState->nested = true;
1568 if (componentStats) {
1569 ComponentStat oldComponentStat = componentStats->componentStat;
1571 componentStats->componentStat = ComponentStat();
1572 componentStats->componentStat.lineNumber = obj->location.start.line;
1575 COMPILE_CHECK(buildObject(obj, ctxt));
1577 COMPILE_CHECK(completeComponentBuild());
1579 componentStats->componentStat = oldComponentStat;
1582 COMPILE_CHECK(buildObject(obj, ctxt));
1584 COMPILE_CHECK(completeComponentBuild());
1587 compileState = oldComponentCompileState;
1593 // Build a sub-object. A sub-object is one that was not created directly by
1594 // QML - such as a grouped property object, or an attached object. Sub-object's
1595 // can't have an id, involve a custom parser, have attached properties etc.
1596 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1598 Q_ASSERT(obj->metatype);
1599 Q_ASSERT(!obj->defaultProperty);
1600 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1603 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1604 if (isSignalPropertyName(prop->name())) {
1605 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1607 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1614 int QQmlCompiler::componentTypeRef()
1616 if (cachedComponentTypeRef == -1) {
1617 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1618 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1619 if (output->types.at(ii).type == t) {
1620 cachedComponentTypeRef = ii;
1624 QQmlCompiledData::TypeReference ref;
1625 ref.className = Component_string;
1627 output->types << ref;
1628 cachedComponentTypeRef = output->types.count() - 1;
1630 return cachedComponentTypeRef;
1633 int QQmlCompiler::translationContextIndex()
1635 if (cachedTranslationContextIndex == -1) {
1636 // This code must match that in the qsTr() implementation
1637 const QString &path = output->name;
1638 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1639 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1641 QByteArray contextUtf8 = context.toUtf8();
1642 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1644 return cachedTranslationContextIndex;
1647 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1648 const BindingContext &ctxt)
1650 Q_ASSERT(obj->metaObject());
1652 const QHashedStringRef &propName = prop->name();
1654 Q_ASSERT(propName.startsWith(on_string));
1655 QString name = propName.mid(2, -1).toString();
1657 // Note that the property name could start with any alpha or '_' or '$' character,
1658 // so we need to do the lower-casing of the first alpha character.
1659 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1660 if (name.at(firstAlphaIndex).isUpper()) {
1661 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1666 bool notInRevision = false;
1668 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1672 if (notInRevision && 0 == property(obj, propName, 0)) {
1673 Q_ASSERT(obj->type != -1);
1674 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1675 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1677 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));
1679 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1683 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1685 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1689 if (prop->value || !prop->values.isOne())
1690 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1692 prop->index = sig->coreIndex;
1695 obj->addSignalProperty(prop);
1697 if (prop->values.first()->object) {
1698 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1699 prop->values.first()->type = Value::SignalObject;
1701 prop->values.first()->type = Value::SignalExpression;
1703 if (!prop->values.first()->value.isScript())
1704 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1706 QString script = prop->values.first()->value.asScript().trimmed();
1707 if (script.isEmpty())
1708 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1710 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1719 Returns true if (value) property \a prop exists on obj, false otherwise.
1721 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1722 QQmlScript::Object *obj)
1724 if (prop->name().isEmpty())
1726 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1729 return property(obj, prop->name()) != 0;
1732 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1733 QQmlScript::Object *obj,
1734 const BindingContext &ctxt)
1736 if (prop->isEmpty())
1737 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1739 const QMetaObject *metaObject = obj->metaObject();
1740 Q_ASSERT(metaObject);
1742 if (isAttachedPropertyName(prop->name())) {
1743 // Setup attached property data
1745 if (ctxt.isSubContext()) {
1746 // Attached properties cannot be used on sub-objects. Sub-objects
1747 // always exist in a binding sub-context, which is what we test
1749 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1753 QQmlImportedNamespace *typeNamespace = 0;
1754 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1756 if (typeNamespace) {
1757 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1760 } else if (!type || !type->attachedPropertiesType()) {
1761 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1765 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1767 Q_ASSERT(type->attachedPropertiesFunction());
1768 prop->index = type->attachedPropertiesId();
1769 prop->value->metatype = type->attachedPropertiesType();
1771 // Setup regular property data
1772 bool notInRevision = false;
1773 QQmlPropertyData *d =
1774 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1776 if (d == 0 && notInRevision) {
1777 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1778 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1780 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));
1782 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1785 prop->index = d->coreIndex;
1787 } else if (prop->isDefault) {
1788 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1789 QQmlPropertyData defaultPropertyData;
1790 defaultPropertyData.load(p, engine);
1792 prop->setName(QLatin1String(p.name()));
1793 prop->core = defaultPropertyData;
1794 prop->index = prop->core.coreIndex;
1797 // We can't error here as the "id" property does not require a
1798 // successful index resolution
1799 if (prop->index != -1)
1800 prop->type = prop->core.propType;
1802 // Check if this is an alias
1803 if (prop->index != -1 &&
1805 prop->parent->type != -1 &&
1806 output->types.at(prop->parent->type).component) {
1808 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1809 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1810 prop->isAlias = true;
1813 if (prop->index != -1 && !prop->values.isEmpty())
1814 prop->parent->setBindingBit(prop->index);
1817 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1819 // The magic "id" behavior doesn't apply when "id" is resolved as a
1820 // default property or to sub-objects (which are always in binding
1822 COMPILE_CHECK(buildIdProperty(prop, obj));
1823 if (prop->type == QVariant::String &&
1824 prop->values.first()->value.isString())
1825 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1827 } else if (isAttachedPropertyName(prop->name())) {
1829 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1831 } else if (prop->index == -1) {
1833 if (prop->isDefault) {
1834 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1836 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1839 } else if (prop->value) {
1841 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1843 } else if (prop->core.isQList()) {
1845 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1847 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1849 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1853 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1860 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
1861 QQmlScript::Property *nsProp,
1862 QQmlScript::Object *obj,
1863 const BindingContext &ctxt)
1866 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1868 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1870 if (!isAttachedPropertyName(prop->name()))
1871 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1873 // Setup attached property data
1876 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1878 if (!type || !type->attachedPropertiesType())
1879 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1882 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1884 Q_ASSERT(type->attachedPropertiesFunction());
1885 prop->index = type->index();
1886 prop->value->metatype = type->attachedPropertiesType();
1888 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1894 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1895 QQmlScript::Object *obj)
1897 if (prop->core.isQList()) {
1898 genListProperty(prop, obj);
1900 genPropertyAssignment(prop, obj);
1904 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1905 QQmlScript::Object *obj)
1907 int listType = enginePrivate->listType(prop->type);
1909 Instruction::FetchQList fetch;
1910 fetch.property = prop->index;
1911 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1912 fetch.type = listType;
1913 output->addInstruction(fetch);
1915 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1917 if (v->type == Value::CreatedObject) {
1919 genObject(v->object);
1920 if (listTypeIsInterface) {
1921 Instruction::AssignObjectList assign;
1922 assign.line = prop->location.start.line;
1923 output->addInstruction(assign);
1925 Instruction::StoreObjectQList store;
1926 output->addInstruction(store);
1929 } else if (v->type == Value::PropertyBinding) {
1931 genBindingAssignment(v, prop, obj);
1937 Instruction::PopQList pop;
1938 output->addInstruction(pop);
1941 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1942 QQmlScript::Object *obj,
1943 QQmlScript::Property *valueTypeProperty)
1945 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1947 Q_ASSERT(v->type == Value::CreatedObject ||
1948 v->type == Value::PropertyBinding ||
1949 v->type == Value::Literal);
1951 if (v->type == Value::CreatedObject) {
1953 genObject(v->object);
1955 if (QQmlMetaType::isInterface(prop->type)) {
1957 Instruction::StoreInterface store;
1958 store.line = v->object->location.start.line;
1959 store.propertyIndex = prop->index;
1960 output->addInstruction(store);
1962 } else if (prop->type == QMetaType::QVariant) {
1964 if (prop->core.isVMEProperty()) {
1965 Instruction::StoreVarObject store;
1966 store.line = v->object->location.start.line;
1967 store.propertyIndex = prop->index;
1968 output->addInstruction(store);
1970 Instruction::StoreVariantObject store;
1971 store.line = v->object->location.start.line;
1972 store.propertyIndex = prop->index;
1973 output->addInstruction(store);
1979 Instruction::StoreObject store;
1980 store.line = v->object->location.start.line;
1981 store.propertyIndex = prop->index;
1982 output->addInstruction(store);
1985 } else if (v->type == Value::PropertyBinding) {
1987 genBindingAssignment(v, prop, obj, valueTypeProperty);
1989 } else if (v->type == Value::Literal) {
1991 genLiteralAssignment(prop, v);
1997 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1999 Q_ASSERT(v->type == Value::ValueSource ||
2000 v->type == Value::ValueInterceptor);
2002 if (v->type == Value::ValueSource) {
2003 genObject(v->object);
2005 Instruction::StoreValueSource store;
2006 if (valueTypeProperty) {
2007 store.property = genValueTypeData(prop, valueTypeProperty);
2010 store.property = prop->core;
2013 QQmlType *valueType = toQmlType(v->object);
2014 store.castValue = valueType->propertyValueSourceCast();
2015 output->addInstruction(store);
2017 } else if (v->type == Value::ValueInterceptor) {
2018 genObject(v->object);
2020 Instruction::StoreValueInterceptor store;
2021 if (valueTypeProperty) {
2022 store.property = genValueTypeData(prop, valueTypeProperty);
2025 store.property = prop->core;
2028 QQmlType *valueType = toQmlType(v->object);
2029 store.castValue = valueType->propertyValueInterceptorCast();
2030 output->addInstruction(store);
2036 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2037 QQmlScript::Object *obj)
2040 prop->values.isMany() ||
2041 prop->values.first()->object)
2042 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2044 QQmlScript::Value *idValue = prop->values.first();
2045 QString val = idValue->primitive();
2047 COMPILE_CHECK(checkValidId(idValue, val));
2049 if (compileState->ids.value(val))
2050 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2052 prop->values.first()->type = Value::Id;
2060 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2063 Q_ASSERT(!compileState->ids.value(id));
2064 Q_ASSERT(obj->id == id);
2065 obj->idIndex = compileState->ids.count();
2066 compileState->ids.append(obj);
2069 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2071 Q_ASSERT(ref->value && !ref->value->bindingReference);
2072 ref->value->bindingReference = ref;
2073 compileState->totalBindingsCount++;
2074 compileState->bindings.prepend(ref);
2077 void QQmlCompiler::saveComponentState()
2079 Q_ASSERT(compileState->root);
2080 Q_ASSERT(compileState->root->componentCompileState == 0);
2082 compileState->root->componentCompileState = compileState;
2085 componentStats->savedComponentStats.append(componentStats->componentStat);
2088 QQmlCompilerTypes::ComponentCompileState *
2089 QQmlCompiler::componentState(QQmlScript::Object *obj)
2091 Q_ASSERT(obj->componentCompileState);
2092 return obj->componentCompileState;
2095 // Build attached property object. In this example,
2099 // GridView is an attached property object.
2100 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2101 QQmlScript::Object *obj,
2102 const BindingContext &ctxt)
2104 Q_ASSERT(prop->value);
2105 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2107 compileState->objectDepth.push();
2109 obj->addAttachedProperty(prop);
2111 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2113 compileState->objectDepth.pop();
2119 // Build "grouped" properties. In this example:
2121 // font.pointSize: 12
2122 // font.family: "Helvetica"
2124 // font is a nested property. pointSize and family are not.
2125 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2126 QQmlScript::Object *obj,
2127 const BindingContext &ctxt)
2129 Q_ASSERT(prop->type != 0);
2130 Q_ASSERT(prop->index != -1);
2132 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2133 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2135 if (!prop->values.isEmpty()) {
2136 if (prop->values.first()->location < prop->value->location) {
2137 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2139 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2143 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2144 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2148 if (prop->isAlias) {
2149 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2150 vtProp->isAlias = true;
2154 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2155 prop->value, obj, ctxt.incr()));
2156 obj->addValueTypeProperty(prop);
2158 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2162 // Load the nested property's meta type
2163 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2164 if (!prop->value->metatype)
2165 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2167 if (!prop->values.isEmpty())
2168 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2170 obj->addGroupedProperty(prop);
2172 compileState->objectDepth.push();
2174 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2176 compileState->objectDepth.pop();
2182 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2183 QQmlScript::Object *obj,
2184 QQmlScript::Object *baseObj,
2185 const BindingContext &ctxt)
2187 compileState->objectDepth.push();
2189 if (obj->defaultProperty)
2190 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2191 obj->metatype = type->metaObject();
2193 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2195 QQmlPropertyData *d = property(obj, prop->name());
2197 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2199 prop->index = d->coreIndex;
2200 prop->type = d->propType;
2202 prop->isValueTypeSubProperty = true;
2205 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2207 if (prop->values.isMany()) {
2208 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2209 } else if (!prop->values.isEmpty()) {
2210 QQmlScript::Value *value = prop->values.first();
2212 if (value->object) {
2213 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2214 } else if (value->value.isScript()) {
2215 // ### Check for writability
2217 //optimization for <Type>.<EnumValue> enum assignments
2218 bool isEnumAssignment = false;
2220 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2221 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2223 if (isEnumAssignment) {
2224 value->type = Value::Literal;
2226 JSBindingReference *reference = pool->New<JSBindingReference>();
2227 reference->expression = value->value;
2228 reference->property = prop;
2229 reference->value = value;
2230 reference->bindingContext = ctxt;
2231 reference->bindingContext.owner++;
2232 addBindingReference(reference);
2233 value->type = Value::PropertyBinding;
2236 COMPILE_CHECK(testLiteralAssignment(prop, value));
2237 value->type = Value::Literal;
2241 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2242 Q_ASSERT(v->object);
2244 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2247 obj->addValueProperty(prop);
2250 compileState->objectDepth.pop();
2255 // Build assignments to QML lists. QML lists are properties of type
2256 // QQmlListProperty<T>. List properties can accept a list of
2257 // objects, or a single binding.
2258 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2259 QQmlScript::Object *obj,
2260 const BindingContext &ctxt)
2262 Q_ASSERT(prop->core.isQList());
2264 compileState->listDepth.push();
2268 obj->addValueProperty(prop);
2270 int listType = enginePrivate->listType(t);
2271 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2273 bool assignedBinding = false;
2274 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2276 v->type = Value::CreatedObject;
2277 COMPILE_CHECK(buildObject(v->object, ctxt));
2279 // We check object coercian here. We check interface assignment
2281 if (!listTypeIsInterface) {
2282 if (!canCoerce(listType, v->object)) {
2283 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2287 } else if (v->value.isScript()) {
2288 if (assignedBinding)
2289 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2291 assignedBinding = true;
2292 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2293 v->type = Value::PropertyBinding;
2295 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2299 compileState->listDepth.pop();
2304 // Compiles an assignment to a QQmlScriptString property
2305 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2306 QQmlScript::Object *obj,
2307 const BindingContext &ctxt)
2309 if (prop->values.isMany())
2310 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2312 if (prop->values.first()->object)
2313 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2315 prop->scriptStringScope = ctxt.stack;
2316 obj->addScriptStringProperty(prop);
2321 // Compile regular property assignments of the form "property: <value>"
2322 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2323 QQmlScript::Object *obj,
2324 const BindingContext &ctxt)
2326 obj->addValueProperty(prop);
2328 if (prop->values.isMany())
2329 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2331 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2334 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2338 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2343 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2344 Q_ASSERT(v->object);
2345 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2351 // Compile assigning a single object instance to a regular property
2352 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2353 QQmlScript::Object *obj,
2354 QQmlScript::Value *v,
2355 const BindingContext &ctxt)
2357 Q_ASSERT(prop->index != -1);
2358 Q_ASSERT(v->object->type != -1);
2360 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2361 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2363 if (QQmlMetaType::isInterface(prop->type)) {
2365 // Assigning an object to an interface ptr property
2366 COMPILE_CHECK(buildObject(v->object, ctxt));
2368 v->type = Value::CreatedObject;
2370 } else if (prop->type == QMetaType::QVariant) {
2372 // Assigning an object to a QVariant
2373 COMPILE_CHECK(buildObject(v->object, ctxt));
2375 v->type = Value::CreatedObject;
2377 // Normally buildObject() will set this up, but we need the static
2378 // meta object earlier to test for assignability. It doesn't matter
2379 // that there may still be outstanding synthesized meta object changes
2380 // on this type, as they are not relevant for assignability testing
2381 v->object->metatype = output->types.at(v->object->type).metaObject();
2382 Q_ASSERT(v->object->metaObject());
2384 // We want to raw metaObject here as the raw metaobject is the
2385 // actual property type before we applied any extensions that might
2386 // effect the properties on the type, but don't effect assignability
2387 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2389 // Will be true if the assgned type inherits propertyMetaObject
2390 bool isAssignable = false;
2391 // Determine isAssignable value
2392 if (propertyMetaObject) {
2393 const QMetaObject *c = v->object->metatype;
2395 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2396 c = c->superClass();
2401 // Simple assignment
2402 COMPILE_CHECK(buildObject(v->object, ctxt));
2404 v->type = Value::CreatedObject;
2405 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2406 // Automatic "Component" insertion
2407 QQmlScript::Object *root = v->object;
2408 QQmlScript::Object *component = pool->New<Object>();
2409 component->type = componentTypeRef();
2410 component->typeName = QStringLiteral("Qt/Component");
2411 component->metatype = &QQmlComponent::staticMetaObject;
2412 component->location = root->location;
2413 QQmlScript::Value *componentValue = pool->New<Value>();
2414 componentValue->object = root;
2415 component->getDefaultProperty()->addValue(componentValue);
2416 v->object = component;
2417 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2419 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2426 // Compile assigning a single object instance to a regular property using the "on" syntax.
2430 // NumberAnimation on x { }
2432 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2433 QQmlScript::Object *obj,
2434 QQmlScript::Object *baseObj,
2435 QQmlScript::Value *v,
2436 const BindingContext &ctxt)
2438 Q_ASSERT(prop->index != -1);
2439 Q_ASSERT(v->object->type != -1);
2443 if (!prop->core.isWritable())
2444 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2447 // Normally buildObject() will set this up, but we need the static
2448 // meta object earlier to test for assignability. It doesn't matter
2449 // that there may still be outstanding synthesized meta object changes
2450 // on this type, as they are not relevant for assignability testing
2451 v->object->metatype = output->types.at(v->object->type).metaObject();
2452 Q_ASSERT(v->object->metaObject());
2454 // Will be true if the assigned type inherits QQmlPropertyValueSource
2455 bool isPropertyValue = false;
2456 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2457 bool isPropertyInterceptor = false;
2458 if (QQmlType *valueType = toQmlType(v->object)) {
2459 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2460 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2463 if (isPropertyValue || isPropertyInterceptor) {
2464 // Assign as a property value source
2465 COMPILE_CHECK(buildObject(v->object, ctxt));
2467 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2468 buildDynamicMeta(baseObj, ForceCreation);
2469 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2471 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2477 // Compile assigning a literal or binding to a regular property
2478 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2479 QQmlScript::Object *obj,
2480 QQmlScript::Value *v,
2481 const BindingContext &ctxt)
2483 Q_ASSERT(prop->index != -1);
2485 if (v->value.isScript()) {
2487 //optimization for <Type>.<EnumValue> enum assignments
2488 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2489 bool isEnumAssignment = false;
2490 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2491 if (isEnumAssignment) {
2492 v->type = Value::Literal;
2497 // Test for other binding optimizations
2498 if (!buildLiteralBinding(v, prop, ctxt))
2499 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2501 v->type = Value::PropertyBinding;
2505 COMPILE_CHECK(testLiteralAssignment(prop, v));
2507 v->type = Value::Literal;
2513 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2514 QQmlScript::Object *obj,
2515 QQmlScript::Value *v,
2518 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2519 *isAssignment = false;
2520 if (!prop->core.isEnum() && !isIntProp)
2523 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2525 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2526 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2528 QString string = v->value.asString();
2529 if (!string.at(0).isUpper())
2533 // Allow enum assignment to ints.
2534 int enumval = evaluateEnum(string.toUtf8());
2535 if (enumval != -1) {
2536 v->type = Value::Literal;
2537 v->value = QQmlScript::Variant((double)enumval);
2538 *isAssignment = true;
2543 QStringList parts = string.split(QLatin1Char('.'));
2544 if (parts.count() != 2)
2547 QString typeName = parts.at(0);
2549 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2551 //handle enums on value types (where obj->typeName is empty)
2552 QString objTypeName = obj->typeName;
2553 if (objTypeName.isEmpty()) {
2554 QQmlType *objType = toQmlType(obj);
2556 objTypeName = objType->qmlTypeName();
2562 QString enumValue = parts.at(1);
2566 if (objTypeName == type->qmlTypeName()) {
2567 // When these two match, we can short cut the search
2568 if (mprop.isFlagType()) {
2569 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2571 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2574 // Otherwise we have to search the whole type
2575 // This matches the logic in QV8TypeWrapper
2576 QByteArray enumName = enumValue.toUtf8();
2577 const QMetaObject *metaObject = type->baseMetaObject();
2579 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2580 QMetaEnum e = metaObject->enumerator(ii);
2581 value = e.keyToValue(enumName.constData(), &ok);
2588 v->type = Value::Literal;
2589 v->value = QQmlScript::Variant((double)value);
2590 *isAssignment = true;
2595 struct StaticQtMetaObject : public QObject
2597 static const QMetaObject *get()
2598 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2601 // Similar logic to above, but not knowing target property.
2602 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2604 int dot = script.indexOf('.');
2606 const QByteArray &scope = script.left(dot);
2608 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2609 if (!type && scope != "Qt")
2611 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2612 const char *key = script.constData() + dot+1;
2613 int i = mo->enumeratorCount();
2616 int v = mo->enumerator(i).keyToValue(key, &ok);
2624 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2626 QQmlType *qmltype = 0;
2627 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2631 return qmltype->metaObject();
2634 // similar to logic of completeComponentBuild, but also sticks data
2635 // into primitives at the end
2636 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2638 QQmlRewrite::RewriteBinding rewriteBinding;
2639 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2641 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2643 return output->indexForString(rewrite);
2646 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2648 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2649 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2652 // Ensures that the dynamic meta specification on obj is valid
2653 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2655 bool seenDefaultProperty = false;
2657 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2658 // Calculating the hash for the names is not a waste as we have to test
2659 // them against the illegalNames set anyway.
2660 QHashField propNames;
2661 QHashField methodNames;
2664 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2665 const QQmlScript::Object::DynamicProperty &prop = *p;
2667 if (prop.isDefaultProperty) {
2668 if (seenDefaultProperty)
2669 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2670 seenDefaultProperty = true;
2673 if (propNames.testAndSet(prop.name.hash())) {
2674 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2675 p2 = obj->dynamicProperties.next(p2)) {
2676 if (p2->name == prop.name) {
2677 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2678 prop.nameLocation.column,
2679 tr("Duplicate property name"));
2684 if (prop.name.at(0).isUpper()) {
2685 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2686 prop.nameLocation.column,
2687 tr("Property names cannot begin with an upper case letter"));
2690 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2691 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2692 prop.nameLocation.column,
2693 tr("Illegal property name"));
2697 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2698 const QQmlScript::Object::DynamicSignal &currSig = *s;
2700 if (methodNames.testAndSet(currSig.name.hash())) {
2701 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2702 s2 = obj->dynamicSignals.next(s2)) {
2703 if (s2->name == currSig.name)
2704 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2708 if (currSig.name.at(0).isUpper())
2709 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2710 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2711 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2714 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2715 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2717 if (methodNames.testAndSet(currSlot.name.hash())) {
2718 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2719 s2 = obj->dynamicSignals.next(s2)) {
2720 if (s2->name == currSlot.name)
2721 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2723 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2724 s2 = obj->dynamicSlots.next(s2)) {
2725 if (s2->name == currSlot.name)
2726 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2730 if (currSlot.name.at(0).isUpper())
2731 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2732 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2733 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2739 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2741 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2742 p = obj->dynamicProperties.next(p)) {
2744 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2747 Property *property = 0;
2748 if (p->isDefaultProperty) {
2749 property = obj->getDefaultProperty();
2751 property = obj->getProperty(p->name);
2752 if (!property->values.isEmpty())
2753 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2757 property->isReadOnlyDeclaration = true;
2759 if (property->value)
2760 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2762 property->values.append(p->defaultValue->values);
2767 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2769 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2772 Q_ASSERT(obj->metatype);
2774 if (mode != ForceCreation &&
2775 obj->dynamicProperties.isEmpty() &&
2776 obj->dynamicSignals.isEmpty() &&
2777 obj->dynamicSlots.isEmpty())
2780 bool resolveAlias = (mode == ResolveAliases);
2782 const Object::DynamicProperty *defaultProperty = 0;
2784 int varPropCount = 0;
2785 int totalPropCount = 0;
2786 int firstPropertyVarIndex = 0;
2788 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2790 if (p->type == Object::DynamicProperty::Alias)
2792 if (p->type == Object::DynamicProperty::Var)
2795 if (p->isDefaultProperty &&
2796 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2797 defaultProperty = p;
2799 if (!resolveAlias) {
2800 // No point doing this for both the alias and non alias cases
2801 QQmlPropertyData *d = property(obj, p->name);
2802 if (d && d->isFinal())
2803 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2807 bool buildData = resolveAlias || aliasCount == 0;
2809 QByteArray dynamicData;
2811 typedef QQmlVMEMetaData VMD;
2813 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2814 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2815 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2816 aliasCount * sizeof(VMD::AliasData), 0);
2819 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2821 QByteArray newClassName = obj->metatype->className();
2822 newClassName.append("_QML_");
2823 newClassName.append(QByteArray::number(uniqueClassId));
2825 if (compileState->root == obj && !compileState->nested) {
2826 QString path = output->url.path();
2827 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2828 if (lastSlash > -1) {
2829 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2830 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2831 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2835 // Size of the array that describes parameter types & names
2836 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2837 + obj->dynamicProperties.count() // for Changed() signals return types
2838 // Return "parameters" don't have names
2839 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2841 QFastMetaBuilder builder;
2843 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2844 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2845 obj->dynamicSlots.count(),
2846 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2847 defaultProperty?1:0, paramDataSize, ¶mIndex);
2850 Object::DynamicProperty::Type dtype;
2852 } builtinTypes[] = {
2853 { Object::DynamicProperty::Var, QMetaType::QVariant },
2854 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2855 { Object::DynamicProperty::Int, QMetaType::Int },
2856 { Object::DynamicProperty::Bool, QMetaType::Bool },
2857 { Object::DynamicProperty::Real, QMetaType::Double },
2858 { Object::DynamicProperty::String, QMetaType::QString },
2859 { Object::DynamicProperty::Url, QMetaType::QUrl },
2860 { Object::DynamicProperty::Color, QMetaType::QColor },
2861 { Object::DynamicProperty::Time, QMetaType::QTime },
2862 { Object::DynamicProperty::Date, QMetaType::QDate },
2863 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2865 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2867 // Reserve dynamic properties
2868 if (obj->dynamicProperties.count()) {
2869 typedef QQmlVMEMetaData VMD;
2871 int effectivePropertyIndex = 0;
2872 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2874 // Reserve space for name
2875 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2876 p->nameRef = builder.newString(p->name.utf8length());
2879 int propertyType = 0; // for VMD
2880 bool readonly = false;
2882 if (p->type == Object::DynamicProperty::Alias) {
2884 } else if (p->type < builtinTypeCount) {
2885 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2886 metaType = builtinTypes[p->type].metaType;
2887 propertyType = metaType;
2890 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2891 p->type == Object::DynamicProperty::Custom);
2893 // XXX don't double resolve this in the case of an alias run
2895 QByteArray customTypeName;
2896 QQmlType *qmltype = 0;
2898 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2899 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2902 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2904 Q_ASSERT(tdata->isComplete());
2906 QQmlCompiledData *data = tdata->compiledData();
2907 customTypeName = data->root->className();
2911 customTypeName = qmltype->typeName();
2914 if (p->type == Object::DynamicProperty::Custom) {
2915 customTypeName += '*';
2916 propertyType = QMetaType::QObjectStar;
2919 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2920 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2923 metaType = QMetaType::type(customTypeName);
2924 Q_ASSERT(metaType != QMetaType::UnknownType);
2925 Q_ASSERT(metaType != QMetaType::Void);
2928 if (p->type == Object::DynamicProperty::Var)
2935 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2936 vmd->propertyCount++;
2937 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2940 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2941 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2942 effectivePropertyIndex);
2944 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2945 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2948 effectivePropertyIndex++;
2952 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2954 vmd->varPropertyCount = varPropCount;
2955 firstPropertyVarIndex = effectivePropertyIndex;
2956 totalPropCount = varPropCount + effectivePropertyIndex;
2957 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2958 if (p->type == Object::DynamicProperty::Var) {
2960 vmd->propertyCount++;
2961 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2964 builder.setProperty(effectivePropertyIndex, p->nameRef,
2965 QMetaType::QVariant,
2966 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2967 effectivePropertyIndex);
2969 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2970 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2973 effectivePropertyIndex++;
2980 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2981 if (p->type == Object::DynamicProperty::Alias) {
2983 Q_ASSERT(buildData);
2984 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2985 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2988 // Even if we aren't resolving the alias, we need a fake signal so that the
2989 // metaobject remains consistent across the resolve and non-resolve alias runs
2990 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2991 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2993 effectivePropertyIndex++;
3000 // Reserve default property
3001 QFastMetaBuilder::StringRef defPropRef;
3002 if (defaultProperty) {
3003 defPropRef = builder.newString(strlen("DefaultProperty"));
3004 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3007 // Reserve dynamic signals
3008 int signalIndex = 0;
3009 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3011 s->nameRef = builder.newString(s->name.utf8length());
3013 int paramCount = s->parameterNames.count();
3014 QVarLengthArray<int, 10> paramTypes(paramCount);
3016 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3017 for (int i = 0; i < paramCount; ++i) {
3018 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3019 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3020 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3025 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3027 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3028 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3029 paramIndex += paramCount*2 + 1;
3033 // Reserve dynamic slots
3034 if (obj->dynamicSlots.count()) {
3036 typedef QQmlVMEMetaData VMD;
3038 int methodIndex = 0;
3039 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3040 s->nameRef = builder.newString(s->name.utf8length());
3041 int paramCount = s->parameterNames.count();
3043 QVarLengthArray<int, 10> paramTypes(paramCount);
3045 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3046 for (int i = 0; i < paramCount; ++i) {
3047 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3048 paramTypes[i] = QMetaType::QVariant;
3052 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3053 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3054 paramIndex += paramCount*2 + 1;
3059 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3060 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3061 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3062 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3063 for (int jj = 0; jj < paramCount; ++jj) {
3064 if (jj) funcScript.append(QLatin1Char(','));
3065 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3067 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3069 QByteArray utf8 = funcScript.toUtf8();
3070 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3072 s->location.start.line };
3074 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3077 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3079 md.bodyOffset = dynamicData.size();
3081 dynamicData.append((const char *)utf8.constData(), utf8.length());
3089 // Now allocate properties
3090 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3092 char *d = p->changedNameRef.data();
3093 p->name.writeUtf8(d);
3094 strcpy(d + p->name.utf8length(), "Changed");
3095 p->changedNameRef.loadByteArrayData();
3097 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3100 p->nameRef.load(p->name);
3103 // Allocate default property if necessary
3104 if (defaultProperty)
3105 defPropRef.load("DefaultProperty");
3107 // Now allocate signals
3108 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.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));
3116 // Now allocate methods
3117 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3118 s->nameRef.load(s->name);
3120 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3121 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3124 // Now allocate class name
3125 classNameRef.load(newClassName);
3127 obj->metadata = builder.toData();
3128 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3130 if (mode == IgnoreAliases && aliasCount)
3131 compileState->aliasingObjects.append(obj);
3133 obj->synthdata = dynamicData;
3135 if (obj->synthCache) {
3136 obj->synthCache->release();
3137 obj->synthCache = 0;
3140 if (obj->type != -1) {
3141 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3142 QQmlPropertyCache *cache =
3143 superCache->copyAndAppend(engine, &obj->extObject,
3144 QQmlPropertyData::NoFlags,
3145 QQmlPropertyData::IsVMEFunction,
3146 QQmlPropertyData::IsVMESignal);
3148 // now we modify the flags appropriately for var properties.
3149 int propertyOffset = obj->extObject.propertyOffset();
3150 QQmlPropertyData *currPropData = 0;
3151 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3152 currPropData = cache->property(pvi + propertyOffset);
3153 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3156 obj->synthCache = cache;
3162 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3165 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3167 QChar ch = val.at(0);
3168 if (ch.isLetter() && !ch.isLower())
3169 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3171 QChar u(QLatin1Char('_'));
3172 if (!ch.isLetter() && ch != u)
3173 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3175 for (int ii = 1; ii < val.count(); ++ii) {
3177 if (!ch.isLetterOrNumber() && ch != u)
3178 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3181 if (enginePrivate->v8engine()->illegalNames().contains(val))
3182 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3187 #include <private/qqmljsparser_p.h>
3189 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3191 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3193 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3194 return QStringList() << name;
3195 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3196 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3198 QStringList rv = astNodeToStringList(expr->base);
3201 rv.append(expr->name.toString());
3204 return QStringList();
3207 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3209 QQmlScript::Object *obj,
3210 int propIndex, int aliasIndex,
3211 Object::DynamicProperty &prop)
3213 Q_ASSERT(!prop.nameRef.isEmpty());
3214 if (!prop.defaultValue)
3215 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3217 if (!prop.defaultValue->values.isOne() ||
3218 prop.defaultValue->values.first()->object ||
3219 !prop.defaultValue->values.first()->value.isScript())
3220 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3222 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3224 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3226 QStringList alias = astNodeToStringList(node);
3228 if (alias.count() < 1 || alias.count() > 3)
3229 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3231 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3233 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3235 QByteArray typeName;
3240 bool writable = false;
3241 bool resettable = false;
3242 if (alias.count() == 2 || alias.count() == 3) {
3243 propIdx = indexOfProperty(idObject, alias.at(1));
3245 if (-1 == propIdx) {
3246 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3247 } else if (propIdx > 0xFFFF) {
3248 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3251 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3252 if (!aliasProperty.isScriptable())
3253 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3255 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3256 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3258 type = aliasProperty.userType();
3260 if (alias.count() == 3) {
3261 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3263 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3265 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3267 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3268 if (valueTypeIndex == -1)
3269 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3270 Q_ASSERT(valueTypeIndex <= 0xFF);
3272 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3273 propIdx |= (valueTypeIndex << 16);
3275 // update the property type
3276 type = aliasProperty.userType();
3279 if (aliasProperty.isEnumType())
3280 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3282 typeName = aliasProperty.typeName();
3284 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3286 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3288 typeName = ref.type->typeName();
3290 typeName = ref.component->root->className();
3295 if (typeName.endsWith('*'))
3296 flags |= QML_ALIAS_FLAG_PTR;
3298 if (type == QMetaType::UnknownType) {
3299 Q_ASSERT(!typeName.isEmpty());
3300 type = QMetaType::type(typeName);
3301 Q_ASSERT(type != QMetaType::UnknownType);
3302 Q_ASSERT(type != QMetaType::Void);
3305 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3307 typedef QQmlVMEMetaData VMD;
3308 VMD *vmd = (QQmlVMEMetaData *)data.data();
3309 *(vmd->aliasData() + aliasIndex) = aliasData;
3311 int propertyFlags = 0;
3313 propertyFlags |= QFastMetaBuilder::Writable;
3315 propertyFlags |= QFastMetaBuilder::Resettable;
3317 builder.setProperty(propIndex, prop.nameRef, type,
3318 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3324 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3325 QQmlScript::Property *prop,
3326 const BindingContext &ctxt)
3328 Q_ASSERT(prop->index != -1);
3329 Q_ASSERT(prop->parent);
3330 Q_ASSERT(prop->parent->metaObject());
3332 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3333 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3335 JSBindingReference *reference = pool->New<JSBindingReference>();
3336 reference->expression = value->value;
3337 reference->property = prop;
3338 reference->value = value;
3339 reference->bindingContext = ctxt;
3340 addBindingReference(reference);
3345 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3346 QQmlScript::Property *prop,
3347 const QQmlCompilerTypes::BindingContext &)
3349 Q_ASSERT(v->value.isScript());
3351 if (!prop->core.isWritable())
3354 AST::Node *binding = v->value.asAST();
3356 if (prop->type == QVariant::String) {
3357 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3358 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3359 if (i->name == qsTrId_string) {
3360 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3361 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3363 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3364 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3365 (!arg2 || !arg2->next)) {
3370 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3371 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3373 TrBindingReference *reference = pool->New<TrBindingReference>();
3374 reference->dataType = BindingReference::TrId;
3375 reference->text = text;
3377 v->bindingReference = reference;
3381 } else if (i->name == qsTr_string) {
3383 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3384 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3385 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3387 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3388 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3389 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3390 (!arg3 || !arg3->next)) {
3396 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3397 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3398 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3400 TrBindingReference *reference = pool->New<TrBindingReference>();
3401 reference->dataType = BindingReference::Tr;
3402 reference->text = text;
3403 reference->comment = comment;
3405 v->bindingReference = reference;
3418 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3419 QQmlScript::Property *prop,
3420 QQmlScript::Object *obj,
3421 QQmlScript::Property *valueTypeProperty)
3424 Q_ASSERT(binding->bindingReference);
3426 const BindingReference &ref = *binding->bindingReference;
3427 if (ref.dataType == BindingReference::TrId) {
3428 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3430 Instruction::StoreTrIdString store;
3431 store.propertyIndex = prop->core.coreIndex;
3432 store.text = output->indexForByteArray(tr.text.toUtf8());
3434 output->addInstruction(store);
3435 } else if (ref.dataType == BindingReference::Tr) {
3436 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3438 Instruction::StoreTrString store;
3439 store.propertyIndex = prop->core.coreIndex;
3440 store.context = translationContextIndex();
3441 store.text = output->indexForByteArray(tr.text.toUtf8());
3442 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3444 output->addInstruction(store);
3445 } else if (ref.dataType == BindingReference::V4) {
3446 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3448 Instruction::StoreV4Binding store;
3449 store.value = js.compiledIndex;
3450 store.context = js.bindingContext.stack;
3451 store.owner = js.bindingContext.owner;
3452 if (valueTypeProperty) {
3453 store.property = (valueTypeProperty->index & 0xFFFF) |
3454 ((valueTypeProperty->type & 0xFF)) << 16 |
3455 ((prop->index & 0xFF) << 24);
3456 store.isRoot = (compileState->root == valueTypeProperty->parent);
3458 store.property = prop->index;
3459 store.isRoot = (compileState->root == obj);
3461 store.line = binding->location.start.line;
3462 store.column = binding->location.start.column;
3463 output->addInstruction(store);
3464 } else if (ref.dataType == BindingReference::V8) {
3465 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3467 Instruction::StoreV8Binding store;
3468 store.value = js.compiledIndex;
3469 store.context = js.bindingContext.stack;
3470 store.owner = js.bindingContext.owner;
3471 if (valueTypeProperty) {
3472 store.isRoot = (compileState->root == valueTypeProperty->parent);
3474 store.isRoot = (compileState->root == obj);
3476 store.line = binding->location.start.line;
3477 store.column = binding->location.start.column;
3479 Q_ASSERT(js.bindingContext.owner == 0 ||
3480 (js.bindingContext.owner != 0 && valueTypeProperty));
3481 if (js.bindingContext.owner) {
3482 store.property = genValueTypeData(prop, valueTypeProperty);
3484 store.property = prop->core;
3487 output->addInstruction(store);
3488 } else if (ref.dataType == BindingReference::QtScript) {
3489 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3491 QQmlInstruction store;
3492 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3493 store.assignBinding.context = js.bindingContext.stack;
3494 store.assignBinding.owner = js.bindingContext.owner;
3495 store.assignBinding.line = binding->location.start.line;
3496 store.assignBinding.column = binding->location.start.column;
3498 if (valueTypeProperty) {
3499 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3501 store.assignBinding.isRoot = (compileState->root == obj);
3504 Q_ASSERT(js.bindingContext.owner == 0 ||
3505 (js.bindingContext.owner != 0 && valueTypeProperty));
3506 if (js.bindingContext.owner) {
3507 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3509 store.assignBinding.property = prop->core;
3511 output->addInstructionHelper(
3512 !prop->isAlias ? QQmlInstruction::StoreBinding
3513 : QQmlInstruction::StoreBindingOnAlias
3516 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3520 int QQmlCompiler::genContextCache()
3522 if (compileState->ids.count() == 0)
3525 QQmlIntegerCache *cache = new QQmlIntegerCache();
3526 cache->reserve(compileState->ids.count());
3527 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3528 cache->add(o->id, o->idIndex);
3530 output->contextCaches.append(cache);
3531 return output->contextCaches.count() - 1;
3535 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3536 QQmlScript::Property *prop)
3538 typedef QQmlPropertyPrivate QDPP;
3539 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3540 enginePrivate->valueTypes[prop->type]->metaObject(),
3541 valueTypeProp->index, engine);
3544 bool QQmlCompiler::completeComponentBuild()
3547 componentStats->componentStat.ids = compileState->ids.count();
3549 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3550 aliasObject = compileState->aliasingObjects.next(aliasObject))
3551 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3553 QV4Compiler::Expression expr(unit->imports());
3554 expr.component = compileState->root;
3555 expr.ids = &compileState->ids;
3556 expr.importCache = output->importCache;
3558 QV4Compiler bindingCompiler;
3560 QList<JSBindingReference*> sharedBindings;
3562 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3564 JSBindingReference &binding = *b;
3566 // ### We don't currently optimize for bindings on alias's - because
3567 // of the solution to QTBUG-13719
3568 if (!binding.property->isAlias) {
3569 expr.context = binding.bindingContext.object;
3570 expr.property = binding.property;
3571 expr.expression = binding.expression;
3573 int index = bindingCompiler.compile(expr, enginePrivate);
3575 binding.dataType = BindingReference::V4;
3576 binding.compiledIndex = index;
3578 componentStats->componentStat.optimizedBindings.append(b->value->location);
3583 // Pre-rewrite the expression
3584 QString expression = binding.expression.asScript();
3586 QQmlRewrite::RewriteBinding rewriteBinding;
3587 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3588 bool isSharable = false;
3589 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3591 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3592 binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3593 binding.dataType = BindingReference::V8;
3594 sharedBindings.append(b);
3597 componentStats->componentStat.sharedBindings.append(b->value->location);
3599 binding.dataType = BindingReference::QtScript;
3602 componentStats->componentStat.scriptBindings.append(b->value->location);
3606 if (!sharedBindings.isEmpty()) {
3608 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3610 return lhs->value->location.start.line < rhs->value->location.start.line;
3614 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3616 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3617 int lineNumber = startLineNumber;
3619 QByteArray functionArray("[", 1);
3620 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3622 JSBindingReference *reference = sharedBindings.at(ii);
3623 QQmlScript::Value *value = reference->value;
3624 const QString &expression = reference->rewrittenExpression;
3626 if (ii != 0) functionArray.append(",", 1);
3628 while (lineNumber < value->location.start.line) {
3630 functionArray.append("\n", 1);
3633 functionArray += expression.toUtf8();
3634 lineNumber += expression.count(QLatin1Char('\n'));
3635 reference->compiledIndex = ii;
3637 functionArray.append("]", 1);
3639 compileState->v8BindingProgram = functionArray;
3640 compileState->v8BindingProgramLine = startLineNumber;
3643 if (bindingCompiler.isValid())
3644 compileState->compiledBindingData = bindingCompiler.program();
3646 // Check pop()'s matched push()'s
3647 Q_ASSERT(compileState->objectDepth.depth() == 0);
3648 Q_ASSERT(compileState->listDepth.depth() == 0);
3650 saveComponentState();
3655 void QQmlCompiler::dumpStats()
3657 Q_ASSERT(componentStats);
3658 qWarning().nospace() << "QML Document: " << output->url.toString();
3659 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3660 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3661 qWarning().nospace() << " Component Line " << stat.lineNumber;
3662 qWarning().nospace() << " Total Objects: " << stat.objects;
3663 qWarning().nospace() << " IDs Used: " << stat.ids;
3664 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3668 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3669 if (0 == (ii % 10)) {
3670 if (ii) output.append("\n");
3675 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3677 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3678 output.append(") ");
3680 if (!output.isEmpty())
3681 qWarning().nospace() << output.constData();
3684 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3687 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3688 if (0 == (ii % 10)) {
3689 if (ii) output.append("\n");
3694 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3696 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3697 output.append(") ");
3699 if (!output.isEmpty())
3700 qWarning().nospace() << output.constData();
3703 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3706 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3707 if (0 == (ii % 10)) {
3708 if (ii) output.append("\n");
3713 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3715 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3716 output.append(") ");
3718 if (!output.isEmpty())
3719 qWarning().nospace() << output.constData();
3725 Returns true if from can be assigned to a (QObject) property of type
3728 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3730 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3731 const QMetaObject *fromMo = from->metaObject();
3734 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3736 fromMo = fromMo->superClass();
3742 Returns the element name, as written in the QML file, for o.
3744 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3747 if (o->type != -1) {
3748 return output->types.at(o->type).className;
3754 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3757 const QMetaObject *mo = from->metatype;
3759 while (!type && mo) {
3760 type = QQmlMetaType::qmlType(mo);
3761 mo = mo->superClass();
3766 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3768 const QMetaObject *mo = obj->metatype;
3770 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3772 return QStringList();
3774 QMetaClassInfo classInfo = mo->classInfo(idx);
3775 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3780 QQmlCompiler::property(QQmlScript::Object *object, int index)
3782 QQmlPropertyCache *cache = 0;
3784 if (object->synthCache)
3785 cache = object->synthCache;
3786 else if (object->type != -1)
3787 cache = output->types[object->type].createPropertyCache(engine);
3789 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3791 return cache->property(index);
3795 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3797 if (notInRevision) *notInRevision = false;
3799 QQmlPropertyCache *cache = 0;
3801 if (object->synthCache)
3802 cache = object->synthCache;
3803 else if (object->type != -1)
3804 cache = output->types[object->type].createPropertyCache(engine);
3806 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3808 QQmlPropertyData *d = cache->property(name);
3810 // Find the first property
3811 while (d && d->isFunction())
3812 d = cache->overrideData(d);
3814 if (d && !cache->isAllowedInRevision(d)) {
3815 if (notInRevision) *notInRevision = true;
3822 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3824 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3826 if (notInRevision) *notInRevision = false;
3828 QQmlPropertyCache *cache = 0;
3830 if (object->synthCache)
3831 cache = object->synthCache;
3832 else if (object->type != -1)
3833 cache = output->types[object->type].createPropertyCache(engine);
3835 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3838 QQmlPropertyData *d = cache->property(name);
3839 if (notInRevision) *notInRevision = false;
3841 while (d && !(d->isFunction()))
3842 d = cache->overrideData(d);
3844 if (d && !cache->isAllowedInRevision(d)) {
3845 if (notInRevision) *notInRevision = true;
3851 if (name.endsWith(Changed_string)) {
3852 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3854 d = property(object, propName, notInRevision);
3856 return cache->method(d->notifyIndex);
3862 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3863 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3864 bool *notInRevision)
3866 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3867 return d?d->coreIndex:-1;
3870 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3871 bool *notInRevision)
3873 return indexOfProperty(object, QStringRef(&name), notInRevision);
3876 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3877 bool *notInRevision)
3879 QQmlPropertyData *d = property(object, name, notInRevision);
3880 return d?d->coreIndex:-1;