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 "qqmlstringconverters_p.h"
48 #include "qqmlengine_p.h"
49 #include "qqmlengine.h"
50 #include "qqmlcontext.h"
51 #include "qqmlmetatype_p.h"
52 #include "qqmlcustomparser_p_p.h"
53 #include "qqmlcontext_p.h"
54 #include "qqmlcomponent_p.h"
55 #include <private/qqmljsast_p.h>
56 #include "qqmlvmemetaobject_p.h"
57 #include "qqmlexpression_p.h"
58 #include "qqmlproperty_p.h"
59 #include "qqmlrewrite_p.h"
60 #include "qqmlscriptstring.h"
61 #include "qqmlglobal_p.h"
62 #include "qqmlbinding_p.h"
63 #include <private/qv4compiler_p.h>
70 #include <QtCore/qdebug.h>
71 #include <QtCore/qdatetime.h>
72 #include <QtCore/qvarlengtharray.h>
74 Q_DECLARE_METATYPE(QList<int>)
75 Q_DECLARE_METATYPE(QList<qreal>)
76 Q_DECLARE_METATYPE(QList<bool>)
77 Q_DECLARE_METATYPE(QList<QString>)
78 Q_DECLARE_METATYPE(QList<QUrl>)
79 Q_DECLARE_METATYPE(QJSValue)
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_module_string(QLatin1String("QML"));
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, QQmlScript::Value *v)
221 const QQmlScript::Variant &value = v->value;
223 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
224 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
226 if (prop->core.isEnum()) {
227 QMetaProperty p = prop->parent->metatype->firstCppMetaObject()->property(prop->index);
230 if (p.isFlagType()) {
231 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
233 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
236 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
238 v->value = QQmlScript::Variant((double)enumValue);
242 int type = prop->type;
245 case QMetaType::QVariant:
247 case QVariant::String:
248 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
250 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
251 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
253 case QVariant::ByteArray:
254 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
257 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
259 case QVariant::RegExp:
260 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
264 bool ok = v->value.isNumber();
266 double n = v->value.asNumber();
267 if (double(uint(n)) != n)
270 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
275 bool ok = v->value.isNumber();
277 double n = v->value.asNumber();
278 if (double(int(n)) != n)
281 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
284 case QMetaType::Float:
285 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
287 case QVariant::Double:
288 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
290 case QVariant::Color:
293 QQmlStringConverters::colorFromString(value.asString(), &ok);
294 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
297 #ifndef QT_NO_DATESTRING
301 QQmlStringConverters::dateFromString(value.asString(), &ok);
302 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
308 QQmlStringConverters::timeFromString(value.asString(), &ok);
309 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
312 case QVariant::DateTime:
315 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
316 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
319 #endif // QT_NO_DATESTRING
320 case QVariant::Point:
321 case QVariant::PointF:
324 QQmlStringConverters::pointFFromString(value.asString(), &ok);
325 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
329 case QVariant::SizeF:
332 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
333 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
337 case QVariant::RectF:
340 QQmlStringConverters::rectFFromString(value.asString(), &ok);
341 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
346 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
349 case QVariant::Vector3D:
351 QQmlInstruction::instr_storeVector3D::QVector3D v3;
352 if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3)))
353 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
356 case QVariant::Vector4D:
358 QQmlInstruction::instr_storeVector4D::QVector4D v4;
359 if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4)))
360 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
365 // check if assigning a literal value to a list property.
366 // in each case, check the singular, since an Array of the specified type
367 // will not go via this literal assignment codepath.
368 if (type == qMetaTypeId<QList<qreal> >()) {
369 if (!v->value.isNumber()) {
370 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
373 } else if (type == qMetaTypeId<QList<int> >()) {
374 bool ok = v->value.isNumber();
376 double n = v->value.asNumber();
377 if (double(int(n)) != n)
380 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
382 } else if (type == qMetaTypeId<QList<bool> >()) {
383 if (!v->value.isBoolean()) {
384 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
387 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
388 if (!v->value.isString()) {
389 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
392 } else if (type == qMetaTypeId<QList<QUrl> >()) {
393 if (!v->value.isString()) {
394 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
397 } else if (type == qMetaTypeId<QJSValue>()) {
401 // otherwise, check for existence of string converter to custom type
402 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
404 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(type))));
412 Generate a store instruction for assigning literal \a v to property \a prop.
414 Any literal assignment that is approved in testLiteralAssignment() must have
415 a corresponding action in this method.
417 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
418 QQmlScript::Value *v)
420 if (prop->core.isEnum()) {
421 Q_ASSERT(v->value.isNumber());
423 int value = (int)v->value.asNumber();
425 Instruction::StoreInteger instr;
426 instr.propertyIndex = prop->index;
428 output->addInstruction(instr);
432 int type = prop->type;
434 case QMetaType::QVariant:
436 if (v->value.isNumber()) {
437 double n = v->value.asNumber();
438 if (double(int(n)) == n) {
439 if (prop->core.isVarProperty()) {
440 Instruction::StoreVarInteger instr;
441 instr.propertyIndex = prop->index;
442 instr.value = int(n);
443 output->addInstruction(instr);
445 Instruction::StoreVariantInteger instr;
446 instr.propertyIndex = prop->index;
447 instr.value = int(n);
448 output->addInstruction(instr);
451 if (prop->core.isVarProperty()) {
452 Instruction::StoreVarDouble instr;
453 instr.propertyIndex = prop->index;
455 output->addInstruction(instr);
457 Instruction::StoreVariantDouble instr;
458 instr.propertyIndex = prop->index;
460 output->addInstruction(instr);
463 } else if (v->value.isBoolean()) {
464 if (prop->core.isVarProperty()) {
465 Instruction::StoreVarBool instr;
466 instr.propertyIndex = prop->index;
467 instr.value = v->value.asBoolean();
468 output->addInstruction(instr);
470 Instruction::StoreVariantBool instr;
471 instr.propertyIndex = prop->index;
472 instr.value = v->value.asBoolean();
473 output->addInstruction(instr);
476 if (prop->core.isVarProperty()) {
477 Instruction::StoreVar instr;
478 instr.propertyIndex = prop->index;
479 instr.value = output->indexForString(v->value.asString());
480 output->addInstruction(instr);
482 Instruction::StoreVariant instr;
483 instr.propertyIndex = prop->index;
484 instr.value = output->indexForString(v->value.asString());
485 output->addInstruction(instr);
490 case QVariant::String:
492 Instruction::StoreString instr;
493 instr.propertyIndex = prop->index;
494 instr.value = output->indexForString(v->value.asString());
495 output->addInstruction(instr);
498 case QVariant::StringList:
500 Instruction::StoreStringList instr;
501 instr.propertyIndex = prop->index;
502 instr.value = output->indexForString(v->value.asString());
503 output->addInstruction(instr);
506 case QVariant::ByteArray:
508 Instruction::StoreByteArray instr;
509 instr.propertyIndex = prop->index;
510 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
511 output->addInstruction(instr);
516 Instruction::StoreUrl instr;
517 QString string = v->value.asString();
518 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
519 instr.propertyIndex = prop->index;
520 instr.value = output->indexForUrl(u);
521 output->addInstruction(instr);
526 Instruction::StoreInteger instr;
527 instr.propertyIndex = prop->index;
528 instr.value = uint(v->value.asNumber());
529 output->addInstruction(instr);
534 Instruction::StoreInteger instr;
535 instr.propertyIndex = prop->index;
536 instr.value = int(v->value.asNumber());
537 output->addInstruction(instr);
540 case QMetaType::Float:
542 Instruction::StoreFloat instr;
543 instr.propertyIndex = prop->index;
544 instr.value = float(v->value.asNumber());
545 output->addInstruction(instr);
548 case QVariant::Double:
550 Instruction::StoreDouble instr;
551 instr.propertyIndex = prop->index;
552 instr.value = v->value.asNumber();
553 output->addInstruction(instr);
556 case QVariant::Color:
558 Instruction::StoreColor instr;
559 instr.propertyIndex = prop->index;
560 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
561 output->addInstruction(instr);
564 #ifndef QT_NO_DATESTRING
567 Instruction::StoreDate instr;
568 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
569 instr.propertyIndex = prop->index;
570 instr.value = d.toJulianDay();
571 output->addInstruction(instr);
576 Instruction::StoreTime instr;
577 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
578 instr.propertyIndex = prop->index;
579 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
580 ::memcpy(&instr.time, &time, sizeof(QTime));
581 output->addInstruction(instr);
584 case QVariant::DateTime:
586 Instruction::StoreDateTime instr;
587 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
588 QTime time = dateTime.time();
589 instr.propertyIndex = prop->index;
590 instr.date = dateTime.date().toJulianDay();
591 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
592 ::memcpy(&instr.time, &time, sizeof(QTime));
593 output->addInstruction(instr);
596 #endif // QT_NO_DATESTRING
597 case QVariant::Point:
599 Instruction::StorePoint instr;
601 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
602 instr.propertyIndex = prop->index;
603 instr.point.xp = point.x();
604 instr.point.yp = point.y();
605 output->addInstruction(instr);
608 case QVariant::PointF:
610 Instruction::StorePointF instr;
612 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
613 instr.propertyIndex = prop->index;
614 instr.point.xp = point.x();
615 instr.point.yp = point.y();
616 output->addInstruction(instr);
621 Instruction::StoreSize instr;
623 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
624 instr.propertyIndex = prop->index;
625 instr.size.wd = size.width();
626 instr.size.ht = size.height();
627 output->addInstruction(instr);
630 case QVariant::SizeF:
632 Instruction::StoreSizeF instr;
634 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
635 instr.propertyIndex = prop->index;
636 instr.size.wd = size.width();
637 instr.size.ht = size.height();
638 output->addInstruction(instr);
643 Instruction::StoreRect instr;
645 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
646 instr.propertyIndex = prop->index;
647 instr.rect.x1 = rect.left();
648 instr.rect.y1 = rect.top();
649 instr.rect.x2 = rect.right();
650 instr.rect.y2 = rect.bottom();
651 output->addInstruction(instr);
654 case QVariant::RectF:
656 Instruction::StoreRectF instr;
658 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
659 instr.propertyIndex = prop->index;
660 instr.rect.xp = rect.left();
661 instr.rect.yp = rect.top();
662 instr.rect.w = rect.width();
663 instr.rect.h = rect.height();
664 output->addInstruction(instr);
669 Instruction::StoreBool instr;
670 bool b = v->value.asBoolean();
671 instr.propertyIndex = prop->index;
673 output->addInstruction(instr);
676 case QVariant::Vector3D:
678 Instruction::StoreVector3D instr;
679 instr.propertyIndex = prop->index;
680 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
681 output->addInstruction(instr);
684 case QVariant::Vector4D:
686 Instruction::StoreVector4D instr;
687 instr.propertyIndex = prop->index;
688 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
689 output->addInstruction(instr);
694 // generate single literal value assignment to a list property if required
695 if (type == qMetaTypeId<QList<qreal> >()) {
696 Instruction::StoreDoubleQList instr;
697 instr.propertyIndex = prop->index;
698 instr.value = v->value.asNumber();
699 output->addInstruction(instr);
701 } else if (type == qMetaTypeId<QList<int> >()) {
702 Instruction::StoreIntegerQList instr;
703 instr.propertyIndex = prop->index;
704 instr.value = int(v->value.asNumber());
705 output->addInstruction(instr);
707 } else if (type == qMetaTypeId<QList<bool> >()) {
708 Instruction::StoreBoolQList instr;
709 bool b = v->value.asBoolean();
710 instr.propertyIndex = prop->index;
712 output->addInstruction(instr);
714 } else if (type == qMetaTypeId<QList<QUrl> >()) {
715 Instruction::StoreUrlQList instr;
716 QString string = v->value.asString();
717 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
718 instr.propertyIndex = prop->index;
719 instr.value = output->indexForUrl(u);
720 output->addInstruction(instr);
722 } else if (type == qMetaTypeId<QList<QString> >()) {
723 Instruction::StoreStringQList instr;
724 instr.propertyIndex = prop->index;
725 instr.value = output->indexForString(v->value.asString());
726 output->addInstruction(instr);
728 } else if (type == qMetaTypeId<QJSValue>()) {
729 if (v->value.isBoolean()) {
730 Instruction::StoreJSValueBool instr;
731 instr.propertyIndex = prop->index;
732 instr.value = v->value.asBoolean();
733 output->addInstruction(instr);
734 } else if (v->value.isNumber()) {
735 double n = v->value.asNumber();
736 if (double(int(n)) == n) {
737 Instruction::StoreJSValueInteger instr;
738 instr.propertyIndex = prop->index;
739 instr.value = int(n);
740 output->addInstruction(instr);
742 Instruction::StoreJSValueDouble instr;
743 instr.propertyIndex = prop->index;
745 output->addInstruction(instr);
748 Instruction::StoreJSValueString instr;
749 instr.propertyIndex = prop->index;
750 instr.value = output->indexForString(v->value.asString());
751 output->addInstruction(instr);
756 // otherwise, generate custom type literal assignment
757 Instruction::AssignCustomType instr;
758 instr.propertyIndex = prop->index;
759 instr.primitive = output->indexForString(v->value.asString());
761 output->addInstruction(instr);
768 Resets data by clearing the lists that the QQmlCompiler modifies.
770 void QQmlCompiler::reset(QQmlCompiledData *data)
773 data->primitives.clear();
775 data->bytecode.resize(0);
779 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
780 with which the QQmlCompiledData will be associated.
782 Returns true on success, false on failure. On failure, the compile errors
783 are available from errors().
785 If the environment variant QML_COMPILER_DUMP is set
786 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
787 on a successful compiler.
789 bool QQmlCompiler::compile(QQmlEngine *engine,
791 QQmlCompiledData *out)
798 QQmlScript::Object *root = unit->parser().tree();
801 this->engine = engine;
802 this->enginePrivate = QQmlEnginePrivate::get(engine);
804 this->unitRoot = root;
808 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
809 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
811 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
812 QQmlCompiledData::TypeReference ref;
814 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
815 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
818 ref.type = tref.type;
819 if (!ref.type->isCreatable()) {
820 QString err = ref.type->noCreationReason();
822 err = tr( "Element is not creatable.");
823 COMPILE_EXCEPTION(parserRef->firstUse, err);
826 if (ref.type->containsRevisionedAttributes()) {
827 QQmlError cacheError;
828 ref.typePropertyCache = enginePrivate->cache(ref.type,
829 resolvedTypes.at(ii).minorVersion,
831 if (!ref.typePropertyCache)
832 COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
833 ref.typePropertyCache->addref();
836 } else if (tref.typeData) {
837 ref.component = tref.typeData->compiledData();
838 ref.component->addref();
847 out->dumpInstructions();
850 Q_ASSERT(out->rootPropertyCache);
858 this->enginePrivate = 0;
860 this->cachedComponentTypeRef = -1;
861 this->cachedTranslationContextIndex = -1;
867 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
869 compileState = pool->New<ComponentCompileState>();
871 compileState->root = tree;
873 componentStats->componentStat.lineNumber = tree->location.start.line;
875 // We generate the importCache before we build the tree so that
876 // it can be used in the binding compiler. Given we "expect" the
877 // QML compilation to succeed, this isn't a waste.
878 output->importCache = new QQmlTypeNameCache();
879 foreach (const QString &ns, unit->namespaces()) {
880 output->importCache->add(ns);
884 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
885 QString qualifier = script.qualifier;
886 QString enclosingNamespace;
888 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
889 if (lastDotIndex != -1) {
890 enclosingNamespace = qualifier.left(lastDotIndex);
891 qualifier = qualifier.mid(lastDotIndex+1);
894 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
897 unit->imports().populateCache(output->importCache, engine);
899 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
902 Instruction::Init init;
903 init.bindingsSize = compileState->totalBindingsCount;
904 init.parserStatusSize = compileState->parserStatusCount;
905 init.contextCache = genContextCache();
906 init.objectStackSize = compileState->objectDepth.maxDepth();
907 init.listStackSize = compileState->listDepth.maxDepth();
908 if (compileState->compiledBindingData.isEmpty())
909 init.compiledBinding = -1;
911 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
912 output->addInstruction(init);
914 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
915 Instruction::StoreImportedScript import;
916 import.value = output->scripts.count();
918 QQmlScriptData *scriptData = script.script->scriptData();
919 scriptData->addref();
920 output->scripts << scriptData;
921 output->addInstruction(import);
924 if (!compileState->v8BindingProgram.isEmpty()) {
925 Instruction::InitV8Bindings bindings;
926 int index = output->programs.count();
928 typedef QQmlCompiledData::V8Program V8Program;
929 output->programs.append(V8Program(compileState->v8BindingProgram, output));
931 bindings.programIndex = index;
932 bindings.line = compileState->v8BindingProgramLine;
933 output->addInstruction(bindings);
938 Instruction::SetDefault def;
939 output->addInstruction(def);
941 Instruction::Done done;
942 output->addInstruction(done);
944 Q_ASSERT(tree->metatype);
945 if (!tree->synthdata.isEmpty()) {
946 enginePrivate->registerCompositeType(output);
947 } else if (output->types.at(tree->type).component) {
948 output->metaTypeId = output->types.at(tree->type).component->metaTypeId;
949 output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId;
951 Q_ASSERT(output->types.at(tree->type).type);
952 output->metaTypeId = output->types.at(tree->type).type->typeId();
953 output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId();
955 if (!tree->synthdata.isEmpty())
956 enginePrivate->registerCompositeType(output);
959 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
961 for (int ii = 0; ii < list.count(); ++ii)
962 if (string == list.at(ii))
968 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
971 componentStats->componentStat.objects++;
973 Q_ASSERT (obj->type != -1);
974 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
975 obj->metatype = tr.createPropertyCache(engine);
977 // This object is a "Component" element.
978 if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
979 COMPILE_CHECK(buildComponent(obj, ctxt));
984 typedef QQmlInstruction I;
985 const I *init = ((const I *)tr.component->bytecode.constData());
986 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
988 // Adjust stack depths to include nested components
989 compileState->objectDepth.pushPop(init->init.objectStackSize);
990 compileState->listDepth.pushPop(init->init.listStackSize);
991 compileState->parserStatusCount += init->init.parserStatusSize;
992 compileState->totalBindingsCount += init->init.bindingsSize;
995 compileState->objectDepth.push();
997 // Object instantiations reset the binding context
998 BindingContext objCtxt(obj);
1000 // Create the synthesized meta object, ignoring aliases
1001 COMPILE_CHECK(checkDynamicMeta(obj));
1002 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
1003 COMPILE_CHECK(buildDynamicMeta(obj, Normal));
1005 // Find the native type and check for the QQmlParserStatus interface
1006 QQmlType *type = toQmlType(obj);
1008 obj->parserStatusCast = type->parserStatusCast();
1009 if (obj->parserStatusCast != -1)
1010 compileState->parserStatusCount++;
1012 // Check if this is a custom parser type. Custom parser types allow
1013 // assignments to non-existent properties. These assignments are then
1014 // compiled by the type.
1015 bool isCustomParser = output->types.at(obj->type).type &&
1016 output->types.at(obj->type).type->customParser() != 0;
1017 QList<QQmlCustomParserProperty> customProps;
1019 // Fetch the list of deferred properties
1020 QStringList deferredList = deferredProperties(obj);
1022 // Must do id property first. This is to ensure that the id given to any
1023 // id reference created matches the order in which the objects are
1025 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1026 if (prop->name() == id_string) {
1027 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1033 Property *defaultProperty = 0;
1034 Property *skipProperty = 0;
1035 if (obj->defaultProperty) {
1036 defaultProperty = obj->defaultProperty;
1038 Property *explicitProperty = 0;
1040 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1041 if (!defaultPropertyName.isEmpty()) {
1042 QString *s = pool->NewString(defaultPropertyName);
1043 QHashedStringRef r(*s);
1045 if (obj->propertiesHashField.test(r.hash())) {
1046 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1047 if (ep->name() == r) {
1048 explicitProperty = ep;
1054 if (!explicitProperty)
1055 defaultProperty->setName(r);
1058 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1060 skipProperty = explicitProperty; // We merge the values into defaultProperty
1062 // Find the correct insertion point
1063 Value *insertPos = 0;
1065 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1066 if (!(v->location.start < explicitProperty->values.first()->location.start))
1071 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1075 QQmlCustomParser *cp = 0;
1077 cp = output->types.at(obj->type).type->customParser();
1079 // Build all explicit properties specified
1080 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1082 if (prop == skipProperty)
1084 if (prop->name() == id_string)
1087 bool canDefer = false;
1088 if (isCustomParser) {
1089 if (doesPropertyExist(prop, obj) &&
1090 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1091 !isAttachedPropertyName(prop->name()))) {
1092 int ids = compileState->ids.count();
1093 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1094 canDefer = ids == compileState->ids.count();
1095 } else if (isSignalPropertyName(prop->name()) &&
1096 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1097 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1099 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1102 if (isSignalPropertyName(prop->name())) {
1103 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1105 int ids = compileState->ids.count();
1106 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1107 canDefer = ids == compileState->ids.count();
1111 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1112 prop->isDeferred = true;
1116 // Build the default property
1117 if (defaultProperty) {
1118 Property *prop = defaultProperty;
1120 bool canDefer = false;
1121 if (isCustomParser) {
1122 if (doesPropertyExist(prop, obj)) {
1123 int ids = compileState->ids.count();
1124 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1125 canDefer = ids == compileState->ids.count();
1127 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1130 int ids = compileState->ids.count();
1131 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1132 canDefer = ids == compileState->ids.count();
1135 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1136 prop->isDeferred = true;
1139 // Compile custom parser parts
1140 if (isCustomParser && !customProps.isEmpty()) {
1142 cp->compiler = this;
1144 obj->custom = cp->compile(customProps);
1147 foreach (QQmlError err, cp->errors()) {
1148 err.setUrl(output->url);
1153 compileState->objectDepth.pop();
1158 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1160 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1161 if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
1166 // Create the object
1167 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1168 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1170 Instruction::CreateSimpleObject create;
1171 create.create = output->types.at(obj->type).type->createFunction();
1172 create.typeSize = output->types.at(obj->type).type->createSize();
1173 create.type = obj->type;
1174 create.line = obj->location.start.line;
1175 create.column = obj->location.start.column;
1176 output->addInstruction(create);
1180 if (output->types.at(obj->type).type) {
1181 Instruction::CreateCppObject create;
1182 create.line = obj->location.start.line;
1183 create.column = obj->location.start.column;
1185 if (!obj->custom.isEmpty())
1186 create.data = output->indexForByteArray(obj->custom);
1187 create.type = obj->type;
1188 create.isRoot = (compileState->root == obj);
1189 output->addInstruction(create);
1191 Instruction::CreateQMLObject create;
1192 create.type = obj->type;
1193 create.isRoot = (compileState->root == obj);
1195 if (!obj->bindingBitmask.isEmpty()) {
1196 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1197 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1199 create.bindingBits = -1;
1201 output->addInstruction(create);
1203 Instruction::CompleteQMLObject complete;
1204 complete.line = obj->location.start.line;
1205 complete.column = obj->location.start.column;
1206 complete.isRoot = (compileState->root == obj);
1207 output->addInstruction(complete);
1211 // Setup the synthesized meta object if necessary
1212 if (!obj->synthdata.isEmpty()) {
1213 Instruction::StoreMetaObject meta;
1214 meta.aliasData = output->indexForByteArray(obj->synthdata);
1215 meta.propertyCache = output->propertyCaches.count();
1217 QQmlPropertyCache *propertyCache = obj->synthCache;
1218 Q_ASSERT(propertyCache);
1219 propertyCache->addref();
1221 if (obj == unitRoot) {
1222 propertyCache->addref();
1223 output->rootPropertyCache = propertyCache;
1226 output->propertyCaches << propertyCache;
1227 output->addInstruction(meta);
1228 } else if (obj == unitRoot) {
1229 output->rootPropertyCache = tr.createPropertyCache(engine);
1230 output->rootPropertyCache->addref();
1233 // Set the object id
1234 if (!obj->id.isEmpty()) {
1235 Instruction::SetId id;
1236 id.value = output->indexForString(obj->id);
1237 id.index = obj->idIndex;
1238 output->addInstruction(id);
1242 if (tr.type && obj->parserStatusCast != -1) {
1243 Instruction::BeginObject begin;
1244 begin.castValue = obj->parserStatusCast;
1245 output->addInstruction(begin);
1251 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1253 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1254 Q_ASSERT(prop->scriptStringScope != -1);
1255 const QString &script = prop->values.first()->value.asScript();
1256 Instruction::StoreScriptString ss;
1257 ss.propertyIndex = prop->index;
1258 ss.value = output->indexForString(script);
1259 ss.scope = prop->scriptStringScope;
1260 // ss.bindingId = rewriteBinding(script, prop->name());
1261 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1262 ss.line = prop->location.start.line;
1263 ss.column = prop->location.start.column;
1264 output->addInstruction(ss);
1267 bool seenDefer = false;
1268 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1269 if (prop->isDeferred) {
1274 genValueProperty(prop, obj);
1277 Instruction::Defer defer;
1278 defer.deferCount = 0;
1279 int deferIdx = output->addInstruction(defer);
1280 int nextInstructionIndex = output->nextInstructionIndex();
1282 Instruction::DeferInit dinit;
1283 // XXX - these are now massive over allocations
1284 dinit.bindingsSize = compileState->totalBindingsCount;
1285 dinit.parserStatusSize = compileState->parserStatusCount;
1286 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1287 dinit.listStackSize = compileState->listDepth.maxDepth();
1288 output->addInstruction(dinit);
1290 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1291 if (!prop->isDeferred)
1293 genValueProperty(prop, obj);
1296 Instruction::Done done;
1297 output->addInstruction(done);
1299 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1302 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1304 QQmlScript::Value *v = prop->values.first();
1306 if (v->type == Value::SignalObject) {
1308 genObject(v->object);
1310 Instruction::AssignSignalObject assign;
1311 assign.line = v->location.start.line;
1312 assign.signal = output->indexForString(prop->name().toString());
1313 output->addInstruction(assign);
1315 } else if (v->type == Value::SignalExpression) {
1317 Instruction::StoreSignal store;
1318 store.signalIndex = prop->index;
1319 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1320 store.value = output->indexForByteArray(rewrite.toUtf8());
1321 store.context = v->signalExpressionContextStack;
1322 store.line = v->location.start.line;
1323 store.column = v->location.start.column;
1324 output->addInstruction(store);
1330 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1331 Instruction::FetchAttached fetch;
1332 fetch.id = prop->index;
1333 fetch.line = prop->location.start.line;
1334 output->addInstruction(fetch);
1336 genObjectBody(prop->value);
1338 Instruction::PopFetchedObject pop;
1339 output->addInstruction(pop);
1342 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1343 Instruction::FetchObject fetch;
1344 fetch.property = prop->index;
1345 fetch.line = prop->location.start.line;
1346 output->addInstruction(fetch);
1348 if (!prop->value->synthdata.isEmpty()) {
1349 Instruction::StoreMetaObject meta;
1350 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1351 meta.propertyCache = output->propertyCaches.count();
1352 QQmlPropertyCache *propertyCache = prop->value->synthCache;
1353 Q_ASSERT(propertyCache);
1354 propertyCache->addref();
1355 output->propertyCaches << propertyCache;
1356 output->addInstruction(meta);
1359 genObjectBody(prop->value);
1361 Instruction::PopFetchedObject pop;
1362 output->addInstruction(pop);
1365 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1367 genValueTypeProperty(obj, prop);
1370 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1371 if (prop->isDeferred)
1374 genValueProperty(prop, obj);
1377 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1379 genValueTypeProperty(obj, prop);
1383 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1385 Instruction::FetchValueType fetch;
1386 fetch.property = prop->index;
1387 fetch.type = prop->type;
1388 fetch.bindingSkipList = 0;
1390 if (obj->type == -1 || output->types.at(obj->type).component) {
1391 // We only have to do this if this is a composite type. If it is a builtin
1392 // type it can't possibly already have bindings that need to be cleared.
1393 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1394 if (!vprop->values.isEmpty()) {
1395 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1396 fetch.bindingSkipList |= (1 << vprop->index);
1401 output->addInstruction(fetch);
1403 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1404 genPropertyAssignment(vprop, prop->value, prop);
1407 Instruction::PopValueType pop;
1408 pop.property = prop->index;
1409 pop.type = prop->type;
1410 pop.bindingSkipList = 0;
1411 output->addInstruction(pop);
1414 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1416 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1419 Instruction::CreateComponent create;
1420 create.line = root->location.start.line;
1421 create.column = root->location.start.column;
1422 create.endLine = root->location.end.line;
1423 create.isRoot = (compileState->root == obj);
1424 int createInstruction = output->addInstruction(create);
1425 int nextInstructionIndex = output->nextInstructionIndex();
1427 ComponentCompileState *oldCompileState = compileState;
1428 compileState = componentState(root);
1430 Instruction::Init init;
1431 init.bindingsSize = compileState->totalBindingsCount;
1432 init.parserStatusSize = compileState->parserStatusCount;
1433 init.contextCache = genContextCache();
1434 init.objectStackSize = compileState->objectDepth.maxDepth();
1435 init.listStackSize = compileState->listDepth.maxDepth();
1436 if (compileState->compiledBindingData.isEmpty())
1437 init.compiledBinding = -1;
1439 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1440 output->addInstruction(init);
1442 if (!compileState->v8BindingProgram.isEmpty()) {
1443 Instruction::InitV8Bindings bindings;
1444 int index = output->programs.count();
1446 typedef QQmlCompiledData::V8Program V8Program;
1447 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1449 bindings.programIndex = index;
1450 bindings.line = compileState->v8BindingProgramLine;
1451 output->addInstruction(bindings);
1456 Instruction::SetDefault def;
1457 output->addInstruction(def);
1459 Instruction::Done done;
1460 output->addInstruction(done);
1462 output->instruction(createInstruction)->createComponent.count =
1463 output->nextInstructionIndex() - nextInstructionIndex;
1465 compileState = oldCompileState;
1467 if (!obj->id.isEmpty()) {
1468 Instruction::SetId id;
1469 id.value = output->indexForString(obj->id);
1470 id.index = obj->idIndex;
1471 output->addInstruction(id);
1474 if (obj == unitRoot) {
1475 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1476 output->rootPropertyCache->addref();
1480 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1481 const BindingContext &ctxt)
1483 // The special "Component" element can only have the id property and a
1484 // default property, that actually defines the component's tree
1486 compileState->objectDepth.push();
1488 // Find, check and set the "id" property (if any)
1489 Property *idProp = 0;
1490 if (obj->properties.isMany() ||
1491 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1492 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1494 if (!obj->properties.isEmpty())
1495 idProp = obj->properties.first();
1498 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1499 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1500 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1502 QString idVal = idProp->values.first()->primitive();
1504 if (compileState->ids.value(idVal))
1505 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1511 // Check the Component tree is well formed
1512 if (obj->defaultProperty &&
1513 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1514 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1515 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1517 if (!obj->dynamicProperties.isEmpty())
1518 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1519 if (!obj->dynamicSignals.isEmpty())
1520 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1521 if (!obj->dynamicSlots.isEmpty())
1522 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1524 QQmlScript::Object *root = 0;
1525 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1526 root = obj->defaultProperty->values.first()->object;
1529 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1531 // Build the component tree
1532 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1534 compileState->objectDepth.pop();
1539 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1540 const BindingContext &ctxt)
1542 ComponentCompileState *oldComponentCompileState = compileState;
1543 compileState = pool->New<ComponentCompileState>();
1544 compileState->root = obj;
1545 compileState->nested = true;
1547 if (componentStats) {
1548 ComponentStat oldComponentStat = componentStats->componentStat;
1550 componentStats->componentStat = ComponentStat();
1551 componentStats->componentStat.lineNumber = obj->location.start.line;
1554 COMPILE_CHECK(buildObject(obj, ctxt));
1556 COMPILE_CHECK(completeComponentBuild());
1558 componentStats->componentStat = oldComponentStat;
1561 COMPILE_CHECK(buildObject(obj, ctxt));
1563 COMPILE_CHECK(completeComponentBuild());
1566 compileState = oldComponentCompileState;
1572 // Build a sub-object. A sub-object is one that was not created directly by
1573 // QML - such as a grouped property object, or an attached object. Sub-object's
1574 // can't have an id, involve a custom parser, have attached properties etc.
1575 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1577 Q_ASSERT(obj->metatype);
1578 Q_ASSERT(!obj->defaultProperty);
1579 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1582 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1583 if (isSignalPropertyName(prop->name())) {
1584 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1586 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1593 int QQmlCompiler::componentTypeRef()
1595 if (cachedComponentTypeRef == -1) {
1596 QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1597 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1598 if (output->types.at(ii).type == t) {
1599 cachedComponentTypeRef = ii;
1603 QQmlCompiledData::TypeReference ref;
1605 output->types << ref;
1606 cachedComponentTypeRef = output->types.count() - 1;
1608 return cachedComponentTypeRef;
1611 int QQmlCompiler::translationContextIndex()
1613 if (cachedTranslationContextIndex == -1) {
1614 // This code must match that in the qsTr() implementation
1615 const QString &path = output->name;
1616 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1617 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1619 QByteArray contextUtf8 = context.toUtf8();
1620 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1622 return cachedTranslationContextIndex;
1625 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1626 const BindingContext &ctxt)
1628 Q_ASSERT(obj->metatype);
1630 const QHashedStringRef &propName = prop->name();
1632 Q_ASSERT(propName.startsWith(on_string));
1633 QString name = propName.mid(2, -1).toString();
1635 // Note that the property name could start with any alpha or '_' or '$' character,
1636 // so we need to do the lower-casing of the first alpha character.
1637 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1638 if (name.at(firstAlphaIndex).isUpper()) {
1639 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1644 bool notInRevision = false;
1646 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1650 if (notInRevision && 0 == property(obj, propName, 0)) {
1651 Q_ASSERT(obj->type != -1);
1652 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1653 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1655 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));
1657 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1661 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1663 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1667 if (prop->value || !prop->values.isOne())
1668 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1670 prop->index = sig->coreIndex;
1673 obj->addSignalProperty(prop);
1675 if (prop->values.first()->object) {
1676 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1677 prop->values.first()->type = Value::SignalObject;
1679 prop->values.first()->type = Value::SignalExpression;
1681 if (!prop->values.first()->value.isScript())
1682 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1684 QString script = prop->values.first()->value.asScript().trimmed();
1685 if (script.isEmpty())
1686 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1688 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1697 Returns true if (value) property \a prop exists on obj, false otherwise.
1699 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1700 QQmlScript::Object *obj)
1702 if (prop->name().isEmpty())
1704 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1707 return property(obj, prop->name()) != 0;
1710 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1711 QQmlScript::Object *obj,
1712 const BindingContext &ctxt)
1714 if (prop->isEmpty())
1715 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1717 if (isAttachedPropertyName(prop->name())) {
1718 // Setup attached property data
1720 if (ctxt.isSubContext()) {
1721 // Attached properties cannot be used on sub-objects. Sub-objects
1722 // always exist in a binding sub-context, which is what we test
1724 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1728 QQmlImportNamespace *typeNamespace = 0;
1729 unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1731 if (typeNamespace) {
1732 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1735 } else if (!type || !type->attachedPropertiesType()) {
1736 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1740 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1742 Q_ASSERT(type->attachedPropertiesFunction());
1743 prop->index = type->attachedPropertiesId();
1744 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1746 // Setup regular property data
1747 bool notInRevision = false;
1748 QQmlPropertyData *d =
1749 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1751 if (d == 0 && notInRevision) {
1752 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1753 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1755 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));
1757 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1760 prop->index = d->coreIndex;
1762 } else if (prop->isDefault) {
1763 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1765 if (!defaultPropertyName.isEmpty()) {
1766 prop->setName(defaultPropertyName);
1767 prop->core = *obj->metatype->defaultProperty();
1768 prop->index = prop->core.coreIndex;
1772 // We can't error here as the "id" property does not require a
1773 // successful index resolution
1774 if (prop->index != -1)
1775 prop->type = prop->core.propType;
1777 // Check if this is an alias
1778 if (prop->index != -1 &&
1780 prop->parent->type != -1 &&
1781 output->types.at(prop->parent->type).component) {
1783 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1784 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1785 prop->isAlias = true;
1788 if (prop->index != -1 && !prop->values.isEmpty())
1789 prop->parent->setBindingBit(prop->index);
1792 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1794 // The magic "id" behavior doesn't apply when "id" is resolved as a
1795 // default property or to sub-objects (which are always in binding
1797 COMPILE_CHECK(buildIdProperty(prop, obj));
1798 if (prop->type == QVariant::String &&
1799 prop->values.first()->value.isString())
1800 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1802 } else if (isAttachedPropertyName(prop->name())) {
1804 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1806 } else if (prop->index == -1) {
1808 if (prop->isDefault) {
1809 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1811 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1814 } else if (prop->value) {
1816 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1818 } else if (prop->core.isQList()) {
1820 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1822 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1824 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1828 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1835 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1836 QQmlScript::Property *nsProp,
1837 QQmlScript::Object *obj,
1838 const BindingContext &ctxt)
1841 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1843 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1845 if (!isAttachedPropertyName(prop->name()))
1846 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1848 // Setup attached property data
1851 unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1853 if (!type || !type->attachedPropertiesType())
1854 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1857 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1859 Q_ASSERT(type->attachedPropertiesFunction());
1860 prop->index = type->index();
1861 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1863 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1869 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1870 QQmlScript::Object *obj)
1872 if (prop->core.isQList()) {
1873 genListProperty(prop, obj);
1875 genPropertyAssignment(prop, obj);
1879 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1880 QQmlScript::Object *obj)
1882 int listType = enginePrivate->listType(prop->type);
1884 Instruction::FetchQList fetch;
1885 fetch.property = prop->index;
1886 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1887 fetch.type = listType;
1888 output->addInstruction(fetch);
1890 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1892 if (v->type == Value::CreatedObject) {
1894 genObject(v->object);
1895 if (listTypeIsInterface) {
1896 Instruction::AssignObjectList assign;
1897 assign.line = prop->location.start.line;
1898 output->addInstruction(assign);
1900 Instruction::StoreObjectQList store;
1901 output->addInstruction(store);
1904 } else if (v->type == Value::PropertyBinding) {
1906 genBindingAssignment(v, prop, obj);
1912 Instruction::PopQList pop;
1913 output->addInstruction(pop);
1916 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1917 QQmlScript::Object *obj,
1918 QQmlScript::Property *valueTypeProperty)
1920 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1922 Q_ASSERT(v->type == Value::CreatedObject ||
1923 v->type == Value::PropertyBinding ||
1924 v->type == Value::Literal);
1926 if (v->type == Value::CreatedObject) {
1928 genObject(v->object);
1930 if (QQmlMetaType::isInterface(prop->type)) {
1932 Instruction::StoreInterface store;
1933 store.line = v->object->location.start.line;
1934 store.propertyIndex = prop->index;
1935 output->addInstruction(store);
1937 } else if (prop->type == QMetaType::QVariant) {
1939 if (prop->core.isVarProperty()) {
1940 Instruction::StoreVarObject store;
1941 store.line = v->object->location.start.line;
1942 store.propertyIndex = prop->index;
1943 output->addInstruction(store);
1945 Instruction::StoreVariantObject store;
1946 store.line = v->object->location.start.line;
1947 store.propertyIndex = prop->index;
1948 output->addInstruction(store);
1954 Instruction::StoreObject store;
1955 store.line = v->object->location.start.line;
1956 store.propertyIndex = prop->index;
1957 output->addInstruction(store);
1960 } else if (v->type == Value::PropertyBinding) {
1962 genBindingAssignment(v, prop, obj, valueTypeProperty);
1964 } else if (v->type == Value::Literal) {
1966 genLiteralAssignment(prop, v);
1972 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1974 Q_ASSERT(v->type == Value::ValueSource ||
1975 v->type == Value::ValueInterceptor);
1977 if (v->type == Value::ValueSource) {
1978 genObject(v->object);
1980 Instruction::StoreValueSource store;
1981 if (valueTypeProperty) {
1982 store.property = genValueTypeData(prop, valueTypeProperty);
1985 store.property = prop->core;
1988 QQmlType *valueType = toQmlType(v->object);
1989 store.castValue = valueType->propertyValueSourceCast();
1990 output->addInstruction(store);
1992 } else if (v->type == Value::ValueInterceptor) {
1993 genObject(v->object);
1995 Instruction::StoreValueInterceptor store;
1996 if (valueTypeProperty) {
1997 store.property = genValueTypeData(prop, valueTypeProperty);
2000 store.property = prop->core;
2003 QQmlType *valueType = toQmlType(v->object);
2004 store.castValue = valueType->propertyValueInterceptorCast();
2005 output->addInstruction(store);
2011 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2012 QQmlScript::Object *obj)
2015 prop->values.isMany() ||
2016 prop->values.first()->object)
2017 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2019 QQmlScript::Value *idValue = prop->values.first();
2020 QString val = idValue->primitive();
2022 COMPILE_CHECK(checkValidId(idValue, val));
2024 if (compileState->ids.value(val))
2025 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2027 prop->values.first()->type = Value::Id;
2035 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2038 Q_ASSERT(!compileState->ids.value(id));
2039 Q_ASSERT(obj->id == id);
2040 obj->idIndex = compileState->ids.count();
2041 compileState->ids.append(obj);
2044 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2046 Q_ASSERT(ref->value && !ref->value->bindingReference);
2047 ref->value->bindingReference = ref;
2048 compileState->totalBindingsCount++;
2049 compileState->bindings.prepend(ref);
2052 void QQmlCompiler::saveComponentState()
2054 Q_ASSERT(compileState->root);
2055 Q_ASSERT(compileState->root->componentCompileState == 0);
2057 compileState->root->componentCompileState = compileState;
2060 componentStats->savedComponentStats.append(componentStats->componentStat);
2063 QQmlCompilerTypes::ComponentCompileState *
2064 QQmlCompiler::componentState(QQmlScript::Object *obj)
2066 Q_ASSERT(obj->componentCompileState);
2067 return obj->componentCompileState;
2070 // Build attached property object. In this example,
2074 // GridView is an attached property object.
2075 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2076 QQmlScript::Object *obj,
2077 const BindingContext &ctxt)
2079 Q_ASSERT(prop->value);
2080 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2082 compileState->objectDepth.push();
2084 obj->addAttachedProperty(prop);
2086 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2088 compileState->objectDepth.pop();
2094 // Build "grouped" properties. In this example:
2096 // font.pointSize: 12
2097 // font.family: "Helvetica"
2099 // font is a nested property. pointSize and family are not.
2100 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2101 QQmlScript::Object *obj,
2102 const BindingContext &ctxt)
2104 Q_ASSERT(prop->type != 0);
2105 Q_ASSERT(prop->index != -1);
2107 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2108 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2110 if (!prop->values.isEmpty()) {
2111 if (prop->values.first()->location < prop->value->location) {
2112 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2114 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2118 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2119 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2123 if (prop->isAlias) {
2124 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2125 vtProp->isAlias = true;
2129 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2130 prop->value, obj, ctxt.incr()));
2131 obj->addValueTypeProperty(prop);
2133 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2137 // Load the nested property's meta type
2138 prop->value->metatype = enginePrivate->propertyCacheForType(prop->type);
2139 if (!prop->value->metatype)
2140 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2142 if (!prop->values.isEmpty())
2143 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2145 obj->addGroupedProperty(prop);
2147 compileState->objectDepth.push();
2149 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2151 compileState->objectDepth.pop();
2157 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2158 QQmlScript::Object *obj,
2159 QQmlScript::Object *baseObj,
2160 const BindingContext &ctxt)
2162 compileState->objectDepth.push();
2164 if (obj->defaultProperty)
2165 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2166 obj->metatype = enginePrivate->cache(type);
2168 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2170 QQmlPropertyData *d = property(obj, prop->name());
2172 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2174 prop->index = d->coreIndex;
2175 prop->type = d->propType;
2177 prop->isValueTypeSubProperty = true;
2180 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2182 if (prop->values.isMany()) {
2183 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2184 } else if (!prop->values.isEmpty()) {
2185 QQmlScript::Value *value = prop->values.first();
2187 if (value->object) {
2188 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2189 } else if (value->value.isScript()) {
2190 // ### Check for writability
2192 //optimization for <Type>.<EnumValue> enum assignments
2193 bool isEnumAssignment = false;
2195 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2196 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2198 if (isEnumAssignment) {
2199 value->type = Value::Literal;
2201 JSBindingReference *reference = pool->New<JSBindingReference>();
2202 reference->expression = value->value;
2203 reference->property = prop;
2204 reference->value = value;
2205 reference->bindingContext = ctxt;
2206 reference->bindingContext.owner++;
2207 addBindingReference(reference);
2208 value->type = Value::PropertyBinding;
2211 COMPILE_CHECK(testLiteralAssignment(prop, value));
2212 value->type = Value::Literal;
2216 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2217 Q_ASSERT(v->object);
2219 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2222 obj->addValueProperty(prop);
2225 compileState->objectDepth.pop();
2230 // Build assignments to QML lists. QML lists are properties of type
2231 // QQmlListProperty<T>. List properties can accept a list of
2232 // objects, or a single binding.
2233 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2234 QQmlScript::Object *obj,
2235 const BindingContext &ctxt)
2237 Q_ASSERT(prop->core.isQList());
2239 compileState->listDepth.push();
2243 obj->addValueProperty(prop);
2245 int listType = enginePrivate->listType(t);
2246 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2248 bool assignedBinding = false;
2249 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2251 v->type = Value::CreatedObject;
2252 COMPILE_CHECK(buildObject(v->object, ctxt));
2254 // We check object coercian here. We check interface assignment
2256 if (!listTypeIsInterface) {
2257 if (!canCoerce(listType, v->object)) {
2258 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2262 } else if (v->value.isScript()) {
2263 if (assignedBinding)
2264 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2266 assignedBinding = true;
2267 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2268 v->type = Value::PropertyBinding;
2270 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2274 compileState->listDepth.pop();
2279 // Compiles an assignment to a QQmlScriptString property
2280 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2281 QQmlScript::Object *obj,
2282 const BindingContext &ctxt)
2284 if (prop->values.isMany())
2285 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2287 if (prop->values.first()->object)
2288 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2290 prop->scriptStringScope = ctxt.stack;
2291 obj->addScriptStringProperty(prop);
2296 // Compile regular property assignments of the form "property: <value>"
2297 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2298 QQmlScript::Object *obj,
2299 const BindingContext &ctxt)
2301 obj->addValueProperty(prop);
2303 if (prop->values.isMany())
2304 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2306 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2309 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2313 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2318 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2319 Q_ASSERT(v->object);
2320 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2326 // Compile assigning a single object instance to a regular property
2327 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2328 QQmlScript::Object *obj,
2329 QQmlScript::Value *v,
2330 const BindingContext &ctxt)
2332 Q_ASSERT(prop->index != -1);
2333 Q_ASSERT(v->object->type != -1);
2335 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2336 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2338 if (QQmlMetaType::isInterface(prop->type)) {
2340 // Assigning an object to an interface ptr property
2341 COMPILE_CHECK(buildObject(v->object, ctxt));
2343 v->type = Value::CreatedObject;
2345 } else if (prop->type == QMetaType::QVariant) {
2347 // Assigning an object to a QVariant
2348 COMPILE_CHECK(buildObject(v->object, ctxt));
2350 v->type = Value::CreatedObject;
2352 // Normally buildObject() will set this up, but we need the static
2353 // meta object earlier to test for assignability. It doesn't matter
2354 // that there may still be outstanding synthesized meta object changes
2355 // on this type, as they are not relevant for assignability testing
2356 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2357 Q_ASSERT(v->object->metatype);
2359 // We want to raw metaObject here as the raw metaobject is the
2360 // actual property type before we applied any extensions that might
2361 // effect the properties on the type, but don't effect assignability
2362 QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type);
2364 // Will be true if the assgned type inherits propertyMetaObject
2365 bool isAssignable = false;
2366 // Determine isAssignable value
2367 if (propertyMetaObject) {
2368 QQmlPropertyCache *c = v->object->metatype;
2369 while (c && !isAssignable) {
2370 isAssignable |= c == propertyMetaObject;
2376 // Simple assignment
2377 COMPILE_CHECK(buildObject(v->object, ctxt));
2379 v->type = Value::CreatedObject;
2380 } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) {
2381 // Automatic "Component" insertion
2382 QQmlScript::Object *root = v->object;
2383 QQmlScript::Object *component = pool->New<Object>();
2384 component->type = componentTypeRef();
2385 component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject);
2386 component->location = root->location;
2387 QQmlScript::Value *componentValue = pool->New<Value>();
2388 componentValue->object = root;
2389 component->getDefaultProperty()->addValue(componentValue);
2390 v->object = component;
2391 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2393 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2400 // Compile assigning a single object instance to a regular property using the "on" syntax.
2404 // NumberAnimation on x { }
2406 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2407 QQmlScript::Object *obj,
2408 QQmlScript::Object *baseObj,
2409 QQmlScript::Value *v,
2410 const BindingContext &ctxt)
2412 Q_ASSERT(prop->index != -1);
2413 Q_ASSERT(v->object->type != -1);
2417 if (!prop->core.isWritable())
2418 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2421 // Normally buildObject() will set this up, but we need the static
2422 // meta object earlier to test for assignability. It doesn't matter
2423 // that there may still be outstanding synthesized meta object changes
2424 // on this type, as they are not relevant for assignability testing
2425 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2426 Q_ASSERT(v->object->metatype);
2428 // Will be true if the assigned type inherits QQmlPropertyValueSource
2429 bool isPropertyValue = false;
2430 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2431 bool isPropertyInterceptor = false;
2432 if (QQmlType *valueType = toQmlType(v->object)) {
2433 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2434 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2437 if (isPropertyValue || isPropertyInterceptor) {
2438 // Assign as a property value source
2439 COMPILE_CHECK(buildObject(v->object, ctxt));
2441 if (isPropertyInterceptor && baseObj->synthdata.isEmpty())
2442 buildDynamicMeta(baseObj, ForceCreation);
2443 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2445 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2451 // Compile assigning a literal or binding to a regular property
2452 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2453 QQmlScript::Object *obj,
2454 QQmlScript::Value *v,
2455 const BindingContext &ctxt)
2457 Q_ASSERT(prop->index != -1);
2459 if (v->value.isScript()) {
2461 //optimization for <Type>.<EnumValue> enum assignments
2462 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2463 bool isEnumAssignment = false;
2464 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2465 if (isEnumAssignment) {
2466 v->type = Value::Literal;
2471 // Test for other binding optimizations
2472 if (!buildLiteralBinding(v, prop, ctxt))
2473 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2475 v->type = Value::PropertyBinding;
2479 COMPILE_CHECK(testLiteralAssignment(prop, v));
2481 v->type = Value::Literal;
2487 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2488 QQmlScript::Object *obj,
2489 QQmlScript::Value *v,
2492 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2493 *isAssignment = false;
2494 if (!prop->core.isEnum() && !isIntProp)
2497 QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2499 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2500 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2502 QString string = v->value.asString();
2503 if (!string.at(0).isUpper())
2506 int dot = string.indexOf(QLatin1Char('.'));
2507 if (dot == -1 || dot == string.length()-1)
2510 if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2513 QHashedStringRef typeName(string.constData(), dot);
2514 QString enumValue = string.mid(dot+1);
2517 // Allow enum assignment to ints.
2518 int enumval = evaluateEnum(typeName, enumValue.toUtf8());
2519 if (enumval != -1) {
2520 v->type = Value::Literal;
2521 v->value = QQmlScript::Variant((double)enumval);
2522 *isAssignment = true;
2528 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2536 if (toQmlType(obj) == type) {
2537 // When these two match, we can short cut the search
2538 if (mprop.isFlagType()) {
2539 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2541 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2544 // Otherwise we have to search the whole type
2545 // This matches the logic in QV8TypeWrapper
2546 QByteArray enumName = enumValue.toUtf8();
2547 const QMetaObject *metaObject = type->baseMetaObject();
2549 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2550 QMetaEnum e = metaObject->enumerator(ii);
2551 value = e.keyToValue(enumName.constData(), &ok);
2558 v->type = Value::Literal;
2559 v->value = QQmlScript::Variant((double)value);
2560 *isAssignment = true;
2565 struct StaticQtMetaObject : public QObject
2567 static const QMetaObject *get()
2568 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2571 // Similar logic to above, but not knowing target property.
2572 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const
2575 if (scope != QLatin1String("Qt")) {
2576 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2581 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2582 int i = mo->enumeratorCount();
2585 int v = mo->enumerator(i).keyToValue(enumValue.constData(), &ok);
2592 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2594 QQmlType *qmltype = 0;
2595 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2599 return qmltype->metaObject();
2602 // similar to logic of completeComponentBuild, but also sticks data
2603 // into primitives at the end
2604 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2606 QQmlRewrite::RewriteBinding rewriteBinding;
2607 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2609 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2611 return output->indexForString(rewrite);
2614 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2616 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2617 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2620 // Ensures that the dynamic meta specification on obj is valid
2621 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2623 bool seenDefaultProperty = false;
2625 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2626 // Calculating the hash for the names is not a waste as we have to test
2627 // them against the illegalNames set anyway.
2628 QHashField propNames;
2629 QHashField methodNames;
2632 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2633 const QQmlScript::Object::DynamicProperty &prop = *p;
2635 if (prop.isDefaultProperty) {
2636 if (seenDefaultProperty)
2637 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2638 seenDefaultProperty = true;
2641 if (propNames.testAndSet(prop.name.hash())) {
2642 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2643 p2 = obj->dynamicProperties.next(p2)) {
2644 if (p2->name == prop.name) {
2645 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2646 prop.nameLocation.column,
2647 tr("Duplicate property name"));
2652 if (prop.name.at(0).isUpper()) {
2653 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2654 prop.nameLocation.column,
2655 tr("Property names cannot begin with an upper case letter"));
2658 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2659 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2660 prop.nameLocation.column,
2661 tr("Illegal property name"));
2665 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2666 const QQmlScript::Object::DynamicSignal &currSig = *s;
2668 if (methodNames.testAndSet(currSig.name.hash())) {
2669 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2670 s2 = obj->dynamicSignals.next(s2)) {
2671 if (s2->name == currSig.name)
2672 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2676 if (currSig.name.at(0).isUpper())
2677 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2678 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2679 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2682 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2683 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2685 if (methodNames.testAndSet(currSlot.name.hash())) {
2686 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2687 s2 = obj->dynamicSignals.next(s2)) {
2688 if (s2->name == currSlot.name)
2689 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2691 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2692 s2 = obj->dynamicSlots.next(s2)) {
2693 if (s2->name == currSlot.name)
2694 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2698 if (currSlot.name.at(0).isUpper())
2699 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2700 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2701 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2707 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2709 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2710 p = obj->dynamicProperties.next(p)) {
2712 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2715 Property *property = 0;
2716 if (p->isDefaultProperty) {
2717 property = obj->getDefaultProperty();
2719 property = obj->getProperty(p->name);
2720 if (!property->values.isEmpty())
2721 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2725 property->isReadOnlyDeclaration = true;
2727 if (property->value)
2728 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2730 property->values.append(p->defaultValue->values);
2735 #include <private/qqmljsparser_p.h>
2737 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2739 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2741 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2742 return QStringList() << name;
2743 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2744 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2746 QStringList rv = astNodeToStringList(expr->base);
2749 rv.append(expr->name.toString());
2752 return QStringList();
2755 static QAtomicInt classIndexCounter(0);
2757 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2760 Q_ASSERT(obj->metatype);
2762 if (mode != ForceCreation &&
2763 obj->dynamicProperties.isEmpty() &&
2764 obj->dynamicSignals.isEmpty() &&
2765 obj->dynamicSlots.isEmpty())
2768 Q_ASSERT(obj->synthCache == 0);
2771 Object::DynamicProperty::Type dtype;
2773 } builtinTypes[] = {
2774 { Object::DynamicProperty::Var, QMetaType::QVariant },
2775 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2776 { Object::DynamicProperty::Int, QMetaType::Int },
2777 { Object::DynamicProperty::Bool, QMetaType::Bool },
2778 { Object::DynamicProperty::Real, QMetaType::Double },
2779 { Object::DynamicProperty::String, QMetaType::QString },
2780 { Object::DynamicProperty::Url, QMetaType::QUrl },
2781 { Object::DynamicProperty::Color, QMetaType::QColor },
2782 { Object::DynamicProperty::Time, QMetaType::QTime },
2783 { Object::DynamicProperty::Date, QMetaType::QDate },
2784 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2785 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2787 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2789 QByteArray newClassName;
2791 if (compileState->root == obj && !compileState->nested) {
2792 QString path = output->url.path();
2793 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2794 if (lastSlash > -1) {
2795 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2796 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2797 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2798 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2801 if (newClassName.isEmpty()) {
2802 newClassName = QQmlMetaObject(obj->metatype).className();
2803 newClassName.append("_QML_");
2804 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2806 QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2807 obj->dynamicProperties.count() +
2808 obj->dynamicSignals.count() +
2809 obj->dynamicSlots.count(),
2810 obj->dynamicProperties.count() +
2811 obj->dynamicSignals.count());
2813 cache->_dynamicClassName = newClassName;
2815 int cStringNameCount = 0;
2818 int varPropCount = 0;
2820 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2821 p = obj->dynamicProperties.next(p)) {
2823 if (p->type == Object::DynamicProperty::Alias)
2825 else if (p->type == Object::DynamicProperty::Var)
2828 if (p->name.isLatin1()) {
2829 p->nameIndex = cStringNameCount;
2830 cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2833 // No point doing this for both the alias and non alias cases
2834 QQmlPropertyData *d = property(obj, p->name);
2835 if (d && d->isFinal())
2836 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2839 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2840 if (s->name.isLatin1()) {
2841 s->nameIndex = cStringNameCount;
2842 cStringNameCount += s->name.length();
2846 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2847 if (s->name.isLatin1()) {
2848 s->nameIndex = cStringNameCount;
2849 cStringNameCount += s->name.length();
2853 char *cStringData = 0;
2854 if (cStringNameCount) {
2855 cache->_dynamicStringData.resize(cStringNameCount);
2856 cStringData = cache->_dynamicStringData.data();
2858 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2859 p = obj->dynamicProperties.next(p)) {
2861 if (p->nameIndex == -1) continue;
2863 char *myData = cStringData + p->nameIndex;
2864 for (int ii = 0; ii < p->name.length(); ++ii)
2865 *myData++ = p->name.at(ii).unicode();
2866 *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2867 *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2870 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2872 if (s->nameIndex == -1) continue;
2874 char *myData = cStringData + s->nameIndex;
2875 for (int ii = 0; ii < s->name.length(); ++ii)
2876 *myData++ = s->name.at(ii).unicode();
2879 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2880 s = obj->dynamicSignals.next(s)) {
2882 if (s->nameIndex == -1) continue;
2884 char *myData = cStringData + s->nameIndex;
2885 for (int ii = 0; ii < s->name.length(); ++ii)
2886 *myData++ = s->name.at(ii).unicode();
2890 QByteArray dynamicData;
2891 typedef QQmlVMEMetaData VMD;
2893 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2894 obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2895 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2896 aliasCount * sizeof(VMD::AliasData), 0);
2898 int effectivePropertyIndex = cache->propertyIndexCacheStart;
2899 int effectiveMethodIndex = cache->methodIndexCacheStart;
2901 // First set up notify signals for properties - first normal, then var, then alias
2902 enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2903 for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2905 if (ii == NSS_Var && varPropCount == 0) continue;
2906 else if (ii == NSS_Alias && aliasCount == 0) continue;
2908 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2909 p = obj->dynamicProperties.next(p)) {
2911 if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2912 p->type == Object::DynamicProperty::Var)) ||
2913 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2914 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2917 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2918 QQmlPropertyData::IsVMESignal;
2920 if (p->nameIndex != -1) {
2921 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2922 p->name.length() + 7 /* strlen("Changed") */);
2923 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2925 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2927 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2933 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2934 int paramCount = s->parameterNames.count();
2936 QList<QByteArray> names;
2937 QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2940 paramTypes[0] = paramCount;
2942 for (int i = 0; i < paramCount; ++i) {
2943 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2944 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2945 names.append(s->parameterNames.at(i).toString().toUtf8());
2949 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2951 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2952 QQmlPropertyData::IsVMESignal;
2954 flags |= QQmlPropertyData::HasArguments;
2956 if (s->nameIndex != -1) {
2957 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2958 cache->appendSignal(name, flags, effectiveMethodIndex++,
2959 paramCount?paramTypes.constData():0, names);
2961 QString name = s->name.toString();
2962 cache->appendSignal(name, flags, effectiveMethodIndex++,
2963 paramCount?paramTypes.constData():0, names);
2969 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2970 int paramCount = s->parameterNames.count();
2972 quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
2975 flags |= QQmlPropertyData::HasArguments;
2977 if (s->nameIndex != -1) {
2978 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2979 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2981 QString name = s->name.toString();
2982 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2987 // Dynamic properties (except var and aliases)
2988 effectiveMethodIndex = cache->methodIndexCacheStart;
2989 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2990 p = obj->dynamicProperties.next(p)) {
2992 if (p->type == Object::DynamicProperty::Alias ||
2993 p->type == Object::DynamicProperty::Var)
2996 int propertyType = 0;
2997 int vmePropertyType = 0;
2998 quint32 propertyFlags = 0;
3000 if (p->type < builtinTypeCount) {
3001 propertyType = builtinTypes[p->type].metaType;
3002 vmePropertyType = propertyType;
3004 if (p->type == Object::DynamicProperty::Variant)
3005 propertyFlags |= QQmlPropertyData::IsQVariant;
3007 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3008 p->type == Object::DynamicProperty::Custom);
3010 QQmlType *qmltype = 0;
3012 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3013 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3016 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3018 Q_ASSERT(tdata->isComplete());
3020 QQmlCompiledData *data = tdata->compiledData();
3022 if (p->type == Object::DynamicProperty::Custom) {
3023 propertyType = data->metaTypeId;
3024 vmePropertyType = QMetaType::QObjectStar;
3026 propertyType = data->listMetaTypeId;
3027 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3032 if (p->type == Object::DynamicProperty::Custom) {
3033 propertyType = qmltype->typeId();
3034 vmePropertyType = QMetaType::QObjectStar;
3036 propertyType = qmltype->qListTypeId();
3037 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3041 if (p->type == Object::DynamicProperty::Custom)
3042 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3044 propertyFlags |= QQmlPropertyData::IsQList;
3047 if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3048 propertyFlags |= QQmlPropertyData::IsWritable;
3050 if (p->nameIndex != -1) {
3051 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3053 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3054 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3055 propertyType, effectiveMethodIndex);
3057 QString propertyName = p->name.toString();
3058 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3059 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3060 propertyType, effectiveMethodIndex);
3063 effectiveMethodIndex++;
3065 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3066 (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3067 vmd->propertyCount++;
3070 // Now do var properties
3071 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3072 p = obj->dynamicProperties.next(p)) {
3074 if (p->type != Object::DynamicProperty::Var)
3077 quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3079 propertyFlags |= QQmlPropertyData::IsWritable;
3081 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3082 (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3083 vmd->propertyCount++;
3084 ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3086 if (p->nameIndex != -1) {
3087 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3089 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3090 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3091 QMetaType::QVariant, effectiveMethodIndex);
3093 QString propertyName = p->name.toString();
3094 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3095 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3096 QMetaType::QVariant, effectiveMethodIndex);
3099 effectiveMethodIndex++;
3102 // Alias property count. Actual data is setup in buildDynamicMetaAliases
3103 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3105 // Dynamic slot data - comes after the property data
3106 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3107 int paramCount = s->parameterNames.count();
3111 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3112 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3113 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3114 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3115 for (int jj = 0; jj < paramCount; ++jj) {
3116 if (jj) funcScript.append(QLatin1Char(','));
3117 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3119 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3121 QByteArray utf8 = funcScript.toUtf8();
3122 VMD::MethodData methodData = { s->parameterNames.count(),
3125 s->location.start.line };
3127 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3128 VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3132 dynamicData.append((const char *)utf8.constData(), utf8.length());
3136 compileState->aliasingObjects.append(obj);
3138 obj->synthdata = dynamicData;
3139 obj->synthCache = cache;
3140 obj->metatype = cache;
3145 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3147 Q_ASSERT(obj->synthCache);
3149 QByteArray &dynamicData = obj->synthdata;
3151 QQmlPropertyCache *cache = obj->synthCache;
3152 char *cStringData = cache->_dynamicStringData.data();
3154 int effectiveMethodIndex = cache->methodIndexCacheStart + cache->propertyIndexCache.count();
3155 int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3156 int effectiveAliasIndex = 0;
3158 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3159 p = obj->dynamicProperties.next(p)) {
3161 if (p->type != Object::DynamicProperty::Alias)
3164 if (!p->defaultValue)
3165 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3167 if (!p->defaultValue->values.isOne() ||
3168 p->defaultValue->values.first()->object ||
3169 !p->defaultValue->values.first()->value.isScript())
3170 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3172 QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3175 QStringList alias = astNodeToStringList(node);
3176 if (alias.count() < 1 || alias.count() > 3)
3177 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3179 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3181 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3184 int notifySignal = -1;
3187 bool writable = false;
3188 bool resettable = false;
3190 quint32 propertyFlags = QQmlPropertyData::IsAlias;
3192 if (alias.count() == 2 || alias.count() == 3) {
3193 QQmlPropertyData *property = this->property(idObject, alias.at(1));
3195 if (!property || property->coreIndex > 0xFFFF)
3196 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3198 propIdx = property->coreIndex;
3199 type = property->propType;
3201 writable = property->isWritable();
3202 resettable = property->isResettable();
3203 notifySignal = property->notifyIndex;
3205 if (alias.count() == 3) {
3206 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3208 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3210 propIdx |= ((unsigned int)type) << 24;
3211 int valueTypeIndex =
3212 valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3213 if (valueTypeIndex == -1)
3214 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3215 Q_ASSERT(valueTypeIndex <= 0xFF);
3217 propIdx |= (valueTypeIndex << 16);
3218 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3219 type = QVariant::Int;
3221 type = valueType->metaObject()->property(valueTypeIndex).userType();
3224 if (property->isEnum()) {
3225 type = QVariant::Int;
3228 propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3230 if (property->isVarProperty())
3231 propertyFlags |= QQmlPropertyData::IsQVariant;
3233 if (property->isQObject())
3234 flags |= QML_ALIAS_FLAG_PTR;
3238 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3240 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3242 type = ref.type->typeId();
3244 type = ref.component->metaTypeId;
3246 flags |= QML_ALIAS_FLAG_PTR;
3247 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3250 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3252 typedef QQmlVMEMetaData VMD;
3253 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3254 *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3256 if (!p->isReadOnly && writable)
3257 propertyFlags |= QQmlPropertyData::IsWritable;
3259 propertyFlags &= ~QQmlPropertyData::IsWritable;
3262 propertyFlags |= QQmlPropertyData::IsResettable;
3264 propertyFlags &= ~QQmlPropertyData::IsResettable;
3266 if (p->nameIndex != -1) {
3267 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3269 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3270 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3271 type, effectiveMethodIndex++);
3273 QString propertyName = p->name.toString();
3274 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3275 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3276 type, effectiveMethodIndex++);
3283 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3286 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3288 QChar ch = val.at(0);
3289 if (ch.isLetter() && !ch.isLower())
3290 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3292 QChar u(QLatin1Char('_'));
3293 if (!ch.isLetter() && ch != u)
3294 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3296 for (int ii = 1; ii < val.count(); ++ii) {
3298 if (!ch.isLetterOrNumber() && ch != u)
3299 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3302 if (enginePrivate->v8engine()->illegalNames().contains(val))
3303 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3308 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3309 QQmlScript::Property *prop,
3310 const BindingContext &ctxt)
3312 Q_ASSERT(prop->index != -1);
3313 Q_ASSERT(prop->parent);
3314 Q_ASSERT(prop->parent->metatype);
3316 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3317 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3319 JSBindingReference *reference = pool->New<JSBindingReference>();
3320 reference->expression = value->value;
3321 reference->property = prop;
3322 reference->value = value;
3323 reference->bindingContext = ctxt;
3324 addBindingReference(reference);
3329 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3330 QQmlScript::Property *prop,
3331 const QQmlCompilerTypes::BindingContext &)
3333 Q_ASSERT(v->value.isScript());
3335 if (!prop->core.isWritable())
3338 AST::Node *binding = v->value.asAST();
3340 if (prop->type == QVariant::String) {
3341 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3342 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3343 if (i->name == qsTrId_string) {
3344 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3345 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3347 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3348 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3349 (!arg2 || !arg2->next)) {
3354 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3355 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3357 TrBindingReference *reference = pool->New<TrBindingReference>();
3358 reference->dataType = BindingReference::TrId;
3359 reference->text = text;
3361 v->bindingReference = reference;
3365 } else if (i->name == qsTr_string) {
3367 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3368 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3369 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3371 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3372 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3373 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3374 (!arg3 || !arg3->next)) {
3380 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3381 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3382 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3384 TrBindingReference *reference = pool->New<TrBindingReference>();
3385 reference->dataType = BindingReference::Tr;
3386 reference->text = text;
3387 reference->comment = comment;
3389 v->bindingReference = reference;
3402 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3403 QQmlScript::Property *prop,
3404 QQmlScript::Object *obj,
3405 QQmlScript::Property *valueTypeProperty)
3408 Q_ASSERT(binding->bindingReference);
3410 const BindingReference &ref = *binding->bindingReference;
3411 if (ref.dataType == BindingReference::TrId) {
3412 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3414 Instruction::StoreTrIdString store;
3415 store.propertyIndex = prop->core.coreIndex;
3416 store.text = output->indexForByteArray(tr.text.toUtf8());
3418 output->addInstruction(store);
3419 } else if (ref.dataType == BindingReference::Tr) {
3420 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3422 Instruction::StoreTrString store;
3423 store.propertyIndex = prop->core.coreIndex;
3424 store.context = translationContextIndex();
3425 store.text = output->indexForByteArray(tr.text.toUtf8());
3426 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3428 output->addInstruction(store);
3429 } else if (ref.dataType == BindingReference::V4) {
3430 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3432 Instruction::StoreV4Binding store;
3433 store.value = js.compiledIndex;
3434 store.context = js.bindingContext.stack;
3435 store.owner = js.bindingContext.owner;
3436 store.isAlias = prop->isAlias;
3437 if (valueTypeProperty) {
3438 store.property = (valueTypeProperty->index & 0xFFFF) |
3439 ((valueTypeProperty->type & 0xFF)) << 16 |
3440 ((prop->index & 0xFF) << 24);
3441 store.isRoot = (compileState->root == valueTypeProperty->parent);
3443 store.property = prop->index;
3444 store.isRoot = (compileState->root == obj);
3446 store.line = binding->location.start.line;
3447 store.column = binding->location.start.column;
3448 output->addInstruction(store);
3449 } else if (ref.dataType == BindingReference::V8) {
3450 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3452 Instruction::StoreV8Binding store;
3453 store.value = js.compiledIndex;
3454 store.context = js.bindingContext.stack;
3455 store.owner = js.bindingContext.owner;
3456 store.isAlias = prop->isAlias;
3457 if (valueTypeProperty) {
3458 store.isRoot = (compileState->root == valueTypeProperty->parent);
3460 store.isRoot = (compileState->root == obj);
3462 store.line = binding->location.start.line;
3463 store.column = binding->location.start.column;
3465 Q_ASSERT(js.bindingContext.owner == 0 ||
3466 (js.bindingContext.owner != 0 && valueTypeProperty));
3467 if (js.bindingContext.owner) {
3468 store.property = genValueTypeData(prop, valueTypeProperty);
3470 store.property = prop->core;
3473 output->addInstruction(store);
3474 } else if (ref.dataType == BindingReference::QtScript) {
3475 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3477 Instruction::StoreBinding store;
3478 store.value = output->indexForString(js.rewrittenExpression);
3479 store.context = js.bindingContext.stack;
3480 store.owner = js.bindingContext.owner;
3481 store.line = binding->location.start.line;
3482 store.column = binding->location.start.column;
3483 store.isAlias = prop->isAlias;
3485 if (valueTypeProperty) {
3486 store.isRoot = (compileState->root == valueTypeProperty->parent);
3488 store.isRoot = (compileState->root == obj);
3491 Q_ASSERT(js.bindingContext.owner == 0 ||
3492 (js.bindingContext.owner != 0 && valueTypeProperty));
3493 if (js.bindingContext.owner) {
3494 store.property = genValueTypeData(prop, valueTypeProperty);
3496 store.property = prop->core;
3499 output->addInstruction(store);
3501 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3505 int QQmlCompiler::genContextCache()
3507 if (compileState->ids.count() == 0)
3510 QQmlIntegerCache *cache = new QQmlIntegerCache();
3511 cache->reserve(compileState->ids.count());
3512 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3513 cache->add(o->id, o->idIndex);
3515 output->contextCaches.append(cache);
3516 return output->contextCaches.count() - 1;
3520 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3521 QQmlScript::Property *prop)
3523 typedef QQmlPropertyPrivate QDPP;
3524 return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3525 valueTypeProp->index, engine);
3528 bool QQmlCompiler::completeComponentBuild()
3531 componentStats->componentStat.ids = compileState->ids.count();
3533 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3534 aliasObject = compileState->aliasingObjects.next(aliasObject))
3535 COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3537 QV4Compiler::Expression expr(unit->imports());
3538 expr.component = compileState->root;
3539 expr.ids = &compileState->ids;
3540 expr.importCache = output->importCache;
3542 QV4Compiler bindingCompiler;
3544 QList<JSBindingReference*> sharedBindings;
3546 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3548 JSBindingReference &binding = *b;
3551 expr.context = binding.bindingContext.object;
3552 expr.property = binding.property;
3553 expr.expression = binding.expression;
3555 int index = bindingCompiler.compile(expr, enginePrivate);
3557 binding.dataType = BindingReference::V4;
3558 binding.compiledIndex = index;
3560 componentStats->componentStat.optimizedBindings.append(b->value->location);
3564 // Pre-rewrite the expression
3565 QString expression = binding.expression.asScript();
3567 QQmlRewrite::RewriteBinding rewriteBinding;
3568 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3569 bool isSharable = false;
3570 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3572 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3573 binding.dataType = BindingReference::V8;
3574 sharedBindings.append(b);
3577 componentStats->componentStat.sharedBindings.append(b->value->location);
3579 binding.dataType = BindingReference::QtScript;
3582 componentStats->componentStat.scriptBindings.append(b->value->location);
3586 if (!sharedBindings.isEmpty()) {
3588 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3590 return lhs->value->location.start.line < rhs->value->location.start.line;
3594 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3596 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3597 int lineNumber = startLineNumber;
3599 QByteArray functionArray("[", 1);
3600 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3602 JSBindingReference *reference = sharedBindings.at(ii);
3603 QQmlScript::Value *value = reference->value;
3604 const QString &expression = reference->rewrittenExpression;
3606 if (ii != 0) functionArray.append(",", 1);
3608 while (lineNumber < value->location.start.line) {
3610 functionArray.append("\n", 1);
3613 functionArray += expression.toUtf8();
3614 lineNumber += expression.count(QLatin1Char('\n'));
3615 reference->compiledIndex = ii;
3617 functionArray.append("]", 1);
3619 compileState->v8BindingProgram = functionArray;
3620 compileState->v8BindingProgramLine = startLineNumber;
3623 if (bindingCompiler.isValid())
3624 compileState->compiledBindingData = bindingCompiler.program();
3626 // Check pop()'s matched push()'s
3627 Q_ASSERT(compileState->objectDepth.depth() == 0);
3628 Q_ASSERT(compileState->listDepth.depth() == 0);
3630 saveComponentState();
3635 void QQmlCompiler::dumpStats()
3637 Q_ASSERT(componentStats);
3638 qWarning().nospace() << "QML Document: " << output->url.toString();
3639 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3640 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3641 qWarning().nospace() << " Component Line " << stat.lineNumber;
3642 qWarning().nospace() << " Total Objects: " << stat.objects;
3643 qWarning().nospace() << " IDs Used: " << stat.ids;
3644 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3648 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3649 if (0 == (ii % 10)) {
3650 if (ii) output.append("\n");
3655 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3657 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3658 output.append(") ");
3660 if (!output.isEmpty())
3661 qWarning().nospace() << output.constData();
3664 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3667 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3668 if (0 == (ii % 10)) {
3669 if (ii) output.append('\n');
3674 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3676 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3677 output.append(") ");
3679 if (!output.isEmpty())
3680 qWarning().nospace() << output.constData();
3683 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3686 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3687 if (0 == (ii % 10)) {
3688 if (ii) output.append('\n');
3693 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3695 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3696 output.append(") ");
3698 if (!output.isEmpty())
3699 qWarning().nospace() << output.constData();
3705 Returns true if from can be assigned to a (QObject) property of type
3708 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3710 QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3711 QQmlPropertyCache *fromMo = from->metatype;
3716 fromMo = fromMo->parent();
3722 Returns the element name, as written in the QML file, for o.
3724 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3727 if (o->type != -1) {
3728 return unit->parser().referencedTypes().at(o->type)->name;
3734 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3736 if (from->type != -1 && output->types.at(from->type).type)
3737 return output->types.at(from->type).type;
3739 const QMetaObject *mo = from->metatype->firstCppMetaObject();
3741 while (!type && mo) {
3742 type = QQmlMetaType::qmlType(mo);
3743 mo = mo->superClass();
3748 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3750 const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3752 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3754 return QStringList();
3756 QMetaClassInfo classInfo = mo->classInfo(idx);
3757 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3762 QQmlCompiler::property(QQmlScript::Object *object, int index)
3764 QQmlPropertyCache *cache = 0;
3766 if (object->synthCache)
3767 cache = object->synthCache;
3768 else if (object->type != -1)
3769 cache = output->types[object->type].createPropertyCache(engine);
3771 cache = object->metatype;
3773 return cache->property(index);
3777 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3779 if (notInRevision) *notInRevision = false;
3781 QQmlPropertyCache *cache = 0;
3783 if (object->synthCache)
3784 cache = object->synthCache;
3785 else if (object->type != -1)
3786 cache = output->types[object->type].createPropertyCache(engine);
3788 cache = object->metatype;
3790 QQmlPropertyData *d = cache->property(name);
3792 // Find the first property
3793 while (d && d->isFunction())
3794 d = cache->overrideData(d);
3796 if (d && !cache->isAllowedInRevision(d)) {
3797 if (notInRevision) *notInRevision = true;
3804 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3806 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3808 if (notInRevision) *notInRevision = false;
3810 QQmlPropertyCache *cache = 0;
3812 if (object->synthCache)
3813 cache = object->synthCache;
3814 else if (object->type != -1)
3815 cache = output->types[object->type].createPropertyCache(engine);
3817 cache = object->metatype;
3820 QQmlPropertyData *d = cache->property(name);
3821 if (notInRevision) *notInRevision = false;
3823 while (d && !(d->isFunction()))
3824 d = cache->overrideData(d);
3826 if (d && !cache->isAllowedInRevision(d)) {
3827 if (notInRevision) *notInRevision = true;
3833 if (name.endsWith(Changed_string)) {
3834 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3836 d = property(object, propName, notInRevision);
3838 return cache->method(d->notifyIndex);
3844 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3845 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3846 bool *notInRevision)
3848 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3849 return d?d->coreIndex:-1;
3852 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3853 bool *notInRevision)
3855 return indexOfProperty(object, QStringRef(&name), notInRevision);
3858 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3859 bool *notInRevision)
3861 QQmlPropertyData *d = property(object, name, notInRevision);
3862 return d?d->coreIndex:-1;