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() || prop->core.propType == QMetaType::Int)
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() || prop->core.propType == QMetaType::Int) {
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 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2529 *isAssignment = false;
2530 if (!prop->core.isEnum() && !isIntProp)
2533 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2535 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2536 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2538 QString string = v->value.asString();
2539 if (!string.at(0).isUpper())
2543 // Allow enum assignment to ints.
2544 int enumval = evaluateEnum(string.toUtf8());
2545 if (enumval != -1) {
2546 v->type = Value::Literal;
2547 v->value = QQmlScript::Variant((double)enumval);
2548 *isAssignment = true;
2553 QStringList parts = string.split(QLatin1Char('.'));
2554 if (parts.count() != 2)
2557 QString typeName = parts.at(0);
2559 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2561 //handle enums on value types (where obj->typeName is empty)
2562 QString objTypeName = obj->typeName;
2563 if (objTypeName.isEmpty()) {
2564 QQmlType *objType = toQmlType(obj);
2566 objTypeName = objType->qmlTypeName();
2572 QString enumValue = parts.at(1);
2576 if (objTypeName == type->qmlTypeName()) {
2577 // When these two match, we can short cut the search
2578 if (mprop.isFlagType()) {
2579 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2581 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2584 // Otherwise we have to search the whole type
2585 // This matches the logic in QV8TypeWrapper
2586 QByteArray enumName = enumValue.toUtf8();
2587 const QMetaObject *metaObject = type->baseMetaObject();
2589 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2590 QMetaEnum e = metaObject->enumerator(ii);
2591 value = e.keyToValue(enumName.constData(), &ok);
2598 v->type = Value::Literal;
2599 v->value = QQmlScript::Variant((double)value);
2600 *isAssignment = true;
2605 struct StaticQtMetaObject : public QObject
2607 static const QMetaObject *get()
2608 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2611 // Similar logic to above, but not knowing target property.
2612 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2614 int dot = script.indexOf('.');
2616 const QByteArray &scope = script.left(dot);
2618 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2619 if (!type && scope != "Qt")
2621 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2622 const char *key = script.constData() + dot+1;
2623 int i = mo->enumeratorCount();
2626 int v = mo->enumerator(i).keyToValue(key, &ok);
2634 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2636 QQmlType *qmltype = 0;
2637 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2641 return qmltype->metaObject();
2644 // similar to logic of completeComponentBuild, but also sticks data
2645 // into primitives at the end
2646 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2648 QQmlRewrite::RewriteBinding rewriteBinding;
2649 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2651 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2653 return output->indexForString(rewrite);
2656 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2658 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2659 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2662 // Ensures that the dynamic meta specification on obj is valid
2663 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2665 bool seenDefaultProperty = false;
2667 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2668 // Calculating the hash for the names is not a waste as we have to test
2669 // them against the illegalNames set anyway.
2670 QHashField propNames;
2671 QHashField methodNames;
2674 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2675 const QQmlScript::Object::DynamicProperty &prop = *p;
2677 if (prop.isDefaultProperty) {
2678 if (seenDefaultProperty)
2679 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2680 seenDefaultProperty = true;
2683 if (propNames.testAndSet(prop.name.hash())) {
2684 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2685 p2 = obj->dynamicProperties.next(p2)) {
2686 if (p2->name == prop.name) {
2687 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2688 prop.nameLocation.column,
2689 tr("Duplicate property name"));
2694 if (prop.name.at(0).isUpper()) {
2695 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2696 prop.nameLocation.column,
2697 tr("Property names cannot begin with an upper case letter"));
2700 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2701 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2702 prop.nameLocation.column,
2703 tr("Illegal property name"));
2707 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2708 const QQmlScript::Object::DynamicSignal &currSig = *s;
2710 if (methodNames.testAndSet(currSig.name.hash())) {
2711 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2712 s2 = obj->dynamicSignals.next(s2)) {
2713 if (s2->name == currSig.name)
2714 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2718 if (currSig.name.at(0).isUpper())
2719 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2720 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2721 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2724 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2725 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2727 if (methodNames.testAndSet(currSlot.name.hash())) {
2728 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2729 s2 = obj->dynamicSignals.next(s2)) {
2730 if (s2->name == currSlot.name)
2731 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2733 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2734 s2 = obj->dynamicSlots.next(s2)) {
2735 if (s2->name == currSlot.name)
2736 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2740 if (currSlot.name.at(0).isUpper())
2741 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2742 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2743 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2749 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2751 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2752 p = obj->dynamicProperties.next(p)) {
2754 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2757 Property *property = 0;
2758 if (p->isDefaultProperty) {
2759 property = obj->getDefaultProperty();
2761 property = obj->getProperty(p->name);
2762 if (!property->values.isEmpty())
2763 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2767 property->isReadOnlyDeclaration = true;
2769 if (property->value)
2770 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2772 property->values.append(p->defaultValue->values);
2777 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2779 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2782 Q_ASSERT(obj->metatype);
2784 if (mode != ForceCreation &&
2785 obj->dynamicProperties.isEmpty() &&
2786 obj->dynamicSignals.isEmpty() &&
2787 obj->dynamicSlots.isEmpty())
2790 bool resolveAlias = (mode == ResolveAliases);
2792 const Object::DynamicProperty *defaultProperty = 0;
2794 int varPropCount = 0;
2795 int totalPropCount = 0;
2796 int firstPropertyVarIndex = 0;
2798 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2800 if (p->type == Object::DynamicProperty::Alias)
2802 if (p->type == Object::DynamicProperty::Var)
2805 if (p->isDefaultProperty &&
2806 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2807 defaultProperty = p;
2809 if (!resolveAlias) {
2810 // No point doing this for both the alias and non alias cases
2811 QQmlPropertyData *d = property(obj, p->name);
2812 if (d && d->isFinal())
2813 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2817 bool buildData = resolveAlias || aliasCount == 0;
2819 QByteArray dynamicData;
2821 typedef QQmlVMEMetaData VMD;
2823 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2824 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2825 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2826 aliasCount * sizeof(VMD::AliasData), 0);
2829 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2831 QByteArray newClassName = obj->metatype->className();
2832 newClassName.append("_QML_");
2833 newClassName.append(QByteArray::number(uniqueClassId));
2835 if (compileState->root == obj && !compileState->nested) {
2836 QString path = output->url.path();
2837 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2838 if (lastSlash > -1) {
2839 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2840 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2841 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2845 QFastMetaBuilder builder;
2846 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2847 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2848 obj->dynamicSlots.count(),
2849 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2850 defaultProperty?1:0);
2853 Object::DynamicProperty::Type dtype;
2855 const char *cppType;
2856 } builtinTypes[] = {
2857 { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" },
2858 { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" },
2859 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2860 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2861 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2862 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2863 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2864 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2865 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2866 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2867 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2869 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2870 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2872 // Reserve dynamic properties
2873 if (obj->dynamicProperties.count()) {
2874 typedef QQmlVMEMetaData VMD;
2876 int effectivePropertyIndex = 0;
2877 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2879 // Reserve space for name
2880 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2881 p->nameRef = builder.newString(p->name.utf8length());
2883 int propertyType = 0;
2884 bool readonly = false;
2885 QFastMetaBuilder::StringRef typeRef;
2887 if (p->type == Object::DynamicProperty::Alias) {
2889 } else if (p->type < builtinTypeCount) {
2890 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2891 propertyType = builtinTypes[p->type].metaType;
2892 if (typeRefs[p->type].isEmpty())
2893 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2894 typeRef = typeRefs[p->type];
2897 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2898 p->type == Object::DynamicProperty::Custom);
2900 // XXX don't double resolve this in the case of an alias run
2902 QByteArray customTypeName;
2903 QQmlType *qmltype = 0;
2905 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2906 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2909 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2911 Q_ASSERT(tdata->isComplete());
2913 QQmlCompiledData *data = tdata->compiledData();
2914 customTypeName = data->root->className();
2918 customTypeName = qmltype->typeName();
2921 if (p->type == Object::DynamicProperty::Custom) {
2922 customTypeName += '*';
2923 propertyType = QMetaType::QObjectStar;
2926 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2927 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2930 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2931 p->typeRef = builder.newString(customTypeName.length());
2932 typeRef = p->typeRef;
2935 if (p->type == Object::DynamicProperty::Var)
2942 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2943 vmd->propertyCount++;
2944 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2947 if (p->type < builtinTypeCount)
2948 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2949 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2950 effectivePropertyIndex);
2952 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2953 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2954 effectivePropertyIndex);
2956 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2957 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2959 effectivePropertyIndex++;
2963 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2965 vmd->varPropertyCount = varPropCount;
2966 firstPropertyVarIndex = effectivePropertyIndex;
2967 totalPropCount = varPropCount + effectivePropertyIndex;
2968 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2969 if (p->type == Object::DynamicProperty::Var) {
2970 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2972 vmd->propertyCount++;
2973 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2976 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2977 QMetaType::QVariant,
2978 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2979 effectivePropertyIndex);
2981 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2982 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2984 effectivePropertyIndex++;
2991 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2992 if (p->type == Object::DynamicProperty::Alias) {
2994 Q_ASSERT(buildData);
2995 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2996 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2999 // Even if we aren't resolving the alias, we need a fake signal so that the
3000 // metaobject remains consistent across the resolve and non-resolve alias runs
3001 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
3002 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
3003 effectivePropertyIndex++;
3010 // Reserve default property
3011 QFastMetaBuilder::StringRef defPropRef;
3012 if (defaultProperty) {
3013 defPropRef = builder.newString(strlen("DefaultProperty"));
3014 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3017 // Reserve dynamic signals
3018 int signalIndex = 0;
3019 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3021 int paramCount = s->parameterNames.count();
3023 int signatureSize = s->name.utf8length() + 2 /* paren */;
3025 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
3026 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
3028 s->signatureRef = builder.newString(signatureSize);
3029 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3032 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3034 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
3038 // Reserve dynamic slots
3039 if (obj->dynamicSlots.count()) {
3041 // Allocate QVariant string
3042 if (typeRefs[0].isEmpty())
3043 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
3045 typedef QQmlVMEMetaData VMD;
3047 int methodIndex = 0;
3048 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3049 int paramCount = s->parameterNames.count();
3051 int signatureSize = s->name.utf8length() + 2 /* paren */;
3053 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
3054 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3056 s->signatureRef = builder.newString(signatureSize);
3057 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3059 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
3063 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3064 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3065 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3066 for (int jj = 0; jj < paramCount; ++jj) {
3067 if (jj) funcScript.append(QLatin1Char(','));
3068 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3070 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3072 QByteArray utf8 = funcScript.toUtf8();
3073 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3075 s->location.start.line };
3077 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3080 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3082 md.bodyOffset = dynamicData.size();
3084 dynamicData.append((const char *)utf8.constData(), utf8.length());
3092 // Now allocate used builtin types
3093 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3094 if (!typeRefs[ii].isEmpty())
3095 typeRefs[ii].load(builtinTypes[ii].cppType);
3098 // Now allocate properties
3099 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3101 char *d = p->changedSignatureRef.data();
3102 p->name.writeUtf8(d);
3103 strcpy(d + p->name.utf8length(), "Changed()");
3105 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3108 p->nameRef.load(p->name);
3110 if (p->type >= builtinTypeCount) {
3111 Q_ASSERT(p->resolvedCustomTypeName);
3112 p->typeRef.load(*p->resolvedCustomTypeName);
3116 // Allocate default property if necessary
3117 if (defaultProperty)
3118 defPropRef.load("DefaultProperty");
3120 // Now allocate signals
3121 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3123 char *d = s->signatureRef.data();
3124 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3125 s->name.writeUtf8(d); d += s->name.utf8length();
3128 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3129 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3130 strcpy(d, s->parameterTypes.at(jj).constData());
3131 d += s->parameterTypes.at(jj).length();
3132 s->parameterNames.at(jj).writeUtf8(d2);
3133 d2 += s->parameterNames.at(jj).utf8length();
3140 // Now allocate methods
3141 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3142 char *d = s->signatureRef.data();
3143 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3144 s->name.writeUtf8(d); d += s->name.utf8length();
3146 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3147 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3148 strcpy(d, "QVariant");
3149 d += strlen("QVariant");
3150 strcpy(d2, s->parameterNames.at(jj).constData());
3151 d2 += s->parameterNames.at(jj).length();
3158 // Now allocate class name
3159 classNameRef.load(newClassName);
3161 obj->metadata = builder.toData();
3162 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3164 if (mode == IgnoreAliases && aliasCount)
3165 compileState->aliasingObjects.append(obj);
3167 obj->synthdata = dynamicData;
3169 if (obj->synthCache) {
3170 obj->synthCache->release();
3171 obj->synthCache = 0;
3174 if (obj->type != -1) {
3175 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3176 QQmlPropertyCache *cache =
3177 superCache->copyAndAppend(engine, &obj->extObject,
3178 QQmlPropertyData::NoFlags,
3179 QQmlPropertyData::IsVMEFunction,
3180 QQmlPropertyData::IsVMESignal);
3182 // now we modify the flags appropriately for var properties.
3183 int propertyOffset = obj->extObject.propertyOffset();
3184 QQmlPropertyData *currPropData = 0;
3185 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3186 currPropData = cache->property(pvi + propertyOffset);
3187 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3190 obj->synthCache = cache;
3196 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3199 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3201 QChar ch = val.at(0);
3202 if (ch.isLetter() && !ch.isLower())
3203 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3205 QChar u(QLatin1Char('_'));
3206 if (!ch.isLetter() && ch != u)
3207 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3209 for (int ii = 1; ii < val.count(); ++ii) {
3211 if (!ch.isLetterOrNumber() && ch != u)
3212 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3215 if (enginePrivate->v8engine()->illegalNames().contains(val))
3216 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3221 #include <private/qqmljsparser_p.h>
3223 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3225 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3227 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3228 return QStringList() << name;
3229 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3230 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3232 QStringList rv = astNodeToStringList(expr->base);
3235 rv.append(expr->name.toString());
3238 return QStringList();
3241 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3243 QQmlScript::Object *obj,
3244 int propIndex, int aliasIndex,
3245 Object::DynamicProperty &prop)
3247 Q_ASSERT(!prop.nameRef.isEmpty());
3248 Q_ASSERT(prop.typeRef.isEmpty());
3249 if (!prop.defaultValue)
3250 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3252 if (!prop.defaultValue->values.isOne() ||
3253 prop.defaultValue->values.first()->object ||
3254 !prop.defaultValue->values.first()->value.isScript())
3255 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3257 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3259 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3261 QStringList alias = astNodeToStringList(node);
3263 if (alias.count() < 1 || alias.count() > 3)
3264 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3266 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3268 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3270 QByteArray typeName;
3275 bool writable = false;
3276 bool resettable = false;
3277 if (alias.count() == 2 || alias.count() == 3) {
3278 propIdx = indexOfProperty(idObject, alias.at(1));
3280 if (-1 == propIdx) {
3281 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3282 } else if (propIdx > 0xFFFF) {
3283 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3286 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3287 if (!aliasProperty.isScriptable())
3288 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3290 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3291 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3293 if (aliasProperty.type() < QVariant::UserType
3294 || uint(aliasProperty.type()) == QMetaType::QVariant)
3295 type = aliasProperty.type();
3297 if (alias.count() == 3) {
3298 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3300 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3302 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3304 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3305 if (valueTypeIndex == -1)
3306 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3307 Q_ASSERT(valueTypeIndex <= 0xFF);
3309 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3310 propIdx |= (valueTypeIndex << 16);
3312 // update the property type
3313 type = aliasProperty.type();
3314 if (type >= (int)QVariant::UserType)
3318 if (aliasProperty.isEnumType())
3319 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3321 typeName = aliasProperty.typeName();
3323 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3325 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3327 typeName = ref.type->typeName();
3329 typeName = ref.component->root->className();
3334 if (typeName.endsWith('*'))
3335 flags |= QML_ALIAS_FLAG_PTR;
3337 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3339 typedef QQmlVMEMetaData VMD;
3340 VMD *vmd = (QQmlVMEMetaData *)data.data();
3341 *(vmd->aliasData() + aliasIndex) = aliasData;
3343 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3344 prop.typeRef = builder.newString(typeName.length());
3346 int propertyFlags = 0;
3348 propertyFlags |= QFastMetaBuilder::Writable;
3350 propertyFlags |= QFastMetaBuilder::Resettable;
3352 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3353 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3359 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3360 QQmlScript::Property *prop,
3361 const BindingContext &ctxt)
3363 Q_ASSERT(prop->index != -1);
3364 Q_ASSERT(prop->parent);
3365 Q_ASSERT(prop->parent->metaObject());
3367 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3368 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3370 JSBindingReference *reference = pool->New<JSBindingReference>();
3371 reference->expression = value->value;
3372 reference->property = prop;
3373 reference->value = value;
3374 reference->bindingContext = ctxt;
3375 addBindingReference(reference);
3380 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3381 QQmlScript::Property *prop,
3382 const QQmlCompilerTypes::BindingContext &)
3384 Q_ASSERT(v->value.isScript());
3386 if (!prop->core.isWritable())
3389 AST::Node *binding = v->value.asAST();
3391 if (prop->type == QVariant::String) {
3392 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3393 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3394 if (i->name == qsTrId_string) {
3395 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3396 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3398 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3399 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3400 (!arg2 || !arg2->next)) {
3405 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3406 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3408 TrBindingReference *reference = pool->New<TrBindingReference>();
3409 reference->dataType = BindingReference::TrId;
3410 reference->text = text;
3412 v->bindingReference = reference;
3416 } else if (i->name == qsTr_string) {
3418 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3419 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3420 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3422 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3423 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3424 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3425 (!arg3 || !arg3->next)) {
3431 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3432 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3433 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3435 TrBindingReference *reference = pool->New<TrBindingReference>();
3436 reference->dataType = BindingReference::Tr;
3437 reference->text = text;
3438 reference->comment = comment;
3440 v->bindingReference = reference;
3453 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3454 QQmlScript::Property *prop,
3455 QQmlScript::Object *obj,
3456 QQmlScript::Property *valueTypeProperty)
3459 Q_ASSERT(binding->bindingReference);
3461 const BindingReference &ref = *binding->bindingReference;
3462 if (ref.dataType == BindingReference::TrId) {
3463 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3465 Instruction::StoreTrIdString store;
3466 store.propertyIndex = prop->core.coreIndex;
3467 store.text = output->indexForByteArray(tr.text.toUtf8());
3469 output->addInstruction(store);
3470 } else if (ref.dataType == BindingReference::Tr) {
3471 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3473 Instruction::StoreTrString store;
3474 store.propertyIndex = prop->core.coreIndex;
3475 store.context = translationContextIndex();
3476 store.text = output->indexForByteArray(tr.text.toUtf8());
3477 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3479 output->addInstruction(store);
3480 } else if (ref.dataType == BindingReference::V4) {
3481 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3483 Instruction::StoreV4Binding store;
3484 store.value = js.compiledIndex;
3485 store.context = js.bindingContext.stack;
3486 store.owner = js.bindingContext.owner;
3487 if (valueTypeProperty) {
3488 store.property = (valueTypeProperty->index & 0xFFFF) |
3489 ((valueTypeProperty->type & 0xFF)) << 16 |
3490 ((prop->index & 0xFF) << 24);
3491 store.isRoot = (compileState->root == valueTypeProperty->parent);
3493 store.property = prop->index;
3494 store.isRoot = (compileState->root == obj);
3496 store.line = binding->location.start.line;
3497 store.column = binding->location.start.column;
3498 output->addInstruction(store);
3499 } else if (ref.dataType == BindingReference::V8) {
3500 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3502 Instruction::StoreV8Binding store;
3503 store.value = js.compiledIndex;
3504 store.context = js.bindingContext.stack;
3505 store.owner = js.bindingContext.owner;
3506 if (valueTypeProperty) {
3507 store.isRoot = (compileState->root == valueTypeProperty->parent);
3509 store.isRoot = (compileState->root == obj);
3511 store.line = binding->location.start.line;
3512 store.column = binding->location.start.column;
3514 Q_ASSERT(js.bindingContext.owner == 0 ||
3515 (js.bindingContext.owner != 0 && valueTypeProperty));
3516 if (js.bindingContext.owner) {
3517 store.property = genValueTypeData(prop, valueTypeProperty);
3519 store.property = prop->core;
3522 output->addInstruction(store);
3523 } else if (ref.dataType == BindingReference::QtScript) {
3524 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3526 QQmlInstruction store;
3527 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3528 store.assignBinding.context = js.bindingContext.stack;
3529 store.assignBinding.owner = js.bindingContext.owner;
3530 store.assignBinding.line = binding->location.start.line;
3531 store.assignBinding.column = binding->location.start.column;
3533 if (valueTypeProperty) {
3534 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3536 store.assignBinding.isRoot = (compileState->root == obj);
3539 Q_ASSERT(js.bindingContext.owner == 0 ||
3540 (js.bindingContext.owner != 0 && valueTypeProperty));
3541 if (js.bindingContext.owner) {
3542 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3544 store.assignBinding.property = prop->core;
3546 output->addInstructionHelper(
3547 !prop->isAlias ? QQmlInstruction::StoreBinding
3548 : QQmlInstruction::StoreBindingOnAlias
3551 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3555 int QQmlCompiler::genContextCache()
3557 if (compileState->ids.count() == 0)
3560 QQmlIntegerCache *cache = new QQmlIntegerCache();
3561 cache->reserve(compileState->ids.count());
3562 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3563 cache->add(o->id, o->idIndex);
3565 output->contextCaches.append(cache);
3566 return output->contextCaches.count() - 1;
3570 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3571 QQmlScript::Property *prop)
3573 typedef QQmlPropertyPrivate QDPP;
3574 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3575 enginePrivate->valueTypes[prop->type]->metaObject(),
3576 valueTypeProp->index, engine);
3579 bool QQmlCompiler::completeComponentBuild()
3582 componentStats->componentStat.ids = compileState->ids.count();
3584 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3585 aliasObject = compileState->aliasingObjects.next(aliasObject))
3586 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3588 QV4Compiler::Expression expr(unit->imports());
3589 expr.component = compileState->root;
3590 expr.ids = &compileState->ids;
3591 expr.importCache = output->importCache;
3593 QV4Compiler bindingCompiler;
3595 QList<JSBindingReference*> sharedBindings;
3597 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3599 JSBindingReference &binding = *b;
3601 // ### We don't currently optimize for bindings on alias's - because
3602 // of the solution to QTBUG-13719
3603 if (!binding.property->isAlias) {
3604 expr.context = binding.bindingContext.object;
3605 expr.property = binding.property;
3606 expr.expression = binding.expression;
3608 int index = bindingCompiler.compile(expr, enginePrivate);
3610 binding.dataType = BindingReference::V4;
3611 binding.compiledIndex = index;
3613 componentStats->componentStat.optimizedBindings.append(b->value->location);
3618 // Pre-rewrite the expression
3619 QString expression = binding.expression.asScript();
3621 QQmlRewrite::RewriteBinding rewriteBinding;
3622 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3623 bool isSharable = false;
3624 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3626 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3627 binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3628 binding.dataType = BindingReference::V8;
3629 sharedBindings.append(b);
3632 componentStats->componentStat.sharedBindings.append(b->value->location);
3634 binding.dataType = BindingReference::QtScript;
3637 componentStats->componentStat.scriptBindings.append(b->value->location);
3641 if (!sharedBindings.isEmpty()) {
3643 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3645 return lhs->value->location.start.line < rhs->value->location.start.line;
3649 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3651 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3652 int lineNumber = startLineNumber;
3654 QByteArray functionArray("[", 1);
3655 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3657 JSBindingReference *reference = sharedBindings.at(ii);
3658 QQmlScript::Value *value = reference->value;
3659 const QString &expression = reference->rewrittenExpression;
3661 if (ii != 0) functionArray.append(",", 1);
3663 while (lineNumber < value->location.start.line) {
3665 functionArray.append("\n", 1);
3668 functionArray += expression.toUtf8();
3669 lineNumber += expression.count(QLatin1Char('\n'));
3670 reference->compiledIndex = ii;
3672 functionArray.append("]", 1);
3674 compileState->v8BindingProgram = functionArray;
3675 compileState->v8BindingProgramLine = startLineNumber;
3678 if (bindingCompiler.isValid())
3679 compileState->compiledBindingData = bindingCompiler.program();
3681 // Check pop()'s matched push()'s
3682 Q_ASSERT(compileState->objectDepth.depth() == 0);
3683 Q_ASSERT(compileState->listDepth.depth() == 0);
3685 saveComponentState();
3690 void QQmlCompiler::dumpStats()
3692 Q_ASSERT(componentStats);
3693 qWarning().nospace() << "QML Document: " << output->url.toString();
3694 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3695 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3696 qWarning().nospace() << " Component Line " << stat.lineNumber;
3697 qWarning().nospace() << " Total Objects: " << stat.objects;
3698 qWarning().nospace() << " IDs Used: " << stat.ids;
3699 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3703 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3704 if (0 == (ii % 10)) {
3705 if (ii) output.append("\n");
3710 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3712 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3713 output.append(") ");
3715 if (!output.isEmpty())
3716 qWarning().nospace() << output.constData();
3719 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3722 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3723 if (0 == (ii % 10)) {
3724 if (ii) output.append("\n");
3729 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3731 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3732 output.append(") ");
3734 if (!output.isEmpty())
3735 qWarning().nospace() << output.constData();
3738 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3741 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3742 if (0 == (ii % 10)) {
3743 if (ii) output.append("\n");
3748 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3750 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3751 output.append(") ");
3753 if (!output.isEmpty())
3754 qWarning().nospace() << output.constData();
3760 Returns true if from can be assigned to a (QObject) property of type
3763 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3765 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3766 const QMetaObject *fromMo = from->metaObject();
3769 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3771 fromMo = fromMo->superClass();
3777 Returns the element name, as written in the QML file, for o.
3779 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3782 if (o->type != -1) {
3783 return output->types.at(o->type).className;
3789 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3792 const QMetaObject *mo = from->metatype;
3794 while (!type && mo) {
3795 type = QQmlMetaType::qmlType(mo);
3796 mo = mo->superClass();
3801 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3803 const QMetaObject *mo = obj->metatype;
3805 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3807 return QStringList();
3809 QMetaClassInfo classInfo = mo->classInfo(idx);
3810 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3815 QQmlCompiler::property(QQmlScript::Object *object, int index)
3817 QQmlPropertyCache *cache = 0;
3819 if (object->synthCache)
3820 cache = object->synthCache;
3821 else if (object->type != -1)
3822 cache = output->types[object->type].createPropertyCache(engine);
3824 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3826 return cache->property(index);
3830 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3832 if (notInRevision) *notInRevision = false;
3834 QQmlPropertyCache *cache = 0;
3836 if (object->synthCache)
3837 cache = object->synthCache;
3838 else if (object->type != -1)
3839 cache = output->types[object->type].createPropertyCache(engine);
3841 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3843 QQmlPropertyData *d = cache->property(name);
3845 // Find the first property
3846 while (d && d->isFunction())
3847 d = cache->overrideData(d);
3849 if (d && !cache->isAllowedInRevision(d)) {
3850 if (notInRevision) *notInRevision = true;
3857 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3859 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3861 if (notInRevision) *notInRevision = false;
3863 QQmlPropertyCache *cache = 0;
3865 if (object->synthCache)
3866 cache = object->synthCache;
3867 else if (object->type != -1)
3868 cache = output->types[object->type].createPropertyCache(engine);
3870 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3873 QQmlPropertyData *d = cache->property(name);
3874 if (notInRevision) *notInRevision = false;
3876 while (d && !(d->isFunction()))
3877 d = cache->overrideData(d);
3879 if (d && !cache->isAllowedInRevision(d)) {
3880 if (notInRevision) *notInRevision = true;
3886 if (name.endsWith(Changed_string)) {
3887 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3889 d = property(object, propName, notInRevision);
3891 return cache->method(d->notifyIndex);
3897 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3898 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3899 bool *notInRevision)
3901 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3902 return d?d->coreIndex:-1;
3905 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3906 bool *notInRevision)
3908 return indexOfProperty(object, QStringRef(&name), notInRevision);
3911 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3912 bool *notInRevision)
3914 QQmlPropertyData *d = property(object, name, notInRevision);
3915 return d?d->coreIndex:-1;