1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcompiler_p.h"
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qqmlstringconverters_p.h"
49 #include "qqmlengine_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlcontext.h"
52 #include "qqmlmetatype_p.h"
53 #include "qqmlcustomparser_p_p.h"
54 #include "qqmlcontext_p.h"
55 #include "qqmlcomponent_p.h"
56 #include <private/qqmljsast_p.h>
57 #include "qqmlvmemetaobject_p.h"
58 #include "qqmlexpression_p.h"
59 #include "qqmlproperty_p.h"
60 #include "qqmlrewrite_p.h"
61 #include "qqmlscriptstring.h"
62 #include "qqmlglobal_p.h"
63 #include "qqmlbinding_p.h"
64 #include <private/qv4compiler_p.h>
72 #include <QtCore/qdebug.h>
73 #include <QtCore/qdatetime.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QQmlJS;
87 using namespace QQmlScript;
88 using namespace QQmlCompilerTypes;
90 static QString id_string(QLatin1String("id"));
91 static QString on_string(QLatin1String("on"));
92 static QString Changed_string(QLatin1String("Changed"));
93 static QString Component_string(QLatin1String("Component"));
94 static QString Component_import_string(QLatin1String("QML/Component"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QQmlCompiler.
101 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
102 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QQmlCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QQmlError> QQmlCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QQmlCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
191 error.setUrl(output->url); \
192 error.setLine(line); \
193 error.setColumn(column); \
194 error.setDescription(desc.trimmed()); \
195 exceptions << error; \
199 #define COMPILE_EXCEPTION(token, desc) \
200 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
205 Returns false if \a is false, otherwise does nothing.
207 #define COMPILE_CHECK(a) \
209 if (!a) return false; \
213 Returns true if literal \a v can be assigned to property \a prop, otherwise
216 This test corresponds to action taken by genLiteralAssignment(). Any change
217 made here, must have a corresponding action in genLiteralAssigment().
219 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
220 QQmlScript::Value *v)
222 const QQmlScript::Variant &value = v->value;
224 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
225 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
227 if (prop->core.isEnum()) {
228 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
231 if (p.isFlagType()) {
232 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
234 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
237 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
239 v->value = QQmlScript::Variant((double)enumValue);
243 int type = prop->type;
246 case QMetaType::QVariant:
248 case QVariant::String:
249 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
251 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
252 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
254 case QVariant::ByteArray:
255 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
258 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
260 case QVariant::RegExp:
261 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
265 bool ok = v->value.isNumber();
267 double n = v->value.asNumber();
268 if (double(uint(n)) != n)
271 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
276 bool ok = v->value.isNumber();
278 double n = v->value.asNumber();
279 if (double(int(n)) != n)
282 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
285 case QMetaType::Float:
286 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
288 case QVariant::Double:
289 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
291 case QVariant::Color:
294 QQmlStringConverters::colorFromString(value.asString(), &ok);
295 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
298 #ifndef QT_NO_DATESTRING
302 QQmlStringConverters::dateFromString(value.asString(), &ok);
303 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
309 QQmlStringConverters::timeFromString(value.asString(), &ok);
310 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
313 case QVariant::DateTime:
316 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
317 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
320 #endif // QT_NO_DATESTRING
321 case QVariant::Point:
322 case QVariant::PointF:
325 QQmlStringConverters::pointFFromString(value.asString(), &ok);
326 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
330 case QVariant::SizeF:
333 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
334 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
338 case QVariant::RectF:
341 QQmlStringConverters::rectFFromString(value.asString(), &ok);
342 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
347 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
350 case QVariant::Vector3D:
353 QQmlStringConverters::vector3DFromString(value.asString(), &ok);
354 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
357 case QVariant::Vector4D:
360 QQmlStringConverters::vector4DFromString(value.asString(), &ok);
361 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
366 // check if assigning a literal value to a list property.
367 // in each case, check the singular, since an Array of the specified type
368 // will not go via this literal assignment codepath.
369 if (type == qMetaTypeId<QList<qreal> >()) {
370 if (!v->value.isNumber()) {
371 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
374 } else if (type == qMetaTypeId<QList<int> >()) {
375 bool ok = v->value.isNumber();
377 double n = v->value.asNumber();
378 if (double(int(n)) != n)
381 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
383 } else if (type == qMetaTypeId<QList<bool> >()) {
384 if (!v->value.isBoolean()) {
385 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
388 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
389 if (!v->value.isString()) {
390 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
393 } else if (type == qMetaTypeId<QList<QUrl> >()) {
394 if (!v->value.isString()) {
395 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
400 // otherwise, check for existence of string converter to custom type
401 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
403 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
410 static QUrl urlFromUserString(const QString &data)
413 // Preserve any valid percent-encoded octets supplied by the source
414 u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
419 Generate a store instruction for assigning literal \a v to property \a prop.
421 Any literal assignment that is approved in testLiteralAssignment() must have
422 a corresponding action in this method.
424 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
425 QQmlScript::Value *v)
427 if (prop->core.isEnum()) {
428 Q_ASSERT(v->value.isNumber());
430 int value = (int)v->value.asNumber();
432 Instruction::StoreInteger instr;
433 instr.propertyIndex = prop->index;
435 output->addInstruction(instr);
439 int type = prop->type;
441 case QMetaType::QVariant:
443 if (v->value.isNumber()) {
444 double n = v->value.asNumber();
445 if (double(int(n)) == n) {
446 if (prop->core.isVMEProperty()) {
447 Instruction::StoreVarInteger instr;
448 instr.propertyIndex = prop->index;
449 instr.value = int(n);
450 output->addInstruction(instr);
452 Instruction::StoreVariantInteger instr;
453 instr.propertyIndex = prop->index;
454 instr.value = int(n);
455 output->addInstruction(instr);
458 if (prop->core.isVMEProperty()) {
459 Instruction::StoreVarDouble instr;
460 instr.propertyIndex = prop->index;
462 output->addInstruction(instr);
464 Instruction::StoreVariantDouble instr;
465 instr.propertyIndex = prop->index;
467 output->addInstruction(instr);
470 } else if (v->value.isBoolean()) {
471 if (prop->core.isVMEProperty()) {
472 Instruction::StoreVarBool instr;
473 instr.propertyIndex = prop->index;
474 instr.value = v->value.asBoolean();
475 output->addInstruction(instr);
477 Instruction::StoreVariantBool instr;
478 instr.propertyIndex = prop->index;
479 instr.value = v->value.asBoolean();
480 output->addInstruction(instr);
483 if (prop->core.isVMEProperty()) {
484 Instruction::StoreVar instr;
485 instr.propertyIndex = prop->index;
486 instr.value = output->indexForString(v->value.asString());
487 output->addInstruction(instr);
489 Instruction::StoreVariant instr;
490 instr.propertyIndex = prop->index;
491 instr.value = output->indexForString(v->value.asString());
492 output->addInstruction(instr);
497 case QVariant::String:
499 Instruction::StoreString instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForString(v->value.asString());
502 output->addInstruction(instr);
505 case QVariant::StringList:
507 Instruction::StoreStringList instr;
508 instr.propertyIndex = prop->index;
509 instr.value = output->indexForString(v->value.asString());
510 output->addInstruction(instr);
513 case QVariant::ByteArray:
515 Instruction::StoreByteArray instr;
516 instr.propertyIndex = prop->index;
517 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
518 output->addInstruction(instr);
523 Instruction::StoreUrl instr;
524 QString string = v->value.asString();
525 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
526 instr.propertyIndex = prop->index;
527 instr.value = output->indexForUrl(u);
528 output->addInstruction(instr);
533 Instruction::StoreInteger instr;
534 instr.propertyIndex = prop->index;
535 instr.value = uint(v->value.asNumber());
536 output->addInstruction(instr);
541 Instruction::StoreInteger instr;
542 instr.propertyIndex = prop->index;
543 instr.value = int(v->value.asNumber());
544 output->addInstruction(instr);
547 case QMetaType::Float:
549 Instruction::StoreFloat instr;
550 instr.propertyIndex = prop->index;
551 instr.value = float(v->value.asNumber());
552 output->addInstruction(instr);
555 case QVariant::Double:
557 Instruction::StoreDouble instr;
558 instr.propertyIndex = prop->index;
559 instr.value = v->value.asNumber();
560 output->addInstruction(instr);
563 case QVariant::Color:
565 Instruction::StoreColor instr;
566 QColor c = QQmlStringConverters::colorFromString(v->value.asString());
567 instr.propertyIndex = prop->index;
568 instr.value = c.rgba();
569 output->addInstruction(instr);
572 #ifndef QT_NO_DATESTRING
575 Instruction::StoreDate instr;
576 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
577 instr.propertyIndex = prop->index;
578 instr.value = d.toJulianDay();
579 output->addInstruction(instr);
584 Instruction::StoreTime instr;
585 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
586 instr.propertyIndex = prop->index;
587 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
588 ::memcpy(&instr.time, &time, sizeof(QTime));
589 output->addInstruction(instr);
592 case QVariant::DateTime:
594 Instruction::StoreDateTime instr;
595 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
596 QTime time = dateTime.time();
597 instr.propertyIndex = prop->index;
598 instr.date = dateTime.date().toJulianDay();
599 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
600 ::memcpy(&instr.time, &time, sizeof(QTime));
601 output->addInstruction(instr);
604 #endif // QT_NO_DATESTRING
605 case QVariant::Point:
607 Instruction::StorePoint instr;
609 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
610 instr.propertyIndex = prop->index;
611 instr.point.xp = point.x();
612 instr.point.yp = point.y();
613 output->addInstruction(instr);
616 case QVariant::PointF:
618 Instruction::StorePointF instr;
620 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
621 instr.propertyIndex = prop->index;
622 instr.point.xp = point.x();
623 instr.point.yp = point.y();
624 output->addInstruction(instr);
629 Instruction::StoreSize instr;
631 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
632 instr.propertyIndex = prop->index;
633 instr.size.wd = size.width();
634 instr.size.ht = size.height();
635 output->addInstruction(instr);
638 case QVariant::SizeF:
640 Instruction::StoreSizeF instr;
642 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
643 instr.propertyIndex = prop->index;
644 instr.size.wd = size.width();
645 instr.size.ht = size.height();
646 output->addInstruction(instr);
651 Instruction::StoreRect instr;
653 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
654 instr.propertyIndex = prop->index;
655 instr.rect.x1 = rect.left();
656 instr.rect.y1 = rect.top();
657 instr.rect.x2 = rect.right();
658 instr.rect.y2 = rect.bottom();
659 output->addInstruction(instr);
662 case QVariant::RectF:
664 Instruction::StoreRectF instr;
666 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
667 instr.propertyIndex = prop->index;
668 instr.rect.xp = rect.left();
669 instr.rect.yp = rect.top();
670 instr.rect.w = rect.width();
671 instr.rect.h = rect.height();
672 output->addInstruction(instr);
677 Instruction::StoreBool instr;
678 bool b = v->value.asBoolean();
679 instr.propertyIndex = prop->index;
681 output->addInstruction(instr);
684 case QVariant::Vector3D:
686 Instruction::StoreVector3D instr;
688 QVector3D vector = QQmlStringConverters::vector3DFromString(v->value.asString(), &ok);
689 instr.propertyIndex = prop->index;
690 instr.vector.xp = vector.x();
691 instr.vector.yp = vector.y();
692 instr.vector.zp = vector.z();
693 output->addInstruction(instr);
696 case QVariant::Vector4D:
698 Instruction::StoreVector4D instr;
700 QVector4D vector = QQmlStringConverters::vector4DFromString(v->value.asString(), &ok);
701 instr.propertyIndex = prop->index;
702 instr.vector.xp = vector.x();
703 instr.vector.yp = vector.y();
704 instr.vector.zp = vector.z();
705 instr.vector.wp = vector.w();
706 output->addInstruction(instr);
711 // generate single literal value assignment to a list property if required
712 if (type == qMetaTypeId<QList<qreal> >()) {
713 Instruction::StoreDoubleQList instr;
714 instr.propertyIndex = prop->index;
715 instr.value = v->value.asNumber();
716 output->addInstruction(instr);
718 } else if (type == qMetaTypeId<QList<int> >()) {
719 Instruction::StoreIntegerQList instr;
720 instr.propertyIndex = prop->index;
721 instr.value = int(v->value.asNumber());
722 output->addInstruction(instr);
724 } else if (type == qMetaTypeId<QList<bool> >()) {
725 Instruction::StoreBoolQList instr;
726 bool b = v->value.asBoolean();
727 instr.propertyIndex = prop->index;
729 output->addInstruction(instr);
731 } else if (type == qMetaTypeId<QList<QUrl> >()) {
732 Instruction::StoreUrlQList instr;
733 QString string = v->value.asString();
734 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
735 instr.propertyIndex = prop->index;
736 instr.value = output->indexForUrl(u);
737 output->addInstruction(instr);
739 } else if (type == qMetaTypeId<QList<QString> >()) {
740 Instruction::StoreStringQList instr;
741 instr.propertyIndex = prop->index;
742 instr.value = output->indexForString(v->value.asString());
743 output->addInstruction(instr);
747 // otherwise, generate custom type literal assignment
748 Instruction::AssignCustomType instr;
749 instr.propertyIndex = prop->index;
750 instr.primitive = output->indexForString(v->value.asString());
752 output->addInstruction(instr);
759 Resets data by clearing the lists that the QQmlCompiler modifies.
761 void QQmlCompiler::reset(QQmlCompiledData *data)
764 data->primitives.clear();
766 data->bytecode.resize(0);
770 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
771 with which the QQmlCompiledData will be associated.
773 Returns true on success, false on failure. On failure, the compile errors
774 are available from errors().
776 If the environment variant QML_COMPILER_DUMP is set
777 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
778 on a successful compiler.
780 bool QQmlCompiler::compile(QQmlEngine *engine,
782 QQmlCompiledData *out)
789 QQmlScript::Object *root = unit->parser().tree();
792 this->engine = engine;
793 this->enginePrivate = QQmlEnginePrivate::get(engine);
795 this->unitRoot = root;
799 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
800 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
802 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
803 QQmlCompiledData::TypeReference ref;
805 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
806 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
809 ref.type = tref.type;
810 if (!ref.type->isCreatable()) {
811 QString err = ref.type->noCreationReason();
813 err = tr( "Element is not creatable.");
814 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
817 if (ref.type->containsRevisionedAttributes()) {
818 QQmlError cacheError;
819 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
821 if (!ref.typePropertyCache)
822 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
823 ref.typePropertyCache->addref();
826 } else if (tref.typeData) {
827 ref.component = tref.typeData->compiledData();
829 ref.className = parserRef->name;
837 out->dumpInstructions();
840 Q_ASSERT(out->rootPropertyCache);
848 this->enginePrivate = 0;
850 this->cachedComponentTypeRef = -1;
851 this->cachedTranslationContextIndex = -1;
857 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
859 compileState = pool->New<ComponentCompileState>();
861 compileState->root = tree;
863 componentStats->componentStat.lineNumber = tree->location.start.line;
865 // We generate the importCache before we build the tree so that
866 // it can be used in the binding compiler. Given we "expect" the
867 // QML compilation to succeed, this isn't a waste.
868 output->importCache = new QQmlTypeNameCache();
869 foreach (const QString &ns, unit->namespaces()) {
870 output->importCache->add(ns);
874 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
875 QString qualifier = script.qualifier;
876 QString enclosingNamespace;
878 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
879 if (lastDotIndex != -1) {
880 enclosingNamespace = qualifier.left(lastDotIndex);
881 qualifier = qualifier.mid(lastDotIndex+1);
884 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
887 unit->imports().populateCache(output->importCache, engine);
889 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
892 Instruction::Init init;
893 init.bindingsSize = compileState->totalBindingsCount;
894 init.parserStatusSize = compileState->parserStatusCount;
895 init.contextCache = genContextCache();
896 init.objectStackSize = compileState->objectDepth.maxDepth();
897 init.listStackSize = compileState->listDepth.maxDepth();
898 if (compileState->compiledBindingData.isEmpty())
899 init.compiledBinding = -1;
901 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
902 output->addInstruction(init);
904 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
905 Instruction::StoreImportedScript import;
906 import.value = output->scripts.count();
908 QQmlScriptData *scriptData = script.script->scriptData();
909 scriptData->addref();
910 output->scripts << scriptData;
911 output->addInstruction(import);
914 if (!compileState->v8BindingProgram.isEmpty()) {
915 Instruction::InitV8Bindings bindings;
916 int index = output->programs.count();
918 typedef QQmlCompiledData::V8Program V8Program;
919 output->programs.append(V8Program(compileState->v8BindingProgram, output));
921 bindings.programIndex = index;
922 bindings.line = compileState->v8BindingProgramLine;
923 output->addInstruction(bindings);
928 Instruction::SetDefault def;
929 output->addInstruction(def);
931 Instruction::Done done;
932 output->addInstruction(done);
934 Q_ASSERT(tree->metatype);
936 if (tree->metadata.isEmpty()) {
937 output->root = tree->metatype;
939 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
940 output->root = &output->rootData;
942 if (!tree->metadata.isEmpty())
943 enginePrivate->registerCompositeType(output);
946 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
948 for (int ii = 0; ii < list.count(); ++ii)
949 if (string == list.at(ii))
955 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
958 componentStats->componentStat.objects++;
960 Q_ASSERT (obj->type != -1);
961 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
962 obj->metatype = tr.metaObject();
965 obj->typeName = tr.type->qmlTypeName();
967 // This object is a "Component" element
968 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
969 COMPILE_CHECK(buildComponent(obj, ctxt));
974 typedef QQmlInstruction I;
975 const I *init = ((const I *)tr.component->bytecode.constData());
976 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
978 // Adjust stack depths to include nested components
979 compileState->objectDepth.pushPop(init->init.objectStackSize);
980 compileState->listDepth.pushPop(init->init.listStackSize);
981 compileState->parserStatusCount += init->init.parserStatusSize;
982 compileState->totalBindingsCount += init->init.bindingsSize;
985 compileState->objectDepth.push();
987 // Object instantiations reset the binding context
988 BindingContext objCtxt(obj);
990 // Create the synthesized meta object, ignoring aliases
991 COMPILE_CHECK(checkDynamicMeta(obj));
992 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
993 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
995 // Find the native type and check for the QQmlParserStatus interface
996 QQmlType *type = toQmlType(obj);
998 obj->parserStatusCast = type->parserStatusCast();
999 if (obj->parserStatusCast != -1)
1000 compileState->parserStatusCount++;
1002 // Check if this is a custom parser type. Custom parser types allow
1003 // assignments to non-existent properties. These assignments are then
1004 // compiled by the type.
1005 bool isCustomParser = output->types.at(obj->type).type &&
1006 output->types.at(obj->type).type->customParser() != 0;
1007 QList<QQmlCustomParserProperty> customProps;
1009 // Fetch the list of deferred properties
1010 QStringList deferredList = deferredProperties(obj);
1012 // Must do id property first. This is to ensure that the id given to any
1013 // id reference created matches the order in which the objects are
1015 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1016 if (prop->name() == id_string) {
1017 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1023 Property *defaultProperty = 0;
1024 Property *skipProperty = 0;
1025 if (obj->defaultProperty) {
1026 defaultProperty = obj->defaultProperty;
1028 Property *explicitProperty = 0;
1030 const QMetaObject *mo = obj->metatype;
1031 int idx = mo->indexOfClassInfo("DefaultProperty");
1033 QMetaClassInfo info = mo->classInfo(idx);
1034 const char *p = info.value();
1038 while (char c = p[plen++]) { ord |= c; };
1042 // Utf8 - unoptimal, but seldom hit
1043 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1044 QHashedStringRef r(*s);
1046 if (obj->propertiesHashField.test(r.hash())) {
1047 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1048 if (ep->name() == r) {
1049 explicitProperty = ep;
1055 if (!explicitProperty)
1056 defaultProperty->setName(r);
1059 QHashedCStringRef r(p, plen);
1061 if (obj->propertiesHashField.test(r.hash())) {
1062 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1063 if (ep->name() == r) {
1064 explicitProperty = ep;
1070 if (!explicitProperty) {
1071 // Set the default property name
1072 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1073 r.writeUtf16(buffer);
1074 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1080 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1082 skipProperty = explicitProperty; // We merge the values into defaultProperty
1084 // Find the correct insertion point
1085 Value *insertPos = 0;
1087 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1088 if (!(v->location.start < explicitProperty->values.first()->location.start))
1093 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1097 QQmlCustomParser *cp = 0;
1099 cp = output->types.at(obj->type).type->customParser();
1101 // Build all explicit properties specified
1102 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1104 if (prop == skipProperty)
1106 if (prop->name() == id_string)
1109 bool canDefer = false;
1110 if (isCustomParser) {
1111 if (doesPropertyExist(prop, obj) &&
1112 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1113 !isAttachedPropertyName(prop->name()))) {
1114 int ids = compileState->ids.count();
1115 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1116 canDefer = ids == compileState->ids.count();
1117 } else if (isSignalPropertyName(prop->name()) &&
1118 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1119 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1121 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1124 if (isSignalPropertyName(prop->name())) {
1125 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1127 int ids = compileState->ids.count();
1128 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1129 canDefer = ids == compileState->ids.count();
1133 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1134 prop->isDeferred = true;
1138 // Build the default property
1139 if (defaultProperty) {
1140 Property *prop = defaultProperty;
1142 bool canDefer = false;
1143 if (isCustomParser) {
1144 if (doesPropertyExist(prop, obj)) {
1145 int ids = compileState->ids.count();
1146 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1147 canDefer = ids == compileState->ids.count();
1149 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1152 int ids = compileState->ids.count();
1153 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1154 canDefer = ids == compileState->ids.count();
1157 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1158 prop->isDeferred = true;
1161 // Compile custom parser parts
1162 if (isCustomParser && !customProps.isEmpty()) {
1164 cp->compiler = this;
1166 obj->custom = cp->compile(customProps);
1169 foreach (QQmlError err, cp->errors()) {
1170 err.setUrl(output->url);
1175 compileState->objectDepth.pop();
1180 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1182 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1183 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1188 // Create the object
1189 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1190 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1192 Instruction::CreateSimpleObject create;
1193 create.create = output->types.at(obj->type).type->createFunction();
1194 create.typeSize = output->types.at(obj->type).type->createSize();
1195 create.type = obj->type;
1196 create.line = obj->location.start.line;
1197 create.column = obj->location.start.column;
1198 output->addInstruction(create);
1202 if (output->types.at(obj->type).type) {
1203 Instruction::CreateCppObject create;
1204 create.line = obj->location.start.line;
1205 create.column = obj->location.start.column;
1207 if (!obj->custom.isEmpty())
1208 create.data = output->indexForByteArray(obj->custom);
1209 create.type = obj->type;
1210 create.isRoot = (compileState->root == obj);
1211 output->addInstruction(create);
1213 Instruction::CreateQMLObject create;
1214 create.type = obj->type;
1215 create.isRoot = (compileState->root == obj);
1217 if (!obj->bindingBitmask.isEmpty()) {
1218 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1219 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1221 create.bindingBits = -1;
1223 output->addInstruction(create);
1225 Instruction::CompleteQMLObject complete;
1226 complete.line = obj->location.start.line;
1227 complete.column = obj->location.start.column;
1228 complete.isRoot = (compileState->root == obj);
1229 output->addInstruction(complete);
1233 // Setup the synthesized meta object if necessary
1234 if (!obj->metadata.isEmpty()) {
1235 Instruction::StoreMetaObject meta;
1236 meta.data = output->indexForByteArray(obj->metadata);
1237 meta.aliasData = output->indexForByteArray(obj->synthdata);
1238 meta.propertyCache = output->propertyCaches.count();
1240 QQmlPropertyCache *propertyCache = obj->synthCache;
1241 Q_ASSERT(propertyCache);
1242 propertyCache->addref();
1244 // Add flag for alias properties
1245 if (!obj->synthdata.isEmpty()) {
1246 const QQmlVMEMetaData *vmeMetaData =
1247 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1248 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1249 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1250 QQmlPropertyData *data = propertyCache->property(index);
1251 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1255 if (obj == unitRoot) {
1256 propertyCache->addref();
1257 output->rootPropertyCache = propertyCache;
1260 output->propertyCaches << propertyCache;
1261 output->addInstruction(meta);
1262 } else if (obj == unitRoot) {
1263 output->rootPropertyCache = tr.createPropertyCache(engine);
1264 output->rootPropertyCache->addref();
1267 // Set the object id
1268 if (!obj->id.isEmpty()) {
1269 Instruction::SetId id;
1270 id.value = output->indexForString(obj->id);
1271 id.index = obj->idIndex;
1272 output->addInstruction(id);
1276 if (tr.type && obj->parserStatusCast != -1) {
1277 Instruction::BeginObject begin;
1278 begin.castValue = obj->parserStatusCast;
1279 output->addInstruction(begin);
1285 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1287 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1288 Q_ASSERT(prop->scriptStringScope != -1);
1289 const QString &script = prop->values.first()->value.asScript();
1290 Instruction::StoreScriptString ss;
1291 ss.propertyIndex = prop->index;
1292 ss.value = output->indexForString(script);
1293 ss.scope = prop->scriptStringScope;
1294 // ss.bindingId = rewriteBinding(script, prop->name());
1295 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1296 ss.line = prop->location.start.line;
1297 ss.column = prop->location.start.column;
1298 output->addInstruction(ss);
1301 bool seenDefer = false;
1302 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1303 if (prop->isDeferred) {
1308 genValueProperty(prop, obj);
1311 Instruction::Defer defer;
1312 defer.deferCount = 0;
1313 int deferIdx = output->addInstruction(defer);
1314 int nextInstructionIndex = output->nextInstructionIndex();
1316 Instruction::DeferInit dinit;
1317 // XXX - these are now massive over allocations
1318 dinit.bindingsSize = compileState->totalBindingsCount;
1319 dinit.parserStatusSize = compileState->parserStatusCount;
1320 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1321 dinit.listStackSize = compileState->listDepth.maxDepth();
1322 output->addInstruction(dinit);
1324 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1325 if (!prop->isDeferred)
1327 genValueProperty(prop, obj);
1330 Instruction::Done done;
1331 output->addInstruction(done);
1333 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1336 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1338 QQmlScript::Value *v = prop->values.first();
1340 if (v->type == Value::SignalObject) {
1342 genObject(v->object);
1344 Instruction::AssignSignalObject assign;
1345 assign.line = v->location.start.line;
1346 assign.signal = output->indexForString(prop->name().toString());
1347 output->addInstruction(assign);
1349 } else if (v->type == Value::SignalExpression) {
1351 Instruction::StoreSignal store;
1352 store.signalIndex = prop->index;
1353 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1354 store.value = output->indexForByteArray(rewrite.toUtf8());
1355 store.context = v->signalExpressionContextStack;
1356 store.line = v->location.start.line;
1357 store.column = v->location.start.column;
1358 output->addInstruction(store);
1364 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1365 Instruction::FetchAttached fetch;
1366 fetch.id = prop->index;
1367 fetch.line = prop->location.start.line;
1368 output->addInstruction(fetch);
1370 genObjectBody(prop->value);
1372 Instruction::PopFetchedObject pop;
1373 output->addInstruction(pop);
1376 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1377 Instruction::FetchObject fetch;
1378 fetch.property = prop->index;
1379 fetch.line = prop->location.start.line;
1380 output->addInstruction(fetch);
1382 if (!prop->value->metadata.isEmpty()) {
1383 Instruction::StoreMetaObject meta;
1384 meta.data = output->indexForByteArray(prop->value->metadata);
1385 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1386 meta.propertyCache = -1;
1387 output->addInstruction(meta);
1390 genObjectBody(prop->value);
1392 Instruction::PopFetchedObject pop;
1393 output->addInstruction(pop);
1396 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1398 genValueTypeProperty(obj, prop);
1401 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1402 if (prop->isDeferred)
1405 genValueProperty(prop, obj);
1408 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1410 genValueTypeProperty(obj, prop);
1414 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1416 Instruction::FetchValueType fetch;
1417 fetch.property = prop->index;
1418 fetch.type = prop->type;
1419 fetch.bindingSkipList = 0;
1421 if (obj->type == -1 || output->types.at(obj->type).component) {
1422 // We only have to do this if this is a composite type. If it is a builtin
1423 // type it can't possibly already have bindings that need to be cleared.
1424 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1425 if (!vprop->values.isEmpty()) {
1426 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1427 fetch.bindingSkipList |= (1 << vprop->index);
1432 output->addInstruction(fetch);
1434 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1435 genPropertyAssignment(vprop, prop->value, prop);
1438 Instruction::PopValueType pop;
1439 pop.property = prop->index;
1440 pop.type = prop->type;
1441 pop.bindingSkipList = 0;
1442 output->addInstruction(pop);
1445 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1447 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1450 Instruction::CreateComponent create;
1451 create.line = root->location.start.line;
1452 create.column = root->location.start.column;
1453 create.endLine = root->location.end.line;
1454 create.isRoot = (compileState->root == obj);
1455 int createInstruction = output->addInstruction(create);
1456 int nextInstructionIndex = output->nextInstructionIndex();
1458 ComponentCompileState *oldCompileState = compileState;
1459 compileState = componentState(root);
1461 Instruction::Init init;
1462 init.bindingsSize = compileState->totalBindingsCount;
1463 init.parserStatusSize = compileState->parserStatusCount;
1464 init.contextCache = genContextCache();
1465 init.objectStackSize = compileState->objectDepth.maxDepth();
1466 init.listStackSize = compileState->listDepth.maxDepth();
1467 if (compileState->compiledBindingData.isEmpty())
1468 init.compiledBinding = -1;
1470 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1471 output->addInstruction(init);
1473 if (!compileState->v8BindingProgram.isEmpty()) {
1474 Instruction::InitV8Bindings bindings;
1475 int index = output->programs.count();
1477 typedef QQmlCompiledData::V8Program V8Program;
1478 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1480 bindings.programIndex = index;
1481 bindings.line = compileState->v8BindingProgramLine;
1482 output->addInstruction(bindings);
1487 Instruction::SetDefault def;
1488 output->addInstruction(def);
1490 Instruction::Done done;
1491 output->addInstruction(done);
1493 output->instruction(createInstruction)->createComponent.count =
1494 output->nextInstructionIndex() - nextInstructionIndex;
1496 compileState = oldCompileState;
1498 if (!obj->id.isEmpty()) {
1499 Instruction::SetId id;
1500 id.value = output->indexForString(obj->id);
1501 id.index = obj->idIndex;
1502 output->addInstruction(id);
1505 if (obj == unitRoot) {
1506 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1507 output->rootPropertyCache->addref();
1511 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1512 const BindingContext &ctxt)
1514 // The special "Component" element can only have the id property and a
1515 // default property, that actually defines the component's tree
1517 compileState->objectDepth.push();
1519 // Find, check and set the "id" property (if any)
1520 Property *idProp = 0;
1521 if (obj->properties.isMany() ||
1522 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1523 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1525 if (!obj->properties.isEmpty())
1526 idProp = obj->properties.first();
1529 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1530 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1531 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1533 QString idVal = idProp->values.first()->primitive();
1535 if (compileState->ids.value(idVal))
1536 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1542 // Check the Component tree is well formed
1543 if (obj->defaultProperty &&
1544 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1545 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1546 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1548 if (!obj->dynamicProperties.isEmpty())
1549 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1550 if (!obj->dynamicSignals.isEmpty())
1551 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1552 if (!obj->dynamicSlots.isEmpty())
1553 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1555 QQmlScript::Object *root = 0;
1556 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1557 root = obj->defaultProperty->values.first()->object;
1560 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1562 // Build the component tree
1563 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1565 compileState->objectDepth.pop();
1570 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1571 const BindingContext &ctxt)
1573 ComponentCompileState *oldComponentCompileState = compileState;
1574 compileState = pool->New<ComponentCompileState>();
1575 compileState->root = obj;
1576 compileState->nested = true;
1578 if (componentStats) {
1579 ComponentStat oldComponentStat = componentStats->componentStat;
1581 componentStats->componentStat = ComponentStat();
1582 componentStats->componentStat.lineNumber = obj->location.start.line;
1585 COMPILE_CHECK(buildObject(obj, ctxt));
1587 COMPILE_CHECK(completeComponentBuild());
1589 componentStats->componentStat = oldComponentStat;
1592 COMPILE_CHECK(buildObject(obj, ctxt));
1594 COMPILE_CHECK(completeComponentBuild());
1597 compileState = oldComponentCompileState;
1603 // Build a sub-object. A sub-object is one that was not created directly by
1604 // QML - such as a grouped property object, or an attached object. Sub-object's
1605 // can't have an id, involve a custom parser, have attached properties etc.
1606 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1608 Q_ASSERT(obj->metatype);
1609 Q_ASSERT(!obj->defaultProperty);
1610 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1613 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1614 if (isSignalPropertyName(prop->name())) {
1615 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1617 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1624 int QQmlCompiler::componentTypeRef()
1626 if (cachedComponentTypeRef == -1) {
1627 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1628 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1629 if (output->types.at(ii).type == t) {
1630 cachedComponentTypeRef = ii;
1634 QQmlCompiledData::TypeReference ref;
1635 ref.className = Component_string;
1637 output->types << ref;
1638 cachedComponentTypeRef = output->types.count() - 1;
1640 return cachedComponentTypeRef;
1643 int QQmlCompiler::translationContextIndex()
1645 if (cachedTranslationContextIndex == -1) {
1646 // This code must match that in the qsTr() implementation
1647 const QString &path = output->name;
1648 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1649 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1651 QByteArray contextUtf8 = context.toUtf8();
1652 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1654 return cachedTranslationContextIndex;
1657 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1658 const BindingContext &ctxt)
1660 Q_ASSERT(obj->metaObject());
1662 const QHashedStringRef &propName = prop->name();
1664 Q_ASSERT(propName.startsWith(on_string));
1665 QString name = propName.mid(2, -1).toString();
1667 // Note that the property name could start with any alpha or '_' or '$' character,
1668 // so we need to do the lower-casing of the first alpha character.
1669 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1670 if (name.at(firstAlphaIndex).isUpper()) {
1671 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1676 bool notInRevision = false;
1678 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1682 if (notInRevision && 0 == property(obj, propName, 0)) {
1683 Q_ASSERT(obj->type != -1);
1684 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1685 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1687 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));
1689 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1693 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1695 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1699 if (prop->value || !prop->values.isOne())
1700 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1702 prop->index = sig->coreIndex;
1705 obj->addSignalProperty(prop);
1707 if (prop->values.first()->object) {
1708 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1709 prop->values.first()->type = Value::SignalObject;
1711 prop->values.first()->type = Value::SignalExpression;
1713 if (!prop->values.first()->value.isScript())
1714 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1716 QString script = prop->values.first()->value.asScript().trimmed();
1717 if (script.isEmpty())
1718 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1720 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1729 Returns true if (value) property \a prop exists on obj, false otherwise.
1731 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1732 QQmlScript::Object *obj)
1734 if (prop->name().isEmpty())
1736 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1739 return property(obj, prop->name()) != 0;
1742 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1743 QQmlScript::Object *obj,
1744 const BindingContext &ctxt)
1746 if (prop->isEmpty())
1747 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1749 const QMetaObject *metaObject = obj->metaObject();
1750 Q_ASSERT(metaObject);
1752 if (isAttachedPropertyName(prop->name())) {
1753 // Setup attached property data
1755 if (ctxt.isSubContext()) {
1756 // Attached properties cannot be used on sub-objects. Sub-objects
1757 // always exist in a binding sub-context, which is what we test
1759 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1763 QQmlImportedNamespace *typeNamespace = 0;
1764 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1766 if (typeNamespace) {
1767 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1770 } else if (!type || !type->attachedPropertiesType()) {
1771 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1775 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1777 Q_ASSERT(type->attachedPropertiesFunction());
1778 prop->index = type->attachedPropertiesId();
1779 prop->value->metatype = type->attachedPropertiesType();
1781 // Setup regular property data
1782 bool notInRevision = false;
1783 QQmlPropertyData *d =
1784 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1786 if (d == 0 && notInRevision) {
1787 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1788 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1790 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));
1792 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1795 prop->index = d->coreIndex;
1797 } else if (prop->isDefault) {
1798 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1799 QQmlPropertyData defaultPropertyData;
1800 defaultPropertyData.load(p, engine);
1802 prop->setName(QLatin1String(p.name()));
1803 prop->core = defaultPropertyData;
1804 prop->index = prop->core.coreIndex;
1807 // We can't error here as the "id" property does not require a
1808 // successful index resolution
1809 if (prop->index != -1)
1810 prop->type = prop->core.propType;
1812 // Check if this is an alias
1813 if (prop->index != -1 &&
1815 prop->parent->type != -1 &&
1816 output->types.at(prop->parent->type).component) {
1818 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1819 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1820 prop->isAlias = true;
1823 if (prop->index != -1 && !prop->values.isEmpty())
1824 prop->parent->setBindingBit(prop->index);
1827 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1829 // The magic "id" behavior doesn't apply when "id" is resolved as a
1830 // default property or to sub-objects (which are always in binding
1832 COMPILE_CHECK(buildIdProperty(prop, obj));
1833 if (prop->type == QVariant::String &&
1834 prop->values.first()->value.isString())
1835 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1837 } else if (isAttachedPropertyName(prop->name())) {
1839 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1841 } else if (prop->index == -1) {
1843 if (prop->isDefault) {
1844 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1846 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1849 } else if (prop->value) {
1851 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1853 } else if (prop->core.isQList()) {
1855 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1857 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1859 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1863 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1870 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
1871 QQmlScript::Property *nsProp,
1872 QQmlScript::Object *obj,
1873 const BindingContext &ctxt)
1876 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1878 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1880 if (!isAttachedPropertyName(prop->name()))
1881 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1883 // Setup attached property data
1886 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1888 if (!type || !type->attachedPropertiesType())
1889 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1892 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1894 Q_ASSERT(type->attachedPropertiesFunction());
1895 prop->index = type->index();
1896 prop->value->metatype = type->attachedPropertiesType();
1898 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1904 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1905 QQmlScript::Object *obj)
1907 if (prop->core.isQList()) {
1908 genListProperty(prop, obj);
1910 genPropertyAssignment(prop, obj);
1914 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1915 QQmlScript::Object *obj)
1917 int listType = enginePrivate->listType(prop->type);
1919 Instruction::FetchQList fetch;
1920 fetch.property = prop->index;
1921 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1922 fetch.type = listType;
1923 output->addInstruction(fetch);
1925 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1927 if (v->type == Value::CreatedObject) {
1929 genObject(v->object);
1930 if (listTypeIsInterface) {
1931 Instruction::AssignObjectList assign;
1932 assign.line = prop->location.start.line;
1933 output->addInstruction(assign);
1935 Instruction::StoreObjectQList store;
1936 output->addInstruction(store);
1939 } else if (v->type == Value::PropertyBinding) {
1941 genBindingAssignment(v, prop, obj);
1947 Instruction::PopQList pop;
1948 output->addInstruction(pop);
1951 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1952 QQmlScript::Object *obj,
1953 QQmlScript::Property *valueTypeProperty)
1955 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1957 Q_ASSERT(v->type == Value::CreatedObject ||
1958 v->type == Value::PropertyBinding ||
1959 v->type == Value::Literal);
1961 if (v->type == Value::CreatedObject) {
1963 genObject(v->object);
1965 if (QQmlMetaType::isInterface(prop->type)) {
1967 Instruction::StoreInterface store;
1968 store.line = v->object->location.start.line;
1969 store.propertyIndex = prop->index;
1970 output->addInstruction(store);
1972 } else if (prop->type == QMetaType::QVariant) {
1974 if (prop->core.isVMEProperty()) {
1975 Instruction::StoreVarObject store;
1976 store.line = v->object->location.start.line;
1977 store.propertyIndex = prop->index;
1978 output->addInstruction(store);
1980 Instruction::StoreVariantObject store;
1981 store.line = v->object->location.start.line;
1982 store.propertyIndex = prop->index;
1983 output->addInstruction(store);
1989 Instruction::StoreObject store;
1990 store.line = v->object->location.start.line;
1991 store.propertyIndex = prop->index;
1992 output->addInstruction(store);
1995 } else if (v->type == Value::PropertyBinding) {
1997 genBindingAssignment(v, prop, obj, valueTypeProperty);
1999 } else if (v->type == Value::Literal) {
2001 genLiteralAssignment(prop, v);
2007 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2009 Q_ASSERT(v->type == Value::ValueSource ||
2010 v->type == Value::ValueInterceptor);
2012 if (v->type == Value::ValueSource) {
2013 genObject(v->object);
2015 Instruction::StoreValueSource store;
2016 if (valueTypeProperty) {
2017 store.property = genValueTypeData(prop, valueTypeProperty);
2020 store.property = prop->core;
2023 QQmlType *valueType = toQmlType(v->object);
2024 store.castValue = valueType->propertyValueSourceCast();
2025 output->addInstruction(store);
2027 } else if (v->type == Value::ValueInterceptor) {
2028 genObject(v->object);
2030 Instruction::StoreValueInterceptor store;
2031 if (valueTypeProperty) {
2032 store.property = genValueTypeData(prop, valueTypeProperty);
2035 store.property = prop->core;
2038 QQmlType *valueType = toQmlType(v->object);
2039 store.castValue = valueType->propertyValueInterceptorCast();
2040 output->addInstruction(store);
2046 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2047 QQmlScript::Object *obj)
2050 prop->values.isMany() ||
2051 prop->values.first()->object)
2052 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2054 QQmlScript::Value *idValue = prop->values.first();
2055 QString val = idValue->primitive();
2057 COMPILE_CHECK(checkValidId(idValue, val));
2059 if (compileState->ids.value(val))
2060 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2062 prop->values.first()->type = Value::Id;
2070 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2073 Q_ASSERT(!compileState->ids.value(id));
2074 Q_ASSERT(obj->id == id);
2075 obj->idIndex = compileState->ids.count();
2076 compileState->ids.append(obj);
2079 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2081 Q_ASSERT(ref->value && !ref->value->bindingReference);
2082 ref->value->bindingReference = ref;
2083 compileState->totalBindingsCount++;
2084 compileState->bindings.prepend(ref);
2087 void QQmlCompiler::saveComponentState()
2089 Q_ASSERT(compileState->root);
2090 Q_ASSERT(compileState->root->componentCompileState == 0);
2092 compileState->root->componentCompileState = compileState;
2095 componentStats->savedComponentStats.append(componentStats->componentStat);
2098 QQmlCompilerTypes::ComponentCompileState *
2099 QQmlCompiler::componentState(QQmlScript::Object *obj)
2101 Q_ASSERT(obj->componentCompileState);
2102 return obj->componentCompileState;
2105 // Build attached property object. In this example,
2109 // GridView is an attached property object.
2110 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2111 QQmlScript::Object *obj,
2112 const BindingContext &ctxt)
2114 Q_ASSERT(prop->value);
2115 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2117 compileState->objectDepth.push();
2119 obj->addAttachedProperty(prop);
2121 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2123 compileState->objectDepth.pop();
2129 // Build "grouped" properties. In this example:
2131 // font.pointSize: 12
2132 // font.family: "Helvetica"
2134 // font is a nested property. pointSize and family are not.
2135 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2136 QQmlScript::Object *obj,
2137 const BindingContext &ctxt)
2139 Q_ASSERT(prop->type != 0);
2140 Q_ASSERT(prop->index != -1);
2142 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2143 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2145 if (!prop->values.isEmpty()) {
2146 if (prop->values.first()->location < prop->value->location) {
2147 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2149 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2153 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2154 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2158 if (prop->isAlias) {
2159 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2160 vtProp->isAlias = true;
2164 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2165 prop->value, obj, ctxt.incr()));
2166 obj->addValueTypeProperty(prop);
2168 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2172 // Load the nested property's meta type
2173 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2174 if (!prop->value->metatype)
2175 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2177 if (!prop->values.isEmpty())
2178 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2180 obj->addGroupedProperty(prop);
2182 compileState->objectDepth.push();
2184 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2186 compileState->objectDepth.pop();
2192 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2193 QQmlScript::Object *obj,
2194 QQmlScript::Object *baseObj,
2195 const BindingContext &ctxt)
2197 compileState->objectDepth.push();
2199 if (obj->defaultProperty)
2200 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2201 obj->metatype = type->metaObject();
2203 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2205 QQmlPropertyData *d = property(obj, prop->name());
2207 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2209 prop->index = d->coreIndex;
2210 prop->type = d->propType;
2212 prop->isValueTypeSubProperty = true;
2215 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2217 if (prop->values.isMany()) {
2218 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2219 } else if (!prop->values.isEmpty()) {
2220 QQmlScript::Value *value = prop->values.first();
2222 if (value->object) {
2223 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2224 } else if (value->value.isScript()) {
2225 // ### Check for writability
2227 //optimization for <Type>.<EnumValue> enum assignments
2228 bool isEnumAssignment = false;
2230 if (prop->core.isEnum())
2231 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2233 if (isEnumAssignment) {
2234 value->type = Value::Literal;
2236 JSBindingReference *reference = pool->New<JSBindingReference>();
2237 reference->expression = value->value;
2238 reference->property = prop;
2239 reference->value = value;
2240 reference->bindingContext = ctxt;
2241 reference->bindingContext.owner++;
2242 addBindingReference(reference);
2243 value->type = Value::PropertyBinding;
2246 COMPILE_CHECK(testLiteralAssignment(prop, value));
2247 value->type = Value::Literal;
2251 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2252 Q_ASSERT(v->object);
2254 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2257 obj->addValueProperty(prop);
2260 compileState->objectDepth.pop();
2265 // Build assignments to QML lists. QML lists are properties of type
2266 // QQmlListProperty<T>. List properties can accept a list of
2267 // objects, or a single binding.
2268 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2269 QQmlScript::Object *obj,
2270 const BindingContext &ctxt)
2272 Q_ASSERT(prop->core.isQList());
2274 compileState->listDepth.push();
2278 obj->addValueProperty(prop);
2280 int listType = enginePrivate->listType(t);
2281 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2283 bool assignedBinding = false;
2284 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2286 v->type = Value::CreatedObject;
2287 COMPILE_CHECK(buildObject(v->object, ctxt));
2289 // We check object coercian here. We check interface assignment
2291 if (!listTypeIsInterface) {
2292 if (!canCoerce(listType, v->object)) {
2293 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2297 } else if (v->value.isScript()) {
2298 if (assignedBinding)
2299 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2301 assignedBinding = true;
2302 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2303 v->type = Value::PropertyBinding;
2305 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2309 compileState->listDepth.pop();
2314 // Compiles an assignment to a QQmlScriptString property
2315 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2316 QQmlScript::Object *obj,
2317 const BindingContext &ctxt)
2319 if (prop->values.isMany())
2320 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2322 if (prop->values.first()->object)
2323 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2325 prop->scriptStringScope = ctxt.stack;
2326 obj->addScriptStringProperty(prop);
2331 // Compile regular property assignments of the form "property: <value>"
2332 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2333 QQmlScript::Object *obj,
2334 const BindingContext &ctxt)
2336 obj->addValueProperty(prop);
2338 if (prop->values.isMany())
2339 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2341 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2344 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2348 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2353 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2354 Q_ASSERT(v->object);
2355 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2361 // Compile assigning a single object instance to a regular property
2362 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2363 QQmlScript::Object *obj,
2364 QQmlScript::Value *v,
2365 const BindingContext &ctxt)
2367 Q_ASSERT(prop->index != -1);
2368 Q_ASSERT(v->object->type != -1);
2370 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2371 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2373 if (QQmlMetaType::isInterface(prop->type)) {
2375 // Assigning an object to an interface ptr property
2376 COMPILE_CHECK(buildObject(v->object, ctxt));
2378 v->type = Value::CreatedObject;
2380 } else if (prop->type == QMetaType::QVariant) {
2382 // Assigning an object to a QVariant
2383 COMPILE_CHECK(buildObject(v->object, ctxt));
2385 v->type = Value::CreatedObject;
2387 // Normally buildObject() will set this up, but we need the static
2388 // meta object earlier to test for assignability. It doesn't matter
2389 // that there may still be outstanding synthesized meta object changes
2390 // on this type, as they are not relevant for assignability testing
2391 v->object->metatype = output->types.at(v->object->type).metaObject();
2392 Q_ASSERT(v->object->metaObject());
2394 // We want to raw metaObject here as the raw metaobject is the
2395 // actual property type before we applied any extensions that might
2396 // effect the properties on the type, but don't effect assignability
2397 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2399 // Will be true if the assgned type inherits propertyMetaObject
2400 bool isAssignable = false;
2401 // Determine isAssignable value
2402 if (propertyMetaObject) {
2403 const QMetaObject *c = v->object->metatype;
2405 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2406 c = c->superClass();
2411 // Simple assignment
2412 COMPILE_CHECK(buildObject(v->object, ctxt));
2414 v->type = Value::CreatedObject;
2415 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2416 // Automatic "Component" insertion
2417 QQmlScript::Object *root = v->object;
2418 QQmlScript::Object *component = pool->New<Object>();
2419 component->type = componentTypeRef();
2420 component->typeName = QStringLiteral("Qt/Component");
2421 component->metatype = &QQmlComponent::staticMetaObject;
2422 component->location = root->location;
2423 QQmlScript::Value *componentValue = pool->New<Value>();
2424 componentValue->object = root;
2425 component->getDefaultProperty()->addValue(componentValue);
2426 v->object = component;
2427 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2429 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2436 // Compile assigning a single object instance to a regular property using the "on" syntax.
2440 // NumberAnimation on x { }
2442 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2443 QQmlScript::Object *obj,
2444 QQmlScript::Object *baseObj,
2445 QQmlScript::Value *v,
2446 const BindingContext &ctxt)
2448 Q_ASSERT(prop->index != -1);
2449 Q_ASSERT(v->object->type != -1);
2453 if (!prop->core.isWritable())
2454 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2457 // Normally buildObject() will set this up, but we need the static
2458 // meta object earlier to test for assignability. It doesn't matter
2459 // that there may still be outstanding synthesized meta object changes
2460 // on this type, as they are not relevant for assignability testing
2461 v->object->metatype = output->types.at(v->object->type).metaObject();
2462 Q_ASSERT(v->object->metaObject());
2464 // Will be true if the assigned type inherits QQmlPropertyValueSource
2465 bool isPropertyValue = false;
2466 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2467 bool isPropertyInterceptor = false;
2468 if (QQmlType *valueType = toQmlType(v->object)) {
2469 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2470 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2473 if (isPropertyValue || isPropertyInterceptor) {
2474 // Assign as a property value source
2475 COMPILE_CHECK(buildObject(v->object, ctxt));
2477 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2478 buildDynamicMeta(baseObj, ForceCreation);
2479 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2481 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2487 // Compile assigning a literal or binding to a regular property
2488 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2489 QQmlScript::Object *obj,
2490 QQmlScript::Value *v,
2491 const BindingContext &ctxt)
2493 Q_ASSERT(prop->index != -1);
2495 if (v->value.isScript()) {
2497 //optimization for <Type>.<EnumValue> enum assignments
2498 if (prop->core.isEnum()) {
2499 bool isEnumAssignment = false;
2500 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2501 if (isEnumAssignment) {
2502 v->type = Value::Literal;
2507 // Test for other binding optimizations
2508 if (!buildLiteralBinding(v, prop, ctxt))
2509 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2511 v->type = Value::PropertyBinding;
2515 COMPILE_CHECK(testLiteralAssignment(prop, v));
2517 v->type = Value::Literal;
2523 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2524 QQmlScript::Object *obj,
2525 QQmlScript::Value *v,
2528 *isAssignment = false;
2529 if (!prop->core.isEnum())
2532 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2534 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2535 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2537 QString string = v->value.asString();
2538 if (!string.at(0).isUpper())
2541 QStringList parts = string.split(QLatin1Char('.'));
2542 if (parts.count() != 2)
2545 QString typeName = parts.at(0);
2547 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2549 //handle enums on value types (where obj->typeName is empty)
2550 QString objTypeName = obj->typeName;
2551 if (objTypeName.isEmpty()) {
2552 QQmlType *objType = toQmlType(obj);
2554 objTypeName = objType->qmlTypeName();
2560 QString enumValue = parts.at(1);
2564 if (objTypeName == type->qmlTypeName()) {
2565 // When these two match, we can short cut the search
2566 if (mprop.isFlagType()) {
2567 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2569 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2572 // Otherwise we have to search the whole type
2573 // This matches the logic in QV8TypeWrapper
2574 QByteArray enumName = enumValue.toUtf8();
2575 const QMetaObject *metaObject = type->baseMetaObject();
2577 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2578 QMetaEnum e = metaObject->enumerator(ii);
2579 value = e.keyToValue(enumName.constData(), &ok);
2586 v->type = Value::Literal;
2587 v->value = QQmlScript::Variant((double)value);
2588 *isAssignment = true;
2593 struct StaticQtMetaObject : public QObject
2595 static const QMetaObject *get()
2596 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2599 // Similar logic to above, but not knowing target property.
2600 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2602 int dot = script.indexOf('.');
2604 const QByteArray &scope = script.left(dot);
2606 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2607 if (!type && scope != "Qt")
2609 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2610 const char *key = script.constData() + dot+1;
2611 int i = mo->enumeratorCount();
2614 int v = mo->enumerator(i).keyToValue(key, &ok);
2622 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2624 QQmlType *qmltype = 0;
2625 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2629 return qmltype->metaObject();
2632 // similar to logic of completeComponentBuild, but also sticks data
2633 // into primitives at the end
2634 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2636 QQmlRewrite::RewriteBinding rewriteBinding;
2637 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2639 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2641 return output->indexForString(rewrite);
2644 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2646 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2647 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2650 // Ensures that the dynamic meta specification on obj is valid
2651 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2653 bool seenDefaultProperty = false;
2655 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2656 // Calculating the hash for the names is not a waste as we have to test
2657 // them against the illegalNames set anyway.
2658 QHashField propNames;
2659 QHashField methodNames;
2662 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2663 const QQmlScript::Object::DynamicProperty &prop = *p;
2665 if (prop.isDefaultProperty) {
2666 if (seenDefaultProperty)
2667 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2668 seenDefaultProperty = true;
2671 if (propNames.testAndSet(prop.name.hash())) {
2672 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2673 p2 = obj->dynamicProperties.next(p2)) {
2674 if (p2->name == prop.name) {
2675 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2676 prop.nameLocation.column,
2677 tr("Duplicate property name"));
2682 if (prop.name.at(0).isUpper()) {
2683 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2684 prop.nameLocation.column,
2685 tr("Property names cannot begin with an upper case letter"));
2688 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2689 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2690 prop.nameLocation.column,
2691 tr("Illegal property name"));
2695 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2696 const QQmlScript::Object::DynamicSignal &currSig = *s;
2698 if (methodNames.testAndSet(currSig.name.hash())) {
2699 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2700 s2 = obj->dynamicSignals.next(s2)) {
2701 if (s2->name == currSig.name)
2702 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2706 if (currSig.name.at(0).isUpper())
2707 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2708 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2709 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2712 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2713 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2715 if (methodNames.testAndSet(currSlot.name.hash())) {
2716 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2717 s2 = obj->dynamicSignals.next(s2)) {
2718 if (s2->name == currSlot.name)
2719 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2721 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2722 s2 = obj->dynamicSlots.next(s2)) {
2723 if (s2->name == currSlot.name)
2724 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2728 if (currSlot.name.at(0).isUpper())
2729 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2730 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2731 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2737 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2739 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2740 p = obj->dynamicProperties.next(p)) {
2742 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2745 Property *property = 0;
2746 if (p->isDefaultProperty) {
2747 property = obj->getDefaultProperty();
2749 property = obj->getProperty(p->name);
2750 if (!property->values.isEmpty())
2751 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2755 property->isReadOnlyDeclaration = true;
2757 if (property->value)
2758 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2760 property->values.append(p->defaultValue->values);
2765 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2767 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2770 Q_ASSERT(obj->metatype);
2772 if (mode != ForceCreation &&
2773 obj->dynamicProperties.isEmpty() &&
2774 obj->dynamicSignals.isEmpty() &&
2775 obj->dynamicSlots.isEmpty())
2778 bool resolveAlias = (mode == ResolveAliases);
2780 const Object::DynamicProperty *defaultProperty = 0;
2782 int varPropCount = 0;
2783 int totalPropCount = 0;
2784 int firstPropertyVarIndex = 0;
2786 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2788 if (p->type == Object::DynamicProperty::Alias)
2790 if (p->type == Object::DynamicProperty::Var)
2793 if (p->isDefaultProperty &&
2794 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2795 defaultProperty = p;
2797 if (!resolveAlias) {
2798 // No point doing this for both the alias and non alias cases
2799 QQmlPropertyData *d = property(obj, p->name);
2800 if (d && d->isFinal())
2801 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2805 bool buildData = resolveAlias || aliasCount == 0;
2807 QByteArray dynamicData;
2809 typedef QQmlVMEMetaData VMD;
2811 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2812 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2813 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2814 aliasCount * sizeof(VMD::AliasData), 0);
2817 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2819 QByteArray newClassName = obj->metatype->className();
2820 newClassName.append("_QML_");
2821 newClassName.append(QByteArray::number(uniqueClassId));
2823 if (compileState->root == obj && !compileState->nested) {
2824 QString path = output->url.path();
2825 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2826 if (lastSlash > -1) {
2827 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2828 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2829 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2833 QFastMetaBuilder builder;
2834 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2835 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2836 obj->dynamicSlots.count(),
2837 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2838 defaultProperty?1:0);
2841 Object::DynamicProperty::Type dtype;
2843 const char *cppType;
2844 } builtinTypes[] = {
2845 { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" },
2846 { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" },
2847 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2848 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2849 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2850 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2851 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2852 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2853 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2854 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2855 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2857 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2858 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2860 // Reserve dynamic properties
2861 if (obj->dynamicProperties.count()) {
2862 typedef QQmlVMEMetaData VMD;
2864 int effectivePropertyIndex = 0;
2865 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2867 // Reserve space for name
2868 p->nameRef = builder.newString(p->name.utf8length());
2870 int propertyType = 0;
2871 bool readonly = false;
2872 QFastMetaBuilder::StringRef typeRef;
2874 if (p->type == Object::DynamicProperty::Alias) {
2876 } else if (p->type < builtinTypeCount) {
2877 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2878 propertyType = builtinTypes[p->type].metaType;
2879 if (typeRefs[p->type].isEmpty())
2880 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2881 typeRef = typeRefs[p->type];
2884 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2885 p->type == Object::DynamicProperty::Custom);
2887 // XXX don't double resolve this in the case of an alias run
2889 QByteArray customTypeName;
2890 QQmlType *qmltype = 0;
2892 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2893 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2896 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2898 Q_ASSERT(tdata->isComplete());
2900 QQmlCompiledData *data = tdata->compiledData();
2901 customTypeName = data->root->className();
2905 customTypeName = qmltype->typeName();
2908 if (p->type == Object::DynamicProperty::Custom) {
2909 customTypeName += '*';
2910 propertyType = QMetaType::QObjectStar;
2913 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2914 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2917 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2918 p->typeRef = builder.newString(customTypeName.length());
2919 typeRef = p->typeRef;
2922 if (p->type == Object::DynamicProperty::Var)
2929 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2930 vmd->propertyCount++;
2931 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2934 if (p->type < builtinTypeCount)
2935 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2936 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2937 effectivePropertyIndex);
2939 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2940 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2941 effectivePropertyIndex);
2943 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2944 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2946 effectivePropertyIndex++;
2950 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2952 vmd->varPropertyCount = varPropCount;
2953 firstPropertyVarIndex = effectivePropertyIndex;
2954 totalPropCount = varPropCount + effectivePropertyIndex;
2955 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2956 if (p->type == Object::DynamicProperty::Var) {
2957 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2959 vmd->propertyCount++;
2960 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2963 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2964 QMetaType::QVariant,
2965 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2966 effectivePropertyIndex);
2968 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2969 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2971 effectivePropertyIndex++;
2978 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2979 if (p->type == Object::DynamicProperty::Alias) {
2981 Q_ASSERT(buildData);
2982 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2983 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2986 // Even if we aren't resolving the alias, we need a fake signal so that the
2987 // metaobject remains consistent across the resolve and non-resolve alias runs
2988 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2989 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2990 effectivePropertyIndex++;
2997 // Reserve default property
2998 QFastMetaBuilder::StringRef defPropRef;
2999 if (defaultProperty) {
3000 defPropRef = builder.newString(strlen("DefaultProperty"));
3001 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3004 // Reserve dynamic signals
3005 int signalIndex = 0;
3006 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3008 int paramCount = s->parameterNames.count();
3010 int signatureSize = s->name.utf8length() + 2 /* paren */;
3012 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
3013 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
3015 s->signatureRef = builder.newString(signatureSize);
3016 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3019 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3021 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
3025 // Reserve dynamic slots
3026 if (obj->dynamicSlots.count()) {
3028 // Allocate QVariant string
3029 if (typeRefs[0].isEmpty())
3030 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
3032 typedef QQmlVMEMetaData VMD;
3034 int methodIndex = 0;
3035 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3036 int paramCount = s->parameterNames.count();
3038 int signatureSize = s->name.utf8length() + 2 /* paren */;
3040 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
3041 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3043 s->signatureRef = builder.newString(signatureSize);
3044 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3046 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
3050 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3051 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3052 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3053 for (int jj = 0; jj < paramCount; ++jj) {
3054 if (jj) funcScript.append(QLatin1Char(','));
3055 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3057 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3059 QByteArray utf8 = funcScript.toUtf8();
3060 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3062 s->location.start.line };
3064 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3067 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3069 md.bodyOffset = dynamicData.size();
3071 dynamicData.append((const char *)utf8.constData(), utf8.length());
3079 // Now allocate used builtin types
3080 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3081 if (!typeRefs[ii].isEmpty())
3082 typeRefs[ii].load(builtinTypes[ii].cppType);
3085 // Now allocate properties
3086 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3088 char *d = p->changedSignatureRef.data();
3089 p->name.writeUtf8(d);
3090 strcpy(d + p->name.utf8length(), "Changed()");
3092 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3095 p->nameRef.load(p->name);
3097 if (p->type >= builtinTypeCount) {
3098 Q_ASSERT(p->resolvedCustomTypeName);
3099 p->typeRef.load(*p->resolvedCustomTypeName);
3103 // Allocate default property if necessary
3104 if (defaultProperty)
3105 strcpy(defPropRef.data(), "DefaultProperty");
3107 // Now allocate signals
3108 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3110 char *d = s->signatureRef.data();
3111 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3112 s->name.writeUtf8(d); d += s->name.utf8length();
3115 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3116 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3117 strcpy(d, s->parameterTypes.at(jj).constData());
3118 d += s->parameterTypes.at(jj).length();
3119 s->parameterNames.at(jj).writeUtf8(d2);
3120 d2 += s->parameterNames.at(jj).utf8length();
3127 // Now allocate methods
3128 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3129 char *d = s->signatureRef.data();
3130 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3131 s->name.writeUtf8(d); d += s->name.utf8length();
3133 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3134 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3135 strcpy(d, "QVariant");
3136 d += strlen("QVariant");
3137 strcpy(d2, s->parameterNames.at(jj).constData());
3138 d2 += s->parameterNames.at(jj).length();
3145 // Now allocate class name
3146 classNameRef.load(newClassName);
3148 obj->metadata = builder.toData();
3149 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3151 if (mode == IgnoreAliases && aliasCount)
3152 compileState->aliasingObjects.append(obj);
3154 obj->synthdata = dynamicData;
3156 if (obj->synthCache) {
3157 obj->synthCache->release();
3158 obj->synthCache = 0;
3161 if (obj->type != -1) {
3162 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3163 QQmlPropertyCache *cache =
3164 superCache->copyAndAppend(engine, &obj->extObject,
3165 QQmlPropertyData::NoFlags,
3166 QQmlPropertyData::IsVMEFunction,
3167 QQmlPropertyData::IsVMESignal);
3169 // now we modify the flags appropriately for var properties.
3170 int propertyOffset = obj->extObject.propertyOffset();
3171 QQmlPropertyData *currPropData = 0;
3172 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3173 currPropData = cache->property(pvi + propertyOffset);
3174 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3177 obj->synthCache = cache;
3183 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3186 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3188 QChar ch = val.at(0);
3189 if (ch.isLetter() && !ch.isLower())
3190 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3192 QChar u(QLatin1Char('_'));
3193 if (!ch.isLetter() && ch != u)
3194 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3196 for (int ii = 1; ii < val.count(); ++ii) {
3198 if (!ch.isLetterOrNumber() && ch != u)
3199 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3202 if (enginePrivate->v8engine()->illegalNames().contains(val))
3203 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3208 #include <private/qqmljsparser_p.h>
3210 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3212 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3214 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3215 return QStringList() << name;
3216 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3217 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3219 QStringList rv = astNodeToStringList(expr->base);
3222 rv.append(expr->name.toString());
3225 return QStringList();
3228 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3230 QQmlScript::Object *obj,
3231 int propIndex, int aliasIndex,
3232 Object::DynamicProperty &prop)
3234 if (!prop.defaultValue)
3235 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3237 if (!prop.defaultValue->values.isOne() ||
3238 prop.defaultValue->values.first()->object ||
3239 !prop.defaultValue->values.first()->value.isScript())
3240 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3242 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3244 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3246 QStringList alias = astNodeToStringList(node);
3248 if (alias.count() < 1 || alias.count() > 3)
3249 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3251 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3253 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3255 QByteArray typeName;
3260 bool writable = false;
3261 bool resettable = false;
3262 if (alias.count() == 2 || alias.count() == 3) {
3263 propIdx = indexOfProperty(idObject, alias.at(1));
3265 if (-1 == propIdx) {
3266 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3267 } else if (propIdx > 0xFFFF) {
3268 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3271 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3272 if (!aliasProperty.isScriptable())
3273 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3275 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3276 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3278 if (aliasProperty.type() < QVariant::UserType
3279 || uint(aliasProperty.type()) == QMetaType::QVariant)
3280 type = aliasProperty.type();
3282 if (alias.count() == 3) {
3283 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3285 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3287 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3289 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3290 if (valueTypeIndex == -1)
3291 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3292 Q_ASSERT(valueTypeIndex <= 0xFF);
3294 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3295 propIdx |= (valueTypeIndex << 16);
3297 // update the property type
3298 type = aliasProperty.type();
3299 if (type >= (int)QVariant::UserType)
3303 if (aliasProperty.isEnumType())
3304 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3306 typeName = aliasProperty.typeName();
3308 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3310 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3312 typeName = ref.type->typeName();
3314 typeName = ref.component->root->className();
3319 if (typeName.endsWith('*'))
3320 flags |= QML_ALIAS_FLAG_PTR;
3322 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3324 typedef QQmlVMEMetaData VMD;
3325 VMD *vmd = (QQmlVMEMetaData *)data.data();
3326 *(vmd->aliasData() + aliasIndex) = aliasData;
3328 prop.nameRef = builder.newString(prop.name.utf8length());
3329 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3330 prop.typeRef = builder.newString(typeName.length());
3332 int propertyFlags = 0;
3334 propertyFlags |= QFastMetaBuilder::Writable;
3336 propertyFlags |= QFastMetaBuilder::Resettable;
3338 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3339 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3345 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3346 QQmlScript::Property *prop,
3347 const BindingContext &ctxt)
3349 Q_ASSERT(prop->index != -1);
3350 Q_ASSERT(prop->parent);
3351 Q_ASSERT(prop->parent->metaObject());
3353 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3354 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3356 JSBindingReference *reference = pool->New<JSBindingReference>();
3357 reference->expression = value->value;
3358 reference->property = prop;
3359 reference->value = value;
3360 reference->bindingContext = ctxt;
3361 addBindingReference(reference);
3366 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3367 QQmlScript::Property *prop,
3368 const QQmlCompilerTypes::BindingContext &)
3370 Q_ASSERT(v->value.isScript());
3372 if (!prop->core.isWritable())
3375 AST::Node *binding = v->value.asAST();
3377 if (prop->type == QVariant::String) {
3378 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3379 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3380 if (i->name == qsTrId_string) {
3381 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3382 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3384 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3385 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3386 (!arg2 || !arg2->next)) {
3391 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3392 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3394 TrBindingReference *reference = pool->New<TrBindingReference>();
3395 reference->dataType = BindingReference::TrId;
3396 reference->text = text;
3398 v->bindingReference = reference;
3402 } else if (i->name == qsTr_string) {
3404 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3405 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3406 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3408 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3409 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3410 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3411 (!arg3 || !arg3->next)) {
3417 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3418 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3419 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3421 TrBindingReference *reference = pool->New<TrBindingReference>();
3422 reference->dataType = BindingReference::Tr;
3423 reference->text = text;
3424 reference->comment = comment;
3426 v->bindingReference = reference;
3439 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3440 QQmlScript::Property *prop,
3441 QQmlScript::Object *obj,
3442 QQmlScript::Property *valueTypeProperty)
3445 Q_ASSERT(binding->bindingReference);
3447 const BindingReference &ref = *binding->bindingReference;
3448 if (ref.dataType == BindingReference::TrId) {
3449 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3451 Instruction::StoreTrIdString store;
3452 store.propertyIndex = prop->core.coreIndex;
3453 store.text = output->indexForByteArray(tr.text.toUtf8());
3455 output->addInstruction(store);
3456 } else if (ref.dataType == BindingReference::Tr) {
3457 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3459 Instruction::StoreTrString store;
3460 store.propertyIndex = prop->core.coreIndex;
3461 store.context = translationContextIndex();
3462 store.text = output->indexForByteArray(tr.text.toUtf8());
3463 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3465 output->addInstruction(store);
3466 } else if (ref.dataType == BindingReference::V4) {
3467 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3469 Instruction::StoreV4Binding store;
3470 store.value = js.compiledIndex;
3471 store.context = js.bindingContext.stack;
3472 store.owner = js.bindingContext.owner;
3473 if (valueTypeProperty) {
3474 store.property = (valueTypeProperty->index & 0xFFFF) |
3475 ((valueTypeProperty->type & 0xFF)) << 16 |
3476 ((prop->index & 0xFF) << 24);
3477 store.isRoot = (compileState->root == valueTypeProperty->parent);
3479 store.property = prop->index;
3480 store.isRoot = (compileState->root == obj);
3482 store.line = binding->location.start.line;
3483 store.column = binding->location.start.column;
3484 output->addInstruction(store);
3485 } else if (ref.dataType == BindingReference::V8) {
3486 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3488 Instruction::StoreV8Binding store;
3489 store.value = js.compiledIndex;
3490 store.context = js.bindingContext.stack;
3491 store.owner = js.bindingContext.owner;
3492 if (valueTypeProperty) {
3493 store.isRoot = (compileState->root == valueTypeProperty->parent);
3495 store.isRoot = (compileState->root == obj);
3497 store.line = binding->location.start.line;
3498 store.column = binding->location.start.column;
3500 Q_ASSERT(js.bindingContext.owner == 0 ||
3501 (js.bindingContext.owner != 0 && valueTypeProperty));
3502 if (js.bindingContext.owner) {
3503 store.property = genValueTypeData(prop, valueTypeProperty);
3505 store.property = prop->core;
3508 output->addInstruction(store);
3509 } else if (ref.dataType == BindingReference::QtScript) {
3510 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3512 QQmlInstruction store;
3513 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3514 store.assignBinding.context = js.bindingContext.stack;
3515 store.assignBinding.owner = js.bindingContext.owner;
3516 store.assignBinding.line = binding->location.start.line;
3517 store.assignBinding.column = binding->location.start.column;
3519 if (valueTypeProperty) {
3520 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3522 store.assignBinding.isRoot = (compileState->root == obj);
3525 Q_ASSERT(js.bindingContext.owner == 0 ||
3526 (js.bindingContext.owner != 0 && valueTypeProperty));
3527 if (js.bindingContext.owner) {
3528 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3530 store.assignBinding.property = prop->core;
3532 output->addInstructionHelper(
3533 !prop->isAlias ? QQmlInstruction::StoreBinding
3534 : QQmlInstruction::StoreBindingOnAlias
3537 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3541 int QQmlCompiler::genContextCache()
3543 if (compileState->ids.count() == 0)
3546 QQmlIntegerCache *cache = new QQmlIntegerCache();
3547 cache->reserve(compileState->ids.count());
3548 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3549 cache->add(o->id, o->idIndex);
3551 output->contextCaches.append(cache);
3552 return output->contextCaches.count() - 1;
3556 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3557 QQmlScript::Property *prop)
3559 typedef QQmlPropertyPrivate QDPP;
3560 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3561 enginePrivate->valueTypes[prop->type]->metaObject(),
3562 valueTypeProp->index, engine);
3565 bool QQmlCompiler::completeComponentBuild()
3568 componentStats->componentStat.ids = compileState->ids.count();
3570 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3571 aliasObject = compileState->aliasingObjects.next(aliasObject))
3572 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3574 QV4Compiler::Expression expr(unit->imports());
3575 expr.component = compileState->root;
3576 expr.ids = &compileState->ids;
3577 expr.importCache = output->importCache;
3579 QV4Compiler bindingCompiler;
3581 QList<JSBindingReference*> sharedBindings;
3583 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3585 JSBindingReference &binding = *b;
3587 // ### We don't currently optimize for bindings on alias's - because
3588 // of the solution to QTBUG-13719
3589 if (!binding.property->isAlias) {
3590 expr.context = binding.bindingContext.object;
3591 expr.property = binding.property;
3592 expr.expression = binding.expression;
3594 int index = bindingCompiler.compile(expr, enginePrivate);
3596 binding.dataType = BindingReference::V4;
3597 binding.compiledIndex = index;
3599 componentStats->componentStat.optimizedBindings.append(b->value->location);
3604 // Pre-rewrite the expression
3605 QString expression = binding.expression.asScript();
3607 QQmlRewrite::RewriteBinding rewriteBinding;
3608 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3609 bool isSharable = false;
3610 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3612 if (isSharable && !binding.property->isValueTypeSubProperty && !binding.property->isAlias /* See above re alias */ &&
3613 binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3614 binding.dataType = BindingReference::V8;
3615 sharedBindings.append(b);
3617 binding.dataType = BindingReference::QtScript;
3621 componentStats->componentStat.scriptBindings.append(b->value->location);
3624 if (!sharedBindings.isEmpty()) {
3626 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3628 return lhs->value->location.start.line < rhs->value->location.start.line;
3632 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3634 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3635 int lineNumber = startLineNumber;
3637 QByteArray functionArray("[", 1);
3638 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3640 JSBindingReference *reference = sharedBindings.at(ii);
3641 QQmlScript::Value *value = reference->value;
3642 const QString &expression = reference->rewrittenExpression;
3644 if (ii != 0) functionArray.append(",", 1);
3646 while (lineNumber < value->location.start.line) {
3648 functionArray.append("\n", 1);
3651 functionArray += expression.toUtf8();
3652 lineNumber += expression.count(QLatin1Char('\n'));
3653 reference->compiledIndex = ii;
3655 functionArray.append("]", 1);
3657 compileState->v8BindingProgram = functionArray;
3658 compileState->v8BindingProgramLine = startLineNumber;
3661 if (bindingCompiler.isValid())
3662 compileState->compiledBindingData = bindingCompiler.program();
3664 // Check pop()'s matched push()'s
3665 Q_ASSERT(compileState->objectDepth.depth() == 0);
3666 Q_ASSERT(compileState->listDepth.depth() == 0);
3668 saveComponentState();
3673 void QQmlCompiler::dumpStats()
3675 Q_ASSERT(componentStats);
3676 qWarning().nospace() << "QML Document: " << output->url.toString();
3677 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3678 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3679 qWarning().nospace() << " Component Line " << stat.lineNumber;
3680 qWarning().nospace() << " Total Objects: " << stat.objects;
3681 qWarning().nospace() << " IDs Used: " << stat.ids;
3682 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3686 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3687 if (0 == (ii % 10)) {
3688 if (ii) output.append("\n");
3693 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3695 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3696 output.append(") ");
3698 if (!output.isEmpty())
3699 qWarning().nospace() << output.constData();
3702 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3705 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3706 if (0 == (ii % 10)) {
3707 if (ii) output.append("\n");
3712 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3714 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3715 output.append(") ");
3717 if (!output.isEmpty())
3718 qWarning().nospace() << output.constData();
3724 Returns true if from can be assigned to a (QObject) property of type
3727 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3729 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3730 const QMetaObject *fromMo = from->metaObject();
3733 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3735 fromMo = fromMo->superClass();
3741 Returns the element name, as written in the QML file, for o.
3743 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3746 if (o->type != -1) {
3747 return output->types.at(o->type).className;
3753 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3756 const QMetaObject *mo = from->metatype;
3758 while (!type && mo) {
3759 type = QQmlMetaType::qmlType(mo);
3760 mo = mo->superClass();
3765 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3767 const QMetaObject *mo = obj->metatype;
3769 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3771 return QStringList();
3773 QMetaClassInfo classInfo = mo->classInfo(idx);
3774 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3779 QQmlCompiler::property(QQmlScript::Object *object, int index)
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 = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3790 return cache->property(index);
3794 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3796 if (notInRevision) *notInRevision = false;
3798 QQmlPropertyCache *cache = 0;
3800 if (object->synthCache)
3801 cache = object->synthCache;
3802 else if (object->type != -1)
3803 cache = output->types[object->type].createPropertyCache(engine);
3805 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3807 QQmlPropertyData *d = cache->property(name);
3809 // Find the first property
3810 while (d && d->isFunction())
3811 d = cache->overrideData(d);
3813 if (d && !cache->isAllowedInRevision(d)) {
3814 if (notInRevision) *notInRevision = true;
3821 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3823 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3825 if (notInRevision) *notInRevision = false;
3827 QQmlPropertyCache *cache = 0;
3829 if (object->synthCache)
3830 cache = object->synthCache;
3831 else if (object->type != -1)
3832 cache = output->types[object->type].createPropertyCache(engine);
3834 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3837 QQmlPropertyData *d = cache->property(name);
3838 if (notInRevision) *notInRevision = false;
3840 while (d && !(d->isFunction()))
3841 d = cache->overrideData(d);
3843 if (d && !cache->isAllowedInRevision(d)) {
3844 if (notInRevision) *notInRevision = true;
3850 if (name.endsWith(Changed_string)) {
3851 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3853 d = property(object, propName, notInRevision);
3855 return cache->method(d->notifyIndex);
3861 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3862 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3863 bool *notInRevision)
3865 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3866 return d?d->coreIndex:-1;
3869 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3870 bool *notInRevision)
3872 return indexOfProperty(object, QStringRef(&name), notInRevision);
3875 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3876 bool *notInRevision)
3878 QQmlPropertyData *d = property(object, name, notInRevision);
3879 return d?d->coreIndex:-1;