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_module_string(QLatin1String("QML"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QQmlCompiler.
101 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
102 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QQmlCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QQmlError> QQmlCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QQmlCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
191 error.setUrl(output->url); \
192 error.setLine(line); \
193 error.setColumn(column); \
194 error.setDescription(desc.trimmed()); \
195 exceptions << error; \
199 #define COMPILE_EXCEPTION(token, desc) \
200 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
205 Returns false if \a is false, otherwise does nothing.
207 #define COMPILE_CHECK(a) \
209 if (!a) return false; \
213 Returns true if literal \a v can be assigned to property \a prop, otherwise
216 This test corresponds to action taken by genLiteralAssignment(). Any change
217 made here, must have a corresponding action in genLiteralAssigment().
219 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
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(QMetaType::typeName(type))));
411 Generate a store instruction for assigning literal \a v to property \a prop.
413 Any literal assignment that is approved in testLiteralAssignment() must have
414 a corresponding action in this method.
416 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
417 QQmlScript::Value *v)
419 if (prop->core.isEnum()) {
420 Q_ASSERT(v->value.isNumber());
422 int value = (int)v->value.asNumber();
424 Instruction::StoreInteger instr;
425 instr.propertyIndex = prop->index;
427 output->addInstruction(instr);
431 int type = prop->type;
433 case QMetaType::QVariant:
435 if (v->value.isNumber()) {
436 double n = v->value.asNumber();
437 if (double(int(n)) == n) {
438 if (prop->core.isVMEProperty()) {
439 Instruction::StoreVarInteger instr;
440 instr.propertyIndex = prop->index;
441 instr.value = int(n);
442 output->addInstruction(instr);
444 Instruction::StoreVariantInteger instr;
445 instr.propertyIndex = prop->index;
446 instr.value = int(n);
447 output->addInstruction(instr);
450 if (prop->core.isVMEProperty()) {
451 Instruction::StoreVarDouble instr;
452 instr.propertyIndex = prop->index;
454 output->addInstruction(instr);
456 Instruction::StoreVariantDouble instr;
457 instr.propertyIndex = prop->index;
459 output->addInstruction(instr);
462 } else if (v->value.isBoolean()) {
463 if (prop->core.isVMEProperty()) {
464 Instruction::StoreVarBool instr;
465 instr.propertyIndex = prop->index;
466 instr.value = v->value.asBoolean();
467 output->addInstruction(instr);
469 Instruction::StoreVariantBool instr;
470 instr.propertyIndex = prop->index;
471 instr.value = v->value.asBoolean();
472 output->addInstruction(instr);
475 if (prop->core.isVMEProperty()) {
476 Instruction::StoreVar instr;
477 instr.propertyIndex = prop->index;
478 instr.value = output->indexForString(v->value.asString());
479 output->addInstruction(instr);
481 Instruction::StoreVariant instr;
482 instr.propertyIndex = prop->index;
483 instr.value = output->indexForString(v->value.asString());
484 output->addInstruction(instr);
489 case QVariant::String:
491 Instruction::StoreString instr;
492 instr.propertyIndex = prop->index;
493 instr.value = output->indexForString(v->value.asString());
494 output->addInstruction(instr);
497 case QVariant::StringList:
499 Instruction::StoreStringList instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForString(v->value.asString());
502 output->addInstruction(instr);
505 case QVariant::ByteArray:
507 Instruction::StoreByteArray instr;
508 instr.propertyIndex = prop->index;
509 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
510 output->addInstruction(instr);
515 Instruction::StoreUrl instr;
516 QString string = v->value.asString();
517 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
518 instr.propertyIndex = prop->index;
519 instr.value = output->indexForUrl(u);
520 output->addInstruction(instr);
525 Instruction::StoreInteger instr;
526 instr.propertyIndex = prop->index;
527 instr.value = uint(v->value.asNumber());
528 output->addInstruction(instr);
533 Instruction::StoreInteger instr;
534 instr.propertyIndex = prop->index;
535 instr.value = int(v->value.asNumber());
536 output->addInstruction(instr);
539 case QMetaType::Float:
541 Instruction::StoreFloat instr;
542 instr.propertyIndex = prop->index;
543 instr.value = float(v->value.asNumber());
544 output->addInstruction(instr);
547 case QVariant::Double:
549 Instruction::StoreDouble instr;
550 instr.propertyIndex = prop->index;
551 instr.value = v->value.asNumber();
552 output->addInstruction(instr);
555 case QVariant::Color:
557 Instruction::StoreColor instr;
558 instr.propertyIndex = prop->index;
559 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
560 output->addInstruction(instr);
563 #ifndef QT_NO_DATESTRING
566 Instruction::StoreDate instr;
567 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
568 instr.propertyIndex = prop->index;
569 instr.value = d.toJulianDay();
570 output->addInstruction(instr);
575 Instruction::StoreTime instr;
576 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
577 instr.propertyIndex = prop->index;
578 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
579 ::memcpy(&instr.time, &time, sizeof(QTime));
580 output->addInstruction(instr);
583 case QVariant::DateTime:
585 Instruction::StoreDateTime instr;
586 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
587 QTime time = dateTime.time();
588 instr.propertyIndex = prop->index;
589 instr.date = dateTime.date().toJulianDay();
590 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
591 ::memcpy(&instr.time, &time, sizeof(QTime));
592 output->addInstruction(instr);
595 #endif // QT_NO_DATESTRING
596 case QVariant::Point:
598 Instruction::StorePoint instr;
600 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
601 instr.propertyIndex = prop->index;
602 instr.point.xp = point.x();
603 instr.point.yp = point.y();
604 output->addInstruction(instr);
607 case QVariant::PointF:
609 Instruction::StorePointF instr;
611 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
612 instr.propertyIndex = prop->index;
613 instr.point.xp = point.x();
614 instr.point.yp = point.y();
615 output->addInstruction(instr);
620 Instruction::StoreSize instr;
622 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
623 instr.propertyIndex = prop->index;
624 instr.size.wd = size.width();
625 instr.size.ht = size.height();
626 output->addInstruction(instr);
629 case QVariant::SizeF:
631 Instruction::StoreSizeF instr;
633 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
634 instr.propertyIndex = prop->index;
635 instr.size.wd = size.width();
636 instr.size.ht = size.height();
637 output->addInstruction(instr);
642 Instruction::StoreRect instr;
644 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
645 instr.propertyIndex = prop->index;
646 instr.rect.x1 = rect.left();
647 instr.rect.y1 = rect.top();
648 instr.rect.x2 = rect.right();
649 instr.rect.y2 = rect.bottom();
650 output->addInstruction(instr);
653 case QVariant::RectF:
655 Instruction::StoreRectF instr;
657 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
658 instr.propertyIndex = prop->index;
659 instr.rect.xp = rect.left();
660 instr.rect.yp = rect.top();
661 instr.rect.w = rect.width();
662 instr.rect.h = rect.height();
663 output->addInstruction(instr);
668 Instruction::StoreBool instr;
669 bool b = v->value.asBoolean();
670 instr.propertyIndex = prop->index;
672 output->addInstruction(instr);
675 case QVariant::Vector3D:
677 Instruction::StoreVector3D instr;
678 instr.propertyIndex = prop->index;
679 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
680 output->addInstruction(instr);
683 case QVariant::Vector4D:
685 Instruction::StoreVector4D instr;
686 instr.propertyIndex = prop->index;
687 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
688 output->addInstruction(instr);
693 // generate single literal value assignment to a list property if required
694 if (type == qMetaTypeId<QList<qreal> >()) {
695 Instruction::StoreDoubleQList instr;
696 instr.propertyIndex = prop->index;
697 instr.value = v->value.asNumber();
698 output->addInstruction(instr);
700 } else if (type == qMetaTypeId<QList<int> >()) {
701 Instruction::StoreIntegerQList instr;
702 instr.propertyIndex = prop->index;
703 instr.value = int(v->value.asNumber());
704 output->addInstruction(instr);
706 } else if (type == qMetaTypeId<QList<bool> >()) {
707 Instruction::StoreBoolQList instr;
708 bool b = v->value.asBoolean();
709 instr.propertyIndex = prop->index;
711 output->addInstruction(instr);
713 } else if (type == qMetaTypeId<QList<QUrl> >()) {
714 Instruction::StoreUrlQList instr;
715 QString string = v->value.asString();
716 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
717 instr.propertyIndex = prop->index;
718 instr.value = output->indexForUrl(u);
719 output->addInstruction(instr);
721 } else if (type == qMetaTypeId<QList<QString> >()) {
722 Instruction::StoreStringQList instr;
723 instr.propertyIndex = prop->index;
724 instr.value = output->indexForString(v->value.asString());
725 output->addInstruction(instr);
729 // otherwise, generate custom type literal assignment
730 Instruction::AssignCustomType instr;
731 instr.propertyIndex = prop->index;
732 instr.primitive = output->indexForString(v->value.asString());
734 output->addInstruction(instr);
741 Resets data by clearing the lists that the QQmlCompiler modifies.
743 void QQmlCompiler::reset(QQmlCompiledData *data)
746 data->primitives.clear();
748 data->bytecode.resize(0);
752 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
753 with which the QQmlCompiledData will be associated.
755 Returns true on success, false on failure. On failure, the compile errors
756 are available from errors().
758 If the environment variant QML_COMPILER_DUMP is set
759 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
760 on a successful compiler.
762 bool QQmlCompiler::compile(QQmlEngine *engine,
764 QQmlCompiledData *out)
771 QQmlScript::Object *root = unit->parser().tree();
774 this->engine = engine;
775 this->enginePrivate = QQmlEnginePrivate::get(engine);
777 this->unitRoot = root;
781 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
782 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
784 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
785 QQmlCompiledData::TypeReference ref;
787 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
788 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
791 ref.type = tref.type;
792 if (!ref.type->isCreatable()) {
793 QString err = ref.type->noCreationReason();
795 err = tr( "Element is not creatable.");
796 COMPILE_EXCEPTION(parserRef->firstUse, err);
799 if (ref.type->containsRevisionedAttributes()) {
800 QQmlError cacheError;
801 ref.typePropertyCache = enginePrivate->cache(ref.type,
802 resolvedTypes.at(ii).minorVersion,
804 if (!ref.typePropertyCache)
805 COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
806 ref.typePropertyCache->addref();
809 } else if (tref.typeData) {
810 ref.component = tref.typeData->compiledData();
811 ref.component->addref();
820 out->dumpInstructions();
823 Q_ASSERT(out->rootPropertyCache);
831 this->enginePrivate = 0;
833 this->cachedComponentTypeRef = -1;
834 this->cachedTranslationContextIndex = -1;
840 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
842 compileState = pool->New<ComponentCompileState>();
844 compileState->root = tree;
846 componentStats->componentStat.lineNumber = tree->location.start.line;
848 // We generate the importCache before we build the tree so that
849 // it can be used in the binding compiler. Given we "expect" the
850 // QML compilation to succeed, this isn't a waste.
851 output->importCache = new QQmlTypeNameCache();
852 foreach (const QString &ns, unit->namespaces()) {
853 output->importCache->add(ns);
857 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
858 QString qualifier = script.qualifier;
859 QString enclosingNamespace;
861 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
862 if (lastDotIndex != -1) {
863 enclosingNamespace = qualifier.left(lastDotIndex);
864 qualifier = qualifier.mid(lastDotIndex+1);
867 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
870 unit->imports().populateCache(output->importCache, engine);
872 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
875 Instruction::Init init;
876 init.bindingsSize = compileState->totalBindingsCount;
877 init.parserStatusSize = compileState->parserStatusCount;
878 init.contextCache = genContextCache();
879 init.objectStackSize = compileState->objectDepth.maxDepth();
880 init.listStackSize = compileState->listDepth.maxDepth();
881 if (compileState->compiledBindingData.isEmpty())
882 init.compiledBinding = -1;
884 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
885 output->addInstruction(init);
887 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
888 Instruction::StoreImportedScript import;
889 import.value = output->scripts.count();
891 QQmlScriptData *scriptData = script.script->scriptData();
892 scriptData->addref();
893 output->scripts << scriptData;
894 output->addInstruction(import);
897 if (!compileState->v8BindingProgram.isEmpty()) {
898 Instruction::InitV8Bindings bindings;
899 int index = output->programs.count();
901 typedef QQmlCompiledData::V8Program V8Program;
902 output->programs.append(V8Program(compileState->v8BindingProgram, output));
904 bindings.programIndex = index;
905 bindings.line = compileState->v8BindingProgramLine;
906 output->addInstruction(bindings);
911 Instruction::SetDefault def;
912 output->addInstruction(def);
914 Instruction::Done done;
915 output->addInstruction(done);
917 Q_ASSERT(tree->metatype);
919 if (tree->metadata.isEmpty()) {
920 output->root = tree->metatype;
922 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
923 output->root = &output->rootData;
925 if (!tree->metadata.isEmpty())
926 enginePrivate->registerCompositeType(output->root);
929 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
931 for (int ii = 0; ii < list.count(); ++ii)
932 if (string == list.at(ii))
938 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
941 componentStats->componentStat.objects++;
943 Q_ASSERT (obj->type != -1);
944 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
945 obj->metatype = tr.metaObject();
947 // This object is a "Component" element
948 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
949 COMPILE_CHECK(buildComponent(obj, ctxt));
954 typedef QQmlInstruction I;
955 const I *init = ((const I *)tr.component->bytecode.constData());
956 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
958 // Adjust stack depths to include nested components
959 compileState->objectDepth.pushPop(init->init.objectStackSize);
960 compileState->listDepth.pushPop(init->init.listStackSize);
961 compileState->parserStatusCount += init->init.parserStatusSize;
962 compileState->totalBindingsCount += init->init.bindingsSize;
965 compileState->objectDepth.push();
967 // Object instantiations reset the binding context
968 BindingContext objCtxt(obj);
970 // Create the synthesized meta object, ignoring aliases
971 COMPILE_CHECK(checkDynamicMeta(obj));
972 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
973 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
975 // Find the native type and check for the QQmlParserStatus interface
976 QQmlType *type = toQmlType(obj);
978 obj->parserStatusCast = type->parserStatusCast();
979 if (obj->parserStatusCast != -1)
980 compileState->parserStatusCount++;
982 // Check if this is a custom parser type. Custom parser types allow
983 // assignments to non-existent properties. These assignments are then
984 // compiled by the type.
985 bool isCustomParser = output->types.at(obj->type).type &&
986 output->types.at(obj->type).type->customParser() != 0;
987 QList<QQmlCustomParserProperty> customProps;
989 // Fetch the list of deferred properties
990 QStringList deferredList = deferredProperties(obj);
992 // Must do id property first. This is to ensure that the id given to any
993 // id reference created matches the order in which the objects are
995 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
996 if (prop->name() == id_string) {
997 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1003 Property *defaultProperty = 0;
1004 Property *skipProperty = 0;
1005 if (obj->defaultProperty) {
1006 defaultProperty = obj->defaultProperty;
1008 Property *explicitProperty = 0;
1010 const QMetaObject *mo = obj->metatype;
1011 int idx = mo->indexOfClassInfo("DefaultProperty");
1013 QMetaClassInfo info = mo->classInfo(idx);
1014 const char *p = info.value();
1018 while (char c = p[plen++]) { ord |= c; };
1022 // Utf8 - unoptimal, but seldom hit
1023 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1024 QHashedStringRef r(*s);
1026 if (obj->propertiesHashField.test(r.hash())) {
1027 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1028 if (ep->name() == r) {
1029 explicitProperty = ep;
1035 if (!explicitProperty)
1036 defaultProperty->setName(r);
1039 QHashedCStringRef r(p, plen);
1041 if (obj->propertiesHashField.test(r.hash())) {
1042 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1043 if (ep->name() == r) {
1044 explicitProperty = ep;
1050 if (!explicitProperty) {
1051 // Set the default property name
1052 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1053 r.writeUtf16(buffer);
1054 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1060 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1062 skipProperty = explicitProperty; // We merge the values into defaultProperty
1064 // Find the correct insertion point
1065 Value *insertPos = 0;
1067 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1068 if (!(v->location.start < explicitProperty->values.first()->location.start))
1073 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1077 QQmlCustomParser *cp = 0;
1079 cp = output->types.at(obj->type).type->customParser();
1081 // Build all explicit properties specified
1082 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1084 if (prop == skipProperty)
1086 if (prop->name() == id_string)
1089 bool canDefer = false;
1090 if (isCustomParser) {
1091 if (doesPropertyExist(prop, obj) &&
1092 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1093 !isAttachedPropertyName(prop->name()))) {
1094 int ids = compileState->ids.count();
1095 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1096 canDefer = ids == compileState->ids.count();
1097 } else if (isSignalPropertyName(prop->name()) &&
1098 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1099 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1101 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1104 if (isSignalPropertyName(prop->name())) {
1105 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1107 int ids = compileState->ids.count();
1108 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1109 canDefer = ids == compileState->ids.count();
1113 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1114 prop->isDeferred = true;
1118 // Build the default property
1119 if (defaultProperty) {
1120 Property *prop = defaultProperty;
1122 bool canDefer = false;
1123 if (isCustomParser) {
1124 if (doesPropertyExist(prop, obj)) {
1125 int ids = compileState->ids.count();
1126 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1127 canDefer = ids == compileState->ids.count();
1129 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1132 int ids = compileState->ids.count();
1133 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1134 canDefer = ids == compileState->ids.count();
1137 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1138 prop->isDeferred = true;
1141 // Compile custom parser parts
1142 if (isCustomParser && !customProps.isEmpty()) {
1144 cp->compiler = this;
1146 obj->custom = cp->compile(customProps);
1149 foreach (QQmlError err, cp->errors()) {
1150 err.setUrl(output->url);
1155 compileState->objectDepth.pop();
1160 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1162 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1163 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1168 // Create the object
1169 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1170 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1172 Instruction::CreateSimpleObject create;
1173 create.create = output->types.at(obj->type).type->createFunction();
1174 create.typeSize = output->types.at(obj->type).type->createSize();
1175 create.type = obj->type;
1176 create.line = obj->location.start.line;
1177 create.column = obj->location.start.column;
1178 output->addInstruction(create);
1182 if (output->types.at(obj->type).type) {
1183 Instruction::CreateCppObject create;
1184 create.line = obj->location.start.line;
1185 create.column = obj->location.start.column;
1187 if (!obj->custom.isEmpty())
1188 create.data = output->indexForByteArray(obj->custom);
1189 create.type = obj->type;
1190 create.isRoot = (compileState->root == obj);
1191 output->addInstruction(create);
1193 Instruction::CreateQMLObject create;
1194 create.type = obj->type;
1195 create.isRoot = (compileState->root == obj);
1197 if (!obj->bindingBitmask.isEmpty()) {
1198 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1199 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1201 create.bindingBits = -1;
1203 output->addInstruction(create);
1205 Instruction::CompleteQMLObject complete;
1206 complete.line = obj->location.start.line;
1207 complete.column = obj->location.start.column;
1208 complete.isRoot = (compileState->root == obj);
1209 output->addInstruction(complete);
1213 // Setup the synthesized meta object if necessary
1214 if (!obj->metadata.isEmpty()) {
1215 Instruction::StoreMetaObject meta;
1216 meta.data = output->indexForByteArray(obj->metadata);
1217 meta.aliasData = output->indexForByteArray(obj->synthdata);
1218 meta.propertyCache = output->propertyCaches.count();
1220 QQmlPropertyCache *propertyCache = obj->synthCache;
1221 Q_ASSERT(propertyCache);
1222 propertyCache->addref();
1224 // Add flag for alias properties
1225 if (!obj->synthdata.isEmpty()) {
1226 const QQmlVMEMetaData *vmeMetaData =
1227 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1228 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1229 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1230 QQmlPropertyData *data = propertyCache->property(index);
1231 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1235 if (obj == unitRoot) {
1236 propertyCache->addref();
1237 output->rootPropertyCache = propertyCache;
1240 output->propertyCaches << propertyCache;
1241 output->addInstruction(meta);
1242 } else if (obj == unitRoot) {
1243 output->rootPropertyCache = tr.createPropertyCache(engine);
1244 output->rootPropertyCache->addref();
1247 // Set the object id
1248 if (!obj->id.isEmpty()) {
1249 Instruction::SetId id;
1250 id.value = output->indexForString(obj->id);
1251 id.index = obj->idIndex;
1252 output->addInstruction(id);
1256 if (tr.type && obj->parserStatusCast != -1) {
1257 Instruction::BeginObject begin;
1258 begin.castValue = obj->parserStatusCast;
1259 output->addInstruction(begin);
1265 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1267 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1268 Q_ASSERT(prop->scriptStringScope != -1);
1269 const QString &script = prop->values.first()->value.asScript();
1270 Instruction::StoreScriptString ss;
1271 ss.propertyIndex = prop->index;
1272 ss.value = output->indexForString(script);
1273 ss.scope = prop->scriptStringScope;
1274 // ss.bindingId = rewriteBinding(script, prop->name());
1275 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1276 ss.line = prop->location.start.line;
1277 ss.column = prop->location.start.column;
1278 output->addInstruction(ss);
1281 bool seenDefer = false;
1282 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1283 if (prop->isDeferred) {
1288 genValueProperty(prop, obj);
1291 Instruction::Defer defer;
1292 defer.deferCount = 0;
1293 int deferIdx = output->addInstruction(defer);
1294 int nextInstructionIndex = output->nextInstructionIndex();
1296 Instruction::DeferInit dinit;
1297 // XXX - these are now massive over allocations
1298 dinit.bindingsSize = compileState->totalBindingsCount;
1299 dinit.parserStatusSize = compileState->parserStatusCount;
1300 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1301 dinit.listStackSize = compileState->listDepth.maxDepth();
1302 output->addInstruction(dinit);
1304 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1305 if (!prop->isDeferred)
1307 genValueProperty(prop, obj);
1310 Instruction::Done done;
1311 output->addInstruction(done);
1313 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1316 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1318 QQmlScript::Value *v = prop->values.first();
1320 if (v->type == Value::SignalObject) {
1322 genObject(v->object);
1324 Instruction::AssignSignalObject assign;
1325 assign.line = v->location.start.line;
1326 assign.signal = output->indexForString(prop->name().toString());
1327 output->addInstruction(assign);
1329 } else if (v->type == Value::SignalExpression) {
1331 Instruction::StoreSignal store;
1332 store.signalIndex = prop->index;
1333 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1334 store.value = output->indexForByteArray(rewrite.toUtf8());
1335 store.context = v->signalExpressionContextStack;
1336 store.line = v->location.start.line;
1337 store.column = v->location.start.column;
1338 output->addInstruction(store);
1344 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1345 Instruction::FetchAttached fetch;
1346 fetch.id = prop->index;
1347 fetch.line = prop->location.start.line;
1348 output->addInstruction(fetch);
1350 genObjectBody(prop->value);
1352 Instruction::PopFetchedObject pop;
1353 output->addInstruction(pop);
1356 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1357 Instruction::FetchObject fetch;
1358 fetch.property = prop->index;
1359 fetch.line = prop->location.start.line;
1360 output->addInstruction(fetch);
1362 if (!prop->value->metadata.isEmpty()) {
1363 Instruction::StoreMetaObject meta;
1364 meta.data = output->indexForByteArray(prop->value->metadata);
1365 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1366 meta.propertyCache = -1;
1367 output->addInstruction(meta);
1370 genObjectBody(prop->value);
1372 Instruction::PopFetchedObject pop;
1373 output->addInstruction(pop);
1376 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1378 genValueTypeProperty(obj, prop);
1381 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1382 if (prop->isDeferred)
1385 genValueProperty(prop, obj);
1388 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1390 genValueTypeProperty(obj, prop);
1394 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1396 Instruction::FetchValueType fetch;
1397 fetch.property = prop->index;
1398 fetch.type = prop->type;
1399 fetch.bindingSkipList = 0;
1401 if (obj->type == -1 || output->types.at(obj->type).component) {
1402 // We only have to do this if this is a composite type. If it is a builtin
1403 // type it can't possibly already have bindings that need to be cleared.
1404 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1405 if (!vprop->values.isEmpty()) {
1406 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1407 fetch.bindingSkipList |= (1 << vprop->index);
1412 output->addInstruction(fetch);
1414 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1415 genPropertyAssignment(vprop, prop->value, prop);
1418 Instruction::PopValueType pop;
1419 pop.property = prop->index;
1420 pop.type = prop->type;
1421 pop.bindingSkipList = 0;
1422 output->addInstruction(pop);
1425 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1427 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1430 Instruction::CreateComponent create;
1431 create.line = root->location.start.line;
1432 create.column = root->location.start.column;
1433 create.endLine = root->location.end.line;
1434 create.isRoot = (compileState->root == obj);
1435 int createInstruction = output->addInstruction(create);
1436 int nextInstructionIndex = output->nextInstructionIndex();
1438 ComponentCompileState *oldCompileState = compileState;
1439 compileState = componentState(root);
1441 Instruction::Init init;
1442 init.bindingsSize = compileState->totalBindingsCount;
1443 init.parserStatusSize = compileState->parserStatusCount;
1444 init.contextCache = genContextCache();
1445 init.objectStackSize = compileState->objectDepth.maxDepth();
1446 init.listStackSize = compileState->listDepth.maxDepth();
1447 if (compileState->compiledBindingData.isEmpty())
1448 init.compiledBinding = -1;
1450 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1451 output->addInstruction(init);
1453 if (!compileState->v8BindingProgram.isEmpty()) {
1454 Instruction::InitV8Bindings bindings;
1455 int index = output->programs.count();
1457 typedef QQmlCompiledData::V8Program V8Program;
1458 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1460 bindings.programIndex = index;
1461 bindings.line = compileState->v8BindingProgramLine;
1462 output->addInstruction(bindings);
1467 Instruction::SetDefault def;
1468 output->addInstruction(def);
1470 Instruction::Done done;
1471 output->addInstruction(done);
1473 output->instruction(createInstruction)->createComponent.count =
1474 output->nextInstructionIndex() - nextInstructionIndex;
1476 compileState = oldCompileState;
1478 if (!obj->id.isEmpty()) {
1479 Instruction::SetId id;
1480 id.value = output->indexForString(obj->id);
1481 id.index = obj->idIndex;
1482 output->addInstruction(id);
1485 if (obj == unitRoot) {
1486 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1487 output->rootPropertyCache->addref();
1491 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1492 const BindingContext &ctxt)
1494 // The special "Component" element can only have the id property and a
1495 // default property, that actually defines the component's tree
1497 compileState->objectDepth.push();
1499 // Find, check and set the "id" property (if any)
1500 Property *idProp = 0;
1501 if (obj->properties.isMany() ||
1502 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1503 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1505 if (!obj->properties.isEmpty())
1506 idProp = obj->properties.first();
1509 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1510 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1511 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1513 QString idVal = idProp->values.first()->primitive();
1515 if (compileState->ids.value(idVal))
1516 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1522 // Check the Component tree is well formed
1523 if (obj->defaultProperty &&
1524 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1525 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1526 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1528 if (!obj->dynamicProperties.isEmpty())
1529 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1530 if (!obj->dynamicSignals.isEmpty())
1531 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1532 if (!obj->dynamicSlots.isEmpty())
1533 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1535 QQmlScript::Object *root = 0;
1536 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1537 root = obj->defaultProperty->values.first()->object;
1540 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1542 // Build the component tree
1543 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1545 compileState->objectDepth.pop();
1550 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1551 const BindingContext &ctxt)
1553 ComponentCompileState *oldComponentCompileState = compileState;
1554 compileState = pool->New<ComponentCompileState>();
1555 compileState->root = obj;
1556 compileState->nested = true;
1558 if (componentStats) {
1559 ComponentStat oldComponentStat = componentStats->componentStat;
1561 componentStats->componentStat = ComponentStat();
1562 componentStats->componentStat.lineNumber = obj->location.start.line;
1565 COMPILE_CHECK(buildObject(obj, ctxt));
1567 COMPILE_CHECK(completeComponentBuild());
1569 componentStats->componentStat = oldComponentStat;
1572 COMPILE_CHECK(buildObject(obj, ctxt));
1574 COMPILE_CHECK(completeComponentBuild());
1577 compileState = oldComponentCompileState;
1583 // Build a sub-object. A sub-object is one that was not created directly by
1584 // QML - such as a grouped property object, or an attached object. Sub-object's
1585 // can't have an id, involve a custom parser, have attached properties etc.
1586 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1588 Q_ASSERT(obj->metatype);
1589 Q_ASSERT(!obj->defaultProperty);
1590 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1593 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1594 if (isSignalPropertyName(prop->name())) {
1595 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1597 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1604 int QQmlCompiler::componentTypeRef()
1606 if (cachedComponentTypeRef == -1) {
1607 QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1608 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1609 if (output->types.at(ii).type == t) {
1610 cachedComponentTypeRef = ii;
1614 QQmlCompiledData::TypeReference ref;
1616 output->types << ref;
1617 cachedComponentTypeRef = output->types.count() - 1;
1619 return cachedComponentTypeRef;
1622 int QQmlCompiler::translationContextIndex()
1624 if (cachedTranslationContextIndex == -1) {
1625 // This code must match that in the qsTr() implementation
1626 const QString &path = output->name;
1627 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1628 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1630 QByteArray contextUtf8 = context.toUtf8();
1631 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1633 return cachedTranslationContextIndex;
1636 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1637 const BindingContext &ctxt)
1639 Q_ASSERT(obj->metaObject());
1641 const QHashedStringRef &propName = prop->name();
1643 Q_ASSERT(propName.startsWith(on_string));
1644 QString name = propName.mid(2, -1).toString();
1646 // Note that the property name could start with any alpha or '_' or '$' character,
1647 // so we need to do the lower-casing of the first alpha character.
1648 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1649 if (name.at(firstAlphaIndex).isUpper()) {
1650 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1655 bool notInRevision = false;
1657 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1661 if (notInRevision && 0 == property(obj, propName, 0)) {
1662 Q_ASSERT(obj->type != -1);
1663 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1664 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1666 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));
1668 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1672 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1674 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1678 if (prop->value || !prop->values.isOne())
1679 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1681 prop->index = sig->coreIndex;
1684 obj->addSignalProperty(prop);
1686 if (prop->values.first()->object) {
1687 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1688 prop->values.first()->type = Value::SignalObject;
1690 prop->values.first()->type = Value::SignalExpression;
1692 if (!prop->values.first()->value.isScript())
1693 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1695 QString script = prop->values.first()->value.asScript().trimmed();
1696 if (script.isEmpty())
1697 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1699 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1708 Returns true if (value) property \a prop exists on obj, false otherwise.
1710 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1711 QQmlScript::Object *obj)
1713 if (prop->name().isEmpty())
1715 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1718 return property(obj, prop->name()) != 0;
1721 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1722 QQmlScript::Object *obj,
1723 const BindingContext &ctxt)
1725 if (prop->isEmpty())
1726 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1728 const QMetaObject *metaObject = obj->metaObject();
1729 Q_ASSERT(metaObject);
1731 if (isAttachedPropertyName(prop->name())) {
1732 // Setup attached property data
1734 if (ctxt.isSubContext()) {
1735 // Attached properties cannot be used on sub-objects. Sub-objects
1736 // always exist in a binding sub-context, which is what we test
1738 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1742 QQmlImportNamespace *typeNamespace = 0;
1743 unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1745 if (typeNamespace) {
1746 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1749 } else if (!type || !type->attachedPropertiesType()) {
1750 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1754 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1756 Q_ASSERT(type->attachedPropertiesFunction());
1757 prop->index = type->attachedPropertiesId();
1758 prop->value->metatype = type->attachedPropertiesType();
1760 // Setup regular property data
1761 bool notInRevision = false;
1762 QQmlPropertyData *d =
1763 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1765 if (d == 0 && notInRevision) {
1766 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1767 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1769 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));
1771 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1774 prop->index = d->coreIndex;
1776 } else if (prop->isDefault) {
1777 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1778 QQmlPropertyData defaultPropertyData;
1779 defaultPropertyData.load(p, engine);
1781 prop->setName(QLatin1String(p.name()));
1782 prop->core = defaultPropertyData;
1783 prop->index = prop->core.coreIndex;
1786 // We can't error here as the "id" property does not require a
1787 // successful index resolution
1788 if (prop->index != -1)
1789 prop->type = prop->core.propType;
1791 // Check if this is an alias
1792 if (prop->index != -1 &&
1794 prop->parent->type != -1 &&
1795 output->types.at(prop->parent->type).component) {
1797 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1798 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1799 prop->isAlias = true;
1802 if (prop->index != -1 && !prop->values.isEmpty())
1803 prop->parent->setBindingBit(prop->index);
1806 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1808 // The magic "id" behavior doesn't apply when "id" is resolved as a
1809 // default property or to sub-objects (which are always in binding
1811 COMPILE_CHECK(buildIdProperty(prop, obj));
1812 if (prop->type == QVariant::String &&
1813 prop->values.first()->value.isString())
1814 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1816 } else if (isAttachedPropertyName(prop->name())) {
1818 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1820 } else if (prop->index == -1) {
1822 if (prop->isDefault) {
1823 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1825 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1828 } else if (prop->value) {
1830 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1832 } else if (prop->core.isQList()) {
1834 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1836 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1838 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1842 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1849 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1850 QQmlScript::Property *nsProp,
1851 QQmlScript::Object *obj,
1852 const BindingContext &ctxt)
1855 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1857 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1859 if (!isAttachedPropertyName(prop->name()))
1860 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1862 // Setup attached property data
1865 unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1867 if (!type || !type->attachedPropertiesType())
1868 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1871 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1873 Q_ASSERT(type->attachedPropertiesFunction());
1874 prop->index = type->index();
1875 prop->value->metatype = type->attachedPropertiesType();
1877 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1883 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1884 QQmlScript::Object *obj)
1886 if (prop->core.isQList()) {
1887 genListProperty(prop, obj);
1889 genPropertyAssignment(prop, obj);
1893 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1894 QQmlScript::Object *obj)
1896 int listType = enginePrivate->listType(prop->type);
1898 Instruction::FetchQList fetch;
1899 fetch.property = prop->index;
1900 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1901 fetch.type = listType;
1902 output->addInstruction(fetch);
1904 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1906 if (v->type == Value::CreatedObject) {
1908 genObject(v->object);
1909 if (listTypeIsInterface) {
1910 Instruction::AssignObjectList assign;
1911 assign.line = prop->location.start.line;
1912 output->addInstruction(assign);
1914 Instruction::StoreObjectQList store;
1915 output->addInstruction(store);
1918 } else if (v->type == Value::PropertyBinding) {
1920 genBindingAssignment(v, prop, obj);
1926 Instruction::PopQList pop;
1927 output->addInstruction(pop);
1930 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1931 QQmlScript::Object *obj,
1932 QQmlScript::Property *valueTypeProperty)
1934 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1936 Q_ASSERT(v->type == Value::CreatedObject ||
1937 v->type == Value::PropertyBinding ||
1938 v->type == Value::Literal);
1940 if (v->type == Value::CreatedObject) {
1942 genObject(v->object);
1944 if (QQmlMetaType::isInterface(prop->type)) {
1946 Instruction::StoreInterface store;
1947 store.line = v->object->location.start.line;
1948 store.propertyIndex = prop->index;
1949 output->addInstruction(store);
1951 } else if (prop->type == QMetaType::QVariant) {
1953 if (prop->core.isVMEProperty()) {
1954 Instruction::StoreVarObject store;
1955 store.line = v->object->location.start.line;
1956 store.propertyIndex = prop->index;
1957 output->addInstruction(store);
1959 Instruction::StoreVariantObject store;
1960 store.line = v->object->location.start.line;
1961 store.propertyIndex = prop->index;
1962 output->addInstruction(store);
1968 Instruction::StoreObject store;
1969 store.line = v->object->location.start.line;
1970 store.propertyIndex = prop->index;
1971 output->addInstruction(store);
1974 } else if (v->type == Value::PropertyBinding) {
1976 genBindingAssignment(v, prop, obj, valueTypeProperty);
1978 } else if (v->type == Value::Literal) {
1980 genLiteralAssignment(prop, v);
1986 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1988 Q_ASSERT(v->type == Value::ValueSource ||
1989 v->type == Value::ValueInterceptor);
1991 if (v->type == Value::ValueSource) {
1992 genObject(v->object);
1994 Instruction::StoreValueSource store;
1995 if (valueTypeProperty) {
1996 store.property = genValueTypeData(prop, valueTypeProperty);
1999 store.property = prop->core;
2002 QQmlType *valueType = toQmlType(v->object);
2003 store.castValue = valueType->propertyValueSourceCast();
2004 output->addInstruction(store);
2006 } else if (v->type == Value::ValueInterceptor) {
2007 genObject(v->object);
2009 Instruction::StoreValueInterceptor store;
2010 if (valueTypeProperty) {
2011 store.property = genValueTypeData(prop, valueTypeProperty);
2014 store.property = prop->core;
2017 QQmlType *valueType = toQmlType(v->object);
2018 store.castValue = valueType->propertyValueInterceptorCast();
2019 output->addInstruction(store);
2025 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2026 QQmlScript::Object *obj)
2029 prop->values.isMany() ||
2030 prop->values.first()->object)
2031 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2033 QQmlScript::Value *idValue = prop->values.first();
2034 QString val = idValue->primitive();
2036 COMPILE_CHECK(checkValidId(idValue, val));
2038 if (compileState->ids.value(val))
2039 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2041 prop->values.first()->type = Value::Id;
2049 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2052 Q_ASSERT(!compileState->ids.value(id));
2053 Q_ASSERT(obj->id == id);
2054 obj->idIndex = compileState->ids.count();
2055 compileState->ids.append(obj);
2058 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2060 Q_ASSERT(ref->value && !ref->value->bindingReference);
2061 ref->value->bindingReference = ref;
2062 compileState->totalBindingsCount++;
2063 compileState->bindings.prepend(ref);
2066 void QQmlCompiler::saveComponentState()
2068 Q_ASSERT(compileState->root);
2069 Q_ASSERT(compileState->root->componentCompileState == 0);
2071 compileState->root->componentCompileState = compileState;
2074 componentStats->savedComponentStats.append(componentStats->componentStat);
2077 QQmlCompilerTypes::ComponentCompileState *
2078 QQmlCompiler::componentState(QQmlScript::Object *obj)
2080 Q_ASSERT(obj->componentCompileState);
2081 return obj->componentCompileState;
2084 // Build attached property object. In this example,
2088 // GridView is an attached property object.
2089 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2090 QQmlScript::Object *obj,
2091 const BindingContext &ctxt)
2093 Q_ASSERT(prop->value);
2094 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2096 compileState->objectDepth.push();
2098 obj->addAttachedProperty(prop);
2100 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2102 compileState->objectDepth.pop();
2108 // Build "grouped" properties. In this example:
2110 // font.pointSize: 12
2111 // font.family: "Helvetica"
2113 // font is a nested property. pointSize and family are not.
2114 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2115 QQmlScript::Object *obj,
2116 const BindingContext &ctxt)
2118 Q_ASSERT(prop->type != 0);
2119 Q_ASSERT(prop->index != -1);
2121 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2122 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2124 if (!prop->values.isEmpty()) {
2125 if (prop->values.first()->location < prop->value->location) {
2126 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2128 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2132 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2133 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2137 if (prop->isAlias) {
2138 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2139 vtProp->isAlias = true;
2143 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2144 prop->value, obj, ctxt.incr()));
2145 obj->addValueTypeProperty(prop);
2147 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2151 // Load the nested property's meta type
2152 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2153 if (!prop->value->metatype)
2154 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2156 if (!prop->values.isEmpty())
2157 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2159 obj->addGroupedProperty(prop);
2161 compileState->objectDepth.push();
2163 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2165 compileState->objectDepth.pop();
2171 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2172 QQmlScript::Object *obj,
2173 QQmlScript::Object *baseObj,
2174 const BindingContext &ctxt)
2176 compileState->objectDepth.push();
2178 if (obj->defaultProperty)
2179 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2180 obj->metatype = type->metaObject();
2182 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2184 QQmlPropertyData *d = property(obj, prop->name());
2186 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2188 prop->index = d->coreIndex;
2189 prop->type = d->propType;
2191 prop->isValueTypeSubProperty = true;
2194 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2196 if (prop->values.isMany()) {
2197 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2198 } else if (!prop->values.isEmpty()) {
2199 QQmlScript::Value *value = prop->values.first();
2201 if (value->object) {
2202 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2203 } else if (value->value.isScript()) {
2204 // ### Check for writability
2206 //optimization for <Type>.<EnumValue> enum assignments
2207 bool isEnumAssignment = false;
2209 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2210 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2212 if (isEnumAssignment) {
2213 value->type = Value::Literal;
2215 JSBindingReference *reference = pool->New<JSBindingReference>();
2216 reference->expression = value->value;
2217 reference->property = prop;
2218 reference->value = value;
2219 reference->bindingContext = ctxt;
2220 reference->bindingContext.owner++;
2221 addBindingReference(reference);
2222 value->type = Value::PropertyBinding;
2225 COMPILE_CHECK(testLiteralAssignment(prop, value));
2226 value->type = Value::Literal;
2230 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2231 Q_ASSERT(v->object);
2233 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2236 obj->addValueProperty(prop);
2239 compileState->objectDepth.pop();
2244 // Build assignments to QML lists. QML lists are properties of type
2245 // QQmlListProperty<T>. List properties can accept a list of
2246 // objects, or a single binding.
2247 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2248 QQmlScript::Object *obj,
2249 const BindingContext &ctxt)
2251 Q_ASSERT(prop->core.isQList());
2253 compileState->listDepth.push();
2257 obj->addValueProperty(prop);
2259 int listType = enginePrivate->listType(t);
2260 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2262 bool assignedBinding = false;
2263 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2265 v->type = Value::CreatedObject;
2266 COMPILE_CHECK(buildObject(v->object, ctxt));
2268 // We check object coercian here. We check interface assignment
2270 if (!listTypeIsInterface) {
2271 if (!canCoerce(listType, v->object)) {
2272 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2276 } else if (v->value.isScript()) {
2277 if (assignedBinding)
2278 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2280 assignedBinding = true;
2281 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2282 v->type = Value::PropertyBinding;
2284 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2288 compileState->listDepth.pop();
2293 // Compiles an assignment to a QQmlScriptString property
2294 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2295 QQmlScript::Object *obj,
2296 const BindingContext &ctxt)
2298 if (prop->values.isMany())
2299 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2301 if (prop->values.first()->object)
2302 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2304 prop->scriptStringScope = ctxt.stack;
2305 obj->addScriptStringProperty(prop);
2310 // Compile regular property assignments of the form "property: <value>"
2311 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2312 QQmlScript::Object *obj,
2313 const BindingContext &ctxt)
2315 obj->addValueProperty(prop);
2317 if (prop->values.isMany())
2318 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2320 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2323 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2327 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2332 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2333 Q_ASSERT(v->object);
2334 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2340 // Compile assigning a single object instance to a regular property
2341 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2342 QQmlScript::Object *obj,
2343 QQmlScript::Value *v,
2344 const BindingContext &ctxt)
2346 Q_ASSERT(prop->index != -1);
2347 Q_ASSERT(v->object->type != -1);
2349 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2350 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2352 if (QQmlMetaType::isInterface(prop->type)) {
2354 // Assigning an object to an interface ptr property
2355 COMPILE_CHECK(buildObject(v->object, ctxt));
2357 v->type = Value::CreatedObject;
2359 } else if (prop->type == QMetaType::QVariant) {
2361 // Assigning an object to a QVariant
2362 COMPILE_CHECK(buildObject(v->object, ctxt));
2364 v->type = Value::CreatedObject;
2366 // Normally buildObject() will set this up, but we need the static
2367 // meta object earlier to test for assignability. It doesn't matter
2368 // that there may still be outstanding synthesized meta object changes
2369 // on this type, as they are not relevant for assignability testing
2370 v->object->metatype = output->types.at(v->object->type).metaObject();
2371 Q_ASSERT(v->object->metaObject());
2373 // We want to raw metaObject here as the raw metaobject is the
2374 // actual property type before we applied any extensions that might
2375 // effect the properties on the type, but don't effect assignability
2376 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2378 // Will be true if the assgned type inherits propertyMetaObject
2379 bool isAssignable = false;
2380 // Determine isAssignable value
2381 if (propertyMetaObject) {
2382 const QMetaObject *c = v->object->metatype;
2384 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2385 c = c->superClass();
2390 // Simple assignment
2391 COMPILE_CHECK(buildObject(v->object, ctxt));
2393 v->type = Value::CreatedObject;
2394 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2395 // Automatic "Component" insertion
2396 QQmlScript::Object *root = v->object;
2397 QQmlScript::Object *component = pool->New<Object>();
2398 component->type = componentTypeRef();
2399 component->metatype = &QQmlComponent::staticMetaObject;
2400 component->location = root->location;
2401 QQmlScript::Value *componentValue = pool->New<Value>();
2402 componentValue->object = root;
2403 component->getDefaultProperty()->addValue(componentValue);
2404 v->object = component;
2405 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2407 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2414 // Compile assigning a single object instance to a regular property using the "on" syntax.
2418 // NumberAnimation on x { }
2420 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2421 QQmlScript::Object *obj,
2422 QQmlScript::Object *baseObj,
2423 QQmlScript::Value *v,
2424 const BindingContext &ctxt)
2426 Q_ASSERT(prop->index != -1);
2427 Q_ASSERT(v->object->type != -1);
2431 if (!prop->core.isWritable())
2432 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2435 // Normally buildObject() will set this up, but we need the static
2436 // meta object earlier to test for assignability. It doesn't matter
2437 // that there may still be outstanding synthesized meta object changes
2438 // on this type, as they are not relevant for assignability testing
2439 v->object->metatype = output->types.at(v->object->type).metaObject();
2440 Q_ASSERT(v->object->metaObject());
2442 // Will be true if the assigned type inherits QQmlPropertyValueSource
2443 bool isPropertyValue = false;
2444 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2445 bool isPropertyInterceptor = false;
2446 if (QQmlType *valueType = toQmlType(v->object)) {
2447 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2448 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2451 if (isPropertyValue || isPropertyInterceptor) {
2452 // Assign as a property value source
2453 COMPILE_CHECK(buildObject(v->object, ctxt));
2455 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2456 buildDynamicMeta(baseObj, ForceCreation);
2457 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2459 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2465 // Compile assigning a literal or binding to a regular property
2466 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2467 QQmlScript::Object *obj,
2468 QQmlScript::Value *v,
2469 const BindingContext &ctxt)
2471 Q_ASSERT(prop->index != -1);
2473 if (v->value.isScript()) {
2475 //optimization for <Type>.<EnumValue> enum assignments
2476 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2477 bool isEnumAssignment = false;
2478 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2479 if (isEnumAssignment) {
2480 v->type = Value::Literal;
2485 // Test for other binding optimizations
2486 if (!buildLiteralBinding(v, prop, ctxt))
2487 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2489 v->type = Value::PropertyBinding;
2493 COMPILE_CHECK(testLiteralAssignment(prop, v));
2495 v->type = Value::Literal;
2501 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2502 QQmlScript::Object *obj,
2503 QQmlScript::Value *v,
2506 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2507 *isAssignment = false;
2508 if (!prop->core.isEnum() && !isIntProp)
2511 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2513 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2514 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2516 QString string = v->value.asString();
2517 if (!string.at(0).isUpper())
2521 // Allow enum assignment to ints.
2522 int enumval = evaluateEnum(string.toUtf8());
2523 if (enumval != -1) {
2524 v->type = Value::Literal;
2525 v->value = QQmlScript::Variant((double)enumval);
2526 *isAssignment = true;
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);
2542 QString enumValue = parts.at(1);
2546 if (toQmlType(obj) == type) {
2547 // When these two match, we can short cut the search
2548 if (mprop.isFlagType()) {
2549 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2551 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2554 // Otherwise we have to search the whole type
2555 // This matches the logic in QV8TypeWrapper
2556 QByteArray enumName = enumValue.toUtf8();
2557 const QMetaObject *metaObject = type->baseMetaObject();
2559 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2560 QMetaEnum e = metaObject->enumerator(ii);
2561 value = e.keyToValue(enumName.constData(), &ok);
2568 v->type = Value::Literal;
2569 v->value = QQmlScript::Variant((double)value);
2570 *isAssignment = true;
2575 struct StaticQtMetaObject : public QObject
2577 static const QMetaObject *get()
2578 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2581 // Similar logic to above, but not knowing target property.
2582 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2584 int dot = script.indexOf('.');
2586 const QByteArray &scope = script.left(dot);
2588 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2589 if (!type && scope != "Qt")
2591 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2592 const char *key = script.constData() + dot+1;
2593 int i = mo->enumeratorCount();
2596 int v = mo->enumerator(i).keyToValue(key, &ok);
2604 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2606 QQmlType *qmltype = 0;
2607 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2611 return qmltype->metaObject();
2614 // similar to logic of completeComponentBuild, but also sticks data
2615 // into primitives at the end
2616 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2618 QQmlRewrite::RewriteBinding rewriteBinding;
2619 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2621 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2623 return output->indexForString(rewrite);
2626 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2628 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2629 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2632 // Ensures that the dynamic meta specification on obj is valid
2633 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2635 bool seenDefaultProperty = false;
2637 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2638 // Calculating the hash for the names is not a waste as we have to test
2639 // them against the illegalNames set anyway.
2640 QHashField propNames;
2641 QHashField methodNames;
2644 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2645 const QQmlScript::Object::DynamicProperty &prop = *p;
2647 if (prop.isDefaultProperty) {
2648 if (seenDefaultProperty)
2649 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2650 seenDefaultProperty = true;
2653 if (propNames.testAndSet(prop.name.hash())) {
2654 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2655 p2 = obj->dynamicProperties.next(p2)) {
2656 if (p2->name == prop.name) {
2657 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2658 prop.nameLocation.column,
2659 tr("Duplicate property name"));
2664 if (prop.name.at(0).isUpper()) {
2665 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2666 prop.nameLocation.column,
2667 tr("Property names cannot begin with an upper case letter"));
2670 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2671 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2672 prop.nameLocation.column,
2673 tr("Illegal property name"));
2677 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2678 const QQmlScript::Object::DynamicSignal &currSig = *s;
2680 if (methodNames.testAndSet(currSig.name.hash())) {
2681 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2682 s2 = obj->dynamicSignals.next(s2)) {
2683 if (s2->name == currSig.name)
2684 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2688 if (currSig.name.at(0).isUpper())
2689 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2690 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2691 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2694 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2695 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2697 if (methodNames.testAndSet(currSlot.name.hash())) {
2698 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2699 s2 = obj->dynamicSignals.next(s2)) {
2700 if (s2->name == currSlot.name)
2701 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2703 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2704 s2 = obj->dynamicSlots.next(s2)) {
2705 if (s2->name == currSlot.name)
2706 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2710 if (currSlot.name.at(0).isUpper())
2711 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2712 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2713 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2719 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2721 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2722 p = obj->dynamicProperties.next(p)) {
2724 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2727 Property *property = 0;
2728 if (p->isDefaultProperty) {
2729 property = obj->getDefaultProperty();
2731 property = obj->getProperty(p->name);
2732 if (!property->values.isEmpty())
2733 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2737 property->isReadOnlyDeclaration = true;
2739 if (property->value)
2740 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2742 property->values.append(p->defaultValue->values);
2747 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2749 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2752 Q_ASSERT(obj->metatype);
2754 if (mode != ForceCreation &&
2755 obj->dynamicProperties.isEmpty() &&
2756 obj->dynamicSignals.isEmpty() &&
2757 obj->dynamicSlots.isEmpty())
2760 bool resolveAlias = (mode == ResolveAliases);
2762 const Object::DynamicProperty *defaultProperty = 0;
2764 int varPropCount = 0;
2765 int totalPropCount = 0;
2766 int firstPropertyVarIndex = 0;
2768 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2770 if (p->type == Object::DynamicProperty::Alias)
2772 if (p->type == Object::DynamicProperty::Var)
2775 if (p->isDefaultProperty &&
2776 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2777 defaultProperty = p;
2779 if (!resolveAlias) {
2780 // No point doing this for both the alias and non alias cases
2781 QQmlPropertyData *d = property(obj, p->name);
2782 if (d && d->isFinal())
2783 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2787 bool buildData = resolveAlias || aliasCount == 0;
2789 QByteArray dynamicData;
2791 typedef QQmlVMEMetaData VMD;
2793 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2794 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2795 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2796 aliasCount * sizeof(VMD::AliasData), 0);
2799 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2801 QByteArray newClassName = obj->metatype->className();
2802 newClassName.append("_QML_");
2803 newClassName.append(QByteArray::number(uniqueClassId));
2805 if (compileState->root == obj && !compileState->nested) {
2806 QString path = output->url.path();
2807 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2808 if (lastSlash > -1) {
2809 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2810 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2811 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2815 // Size of the array that describes parameter types & names
2816 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2817 + obj->dynamicProperties.count() // for Changed() signals return types
2818 // Return "parameters" don't have names
2819 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2821 QFastMetaBuilder builder;
2823 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2824 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2825 obj->dynamicSlots.count(),
2826 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2827 defaultProperty?1:0, paramDataSize, ¶mIndex);
2830 Object::DynamicProperty::Type dtype;
2832 } builtinTypes[] = {
2833 { Object::DynamicProperty::Var, QMetaType::QVariant },
2834 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2835 { Object::DynamicProperty::Int, QMetaType::Int },
2836 { Object::DynamicProperty::Bool, QMetaType::Bool },
2837 { Object::DynamicProperty::Real, QMetaType::Double },
2838 { Object::DynamicProperty::String, QMetaType::QString },
2839 { Object::DynamicProperty::Url, QMetaType::QUrl },
2840 { Object::DynamicProperty::Color, QMetaType::QColor },
2841 { Object::DynamicProperty::Time, QMetaType::QTime },
2842 { Object::DynamicProperty::Date, QMetaType::QDate },
2843 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2844 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2846 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2848 // Reserve dynamic properties
2849 if (obj->dynamicProperties.count()) {
2850 typedef QQmlVMEMetaData VMD;
2852 int effectivePropertyIndex = 0;
2853 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2855 // Reserve space for name
2856 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2857 p->nameRef = builder.newString(p->name.utf8length());
2860 int propertyType = 0; // for VMD
2861 bool readonly = false;
2863 if (p->type == Object::DynamicProperty::Alias) {
2865 } else if (p->type < builtinTypeCount) {
2866 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2867 metaType = builtinTypes[p->type].metaType;
2868 propertyType = metaType;
2871 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2872 p->type == Object::DynamicProperty::Custom);
2874 // XXX don't double resolve this in the case of an alias run
2876 QByteArray customTypeName;
2877 QQmlType *qmltype = 0;
2879 if (!unit->imports().resolveType(p->customType, &qmltype, &url, 0, 0, 0))
2880 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2883 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
2885 Q_ASSERT(tdata->isComplete());
2886 customTypeName = tdata->compiledData()->root->className();
2889 customTypeName = qmltype->typeName();
2892 if (p->type == Object::DynamicProperty::Custom) {
2893 customTypeName += '*';
2894 propertyType = QMetaType::QObjectStar;
2897 customTypeName = QByteArrayLiteral("QQmlListProperty<") + customTypeName + '>';
2898 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2901 metaType = QMetaType::type(customTypeName);
2902 Q_ASSERT(metaType != QMetaType::UnknownType);
2903 Q_ASSERT(metaType != QMetaType::Void);
2906 if (p->type == Object::DynamicProperty::Var)
2913 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2914 vmd->propertyCount++;
2915 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2918 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2919 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2920 effectivePropertyIndex);
2922 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2923 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2926 effectivePropertyIndex++;
2930 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2932 vmd->varPropertyCount = varPropCount;
2933 firstPropertyVarIndex = effectivePropertyIndex;
2934 totalPropCount = varPropCount + effectivePropertyIndex;
2935 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2936 if (p->type == Object::DynamicProperty::Var) {
2938 vmd->propertyCount++;
2939 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2942 builder.setProperty(effectivePropertyIndex, p->nameRef,
2943 QMetaType::QVariant,
2944 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2945 effectivePropertyIndex);
2947 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2948 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2951 effectivePropertyIndex++;
2958 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2959 if (p->type == Object::DynamicProperty::Alias) {
2961 Q_ASSERT(buildData);
2962 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2963 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2966 // Even if we aren't resolving the alias, we need a fake signal so that the
2967 // metaobject remains consistent across the resolve and non-resolve alias runs
2968 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2969 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2971 effectivePropertyIndex++;
2978 // Reserve default property
2979 QFastMetaBuilder::StringRef defPropRef;
2980 if (defaultProperty) {
2981 defPropRef = builder.newString(int(sizeof("DefaultProperty")) - 1);
2982 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2985 // Reserve dynamic signals
2986 int signalIndex = 0;
2987 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2989 s->nameRef = builder.newString(s->name.utf8length());
2991 int paramCount = s->parameterNames.count();
2992 QVarLengthArray<int, 10> paramTypes(paramCount);
2994 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
2995 for (int i = 0; i < paramCount; ++i) {
2996 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
2997 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2998 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3003 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3005 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3006 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3007 paramIndex += paramCount*2 + 1;
3011 // Reserve dynamic slots
3012 if (obj->dynamicSlots.count()) {
3014 typedef QQmlVMEMetaData VMD;
3016 int methodIndex = 0;
3017 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3018 s->nameRef = builder.newString(s->name.utf8length());
3019 int paramCount = s->parameterNames.count();
3021 QVarLengthArray<int, 10> paramTypes(paramCount);
3023 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3024 for (int i = 0; i < paramCount; ++i) {
3025 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3026 paramTypes[i] = QMetaType::QVariant;
3030 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3031 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3032 paramIndex += paramCount*2 + 1;
3037 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3038 funcScript.reserve(int(sizeof("(function ")) - 1 + s->name.length() + 1 /* lparen */ +
3039 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3040 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3041 for (int jj = 0; jj < paramCount; ++jj) {
3042 if (jj) funcScript.append(QLatin1Char(','));
3043 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3045 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3047 QByteArray utf8 = funcScript.toUtf8();
3048 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3050 s->location.start.line };
3052 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3055 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3057 md.bodyOffset = dynamicData.size();
3059 dynamicData.append((const char *)utf8.constData(), utf8.length());
3067 // Now allocate properties
3068 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3070 char *d = p->changedNameRef.data();
3071 p->name.writeUtf8(d);
3072 strcpy(d + p->name.utf8length(), "Changed");
3073 p->changedNameRef.loadByteArrayData();
3075 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3078 p->nameRef.load(p->name);
3081 // Allocate default property if necessary
3082 if (defaultProperty)
3083 defPropRef.load("DefaultProperty");
3085 // Now allocate signals
3086 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3088 s->nameRef.load(s->name);
3090 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3091 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3094 // Now allocate methods
3095 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3096 s->nameRef.load(s->name);
3098 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3099 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3102 // Now allocate class name
3103 classNameRef.load(newClassName);
3105 obj->metadata = builder.toData();
3106 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3108 if (mode == IgnoreAliases && aliasCount)
3109 compileState->aliasingObjects.append(obj);
3111 obj->synthdata = dynamicData;
3113 if (obj->synthCache) {
3114 obj->synthCache->release();
3115 obj->synthCache = 0;
3118 if (obj->type != -1) {
3119 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3120 QQmlPropertyCache *cache =
3121 superCache->copyAndAppend(engine, &obj->extObject,
3122 QQmlPropertyData::NoFlags,
3123 QQmlPropertyData::IsVMEFunction,
3124 QQmlPropertyData::IsVMESignal);
3126 // now we modify the flags appropriately for var properties.
3127 int propertyOffset = obj->extObject.propertyOffset();
3128 QQmlPropertyData *currPropData = 0;
3129 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3130 currPropData = cache->property(pvi + propertyOffset);
3131 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3134 obj->synthCache = cache;
3140 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3143 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3145 QChar ch = val.at(0);
3146 if (ch.isLetter() && !ch.isLower())
3147 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3149 QChar u(QLatin1Char('_'));
3150 if (!ch.isLetter() && ch != u)
3151 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3153 for (int ii = 1; ii < val.count(); ++ii) {
3155 if (!ch.isLetterOrNumber() && ch != u)
3156 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3159 if (enginePrivate->v8engine()->illegalNames().contains(val))
3160 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3165 #include <private/qqmljsparser_p.h>
3167 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3169 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3171 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3172 return QStringList() << name;
3173 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3174 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3176 QStringList rv = astNodeToStringList(expr->base);
3179 rv.append(expr->name.toString());
3182 return QStringList();
3185 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3187 QQmlScript::Object *obj,
3188 int propIndex, int aliasIndex,
3189 Object::DynamicProperty &prop)
3191 Q_ASSERT(!prop.nameRef.isEmpty());
3192 if (!prop.defaultValue)
3193 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3195 if (!prop.defaultValue->values.isOne() ||
3196 prop.defaultValue->values.first()->object ||
3197 !prop.defaultValue->values.first()->value.isScript())
3198 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3200 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3202 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3204 QStringList alias = astNodeToStringList(node);
3206 if (alias.count() < 1 || alias.count() > 3)
3207 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3209 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3211 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3213 QByteArray typeName;
3218 bool writable = false;
3219 bool resettable = false;
3220 if (alias.count() == 2 || alias.count() == 3) {
3221 propIdx = indexOfProperty(idObject, alias.at(1));
3223 if (-1 == propIdx) {
3224 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3225 } else if (propIdx > 0xFFFF) {
3226 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3229 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3230 if (!aliasProperty.isScriptable())
3231 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3233 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3234 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3236 type = aliasProperty.userType();
3238 if (alias.count() == 3) {
3239 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3241 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3243 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3245 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3246 if (valueTypeIndex == -1)
3247 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3248 Q_ASSERT(valueTypeIndex <= 0xFF);
3250 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3251 propIdx |= (valueTypeIndex << 16);
3253 // update the property type
3254 type = aliasProperty.userType();
3257 if (aliasProperty.isEnumType())
3258 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3260 typeName = aliasProperty.typeName();
3262 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3264 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3266 typeName = ref.type->typeName();
3268 typeName = ref.component->root->className();
3273 if (typeName.endsWith('*'))
3274 flags |= QML_ALIAS_FLAG_PTR;
3276 if (type == QMetaType::UnknownType) {
3277 Q_ASSERT(!typeName.isEmpty());
3278 type = QMetaType::type(typeName);
3279 Q_ASSERT(type != QMetaType::UnknownType);
3280 Q_ASSERT(type != QMetaType::Void);
3283 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3285 typedef QQmlVMEMetaData VMD;
3286 VMD *vmd = (QQmlVMEMetaData *)data.data();
3287 *(vmd->aliasData() + aliasIndex) = aliasData;
3289 int propertyFlags = 0;
3291 propertyFlags |= QFastMetaBuilder::Writable;
3293 propertyFlags |= QFastMetaBuilder::Resettable;
3295 builder.setProperty(propIndex, prop.nameRef, type,
3296 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3302 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3303 QQmlScript::Property *prop,
3304 const BindingContext &ctxt)
3306 Q_ASSERT(prop->index != -1);
3307 Q_ASSERT(prop->parent);
3308 Q_ASSERT(prop->parent->metaObject());
3310 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3311 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3313 JSBindingReference *reference = pool->New<JSBindingReference>();
3314 reference->expression = value->value;
3315 reference->property = prop;
3316 reference->value = value;
3317 reference->bindingContext = ctxt;
3318 addBindingReference(reference);
3323 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3324 QQmlScript::Property *prop,
3325 const QQmlCompilerTypes::BindingContext &)
3327 Q_ASSERT(v->value.isScript());
3329 if (!prop->core.isWritable())
3332 AST::Node *binding = v->value.asAST();
3334 if (prop->type == QVariant::String) {
3335 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3336 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3337 if (i->name == qsTrId_string) {
3338 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3339 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3341 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3342 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3343 (!arg2 || !arg2->next)) {
3348 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3349 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3351 TrBindingReference *reference = pool->New<TrBindingReference>();
3352 reference->dataType = BindingReference::TrId;
3353 reference->text = text;
3355 v->bindingReference = reference;
3359 } else if (i->name == qsTr_string) {
3361 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3362 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3363 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3365 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3366 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3367 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3368 (!arg3 || !arg3->next)) {
3374 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3375 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3376 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3378 TrBindingReference *reference = pool->New<TrBindingReference>();
3379 reference->dataType = BindingReference::Tr;
3380 reference->text = text;
3381 reference->comment = comment;
3383 v->bindingReference = reference;
3396 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3397 QQmlScript::Property *prop,
3398 QQmlScript::Object *obj,
3399 QQmlScript::Property *valueTypeProperty)
3402 Q_ASSERT(binding->bindingReference);
3404 const BindingReference &ref = *binding->bindingReference;
3405 if (ref.dataType == BindingReference::TrId) {
3406 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3408 Instruction::StoreTrIdString store;
3409 store.propertyIndex = prop->core.coreIndex;
3410 store.text = output->indexForByteArray(tr.text.toUtf8());
3412 output->addInstruction(store);
3413 } else if (ref.dataType == BindingReference::Tr) {
3414 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3416 Instruction::StoreTrString store;
3417 store.propertyIndex = prop->core.coreIndex;
3418 store.context = translationContextIndex();
3419 store.text = output->indexForByteArray(tr.text.toUtf8());
3420 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3422 output->addInstruction(store);
3423 } else if (ref.dataType == BindingReference::V4) {
3424 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3426 Instruction::StoreV4Binding store;
3427 store.value = js.compiledIndex;
3428 store.context = js.bindingContext.stack;
3429 store.owner = js.bindingContext.owner;
3430 store.isAlias = prop->isAlias;
3431 if (valueTypeProperty) {
3432 store.property = (valueTypeProperty->index & 0xFFFF) |
3433 ((valueTypeProperty->type & 0xFF)) << 16 |
3434 ((prop->index & 0xFF) << 24);
3435 store.isRoot = (compileState->root == valueTypeProperty->parent);
3437 store.property = prop->index;
3438 store.isRoot = (compileState->root == obj);
3440 store.line = binding->location.start.line;
3441 store.column = binding->location.start.column;
3442 output->addInstruction(store);
3443 } else if (ref.dataType == BindingReference::V8) {
3444 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3446 Instruction::StoreV8Binding store;
3447 store.value = js.compiledIndex;
3448 store.context = js.bindingContext.stack;
3449 store.owner = js.bindingContext.owner;
3450 store.isAlias = prop->isAlias;
3451 if (valueTypeProperty) {
3452 store.isRoot = (compileState->root == valueTypeProperty->parent);
3454 store.isRoot = (compileState->root == obj);
3456 store.line = binding->location.start.line;
3457 store.column = binding->location.start.column;
3459 Q_ASSERT(js.bindingContext.owner == 0 ||
3460 (js.bindingContext.owner != 0 && valueTypeProperty));
3461 if (js.bindingContext.owner) {
3462 store.property = genValueTypeData(prop, valueTypeProperty);
3464 store.property = prop->core;
3467 output->addInstruction(store);
3468 } else if (ref.dataType == BindingReference::QtScript) {
3469 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3471 Instruction::StoreBinding store;
3472 store.value = output->indexForString(js.rewrittenExpression);
3473 store.context = js.bindingContext.stack;
3474 store.owner = js.bindingContext.owner;
3475 store.line = binding->location.start.line;
3476 store.column = binding->location.start.column;
3477 store.isAlias = prop->isAlias;
3479 if (valueTypeProperty) {
3480 store.isRoot = (compileState->root == valueTypeProperty->parent);
3482 store.isRoot = (compileState->root == obj);
3485 Q_ASSERT(js.bindingContext.owner == 0 ||
3486 (js.bindingContext.owner != 0 && valueTypeProperty));
3487 if (js.bindingContext.owner) {
3488 store.property = genValueTypeData(prop, valueTypeProperty);
3490 store.property = prop->core;
3493 output->addInstruction(store);
3495 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3499 int QQmlCompiler::genContextCache()
3501 if (compileState->ids.count() == 0)
3504 QQmlIntegerCache *cache = new QQmlIntegerCache();
3505 cache->reserve(compileState->ids.count());
3506 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3507 cache->add(o->id, o->idIndex);
3509 output->contextCaches.append(cache);
3510 return output->contextCaches.count() - 1;
3514 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3515 QQmlScript::Property *prop)
3517 typedef QQmlPropertyPrivate QDPP;
3518 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3519 enginePrivate->valueTypes[prop->type]->metaObject(),
3520 valueTypeProp->index, engine);
3523 bool QQmlCompiler::completeComponentBuild()
3526 componentStats->componentStat.ids = compileState->ids.count();
3528 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3529 aliasObject = compileState->aliasingObjects.next(aliasObject))
3530 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3532 QV4Compiler::Expression expr(unit->imports());
3533 expr.component = compileState->root;
3534 expr.ids = &compileState->ids;
3535 expr.importCache = output->importCache;
3537 QV4Compiler bindingCompiler;
3539 QList<JSBindingReference*> sharedBindings;
3541 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3543 JSBindingReference &binding = *b;
3546 expr.context = binding.bindingContext.object;
3547 expr.property = binding.property;
3548 expr.expression = binding.expression;
3550 int index = bindingCompiler.compile(expr, enginePrivate);
3552 binding.dataType = BindingReference::V4;
3553 binding.compiledIndex = index;
3555 componentStats->componentStat.optimizedBindings.append(b->value->location);
3559 // Pre-rewrite the expression
3560 QString expression = binding.expression.asScript();
3562 QQmlRewrite::RewriteBinding rewriteBinding;
3563 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3564 bool isSharable = false;
3565 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3567 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3568 binding.dataType = BindingReference::V8;
3569 sharedBindings.append(b);
3572 componentStats->componentStat.sharedBindings.append(b->value->location);
3574 binding.dataType = BindingReference::QtScript;
3577 componentStats->componentStat.scriptBindings.append(b->value->location);
3581 if (!sharedBindings.isEmpty()) {
3583 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3585 return lhs->value->location.start.line < rhs->value->location.start.line;
3589 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3591 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3592 int lineNumber = startLineNumber;
3594 QByteArray functionArray("[", 1);
3595 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3597 JSBindingReference *reference = sharedBindings.at(ii);
3598 QQmlScript::Value *value = reference->value;
3599 const QString &expression = reference->rewrittenExpression;
3601 if (ii != 0) functionArray.append(",", 1);
3603 while (lineNumber < value->location.start.line) {
3605 functionArray.append("\n", 1);
3608 functionArray += expression.toUtf8();
3609 lineNumber += expression.count(QLatin1Char('\n'));
3610 reference->compiledIndex = ii;
3612 functionArray.append("]", 1);
3614 compileState->v8BindingProgram = functionArray;
3615 compileState->v8BindingProgramLine = startLineNumber;
3618 if (bindingCompiler.isValid())
3619 compileState->compiledBindingData = bindingCompiler.program();
3621 // Check pop()'s matched push()'s
3622 Q_ASSERT(compileState->objectDepth.depth() == 0);
3623 Q_ASSERT(compileState->listDepth.depth() == 0);
3625 saveComponentState();
3630 void QQmlCompiler::dumpStats()
3632 Q_ASSERT(componentStats);
3633 qWarning().nospace() << "QML Document: " << output->url.toString();
3634 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3635 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3636 qWarning().nospace() << " Component Line " << stat.lineNumber;
3637 qWarning().nospace() << " Total Objects: " << stat.objects;
3638 qWarning().nospace() << " IDs Used: " << stat.ids;
3639 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3643 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3644 if (0 == (ii % 10)) {
3645 if (ii) output.append("\n");
3650 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3652 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3653 output.append(") ");
3655 if (!output.isEmpty())
3656 qWarning().nospace() << output.constData();
3659 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3662 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3663 if (0 == (ii % 10)) {
3664 if (ii) output.append('\n');
3669 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3671 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3672 output.append(") ");
3674 if (!output.isEmpty())
3675 qWarning().nospace() << output.constData();
3678 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3681 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3682 if (0 == (ii % 10)) {
3683 if (ii) output.append('\n');
3688 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3690 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3691 output.append(") ");
3693 if (!output.isEmpty())
3694 qWarning().nospace() << output.constData();
3700 Returns true if from can be assigned to a (QObject) property of type
3703 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3705 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3706 const QMetaObject *fromMo = from->metaObject();
3709 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3711 fromMo = fromMo->superClass();
3717 Returns the element name, as written in the QML file, for o.
3719 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3722 if (o->type != -1) {
3723 return unit->parser().referencedTypes().at(o->type)->name;
3729 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3731 if (from->type != -1 && output->types.at(from->type).type)
3732 return output->types.at(from->type).type;
3735 const QMetaObject *mo = from->metatype;
3737 while (!type && mo) {
3738 type = QQmlMetaType::qmlType(mo);
3739 mo = mo->superClass();
3744 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3746 const QMetaObject *mo = obj->metatype;
3748 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3750 return QStringList();
3752 QMetaClassInfo classInfo = mo->classInfo(idx);
3753 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3758 QQmlCompiler::property(QQmlScript::Object *object, int index)
3760 QQmlPropertyCache *cache = 0;
3762 if (object->synthCache)
3763 cache = object->synthCache;
3764 else if (object->type != -1)
3765 cache = output->types[object->type].createPropertyCache(engine);
3767 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3769 return cache->property(index);
3773 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3775 if (notInRevision) *notInRevision = false;
3777 QQmlPropertyCache *cache = 0;
3779 if (object->synthCache)
3780 cache = object->synthCache;
3781 else if (object->type != -1)
3782 cache = output->types[object->type].createPropertyCache(engine);
3784 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3786 QQmlPropertyData *d = cache->property(name);
3788 // Find the first property
3789 while (d && d->isFunction())
3790 d = cache->overrideData(d);
3792 if (d && !cache->isAllowedInRevision(d)) {
3793 if (notInRevision) *notInRevision = true;
3800 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3802 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3804 if (notInRevision) *notInRevision = false;
3806 QQmlPropertyCache *cache = 0;
3808 if (object->synthCache)
3809 cache = object->synthCache;
3810 else if (object->type != -1)
3811 cache = output->types[object->type].createPropertyCache(engine);
3813 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3816 QQmlPropertyData *d = cache->property(name);
3817 if (notInRevision) *notInRevision = false;
3819 while (d && !(d->isFunction()))
3820 d = cache->overrideData(d);
3822 if (d && !cache->isAllowedInRevision(d)) {
3823 if (notInRevision) *notInRevision = true;
3829 if (name.endsWith(Changed_string)) {
3830 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3832 d = property(object, propName, notInRevision);
3834 return cache->method(d->notifyIndex);
3840 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3841 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3842 bool *notInRevision)
3844 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3845 return d?d->coreIndex:-1;
3848 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3849 bool *notInRevision)
3851 return indexOfProperty(object, QStringRef(&name), notInRevision);
3854 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3855 bool *notInRevision)
3857 QQmlPropertyData *d = property(object, name, notInRevision);
3858 return d?d->coreIndex:-1;