1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcompiler_p.h"
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qqmlstringconverters_p.h"
49 #include "qqmlengine_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlcontext.h"
52 #include "qqmlmetatype_p.h"
53 #include "qqmlcustomparser_p_p.h"
54 #include "qqmlcontext_p.h"
55 #include "qqmlcomponent_p.h"
56 #include <private/qqmljsast_p.h>
57 #include "qqmlvmemetaobject_p.h"
58 #include "qqmlexpression_p.h"
59 #include "qqmlproperty_p.h"
60 #include "qqmlrewrite_p.h"
61 #include "qqmlscriptstring.h"
62 #include "qqmlglobal_p.h"
63 #include "qqmlbinding_p.h"
64 #include <private/qv4compiler_p.h>
71 #include <QtCore/qdebug.h>
72 #include <QtCore/qdatetime.h>
73 #include <QtCore/qvarlengtharray.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QQmlJS;
87 using namespace QQmlScript;
88 using namespace QQmlCompilerTypes;
90 static QString id_string(QLatin1String("id"));
91 static QString on_string(QLatin1String("on"));
92 static QString Changed_string(QLatin1String("Changed"));
93 static QString Component_string(QLatin1String("Component"));
94 static QString Component_import_string(QLatin1String("QML/Component"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QQmlCompiler.
101 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
102 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QQmlCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QQmlError> QQmlCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QQmlCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
191 error.setUrl(output->url); \
192 error.setLine(line); \
193 error.setColumn(column); \
194 error.setDescription(desc.trimmed()); \
195 exceptions << error; \
199 #define COMPILE_EXCEPTION(token, desc) \
200 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
205 Returns false if \a is false, otherwise does nothing.
207 #define COMPILE_CHECK(a) \
209 if (!a) return false; \
213 Returns true if literal \a v can be assigned to property \a prop, otherwise
216 This test corresponds to action taken by genLiteralAssignment(). Any change
217 made here, must have a corresponding action in genLiteralAssigment().
219 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
220 QQmlScript::Value *v)
222 const QQmlScript::Variant &value = v->value;
224 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
225 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
227 if (prop->core.isEnum()) {
228 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
231 if (p.isFlagType()) {
232 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
234 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
237 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
239 v->value = QQmlScript::Variant((double)enumValue);
243 int type = prop->type;
246 case QMetaType::QVariant:
248 case QVariant::String:
249 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
251 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
252 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
254 case QVariant::ByteArray:
255 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
258 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
260 case QVariant::RegExp:
261 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
265 bool ok = v->value.isNumber();
267 double n = v->value.asNumber();
268 if (double(uint(n)) != n)
271 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
276 bool ok = v->value.isNumber();
278 double n = v->value.asNumber();
279 if (double(int(n)) != n)
282 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
285 case QMetaType::Float:
286 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
288 case QVariant::Double:
289 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
291 case QVariant::Color:
294 QQmlStringConverters::colorFromString(value.asString(), &ok);
295 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
298 #ifndef QT_NO_DATESTRING
302 QQmlStringConverters::dateFromString(value.asString(), &ok);
303 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
309 QQmlStringConverters::timeFromString(value.asString(), &ok);
310 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
313 case QVariant::DateTime:
316 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
317 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
320 #endif // QT_NO_DATESTRING
321 case QVariant::Point:
322 case QVariant::PointF:
325 QQmlStringConverters::pointFFromString(value.asString(), &ok);
326 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
330 case QVariant::SizeF:
333 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
334 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
338 case QVariant::RectF:
341 QQmlStringConverters::rectFFromString(value.asString(), &ok);
342 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
347 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
350 case QVariant::Vector3D:
352 QQmlInstruction::instr_storeVector3D::QVector3D v3;
353 if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3)))
354 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
357 case QVariant::Vector4D:
359 QQmlInstruction::instr_storeVector4D::QVector4D v4;
360 if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4)))
361 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
366 // check if assigning a literal value to a list property.
367 // in each case, check the singular, since an Array of the specified type
368 // will not go via this literal assignment codepath.
369 if (type == qMetaTypeId<QList<qreal> >()) {
370 if (!v->value.isNumber()) {
371 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
374 } else if (type == qMetaTypeId<QList<int> >()) {
375 bool ok = v->value.isNumber();
377 double n = v->value.asNumber();
378 if (double(int(n)) != n)
381 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
383 } else if (type == qMetaTypeId<QList<bool> >()) {
384 if (!v->value.isBoolean()) {
385 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
388 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
389 if (!v->value.isString()) {
390 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
393 } else if (type == qMetaTypeId<QList<QUrl> >()) {
394 if (!v->value.isString()) {
395 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
400 // otherwise, check for existence of string converter to custom type
401 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
403 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
410 static QUrl urlFromUserString(const QString &data)
413 // Preserve any valid percent-encoded octets supplied by the source
414 u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
419 Generate a store instruction for assigning literal \a v to property \a prop.
421 Any literal assignment that is approved in testLiteralAssignment() must have
422 a corresponding action in this method.
424 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
425 QQmlScript::Value *v)
427 if (prop->core.isEnum()) {
428 Q_ASSERT(v->value.isNumber());
430 int value = (int)v->value.asNumber();
432 Instruction::StoreInteger instr;
433 instr.propertyIndex = prop->index;
435 output->addInstruction(instr);
439 int type = prop->type;
441 case QMetaType::QVariant:
443 if (v->value.isNumber()) {
444 double n = v->value.asNumber();
445 if (double(int(n)) == n) {
446 if (prop->core.isVMEProperty()) {
447 Instruction::StoreVarInteger instr;
448 instr.propertyIndex = prop->index;
449 instr.value = int(n);
450 output->addInstruction(instr);
452 Instruction::StoreVariantInteger instr;
453 instr.propertyIndex = prop->index;
454 instr.value = int(n);
455 output->addInstruction(instr);
458 if (prop->core.isVMEProperty()) {
459 Instruction::StoreVarDouble instr;
460 instr.propertyIndex = prop->index;
462 output->addInstruction(instr);
464 Instruction::StoreVariantDouble instr;
465 instr.propertyIndex = prop->index;
467 output->addInstruction(instr);
470 } else if (v->value.isBoolean()) {
471 if (prop->core.isVMEProperty()) {
472 Instruction::StoreVarBool instr;
473 instr.propertyIndex = prop->index;
474 instr.value = v->value.asBoolean();
475 output->addInstruction(instr);
477 Instruction::StoreVariantBool instr;
478 instr.propertyIndex = prop->index;
479 instr.value = v->value.asBoolean();
480 output->addInstruction(instr);
483 if (prop->core.isVMEProperty()) {
484 Instruction::StoreVar instr;
485 instr.propertyIndex = prop->index;
486 instr.value = output->indexForString(v->value.asString());
487 output->addInstruction(instr);
489 Instruction::StoreVariant instr;
490 instr.propertyIndex = prop->index;
491 instr.value = output->indexForString(v->value.asString());
492 output->addInstruction(instr);
497 case QVariant::String:
499 Instruction::StoreString instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForString(v->value.asString());
502 output->addInstruction(instr);
505 case QVariant::StringList:
507 Instruction::StoreStringList instr;
508 instr.propertyIndex = prop->index;
509 instr.value = output->indexForString(v->value.asString());
510 output->addInstruction(instr);
513 case QVariant::ByteArray:
515 Instruction::StoreByteArray instr;
516 instr.propertyIndex = prop->index;
517 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
518 output->addInstruction(instr);
523 Instruction::StoreUrl instr;
524 QString string = v->value.asString();
525 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
526 instr.propertyIndex = prop->index;
527 instr.value = output->indexForUrl(u);
528 output->addInstruction(instr);
533 Instruction::StoreInteger instr;
534 instr.propertyIndex = prop->index;
535 instr.value = uint(v->value.asNumber());
536 output->addInstruction(instr);
541 Instruction::StoreInteger instr;
542 instr.propertyIndex = prop->index;
543 instr.value = int(v->value.asNumber());
544 output->addInstruction(instr);
547 case QMetaType::Float:
549 Instruction::StoreFloat instr;
550 instr.propertyIndex = prop->index;
551 instr.value = float(v->value.asNumber());
552 output->addInstruction(instr);
555 case QVariant::Double:
557 Instruction::StoreDouble instr;
558 instr.propertyIndex = prop->index;
559 instr.value = v->value.asNumber();
560 output->addInstruction(instr);
563 case QVariant::Color:
565 Instruction::StoreColor instr;
566 instr.propertyIndex = prop->index;
567 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
568 output->addInstruction(instr);
571 #ifndef QT_NO_DATESTRING
574 Instruction::StoreDate instr;
575 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
576 instr.propertyIndex = prop->index;
577 instr.value = d.toJulianDay();
578 output->addInstruction(instr);
583 Instruction::StoreTime instr;
584 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
585 instr.propertyIndex = prop->index;
586 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
587 ::memcpy(&instr.time, &time, sizeof(QTime));
588 output->addInstruction(instr);
591 case QVariant::DateTime:
593 Instruction::StoreDateTime instr;
594 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
595 QTime time = dateTime.time();
596 instr.propertyIndex = prop->index;
597 instr.date = dateTime.date().toJulianDay();
598 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
599 ::memcpy(&instr.time, &time, sizeof(QTime));
600 output->addInstruction(instr);
603 #endif // QT_NO_DATESTRING
604 case QVariant::Point:
606 Instruction::StorePoint instr;
608 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
609 instr.propertyIndex = prop->index;
610 instr.point.xp = point.x();
611 instr.point.yp = point.y();
612 output->addInstruction(instr);
615 case QVariant::PointF:
617 Instruction::StorePointF instr;
619 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
620 instr.propertyIndex = prop->index;
621 instr.point.xp = point.x();
622 instr.point.yp = point.y();
623 output->addInstruction(instr);
628 Instruction::StoreSize instr;
630 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
631 instr.propertyIndex = prop->index;
632 instr.size.wd = size.width();
633 instr.size.ht = size.height();
634 output->addInstruction(instr);
637 case QVariant::SizeF:
639 Instruction::StoreSizeF instr;
641 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
642 instr.propertyIndex = prop->index;
643 instr.size.wd = size.width();
644 instr.size.ht = size.height();
645 output->addInstruction(instr);
650 Instruction::StoreRect instr;
652 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
653 instr.propertyIndex = prop->index;
654 instr.rect.x1 = rect.left();
655 instr.rect.y1 = rect.top();
656 instr.rect.x2 = rect.right();
657 instr.rect.y2 = rect.bottom();
658 output->addInstruction(instr);
661 case QVariant::RectF:
663 Instruction::StoreRectF instr;
665 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
666 instr.propertyIndex = prop->index;
667 instr.rect.xp = rect.left();
668 instr.rect.yp = rect.top();
669 instr.rect.w = rect.width();
670 instr.rect.h = rect.height();
671 output->addInstruction(instr);
676 Instruction::StoreBool instr;
677 bool b = v->value.asBoolean();
678 instr.propertyIndex = prop->index;
680 output->addInstruction(instr);
683 case QVariant::Vector3D:
685 Instruction::StoreVector3D instr;
686 instr.propertyIndex = prop->index;
687 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
688 output->addInstruction(instr);
691 case QVariant::Vector4D:
693 Instruction::StoreVector4D instr;
694 instr.propertyIndex = prop->index;
695 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
696 output->addInstruction(instr);
701 // generate single literal value assignment to a list property if required
702 if (type == qMetaTypeId<QList<qreal> >()) {
703 Instruction::StoreDoubleQList instr;
704 instr.propertyIndex = prop->index;
705 instr.value = v->value.asNumber();
706 output->addInstruction(instr);
708 } else if (type == qMetaTypeId<QList<int> >()) {
709 Instruction::StoreIntegerQList instr;
710 instr.propertyIndex = prop->index;
711 instr.value = int(v->value.asNumber());
712 output->addInstruction(instr);
714 } else if (type == qMetaTypeId<QList<bool> >()) {
715 Instruction::StoreBoolQList instr;
716 bool b = v->value.asBoolean();
717 instr.propertyIndex = prop->index;
719 output->addInstruction(instr);
721 } else if (type == qMetaTypeId<QList<QUrl> >()) {
722 Instruction::StoreUrlQList instr;
723 QString string = v->value.asString();
724 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
725 instr.propertyIndex = prop->index;
726 instr.value = output->indexForUrl(u);
727 output->addInstruction(instr);
729 } else if (type == qMetaTypeId<QList<QString> >()) {
730 Instruction::StoreStringQList instr;
731 instr.propertyIndex = prop->index;
732 instr.value = output->indexForString(v->value.asString());
733 output->addInstruction(instr);
737 // otherwise, generate custom type literal assignment
738 Instruction::AssignCustomType instr;
739 instr.propertyIndex = prop->index;
740 instr.primitive = output->indexForString(v->value.asString());
742 output->addInstruction(instr);
749 Resets data by clearing the lists that the QQmlCompiler modifies.
751 void QQmlCompiler::reset(QQmlCompiledData *data)
754 data->primitives.clear();
756 data->bytecode.resize(0);
760 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
761 with which the QQmlCompiledData will be associated.
763 Returns true on success, false on failure. On failure, the compile errors
764 are available from errors().
766 If the environment variant QML_COMPILER_DUMP is set
767 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
768 on a successful compiler.
770 bool QQmlCompiler::compile(QQmlEngine *engine,
772 QQmlCompiledData *out)
779 QQmlScript::Object *root = unit->parser().tree();
782 this->engine = engine;
783 this->enginePrivate = QQmlEnginePrivate::get(engine);
785 this->unitRoot = root;
789 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
790 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
792 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
793 QQmlCompiledData::TypeReference ref;
795 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
796 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
799 ref.type = tref.type;
800 if (!ref.type->isCreatable()) {
801 QString err = ref.type->noCreationReason();
803 err = tr( "Element is not creatable.");
804 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
807 if (ref.type->containsRevisionedAttributes()) {
808 QQmlError cacheError;
809 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
811 if (!ref.typePropertyCache)
812 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
813 ref.typePropertyCache->addref();
816 } else if (tref.typeData) {
817 ref.component = tref.typeData->compiledData();
819 ref.className = parserRef->name;
827 out->dumpInstructions();
830 Q_ASSERT(out->rootPropertyCache);
838 this->enginePrivate = 0;
840 this->cachedComponentTypeRef = -1;
841 this->cachedTranslationContextIndex = -1;
847 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
849 compileState = pool->New<ComponentCompileState>();
851 compileState->root = tree;
853 componentStats->componentStat.lineNumber = tree->location.start.line;
855 // We generate the importCache before we build the tree so that
856 // it can be used in the binding compiler. Given we "expect" the
857 // QML compilation to succeed, this isn't a waste.
858 output->importCache = new QQmlTypeNameCache();
859 foreach (const QString &ns, unit->namespaces()) {
860 output->importCache->add(ns);
864 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
865 QString qualifier = script.qualifier;
866 QString enclosingNamespace;
868 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
869 if (lastDotIndex != -1) {
870 enclosingNamespace = qualifier.left(lastDotIndex);
871 qualifier = qualifier.mid(lastDotIndex+1);
874 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
877 unit->imports().populateCache(output->importCache, engine);
879 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
882 Instruction::Init init;
883 init.bindingsSize = compileState->totalBindingsCount;
884 init.parserStatusSize = compileState->parserStatusCount;
885 init.contextCache = genContextCache();
886 init.objectStackSize = compileState->objectDepth.maxDepth();
887 init.listStackSize = compileState->listDepth.maxDepth();
888 if (compileState->compiledBindingData.isEmpty())
889 init.compiledBinding = -1;
891 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
892 output->addInstruction(init);
894 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
895 Instruction::StoreImportedScript import;
896 import.value = output->scripts.count();
898 QQmlScriptData *scriptData = script.script->scriptData();
899 scriptData->addref();
900 output->scripts << scriptData;
901 output->addInstruction(import);
904 if (!compileState->v8BindingProgram.isEmpty()) {
905 Instruction::InitV8Bindings bindings;
906 int index = output->programs.count();
908 typedef QQmlCompiledData::V8Program V8Program;
909 output->programs.append(V8Program(compileState->v8BindingProgram, output));
911 bindings.programIndex = index;
912 bindings.line = compileState->v8BindingProgramLine;
913 output->addInstruction(bindings);
918 Instruction::SetDefault def;
919 output->addInstruction(def);
921 Instruction::Done done;
922 output->addInstruction(done);
924 Q_ASSERT(tree->metatype);
926 if (tree->metadata.isEmpty()) {
927 output->root = tree->metatype;
929 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
930 output->root = &output->rootData;
932 if (!tree->metadata.isEmpty())
933 enginePrivate->registerCompositeType(output);
936 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
938 for (int ii = 0; ii < list.count(); ++ii)
939 if (string == list.at(ii))
945 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
948 componentStats->componentStat.objects++;
950 Q_ASSERT (obj->type != -1);
951 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
952 obj->metatype = tr.metaObject();
955 obj->typeName = tr.type->qmlTypeName();
957 // This object is a "Component" element
958 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
959 COMPILE_CHECK(buildComponent(obj, ctxt));
964 typedef QQmlInstruction I;
965 const I *init = ((const I *)tr.component->bytecode.constData());
966 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
968 // Adjust stack depths to include nested components
969 compileState->objectDepth.pushPop(init->init.objectStackSize);
970 compileState->listDepth.pushPop(init->init.listStackSize);
971 compileState->parserStatusCount += init->init.parserStatusSize;
972 compileState->totalBindingsCount += init->init.bindingsSize;
975 compileState->objectDepth.push();
977 // Object instantiations reset the binding context
978 BindingContext objCtxt(obj);
980 // Create the synthesized meta object, ignoring aliases
981 COMPILE_CHECK(checkDynamicMeta(obj));
982 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
983 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
985 // Find the native type and check for the QQmlParserStatus interface
986 QQmlType *type = toQmlType(obj);
988 obj->parserStatusCast = type->parserStatusCast();
989 if (obj->parserStatusCast != -1)
990 compileState->parserStatusCount++;
992 // Check if this is a custom parser type. Custom parser types allow
993 // assignments to non-existent properties. These assignments are then
994 // compiled by the type.
995 bool isCustomParser = output->types.at(obj->type).type &&
996 output->types.at(obj->type).type->customParser() != 0;
997 QList<QQmlCustomParserProperty> customProps;
999 // Fetch the list of deferred properties
1000 QStringList deferredList = deferredProperties(obj);
1002 // Must do id property first. This is to ensure that the id given to any
1003 // id reference created matches the order in which the objects are
1005 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1006 if (prop->name() == id_string) {
1007 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1013 Property *defaultProperty = 0;
1014 Property *skipProperty = 0;
1015 if (obj->defaultProperty) {
1016 defaultProperty = obj->defaultProperty;
1018 Property *explicitProperty = 0;
1020 const QMetaObject *mo = obj->metatype;
1021 int idx = mo->indexOfClassInfo("DefaultProperty");
1023 QMetaClassInfo info = mo->classInfo(idx);
1024 const char *p = info.value();
1028 while (char c = p[plen++]) { ord |= c; };
1032 // Utf8 - unoptimal, but seldom hit
1033 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1034 QHashedStringRef r(*s);
1036 if (obj->propertiesHashField.test(r.hash())) {
1037 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1038 if (ep->name() == r) {
1039 explicitProperty = ep;
1045 if (!explicitProperty)
1046 defaultProperty->setName(r);
1049 QHashedCStringRef r(p, plen);
1051 if (obj->propertiesHashField.test(r.hash())) {
1052 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1053 if (ep->name() == r) {
1054 explicitProperty = ep;
1060 if (!explicitProperty) {
1061 // Set the default property name
1062 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1063 r.writeUtf16(buffer);
1064 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1070 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1072 skipProperty = explicitProperty; // We merge the values into defaultProperty
1074 // Find the correct insertion point
1075 Value *insertPos = 0;
1077 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1078 if (!(v->location.start < explicitProperty->values.first()->location.start))
1083 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1087 QQmlCustomParser *cp = 0;
1089 cp = output->types.at(obj->type).type->customParser();
1091 // Build all explicit properties specified
1092 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1094 if (prop == skipProperty)
1096 if (prop->name() == id_string)
1099 bool canDefer = false;
1100 if (isCustomParser) {
1101 if (doesPropertyExist(prop, obj) &&
1102 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1103 !isAttachedPropertyName(prop->name()))) {
1104 int ids = compileState->ids.count();
1105 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1106 canDefer = ids == compileState->ids.count();
1107 } else if (isSignalPropertyName(prop->name()) &&
1108 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1109 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1111 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1114 if (isSignalPropertyName(prop->name())) {
1115 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1117 int ids = compileState->ids.count();
1118 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1119 canDefer = ids == compileState->ids.count();
1123 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1124 prop->isDeferred = true;
1128 // Build the default property
1129 if (defaultProperty) {
1130 Property *prop = defaultProperty;
1132 bool canDefer = false;
1133 if (isCustomParser) {
1134 if (doesPropertyExist(prop, obj)) {
1135 int ids = compileState->ids.count();
1136 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1137 canDefer = ids == compileState->ids.count();
1139 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1142 int ids = compileState->ids.count();
1143 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1144 canDefer = ids == compileState->ids.count();
1147 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1148 prop->isDeferred = true;
1151 // Compile custom parser parts
1152 if (isCustomParser && !customProps.isEmpty()) {
1154 cp->compiler = this;
1156 obj->custom = cp->compile(customProps);
1159 foreach (QQmlError err, cp->errors()) {
1160 err.setUrl(output->url);
1165 compileState->objectDepth.pop();
1170 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1172 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1173 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1178 // Create the object
1179 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1180 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1182 Instruction::CreateSimpleObject create;
1183 create.create = output->types.at(obj->type).type->createFunction();
1184 create.typeSize = output->types.at(obj->type).type->createSize();
1185 create.type = obj->type;
1186 create.line = obj->location.start.line;
1187 create.column = obj->location.start.column;
1188 output->addInstruction(create);
1192 if (output->types.at(obj->type).type) {
1193 Instruction::CreateCppObject create;
1194 create.line = obj->location.start.line;
1195 create.column = obj->location.start.column;
1197 if (!obj->custom.isEmpty())
1198 create.data = output->indexForByteArray(obj->custom);
1199 create.type = obj->type;
1200 create.isRoot = (compileState->root == obj);
1201 output->addInstruction(create);
1203 Instruction::CreateQMLObject create;
1204 create.type = obj->type;
1205 create.isRoot = (compileState->root == obj);
1207 if (!obj->bindingBitmask.isEmpty()) {
1208 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1209 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1211 create.bindingBits = -1;
1213 output->addInstruction(create);
1215 Instruction::CompleteQMLObject complete;
1216 complete.line = obj->location.start.line;
1217 complete.column = obj->location.start.column;
1218 complete.isRoot = (compileState->root == obj);
1219 output->addInstruction(complete);
1223 // Setup the synthesized meta object if necessary
1224 if (!obj->metadata.isEmpty()) {
1225 Instruction::StoreMetaObject meta;
1226 meta.data = output->indexForByteArray(obj->metadata);
1227 meta.aliasData = output->indexForByteArray(obj->synthdata);
1228 meta.propertyCache = output->propertyCaches.count();
1230 QQmlPropertyCache *propertyCache = obj->synthCache;
1231 Q_ASSERT(propertyCache);
1232 propertyCache->addref();
1234 // Add flag for alias properties
1235 if (!obj->synthdata.isEmpty()) {
1236 const QQmlVMEMetaData *vmeMetaData =
1237 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1238 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1239 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1240 QQmlPropertyData *data = propertyCache->property(index);
1241 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1245 if (obj == unitRoot) {
1246 propertyCache->addref();
1247 output->rootPropertyCache = propertyCache;
1250 output->propertyCaches << propertyCache;
1251 output->addInstruction(meta);
1252 } else if (obj == unitRoot) {
1253 output->rootPropertyCache = tr.createPropertyCache(engine);
1254 output->rootPropertyCache->addref();
1257 // Set the object id
1258 if (!obj->id.isEmpty()) {
1259 Instruction::SetId id;
1260 id.value = output->indexForString(obj->id);
1261 id.index = obj->idIndex;
1262 output->addInstruction(id);
1266 if (tr.type && obj->parserStatusCast != -1) {
1267 Instruction::BeginObject begin;
1268 begin.castValue = obj->parserStatusCast;
1269 output->addInstruction(begin);
1275 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1277 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1278 Q_ASSERT(prop->scriptStringScope != -1);
1279 const QString &script = prop->values.first()->value.asScript();
1280 Instruction::StoreScriptString ss;
1281 ss.propertyIndex = prop->index;
1282 ss.value = output->indexForString(script);
1283 ss.scope = prop->scriptStringScope;
1284 // ss.bindingId = rewriteBinding(script, prop->name());
1285 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1286 ss.line = prop->location.start.line;
1287 ss.column = prop->location.start.column;
1288 output->addInstruction(ss);
1291 bool seenDefer = false;
1292 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1293 if (prop->isDeferred) {
1298 genValueProperty(prop, obj);
1301 Instruction::Defer defer;
1302 defer.deferCount = 0;
1303 int deferIdx = output->addInstruction(defer);
1304 int nextInstructionIndex = output->nextInstructionIndex();
1306 Instruction::DeferInit dinit;
1307 // XXX - these are now massive over allocations
1308 dinit.bindingsSize = compileState->totalBindingsCount;
1309 dinit.parserStatusSize = compileState->parserStatusCount;
1310 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1311 dinit.listStackSize = compileState->listDepth.maxDepth();
1312 output->addInstruction(dinit);
1314 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1315 if (!prop->isDeferred)
1317 genValueProperty(prop, obj);
1320 Instruction::Done done;
1321 output->addInstruction(done);
1323 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1326 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1328 QQmlScript::Value *v = prop->values.first();
1330 if (v->type == Value::SignalObject) {
1332 genObject(v->object);
1334 Instruction::AssignSignalObject assign;
1335 assign.line = v->location.start.line;
1336 assign.signal = output->indexForString(prop->name().toString());
1337 output->addInstruction(assign);
1339 } else if (v->type == Value::SignalExpression) {
1341 Instruction::StoreSignal store;
1342 store.signalIndex = prop->index;
1343 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1344 store.value = output->indexForByteArray(rewrite.toUtf8());
1345 store.context = v->signalExpressionContextStack;
1346 store.line = v->location.start.line;
1347 store.column = v->location.start.column;
1348 output->addInstruction(store);
1354 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1355 Instruction::FetchAttached fetch;
1356 fetch.id = prop->index;
1357 fetch.line = prop->location.start.line;
1358 output->addInstruction(fetch);
1360 genObjectBody(prop->value);
1362 Instruction::PopFetchedObject pop;
1363 output->addInstruction(pop);
1366 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1367 Instruction::FetchObject fetch;
1368 fetch.property = prop->index;
1369 fetch.line = prop->location.start.line;
1370 output->addInstruction(fetch);
1372 if (!prop->value->metadata.isEmpty()) {
1373 Instruction::StoreMetaObject meta;
1374 meta.data = output->indexForByteArray(prop->value->metadata);
1375 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1376 meta.propertyCache = -1;
1377 output->addInstruction(meta);
1380 genObjectBody(prop->value);
1382 Instruction::PopFetchedObject pop;
1383 output->addInstruction(pop);
1386 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1388 genValueTypeProperty(obj, prop);
1391 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1392 if (prop->isDeferred)
1395 genValueProperty(prop, obj);
1398 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1400 genValueTypeProperty(obj, prop);
1404 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1406 Instruction::FetchValueType fetch;
1407 fetch.property = prop->index;
1408 fetch.type = prop->type;
1409 fetch.bindingSkipList = 0;
1411 if (obj->type == -1 || output->types.at(obj->type).component) {
1412 // We only have to do this if this is a composite type. If it is a builtin
1413 // type it can't possibly already have bindings that need to be cleared.
1414 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1415 if (!vprop->values.isEmpty()) {
1416 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1417 fetch.bindingSkipList |= (1 << vprop->index);
1422 output->addInstruction(fetch);
1424 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1425 genPropertyAssignment(vprop, prop->value, prop);
1428 Instruction::PopValueType pop;
1429 pop.property = prop->index;
1430 pop.type = prop->type;
1431 pop.bindingSkipList = 0;
1432 output->addInstruction(pop);
1435 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1437 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1440 Instruction::CreateComponent create;
1441 create.line = root->location.start.line;
1442 create.column = root->location.start.column;
1443 create.endLine = root->location.end.line;
1444 create.isRoot = (compileState->root == obj);
1445 int createInstruction = output->addInstruction(create);
1446 int nextInstructionIndex = output->nextInstructionIndex();
1448 ComponentCompileState *oldCompileState = compileState;
1449 compileState = componentState(root);
1451 Instruction::Init init;
1452 init.bindingsSize = compileState->totalBindingsCount;
1453 init.parserStatusSize = compileState->parserStatusCount;
1454 init.contextCache = genContextCache();
1455 init.objectStackSize = compileState->objectDepth.maxDepth();
1456 init.listStackSize = compileState->listDepth.maxDepth();
1457 if (compileState->compiledBindingData.isEmpty())
1458 init.compiledBinding = -1;
1460 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1461 output->addInstruction(init);
1463 if (!compileState->v8BindingProgram.isEmpty()) {
1464 Instruction::InitV8Bindings bindings;
1465 int index = output->programs.count();
1467 typedef QQmlCompiledData::V8Program V8Program;
1468 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1470 bindings.programIndex = index;
1471 bindings.line = compileState->v8BindingProgramLine;
1472 output->addInstruction(bindings);
1477 Instruction::SetDefault def;
1478 output->addInstruction(def);
1480 Instruction::Done done;
1481 output->addInstruction(done);
1483 output->instruction(createInstruction)->createComponent.count =
1484 output->nextInstructionIndex() - nextInstructionIndex;
1486 compileState = oldCompileState;
1488 if (!obj->id.isEmpty()) {
1489 Instruction::SetId id;
1490 id.value = output->indexForString(obj->id);
1491 id.index = obj->idIndex;
1492 output->addInstruction(id);
1495 if (obj == unitRoot) {
1496 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1497 output->rootPropertyCache->addref();
1501 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1502 const BindingContext &ctxt)
1504 // The special "Component" element can only have the id property and a
1505 // default property, that actually defines the component's tree
1507 compileState->objectDepth.push();
1509 // Find, check and set the "id" property (if any)
1510 Property *idProp = 0;
1511 if (obj->properties.isMany() ||
1512 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1513 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1515 if (!obj->properties.isEmpty())
1516 idProp = obj->properties.first();
1519 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1520 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1521 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1523 QString idVal = idProp->values.first()->primitive();
1525 if (compileState->ids.value(idVal))
1526 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1532 // Check the Component tree is well formed
1533 if (obj->defaultProperty &&
1534 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1535 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1536 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1538 if (!obj->dynamicProperties.isEmpty())
1539 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1540 if (!obj->dynamicSignals.isEmpty())
1541 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1542 if (!obj->dynamicSlots.isEmpty())
1543 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1545 QQmlScript::Object *root = 0;
1546 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1547 root = obj->defaultProperty->values.first()->object;
1550 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1552 // Build the component tree
1553 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1555 compileState->objectDepth.pop();
1560 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1561 const BindingContext &ctxt)
1563 ComponentCompileState *oldComponentCompileState = compileState;
1564 compileState = pool->New<ComponentCompileState>();
1565 compileState->root = obj;
1566 compileState->nested = true;
1568 if (componentStats) {
1569 ComponentStat oldComponentStat = componentStats->componentStat;
1571 componentStats->componentStat = ComponentStat();
1572 componentStats->componentStat.lineNumber = obj->location.start.line;
1575 COMPILE_CHECK(buildObject(obj, ctxt));
1577 COMPILE_CHECK(completeComponentBuild());
1579 componentStats->componentStat = oldComponentStat;
1582 COMPILE_CHECK(buildObject(obj, ctxt));
1584 COMPILE_CHECK(completeComponentBuild());
1587 compileState = oldComponentCompileState;
1593 // Build a sub-object. A sub-object is one that was not created directly by
1594 // QML - such as a grouped property object, or an attached object. Sub-object's
1595 // can't have an id, involve a custom parser, have attached properties etc.
1596 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1598 Q_ASSERT(obj->metatype);
1599 Q_ASSERT(!obj->defaultProperty);
1600 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1603 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1604 if (isSignalPropertyName(prop->name())) {
1605 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1607 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1614 int QQmlCompiler::componentTypeRef()
1616 if (cachedComponentTypeRef == -1) {
1617 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1618 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1619 if (output->types.at(ii).type == t) {
1620 cachedComponentTypeRef = ii;
1624 QQmlCompiledData::TypeReference ref;
1625 ref.className = Component_string;
1627 output->types << ref;
1628 cachedComponentTypeRef = output->types.count() - 1;
1630 return cachedComponentTypeRef;
1633 int QQmlCompiler::translationContextIndex()
1635 if (cachedTranslationContextIndex == -1) {
1636 // This code must match that in the qsTr() implementation
1637 const QString &path = output->name;
1638 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1639 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1641 QByteArray contextUtf8 = context.toUtf8();
1642 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1644 return cachedTranslationContextIndex;
1647 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1648 const BindingContext &ctxt)
1650 Q_ASSERT(obj->metaObject());
1652 const QHashedStringRef &propName = prop->name();
1654 Q_ASSERT(propName.startsWith(on_string));
1655 QString name = propName.mid(2, -1).toString();
1657 // Note that the property name could start with any alpha or '_' or '$' character,
1658 // so we need to do the lower-casing of the first alpha character.
1659 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1660 if (name.at(firstAlphaIndex).isUpper()) {
1661 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1666 bool notInRevision = false;
1668 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1672 if (notInRevision && 0 == property(obj, propName, 0)) {
1673 Q_ASSERT(obj->type != -1);
1674 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1675 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1677 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1679 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1683 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1685 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1689 if (prop->value || !prop->values.isOne())
1690 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1692 prop->index = sig->coreIndex;
1695 obj->addSignalProperty(prop);
1697 if (prop->values.first()->object) {
1698 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1699 prop->values.first()->type = Value::SignalObject;
1701 prop->values.first()->type = Value::SignalExpression;
1703 if (!prop->values.first()->value.isScript())
1704 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1706 QString script = prop->values.first()->value.asScript().trimmed();
1707 if (script.isEmpty())
1708 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1710 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1719 Returns true if (value) property \a prop exists on obj, false otherwise.
1721 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1722 QQmlScript::Object *obj)
1724 if (prop->name().isEmpty())
1726 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1729 return property(obj, prop->name()) != 0;
1732 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1733 QQmlScript::Object *obj,
1734 const BindingContext &ctxt)
1736 if (prop->isEmpty())
1737 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1739 const QMetaObject *metaObject = obj->metaObject();
1740 Q_ASSERT(metaObject);
1742 if (isAttachedPropertyName(prop->name())) {
1743 // Setup attached property data
1745 if (ctxt.isSubContext()) {
1746 // Attached properties cannot be used on sub-objects. Sub-objects
1747 // always exist in a binding sub-context, which is what we test
1749 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1753 QQmlImportedNamespace *typeNamespace = 0;
1754 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1756 if (typeNamespace) {
1757 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1760 } else if (!type || !type->attachedPropertiesType()) {
1761 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1765 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1767 Q_ASSERT(type->attachedPropertiesFunction());
1768 prop->index = type->attachedPropertiesId();
1769 prop->value->metatype = type->attachedPropertiesType();
1771 // Setup regular property data
1772 bool notInRevision = false;
1773 QQmlPropertyData *d =
1774 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1776 if (d == 0 && notInRevision) {
1777 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1778 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1780 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1782 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1785 prop->index = d->coreIndex;
1787 } else if (prop->isDefault) {
1788 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1789 QQmlPropertyData defaultPropertyData;
1790 defaultPropertyData.load(p, engine);
1792 prop->setName(QLatin1String(p.name()));
1793 prop->core = defaultPropertyData;
1794 prop->index = prop->core.coreIndex;
1797 // We can't error here as the "id" property does not require a
1798 // successful index resolution
1799 if (prop->index != -1)
1800 prop->type = prop->core.propType;
1802 // Check if this is an alias
1803 if (prop->index != -1 &&
1805 prop->parent->type != -1 &&
1806 output->types.at(prop->parent->type).component) {
1808 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1809 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1810 prop->isAlias = true;
1813 if (prop->index != -1 && !prop->values.isEmpty())
1814 prop->parent->setBindingBit(prop->index);
1817 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1819 // The magic "id" behavior doesn't apply when "id" is resolved as a
1820 // default property or to sub-objects (which are always in binding
1822 COMPILE_CHECK(buildIdProperty(prop, obj));
1823 if (prop->type == QVariant::String &&
1824 prop->values.first()->value.isString())
1825 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1827 } else if (isAttachedPropertyName(prop->name())) {
1829 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1831 } else if (prop->index == -1) {
1833 if (prop->isDefault) {
1834 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1836 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1839 } else if (prop->value) {
1841 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1843 } else if (prop->core.isQList()) {
1845 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1847 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1849 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1853 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1860 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
1861 QQmlScript::Property *nsProp,
1862 QQmlScript::Object *obj,
1863 const BindingContext &ctxt)
1866 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1868 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1870 if (!isAttachedPropertyName(prop->name()))
1871 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1873 // Setup attached property data
1876 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1878 if (!type || !type->attachedPropertiesType())
1879 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1882 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1884 Q_ASSERT(type->attachedPropertiesFunction());
1885 prop->index = type->index();
1886 prop->value->metatype = type->attachedPropertiesType();
1888 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1894 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1895 QQmlScript::Object *obj)
1897 if (prop->core.isQList()) {
1898 genListProperty(prop, obj);
1900 genPropertyAssignment(prop, obj);
1904 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1905 QQmlScript::Object *obj)
1907 int listType = enginePrivate->listType(prop->type);
1909 Instruction::FetchQList fetch;
1910 fetch.property = prop->index;
1911 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1912 fetch.type = listType;
1913 output->addInstruction(fetch);
1915 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1917 if (v->type == Value::CreatedObject) {
1919 genObject(v->object);
1920 if (listTypeIsInterface) {
1921 Instruction::AssignObjectList assign;
1922 assign.line = prop->location.start.line;
1923 output->addInstruction(assign);
1925 Instruction::StoreObjectQList store;
1926 output->addInstruction(store);
1929 } else if (v->type == Value::PropertyBinding) {
1931 genBindingAssignment(v, prop, obj);
1937 Instruction::PopQList pop;
1938 output->addInstruction(pop);
1941 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1942 QQmlScript::Object *obj,
1943 QQmlScript::Property *valueTypeProperty)
1945 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1947 Q_ASSERT(v->type == Value::CreatedObject ||
1948 v->type == Value::PropertyBinding ||
1949 v->type == Value::Literal);
1951 if (v->type == Value::CreatedObject) {
1953 genObject(v->object);
1955 if (QQmlMetaType::isInterface(prop->type)) {
1957 Instruction::StoreInterface store;
1958 store.line = v->object->location.start.line;
1959 store.propertyIndex = prop->index;
1960 output->addInstruction(store);
1962 } else if (prop->type == QMetaType::QVariant) {
1964 if (prop->core.isVMEProperty()) {
1965 Instruction::StoreVarObject store;
1966 store.line = v->object->location.start.line;
1967 store.propertyIndex = prop->index;
1968 output->addInstruction(store);
1970 Instruction::StoreVariantObject store;
1971 store.line = v->object->location.start.line;
1972 store.propertyIndex = prop->index;
1973 output->addInstruction(store);
1979 Instruction::StoreObject store;
1980 store.line = v->object->location.start.line;
1981 store.propertyIndex = prop->index;
1982 output->addInstruction(store);
1985 } else if (v->type == Value::PropertyBinding) {
1987 genBindingAssignment(v, prop, obj, valueTypeProperty);
1989 } else if (v->type == Value::Literal) {
1991 genLiteralAssignment(prop, v);
1997 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1999 Q_ASSERT(v->type == Value::ValueSource ||
2000 v->type == Value::ValueInterceptor);
2002 if (v->type == Value::ValueSource) {
2003 genObject(v->object);
2005 Instruction::StoreValueSource store;
2006 if (valueTypeProperty) {
2007 store.property = genValueTypeData(prop, valueTypeProperty);
2010 store.property = prop->core;
2013 QQmlType *valueType = toQmlType(v->object);
2014 store.castValue = valueType->propertyValueSourceCast();
2015 output->addInstruction(store);
2017 } else if (v->type == Value::ValueInterceptor) {
2018 genObject(v->object);
2020 Instruction::StoreValueInterceptor store;
2021 if (valueTypeProperty) {
2022 store.property = genValueTypeData(prop, valueTypeProperty);
2025 store.property = prop->core;
2028 QQmlType *valueType = toQmlType(v->object);
2029 store.castValue = valueType->propertyValueInterceptorCast();
2030 output->addInstruction(store);
2036 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2037 QQmlScript::Object *obj)
2040 prop->values.isMany() ||
2041 prop->values.first()->object)
2042 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2044 QQmlScript::Value *idValue = prop->values.first();
2045 QString val = idValue->primitive();
2047 COMPILE_CHECK(checkValidId(idValue, val));
2049 if (compileState->ids.value(val))
2050 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2052 prop->values.first()->type = Value::Id;
2060 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2063 Q_ASSERT(!compileState->ids.value(id));
2064 Q_ASSERT(obj->id == id);
2065 obj->idIndex = compileState->ids.count();
2066 compileState->ids.append(obj);
2069 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2071 Q_ASSERT(ref->value && !ref->value->bindingReference);
2072 ref->value->bindingReference = ref;
2073 compileState->totalBindingsCount++;
2074 compileState->bindings.prepend(ref);
2077 void QQmlCompiler::saveComponentState()
2079 Q_ASSERT(compileState->root);
2080 Q_ASSERT(compileState->root->componentCompileState == 0);
2082 compileState->root->componentCompileState = compileState;
2085 componentStats->savedComponentStats.append(componentStats->componentStat);
2088 QQmlCompilerTypes::ComponentCompileState *
2089 QQmlCompiler::componentState(QQmlScript::Object *obj)
2091 Q_ASSERT(obj->componentCompileState);
2092 return obj->componentCompileState;
2095 // Build attached property object. In this example,
2099 // GridView is an attached property object.
2100 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2101 QQmlScript::Object *obj,
2102 const BindingContext &ctxt)
2104 Q_ASSERT(prop->value);
2105 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2107 compileState->objectDepth.push();
2109 obj->addAttachedProperty(prop);
2111 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2113 compileState->objectDepth.pop();
2119 // Build "grouped" properties. In this example:
2121 // font.pointSize: 12
2122 // font.family: "Helvetica"
2124 // font is a nested property. pointSize and family are not.
2125 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2126 QQmlScript::Object *obj,
2127 const BindingContext &ctxt)
2129 Q_ASSERT(prop->type != 0);
2130 Q_ASSERT(prop->index != -1);
2132 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2133 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2135 if (!prop->values.isEmpty()) {
2136 if (prop->values.first()->location < prop->value->location) {
2137 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2139 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2143 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2144 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2148 if (prop->isAlias) {
2149 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2150 vtProp->isAlias = true;
2154 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2155 prop->value, obj, ctxt.incr()));
2156 obj->addValueTypeProperty(prop);
2158 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2162 // Load the nested property's meta type
2163 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2164 if (!prop->value->metatype)
2165 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2167 if (!prop->values.isEmpty())
2168 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2170 obj->addGroupedProperty(prop);
2172 compileState->objectDepth.push();
2174 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2176 compileState->objectDepth.pop();
2182 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2183 QQmlScript::Object *obj,
2184 QQmlScript::Object *baseObj,
2185 const BindingContext &ctxt)
2187 compileState->objectDepth.push();
2189 if (obj->defaultProperty)
2190 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2191 obj->metatype = type->metaObject();
2193 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2195 QQmlPropertyData *d = property(obj, prop->name());
2197 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2199 prop->index = d->coreIndex;
2200 prop->type = d->propType;
2202 prop->isValueTypeSubProperty = true;
2205 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2207 if (prop->values.isMany()) {
2208 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2209 } else if (!prop->values.isEmpty()) {
2210 QQmlScript::Value *value = prop->values.first();
2212 if (value->object) {
2213 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2214 } else if (value->value.isScript()) {
2215 // ### Check for writability
2217 //optimization for <Type>.<EnumValue> enum assignments
2218 bool isEnumAssignment = false;
2220 if (prop->core.isEnum())
2221 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2223 if (isEnumAssignment) {
2224 value->type = Value::Literal;
2226 JSBindingReference *reference = pool->New<JSBindingReference>();
2227 reference->expression = value->value;
2228 reference->property = prop;
2229 reference->value = value;
2230 reference->bindingContext = ctxt;
2231 reference->bindingContext.owner++;
2232 addBindingReference(reference);
2233 value->type = Value::PropertyBinding;
2236 COMPILE_CHECK(testLiteralAssignment(prop, value));
2237 value->type = Value::Literal;
2241 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2242 Q_ASSERT(v->object);
2244 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2247 obj->addValueProperty(prop);
2250 compileState->objectDepth.pop();
2255 // Build assignments to QML lists. QML lists are properties of type
2256 // QQmlListProperty<T>. List properties can accept a list of
2257 // objects, or a single binding.
2258 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2259 QQmlScript::Object *obj,
2260 const BindingContext &ctxt)
2262 Q_ASSERT(prop->core.isQList());
2264 compileState->listDepth.push();
2268 obj->addValueProperty(prop);
2270 int listType = enginePrivate->listType(t);
2271 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2273 bool assignedBinding = false;
2274 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2276 v->type = Value::CreatedObject;
2277 COMPILE_CHECK(buildObject(v->object, ctxt));
2279 // We check object coercian here. We check interface assignment
2281 if (!listTypeIsInterface) {
2282 if (!canCoerce(listType, v->object)) {
2283 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2287 } else if (v->value.isScript()) {
2288 if (assignedBinding)
2289 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2291 assignedBinding = true;
2292 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2293 v->type = Value::PropertyBinding;
2295 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2299 compileState->listDepth.pop();
2304 // Compiles an assignment to a QQmlScriptString property
2305 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2306 QQmlScript::Object *obj,
2307 const BindingContext &ctxt)
2309 if (prop->values.isMany())
2310 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2312 if (prop->values.first()->object)
2313 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2315 prop->scriptStringScope = ctxt.stack;
2316 obj->addScriptStringProperty(prop);
2321 // Compile regular property assignments of the form "property: <value>"
2322 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2323 QQmlScript::Object *obj,
2324 const BindingContext &ctxt)
2326 obj->addValueProperty(prop);
2328 if (prop->values.isMany())
2329 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2331 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2334 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2338 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2343 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2344 Q_ASSERT(v->object);
2345 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2351 // Compile assigning a single object instance to a regular property
2352 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2353 QQmlScript::Object *obj,
2354 QQmlScript::Value *v,
2355 const BindingContext &ctxt)
2357 Q_ASSERT(prop->index != -1);
2358 Q_ASSERT(v->object->type != -1);
2360 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2361 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2363 if (QQmlMetaType::isInterface(prop->type)) {
2365 // Assigning an object to an interface ptr property
2366 COMPILE_CHECK(buildObject(v->object, ctxt));
2368 v->type = Value::CreatedObject;
2370 } else if (prop->type == QMetaType::QVariant) {
2372 // Assigning an object to a QVariant
2373 COMPILE_CHECK(buildObject(v->object, ctxt));
2375 v->type = Value::CreatedObject;
2377 // Normally buildObject() will set this up, but we need the static
2378 // meta object earlier to test for assignability. It doesn't matter
2379 // that there may still be outstanding synthesized meta object changes
2380 // on this type, as they are not relevant for assignability testing
2381 v->object->metatype = output->types.at(v->object->type).metaObject();
2382 Q_ASSERT(v->object->metaObject());
2384 // We want to raw metaObject here as the raw metaobject is the
2385 // actual property type before we applied any extensions that might
2386 // effect the properties on the type, but don't effect assignability
2387 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2389 // Will be true if the assgned type inherits propertyMetaObject
2390 bool isAssignable = false;
2391 // Determine isAssignable value
2392 if (propertyMetaObject) {
2393 const QMetaObject *c = v->object->metatype;
2395 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2396 c = c->superClass();
2401 // Simple assignment
2402 COMPILE_CHECK(buildObject(v->object, ctxt));
2404 v->type = Value::CreatedObject;
2405 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2406 // Automatic "Component" insertion
2407 QQmlScript::Object *root = v->object;
2408 QQmlScript::Object *component = pool->New<Object>();
2409 component->type = componentTypeRef();
2410 component->typeName = QStringLiteral("Qt/Component");
2411 component->metatype = &QQmlComponent::staticMetaObject;
2412 component->location = root->location;
2413 QQmlScript::Value *componentValue = pool->New<Value>();
2414 componentValue->object = root;
2415 component->getDefaultProperty()->addValue(componentValue);
2416 v->object = component;
2417 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2419 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2426 // Compile assigning a single object instance to a regular property using the "on" syntax.
2430 // NumberAnimation on x { }
2432 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2433 QQmlScript::Object *obj,
2434 QQmlScript::Object *baseObj,
2435 QQmlScript::Value *v,
2436 const BindingContext &ctxt)
2438 Q_ASSERT(prop->index != -1);
2439 Q_ASSERT(v->object->type != -1);
2443 if (!prop->core.isWritable())
2444 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2447 // Normally buildObject() will set this up, but we need the static
2448 // meta object earlier to test for assignability. It doesn't matter
2449 // that there may still be outstanding synthesized meta object changes
2450 // on this type, as they are not relevant for assignability testing
2451 v->object->metatype = output->types.at(v->object->type).metaObject();
2452 Q_ASSERT(v->object->metaObject());
2454 // Will be true if the assigned type inherits QQmlPropertyValueSource
2455 bool isPropertyValue = false;
2456 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2457 bool isPropertyInterceptor = false;
2458 if (QQmlType *valueType = toQmlType(v->object)) {
2459 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2460 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2463 if (isPropertyValue || isPropertyInterceptor) {
2464 // Assign as a property value source
2465 COMPILE_CHECK(buildObject(v->object, ctxt));
2467 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2468 buildDynamicMeta(baseObj, ForceCreation);
2469 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2471 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2477 // Compile assigning a literal or binding to a regular property
2478 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2479 QQmlScript::Object *obj,
2480 QQmlScript::Value *v,
2481 const BindingContext &ctxt)
2483 Q_ASSERT(prop->index != -1);
2485 if (v->value.isScript()) {
2487 //optimization for <Type>.<EnumValue> enum assignments
2488 if (prop->core.isEnum()) {
2489 bool isEnumAssignment = false;
2490 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2491 if (isEnumAssignment) {
2492 v->type = Value::Literal;
2497 // Test for other binding optimizations
2498 if (!buildLiteralBinding(v, prop, ctxt))
2499 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2501 v->type = Value::PropertyBinding;
2505 COMPILE_CHECK(testLiteralAssignment(prop, v));
2507 v->type = Value::Literal;
2513 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2514 QQmlScript::Object *obj,
2515 QQmlScript::Value *v,
2518 *isAssignment = false;
2519 if (!prop->core.isEnum())
2522 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2524 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2525 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2527 QString string = v->value.asString();
2528 if (!string.at(0).isUpper())
2531 QStringList parts = string.split(QLatin1Char('.'));
2532 if (parts.count() != 2)
2535 QString typeName = parts.at(0);
2537 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2539 //handle enums on value types (where obj->typeName is empty)
2540 QString objTypeName = obj->typeName;
2541 if (objTypeName.isEmpty()) {
2542 QQmlType *objType = toQmlType(obj);
2544 objTypeName = objType->qmlTypeName();
2550 QString enumValue = parts.at(1);
2554 if (objTypeName == type->qmlTypeName()) {
2555 // When these two match, we can short cut the search
2556 if (mprop.isFlagType()) {
2557 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2559 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2562 // Otherwise we have to search the whole type
2563 // This matches the logic in QV8TypeWrapper
2564 QByteArray enumName = enumValue.toUtf8();
2565 const QMetaObject *metaObject = type->baseMetaObject();
2567 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2568 QMetaEnum e = metaObject->enumerator(ii);
2569 value = e.keyToValue(enumName.constData(), &ok);
2576 v->type = Value::Literal;
2577 v->value = QQmlScript::Variant((double)value);
2578 *isAssignment = true;
2583 struct StaticQtMetaObject : public QObject
2585 static const QMetaObject *get()
2586 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2589 // Similar logic to above, but not knowing target property.
2590 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2592 int dot = script.indexOf('.');
2594 const QByteArray &scope = script.left(dot);
2596 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2597 if (!type && scope != "Qt")
2599 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2600 const char *key = script.constData() + dot+1;
2601 int i = mo->enumeratorCount();
2604 int v = mo->enumerator(i).keyToValue(key, &ok);
2612 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2614 QQmlType *qmltype = 0;
2615 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2619 return qmltype->metaObject();
2622 // similar to logic of completeComponentBuild, but also sticks data
2623 // into primitives at the end
2624 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2626 QQmlRewrite::RewriteBinding rewriteBinding;
2627 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2629 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2631 return output->indexForString(rewrite);
2634 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2636 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2637 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2640 // Ensures that the dynamic meta specification on obj is valid
2641 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2643 bool seenDefaultProperty = false;
2645 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2646 // Calculating the hash for the names is not a waste as we have to test
2647 // them against the illegalNames set anyway.
2648 QHashField propNames;
2649 QHashField methodNames;
2652 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2653 const QQmlScript::Object::DynamicProperty &prop = *p;
2655 if (prop.isDefaultProperty) {
2656 if (seenDefaultProperty)
2657 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2658 seenDefaultProperty = true;
2661 if (propNames.testAndSet(prop.name.hash())) {
2662 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2663 p2 = obj->dynamicProperties.next(p2)) {
2664 if (p2->name == prop.name) {
2665 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2666 prop.nameLocation.column,
2667 tr("Duplicate property name"));
2672 if (prop.name.at(0).isUpper()) {
2673 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2674 prop.nameLocation.column,
2675 tr("Property names cannot begin with an upper case letter"));
2678 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2679 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2680 prop.nameLocation.column,
2681 tr("Illegal property name"));
2685 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2686 const QQmlScript::Object::DynamicSignal &currSig = *s;
2688 if (methodNames.testAndSet(currSig.name.hash())) {
2689 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2690 s2 = obj->dynamicSignals.next(s2)) {
2691 if (s2->name == currSig.name)
2692 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2696 if (currSig.name.at(0).isUpper())
2697 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2698 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2699 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2702 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2703 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2705 if (methodNames.testAndSet(currSlot.name.hash())) {
2706 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2707 s2 = obj->dynamicSignals.next(s2)) {
2708 if (s2->name == currSlot.name)
2709 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2711 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2712 s2 = obj->dynamicSlots.next(s2)) {
2713 if (s2->name == currSlot.name)
2714 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2718 if (currSlot.name.at(0).isUpper())
2719 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2720 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2721 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2727 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2729 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2730 p = obj->dynamicProperties.next(p)) {
2732 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2735 Property *property = 0;
2736 if (p->isDefaultProperty) {
2737 property = obj->getDefaultProperty();
2739 property = obj->getProperty(p->name);
2740 if (!property->values.isEmpty())
2741 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2745 property->isReadOnlyDeclaration = true;
2747 if (property->value)
2748 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2750 property->values.append(p->defaultValue->values);
2755 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2757 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2760 Q_ASSERT(obj->metatype);
2762 if (mode != ForceCreation &&
2763 obj->dynamicProperties.isEmpty() &&
2764 obj->dynamicSignals.isEmpty() &&
2765 obj->dynamicSlots.isEmpty())
2768 bool resolveAlias = (mode == ResolveAliases);
2770 const Object::DynamicProperty *defaultProperty = 0;
2772 int varPropCount = 0;
2773 int totalPropCount = 0;
2774 int firstPropertyVarIndex = 0;
2776 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2778 if (p->type == Object::DynamicProperty::Alias)
2780 if (p->type == Object::DynamicProperty::Var)
2783 if (p->isDefaultProperty &&
2784 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2785 defaultProperty = p;
2787 if (!resolveAlias) {
2788 // No point doing this for both the alias and non alias cases
2789 QQmlPropertyData *d = property(obj, p->name);
2790 if (d && d->isFinal())
2791 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2795 bool buildData = resolveAlias || aliasCount == 0;
2797 QByteArray dynamicData;
2799 typedef QQmlVMEMetaData VMD;
2801 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2802 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2803 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2804 aliasCount * sizeof(VMD::AliasData), 0);
2807 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2809 QByteArray newClassName = obj->metatype->className();
2810 newClassName.append("_QML_");
2811 newClassName.append(QByteArray::number(uniqueClassId));
2813 if (compileState->root == obj && !compileState->nested) {
2814 QString path = output->url.path();
2815 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2816 if (lastSlash > -1) {
2817 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2818 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2819 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2823 // Size of the array that describes parameter types & names
2824 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2825 + obj->dynamicProperties.count() // for Changed() signals return types
2826 // Return "parameters" don't have names
2827 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2829 QFastMetaBuilder builder;
2831 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2832 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2833 obj->dynamicSlots.count(),
2834 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2835 defaultProperty?1:0, paramDataSize, ¶mIndex);
2838 Object::DynamicProperty::Type dtype;
2840 } builtinTypes[] = {
2841 { Object::DynamicProperty::Var, QMetaType::QVariant },
2842 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2843 { Object::DynamicProperty::Int, QMetaType::Int },
2844 { Object::DynamicProperty::Bool, QMetaType::Bool },
2845 { Object::DynamicProperty::Real, QMetaType::Double },
2846 { Object::DynamicProperty::String, QMetaType::QString },
2847 { Object::DynamicProperty::Url, QMetaType::QUrl },
2848 { Object::DynamicProperty::Color, QMetaType::QColor },
2849 { Object::DynamicProperty::Time, QMetaType::QTime },
2850 { Object::DynamicProperty::Date, QMetaType::QDate },
2851 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2853 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2855 // Reserve dynamic properties
2856 if (obj->dynamicProperties.count()) {
2857 typedef QQmlVMEMetaData VMD;
2859 int effectivePropertyIndex = 0;
2860 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2862 // Reserve space for name
2863 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2864 p->nameRef = builder.newString(p->name.utf8length());
2867 int propertyType = 0; // for VMD
2868 bool readonly = false;
2870 if (p->type == Object::DynamicProperty::Alias) {
2872 } else if (p->type < builtinTypeCount) {
2873 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2874 metaType = builtinTypes[p->type].metaType;
2875 propertyType = metaType;
2878 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2879 p->type == Object::DynamicProperty::Custom);
2881 // XXX don't double resolve this in the case of an alias run
2883 QByteArray customTypeName;
2884 QQmlType *qmltype = 0;
2886 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2887 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2890 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2892 Q_ASSERT(tdata->isComplete());
2894 QQmlCompiledData *data = tdata->compiledData();
2895 customTypeName = data->root->className();
2899 customTypeName = qmltype->typeName();
2902 if (p->type == Object::DynamicProperty::Custom) {
2903 customTypeName += '*';
2904 propertyType = QMetaType::QObjectStar;
2907 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2908 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2911 metaType = QMetaType::type(customTypeName);
2912 Q_ASSERT(metaType != QMetaType::UnknownType);
2913 Q_ASSERT(metaType != QMetaType::Void);
2916 if (p->type == Object::DynamicProperty::Var)
2923 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2924 vmd->propertyCount++;
2925 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2928 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2929 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2930 effectivePropertyIndex);
2932 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2933 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2936 effectivePropertyIndex++;
2940 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2942 vmd->varPropertyCount = varPropCount;
2943 firstPropertyVarIndex = effectivePropertyIndex;
2944 totalPropCount = varPropCount + effectivePropertyIndex;
2945 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2946 if (p->type == Object::DynamicProperty::Var) {
2948 vmd->propertyCount++;
2949 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2952 builder.setProperty(effectivePropertyIndex, p->nameRef,
2953 QMetaType::QVariant,
2954 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2955 effectivePropertyIndex);
2957 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2958 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2961 effectivePropertyIndex++;
2968 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2969 if (p->type == Object::DynamicProperty::Alias) {
2971 Q_ASSERT(buildData);
2972 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2973 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2976 // Even if we aren't resolving the alias, we need a fake signal so that the
2977 // metaobject remains consistent across the resolve and non-resolve alias runs
2978 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2979 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2981 effectivePropertyIndex++;
2988 // Reserve default property
2989 QFastMetaBuilder::StringRef defPropRef;
2990 if (defaultProperty) {
2991 defPropRef = builder.newString(strlen("DefaultProperty"));
2992 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2995 // Reserve dynamic signals
2996 int signalIndex = 0;
2997 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2999 s->nameRef = builder.newString(s->name.utf8length());
3001 int paramCount = s->parameterNames.count();
3002 QVarLengthArray<int, 10> paramTypes(paramCount);
3004 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3005 for (int i = 0; i < paramCount; ++i) {
3006 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3007 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3008 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3013 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3015 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3016 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3017 paramIndex += paramCount*2 + 1;
3021 // Reserve dynamic slots
3022 if (obj->dynamicSlots.count()) {
3024 typedef QQmlVMEMetaData VMD;
3026 int methodIndex = 0;
3027 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3028 s->nameRef = builder.newString(s->name.utf8length());
3029 int paramCount = s->parameterNames.count();
3031 QVarLengthArray<int, 10> paramTypes(paramCount);
3033 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3034 for (int i = 0; i < paramCount; ++i) {
3035 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3036 paramTypes[i] = QMetaType::QVariant;
3040 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3041 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3042 paramIndex += paramCount*2 + 1;
3047 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3048 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3049 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3050 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3051 for (int jj = 0; jj < paramCount; ++jj) {
3052 if (jj) funcScript.append(QLatin1Char(','));
3053 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3055 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3057 QByteArray utf8 = funcScript.toUtf8();
3058 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3060 s->location.start.line };
3062 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3065 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3067 md.bodyOffset = dynamicData.size();
3069 dynamicData.append((const char *)utf8.constData(), utf8.length());
3077 // Now allocate properties
3078 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3080 char *d = p->changedNameRef.data();
3081 p->name.writeUtf8(d);
3082 strcpy(d + p->name.utf8length(), "Changed");
3083 p->changedNameRef.loadByteArrayData();
3085 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3088 p->nameRef.load(p->name);
3091 // Allocate default property if necessary
3092 if (defaultProperty)
3093 defPropRef.load("DefaultProperty");
3095 // Now allocate signals
3096 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3098 s->nameRef.load(s->name);
3100 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3101 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3104 // Now allocate methods
3105 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3106 s->nameRef.load(s->name);
3108 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3109 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3112 // Now allocate class name
3113 classNameRef.load(newClassName);
3115 obj->metadata = builder.toData();
3116 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3118 if (mode == IgnoreAliases && aliasCount)
3119 compileState->aliasingObjects.append(obj);
3121 obj->synthdata = dynamicData;
3123 if (obj->synthCache) {
3124 obj->synthCache->release();
3125 obj->synthCache = 0;
3128 if (obj->type != -1) {
3129 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3130 QQmlPropertyCache *cache =
3131 superCache->copyAndAppend(engine, &obj->extObject,
3132 QQmlPropertyData::NoFlags,
3133 QQmlPropertyData::IsVMEFunction,
3134 QQmlPropertyData::IsVMESignal);
3136 // now we modify the flags appropriately for var properties.
3137 int propertyOffset = obj->extObject.propertyOffset();
3138 QQmlPropertyData *currPropData = 0;
3139 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3140 currPropData = cache->property(pvi + propertyOffset);
3141 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3144 obj->synthCache = cache;
3150 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3153 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3155 QChar ch = val.at(0);
3156 if (ch.isLetter() && !ch.isLower())
3157 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3159 QChar u(QLatin1Char('_'));
3160 if (!ch.isLetter() && ch != u)
3161 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3163 for (int ii = 1; ii < val.count(); ++ii) {
3165 if (!ch.isLetterOrNumber() && ch != u)
3166 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3169 if (enginePrivate->v8engine()->illegalNames().contains(val))
3170 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3175 #include <private/qqmljsparser_p.h>
3177 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3179 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3181 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3182 return QStringList() << name;
3183 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3184 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3186 QStringList rv = astNodeToStringList(expr->base);
3189 rv.append(expr->name.toString());
3192 return QStringList();
3195 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3197 QQmlScript::Object *obj,
3198 int propIndex, int aliasIndex,
3199 Object::DynamicProperty &prop)
3201 Q_ASSERT(!prop.nameRef.isEmpty());
3202 if (!prop.defaultValue)
3203 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3205 if (!prop.defaultValue->values.isOne() ||
3206 prop.defaultValue->values.first()->object ||
3207 !prop.defaultValue->values.first()->value.isScript())
3208 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3210 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3212 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3214 QStringList alias = astNodeToStringList(node);
3216 if (alias.count() < 1 || alias.count() > 3)
3217 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3219 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3221 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3223 QByteArray typeName;
3228 bool writable = false;
3229 bool resettable = false;
3230 if (alias.count() == 2 || alias.count() == 3) {
3231 propIdx = indexOfProperty(idObject, alias.at(1));
3233 if (-1 == propIdx) {
3234 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3235 } else if (propIdx > 0xFFFF) {
3236 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3239 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3240 if (!aliasProperty.isScriptable())
3241 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3243 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3244 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3246 type = aliasProperty.userType();
3248 if (alias.count() == 3) {
3249 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3251 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3253 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3255 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3256 if (valueTypeIndex == -1)
3257 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3258 Q_ASSERT(valueTypeIndex <= 0xFF);
3260 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3261 propIdx |= (valueTypeIndex << 16);
3263 // update the property type
3264 type = aliasProperty.userType();
3267 if (aliasProperty.isEnumType())
3268 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3270 typeName = aliasProperty.typeName();
3272 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3274 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3276 typeName = ref.type->typeName();
3278 typeName = ref.component->root->className();
3283 if (typeName.endsWith('*'))
3284 flags |= QML_ALIAS_FLAG_PTR;
3286 if (type == QMetaType::UnknownType) {
3287 Q_ASSERT(!typeName.isEmpty());
3288 type = QMetaType::type(typeName);
3289 Q_ASSERT(type != QMetaType::UnknownType);
3290 Q_ASSERT(type != QMetaType::Void);
3293 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3295 typedef QQmlVMEMetaData VMD;
3296 VMD *vmd = (QQmlVMEMetaData *)data.data();
3297 *(vmd->aliasData() + aliasIndex) = aliasData;
3299 int propertyFlags = 0;
3301 propertyFlags |= QFastMetaBuilder::Writable;
3303 propertyFlags |= QFastMetaBuilder::Resettable;
3305 builder.setProperty(propIndex, prop.nameRef, type,
3306 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3312 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3313 QQmlScript::Property *prop,
3314 const BindingContext &ctxt)
3316 Q_ASSERT(prop->index != -1);
3317 Q_ASSERT(prop->parent);
3318 Q_ASSERT(prop->parent->metaObject());
3320 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3321 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3323 JSBindingReference *reference = pool->New<JSBindingReference>();
3324 reference->expression = value->value;
3325 reference->property = prop;
3326 reference->value = value;
3327 reference->bindingContext = ctxt;
3328 addBindingReference(reference);
3333 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3334 QQmlScript::Property *prop,
3335 const QQmlCompilerTypes::BindingContext &)
3337 Q_ASSERT(v->value.isScript());
3339 if (!prop->core.isWritable())
3342 AST::Node *binding = v->value.asAST();
3344 if (prop->type == QVariant::String) {
3345 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3346 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3347 if (i->name == qsTrId_string) {
3348 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3349 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3351 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3352 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3353 (!arg2 || !arg2->next)) {
3358 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3359 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3361 TrBindingReference *reference = pool->New<TrBindingReference>();
3362 reference->dataType = BindingReference::TrId;
3363 reference->text = text;
3365 v->bindingReference = reference;
3369 } else if (i->name == qsTr_string) {
3371 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3372 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3373 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3375 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3376 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3377 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3378 (!arg3 || !arg3->next)) {
3384 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3385 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3386 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3388 TrBindingReference *reference = pool->New<TrBindingReference>();
3389 reference->dataType = BindingReference::Tr;
3390 reference->text = text;
3391 reference->comment = comment;
3393 v->bindingReference = reference;
3406 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3407 QQmlScript::Property *prop,
3408 QQmlScript::Object *obj,
3409 QQmlScript::Property *valueTypeProperty)
3412 Q_ASSERT(binding->bindingReference);
3414 const BindingReference &ref = *binding->bindingReference;
3415 if (ref.dataType == BindingReference::TrId) {
3416 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3418 Instruction::StoreTrIdString store;
3419 store.propertyIndex = prop->core.coreIndex;
3420 store.text = output->indexForByteArray(tr.text.toUtf8());
3422 output->addInstruction(store);
3423 } else if (ref.dataType == BindingReference::Tr) {
3424 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3426 Instruction::StoreTrString store;
3427 store.propertyIndex = prop->core.coreIndex;
3428 store.context = translationContextIndex();
3429 store.text = output->indexForByteArray(tr.text.toUtf8());
3430 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3432 output->addInstruction(store);
3433 } else if (ref.dataType == BindingReference::V4) {
3434 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3436 Instruction::StoreV4Binding store;
3437 store.value = js.compiledIndex;
3438 store.context = js.bindingContext.stack;
3439 store.owner = js.bindingContext.owner;
3440 if (valueTypeProperty) {
3441 store.property = (valueTypeProperty->index & 0xFFFF) |
3442 ((valueTypeProperty->type & 0xFF)) << 16 |
3443 ((prop->index & 0xFF) << 24);
3444 store.isRoot = (compileState->root == valueTypeProperty->parent);
3446 store.property = prop->index;
3447 store.isRoot = (compileState->root == obj);
3449 store.line = binding->location.start.line;
3450 store.column = binding->location.start.column;
3451 output->addInstruction(store);
3452 } else if (ref.dataType == BindingReference::V8) {
3453 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3455 Instruction::StoreV8Binding store;
3456 store.value = js.compiledIndex;
3457 store.context = js.bindingContext.stack;
3458 store.owner = js.bindingContext.owner;
3459 if (valueTypeProperty) {
3460 store.isRoot = (compileState->root == valueTypeProperty->parent);
3462 store.isRoot = (compileState->root == obj);
3464 store.line = binding->location.start.line;
3465 store.column = binding->location.start.column;
3467 Q_ASSERT(js.bindingContext.owner == 0 ||
3468 (js.bindingContext.owner != 0 && valueTypeProperty));
3469 if (js.bindingContext.owner) {
3470 store.property = genValueTypeData(prop, valueTypeProperty);
3472 store.property = prop->core;
3475 output->addInstruction(store);
3476 } else if (ref.dataType == BindingReference::QtScript) {
3477 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3479 QQmlInstruction store;
3480 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3481 store.assignBinding.context = js.bindingContext.stack;
3482 store.assignBinding.owner = js.bindingContext.owner;
3483 store.assignBinding.line = binding->location.start.line;
3484 store.assignBinding.column = binding->location.start.column;
3486 if (valueTypeProperty) {
3487 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3489 store.assignBinding.isRoot = (compileState->root == obj);
3492 Q_ASSERT(js.bindingContext.owner == 0 ||
3493 (js.bindingContext.owner != 0 && valueTypeProperty));
3494 if (js.bindingContext.owner) {
3495 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3497 store.assignBinding.property = prop->core;
3499 output->addInstructionHelper(
3500 !prop->isAlias ? QQmlInstruction::StoreBinding
3501 : QQmlInstruction::StoreBindingOnAlias
3504 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3508 int QQmlCompiler::genContextCache()
3510 if (compileState->ids.count() == 0)
3513 QQmlIntegerCache *cache = new QQmlIntegerCache();
3514 cache->reserve(compileState->ids.count());
3515 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3516 cache->add(o->id, o->idIndex);
3518 output->contextCaches.append(cache);
3519 return output->contextCaches.count() - 1;
3523 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3524 QQmlScript::Property *prop)
3526 typedef QQmlPropertyPrivate QDPP;
3527 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3528 enginePrivate->valueTypes[prop->type]->metaObject(),
3529 valueTypeProp->index, engine);
3532 bool QQmlCompiler::completeComponentBuild()
3535 componentStats->componentStat.ids = compileState->ids.count();
3537 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3538 aliasObject = compileState->aliasingObjects.next(aliasObject))
3539 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3541 QV4Compiler::Expression expr(unit->imports());
3542 expr.component = compileState->root;
3543 expr.ids = &compileState->ids;
3544 expr.importCache = output->importCache;
3546 QV4Compiler bindingCompiler;
3548 QList<JSBindingReference*> sharedBindings;
3550 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3552 JSBindingReference &binding = *b;
3554 // ### We don't currently optimize for bindings on alias's - because
3555 // of the solution to QTBUG-13719
3556 if (!binding.property->isAlias) {
3557 expr.context = binding.bindingContext.object;
3558 expr.property = binding.property;
3559 expr.expression = binding.expression;
3561 int index = bindingCompiler.compile(expr, enginePrivate);
3563 binding.dataType = BindingReference::V4;
3564 binding.compiledIndex = index;
3566 componentStats->componentStat.optimizedBindings.append(b->value->location);
3571 // Pre-rewrite the expression
3572 QString expression = binding.expression.asScript();
3574 QQmlRewrite::RewriteBinding rewriteBinding;
3575 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3576 bool isSharable = false;
3577 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3579 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3580 binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3581 binding.dataType = BindingReference::V8;
3582 sharedBindings.append(b);
3585 componentStats->componentStat.sharedBindings.append(b->value->location);
3587 binding.dataType = BindingReference::QtScript;
3590 componentStats->componentStat.scriptBindings.append(b->value->location);
3594 if (!sharedBindings.isEmpty()) {
3596 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3598 return lhs->value->location.start.line < rhs->value->location.start.line;
3602 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3604 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3605 int lineNumber = startLineNumber;
3607 QByteArray functionArray("[", 1);
3608 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3610 JSBindingReference *reference = sharedBindings.at(ii);
3611 QQmlScript::Value *value = reference->value;
3612 const QString &expression = reference->rewrittenExpression;
3614 if (ii != 0) functionArray.append(",", 1);
3616 while (lineNumber < value->location.start.line) {
3618 functionArray.append("\n", 1);
3621 functionArray += expression.toUtf8();
3622 lineNumber += expression.count(QLatin1Char('\n'));
3623 reference->compiledIndex = ii;
3625 functionArray.append("]", 1);
3627 compileState->v8BindingProgram = functionArray;
3628 compileState->v8BindingProgramLine = startLineNumber;
3631 if (bindingCompiler.isValid())
3632 compileState->compiledBindingData = bindingCompiler.program();
3634 // Check pop()'s matched push()'s
3635 Q_ASSERT(compileState->objectDepth.depth() == 0);
3636 Q_ASSERT(compileState->listDepth.depth() == 0);
3638 saveComponentState();
3643 void QQmlCompiler::dumpStats()
3645 Q_ASSERT(componentStats);
3646 qWarning().nospace() << "QML Document: " << output->url.toString();
3647 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3648 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3649 qWarning().nospace() << " Component Line " << stat.lineNumber;
3650 qWarning().nospace() << " Total Objects: " << stat.objects;
3651 qWarning().nospace() << " IDs Used: " << stat.ids;
3652 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3656 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3657 if (0 == (ii % 10)) {
3658 if (ii) output.append("\n");
3663 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3665 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3666 output.append(") ");
3668 if (!output.isEmpty())
3669 qWarning().nospace() << output.constData();
3672 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3675 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3676 if (0 == (ii % 10)) {
3677 if (ii) output.append("\n");
3682 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3684 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3685 output.append(") ");
3687 if (!output.isEmpty())
3688 qWarning().nospace() << output.constData();
3691 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3694 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3695 if (0 == (ii % 10)) {
3696 if (ii) output.append("\n");
3701 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3703 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3704 output.append(") ");
3706 if (!output.isEmpty())
3707 qWarning().nospace() << output.constData();
3713 Returns true if from can be assigned to a (QObject) property of type
3716 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3718 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3719 const QMetaObject *fromMo = from->metaObject();
3722 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3724 fromMo = fromMo->superClass();
3730 Returns the element name, as written in the QML file, for o.
3732 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3735 if (o->type != -1) {
3736 return output->types.at(o->type).className;
3742 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3745 const QMetaObject *mo = from->metatype;
3747 while (!type && mo) {
3748 type = QQmlMetaType::qmlType(mo);
3749 mo = mo->superClass();
3754 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3756 const QMetaObject *mo = obj->metatype;
3758 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3760 return QStringList();
3762 QMetaClassInfo classInfo = mo->classInfo(idx);
3763 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3768 QQmlCompiler::property(QQmlScript::Object *object, int index)
3770 QQmlPropertyCache *cache = 0;
3772 if (object->synthCache)
3773 cache = object->synthCache;
3774 else if (object->type != -1)
3775 cache = output->types[object->type].createPropertyCache(engine);
3777 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3779 return cache->property(index);
3783 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3785 if (notInRevision) *notInRevision = false;
3787 QQmlPropertyCache *cache = 0;
3789 if (object->synthCache)
3790 cache = object->synthCache;
3791 else if (object->type != -1)
3792 cache = output->types[object->type].createPropertyCache(engine);
3794 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3796 QQmlPropertyData *d = cache->property(name);
3798 // Find the first property
3799 while (d && d->isFunction())
3800 d = cache->overrideData(d);
3802 if (d && !cache->isAllowedInRevision(d)) {
3803 if (notInRevision) *notInRevision = true;
3810 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3812 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3814 if (notInRevision) *notInRevision = false;
3816 QQmlPropertyCache *cache = 0;
3818 if (object->synthCache)
3819 cache = object->synthCache;
3820 else if (object->type != -1)
3821 cache = output->types[object->type].createPropertyCache(engine);
3823 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3826 QQmlPropertyData *d = cache->property(name);
3827 if (notInRevision) *notInRevision = false;
3829 while (d && !(d->isFunction()))
3830 d = cache->overrideData(d);
3832 if (d && !cache->isAllowedInRevision(d)) {
3833 if (notInRevision) *notInRevision = true;
3839 if (name.endsWith(Changed_string)) {
3840 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3842 d = property(object, propName, notInRevision);
3844 return cache->method(d->notifyIndex);
3850 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3851 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3852 bool *notInRevision)
3854 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3855 return d?d->coreIndex:-1;
3858 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3859 bool *notInRevision)
3861 return indexOfProperty(object, QStringRef(&name), notInRevision);
3864 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3865 bool *notInRevision)
3867 QQmlPropertyData *d = property(object, name, notInRevision);
3868 return d?d->coreIndex:-1;