1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcompiler_p.h"
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include "qqmlstringconverters_p.h"
48 #include "qqmlengine_p.h"
49 #include "qqmlengine.h"
50 #include "qqmlcontext.h"
51 #include "qqmlmetatype_p.h"
52 #include "qqmlcustomparser_p_p.h"
53 #include "qqmlcontext_p.h"
54 #include "qqmlcomponent_p.h"
55 #include <private/qqmljsast_p.h>
56 #include "qqmlvmemetaobject_p.h"
57 #include "qqmlexpression_p.h"
58 #include "qqmlproperty_p.h"
59 #include "qqmlrewrite_p.h"
60 #include "qqmlscriptstring.h"
61 #include "qqmlglobal_p.h"
62 #include "qqmlbinding_p.h"
63 #include <private/qv4compiler_p.h>
70 #include <QtCore/qdebug.h>
71 #include <QtCore/qdatetime.h>
72 #include <QtCore/qvarlengtharray.h>
74 Q_DECLARE_METATYPE(QList<int>)
75 Q_DECLARE_METATYPE(QList<qreal>)
76 Q_DECLARE_METATYPE(QList<bool>)
77 Q_DECLARE_METATYPE(QList<QString>)
78 Q_DECLARE_METATYPE(QList<QUrl>)
79 Q_DECLARE_METATYPE(QJSValue)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QQmlJS;
87 using namespace QQmlScript;
88 using namespace QQmlCompilerTypes;
90 static QString id_string(QLatin1String("id"));
91 static QString on_string(QLatin1String("on"));
92 static QString Changed_string(QLatin1String("Changed"));
93 static QString Component_string(QLatin1String("Component"));
94 static QString Component_module_string(QLatin1String("QML"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QQmlCompiler.
101 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
102 : compileState(0), pool(pool), output(0), engine(0), enginePrivate(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QQmlCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QQmlError> QQmlCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QQmlCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
191 error.setUrl(output->url); \
192 error.setLine(line); \
193 error.setColumn(column); \
194 error.setDescription(desc.trimmed()); \
195 exceptions << error; \
199 #define COMPILE_EXCEPTION(token, desc) \
200 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
205 Returns false if \a is false, otherwise does nothing.
207 #define COMPILE_CHECK(a) \
209 if (!a) return false; \
213 Returns true if literal \a v can be assigned to property \a prop, otherwise
216 This test corresponds to action taken by genLiteralAssignment(). Any change
217 made here, must have a corresponding action in genLiteralAssigment().
219 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, QQmlScript::Value *v)
221 const QQmlScript::Variant &value = v->value;
223 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
224 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
226 if (prop->core.isEnum()) {
227 QMetaProperty p = prop->parent->metatype->firstCppMetaObject()->property(prop->index);
230 if (p.isFlagType()) {
231 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
233 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
236 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
238 v->value = QQmlScript::Variant((double)enumValue);
242 int type = prop->type;
245 case QMetaType::QVariant:
247 case QVariant::String:
248 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
250 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
251 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
253 case QVariant::ByteArray:
254 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
257 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
259 case QVariant::RegExp:
260 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
264 bool ok = v->value.isNumber();
266 double n = v->value.asNumber();
267 if (double(uint(n)) != n)
270 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
275 bool ok = v->value.isNumber();
277 double n = v->value.asNumber();
278 if (double(int(n)) != n)
281 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
284 case QMetaType::Float:
285 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
287 case QVariant::Double:
288 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
290 case QVariant::Color:
293 QQmlStringConverters::colorFromString(value.asString(), &ok);
294 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
297 #ifndef QT_NO_DATESTRING
301 QQmlStringConverters::dateFromString(value.asString(), &ok);
302 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
308 QQmlStringConverters::timeFromString(value.asString(), &ok);
309 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
312 case QVariant::DateTime:
315 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
316 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
319 #endif // QT_NO_DATESTRING
320 case QVariant::Point:
321 case QVariant::PointF:
324 QQmlStringConverters::pointFFromString(value.asString(), &ok);
325 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
329 case QVariant::SizeF:
332 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
333 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
337 case QVariant::RectF:
340 QQmlStringConverters::rectFFromString(value.asString(), &ok);
341 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
346 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
349 case QVariant::Vector3D:
351 QQmlInstruction::instr_storeVector3D::QVector3D v3;
352 if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3)))
353 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
356 case QVariant::Vector4D:
358 QQmlInstruction::instr_storeVector4D::QVector4D v4;
359 if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4)))
360 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
365 // check if assigning a literal value to a list property.
366 // in each case, check the singular, since an Array of the specified type
367 // will not go via this literal assignment codepath.
368 if (type == qMetaTypeId<QList<qreal> >()) {
369 if (!v->value.isNumber()) {
370 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
373 } else if (type == qMetaTypeId<QList<int> >()) {
374 bool ok = v->value.isNumber();
376 double n = v->value.asNumber();
377 if (double(int(n)) != n)
380 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
382 } else if (type == qMetaTypeId<QList<bool> >()) {
383 if (!v->value.isBoolean()) {
384 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
387 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
388 if (!v->value.isString()) {
389 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
392 } else if (type == qMetaTypeId<QList<QUrl> >()) {
393 if (!v->value.isString()) {
394 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
397 } else if (type == qMetaTypeId<QJSValue>()) {
401 // otherwise, check for existence of string converter to custom type
402 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
404 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(type))));
412 Generate a store instruction for assigning literal \a v to property \a prop.
414 Any literal assignment that is approved in testLiteralAssignment() must have
415 a corresponding action in this method.
417 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
418 QQmlScript::Value *v)
420 if (prop->core.isEnum()) {
421 Q_ASSERT(v->value.isNumber());
423 int value = (int)v->value.asNumber();
425 Instruction::StoreInteger instr;
426 instr.propertyIndex = prop->index;
428 output->addInstruction(instr);
432 int type = prop->type;
434 case QMetaType::QVariant:
436 if (v->value.isNumber()) {
437 double n = v->value.asNumber();
438 if (double(int(n)) == n) {
439 if (prop->core.isVarProperty()) {
440 Instruction::StoreVarInteger instr;
441 instr.propertyIndex = prop->index;
442 instr.value = int(n);
443 output->addInstruction(instr);
445 Instruction::StoreVariantInteger instr;
446 instr.propertyIndex = prop->index;
447 instr.value = int(n);
448 output->addInstruction(instr);
451 if (prop->core.isVarProperty()) {
452 Instruction::StoreVarDouble instr;
453 instr.propertyIndex = prop->index;
455 output->addInstruction(instr);
457 Instruction::StoreVariantDouble instr;
458 instr.propertyIndex = prop->index;
460 output->addInstruction(instr);
463 } else if (v->value.isBoolean()) {
464 if (prop->core.isVarProperty()) {
465 Instruction::StoreVarBool instr;
466 instr.propertyIndex = prop->index;
467 instr.value = v->value.asBoolean();
468 output->addInstruction(instr);
470 Instruction::StoreVariantBool instr;
471 instr.propertyIndex = prop->index;
472 instr.value = v->value.asBoolean();
473 output->addInstruction(instr);
476 if (prop->core.isVarProperty()) {
477 Instruction::StoreVar instr;
478 instr.propertyIndex = prop->index;
479 instr.value = output->indexForString(v->value.asString());
480 output->addInstruction(instr);
482 Instruction::StoreVariant instr;
483 instr.propertyIndex = prop->index;
484 instr.value = output->indexForString(v->value.asString());
485 output->addInstruction(instr);
490 case QVariant::String:
492 Instruction::StoreString instr;
493 instr.propertyIndex = prop->index;
494 instr.value = output->indexForString(v->value.asString());
495 output->addInstruction(instr);
498 case QVariant::StringList:
500 Instruction::StoreStringList instr;
501 instr.propertyIndex = prop->index;
502 instr.value = output->indexForString(v->value.asString());
503 output->addInstruction(instr);
506 case QVariant::ByteArray:
508 Instruction::StoreByteArray instr;
509 instr.propertyIndex = prop->index;
510 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
511 output->addInstruction(instr);
516 Instruction::StoreUrl instr;
517 QString string = v->value.asString();
518 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
519 instr.propertyIndex = prop->index;
520 instr.value = output->indexForUrl(u);
521 output->addInstruction(instr);
526 Instruction::StoreInteger instr;
527 instr.propertyIndex = prop->index;
528 instr.value = uint(v->value.asNumber());
529 output->addInstruction(instr);
534 Instruction::StoreInteger instr;
535 instr.propertyIndex = prop->index;
536 instr.value = int(v->value.asNumber());
537 output->addInstruction(instr);
540 case QMetaType::Float:
542 Instruction::StoreFloat instr;
543 instr.propertyIndex = prop->index;
544 instr.value = float(v->value.asNumber());
545 output->addInstruction(instr);
548 case QVariant::Double:
550 Instruction::StoreDouble instr;
551 instr.propertyIndex = prop->index;
552 instr.value = v->value.asNumber();
553 output->addInstruction(instr);
556 case QVariant::Color:
558 Instruction::StoreColor instr;
559 instr.propertyIndex = prop->index;
560 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
561 output->addInstruction(instr);
564 #ifndef QT_NO_DATESTRING
567 Instruction::StoreDate instr;
568 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
569 instr.propertyIndex = prop->index;
570 instr.value = d.toJulianDay();
571 output->addInstruction(instr);
576 Instruction::StoreTime instr;
577 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
578 instr.propertyIndex = prop->index;
579 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
580 ::memcpy(&instr.time, &time, sizeof(QTime));
581 output->addInstruction(instr);
584 case QVariant::DateTime:
586 Instruction::StoreDateTime instr;
587 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
588 QTime time = dateTime.time();
589 instr.propertyIndex = prop->index;
590 instr.date = dateTime.date().toJulianDay();
591 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
592 ::memcpy(&instr.time, &time, sizeof(QTime));
593 output->addInstruction(instr);
596 #endif // QT_NO_DATESTRING
597 case QVariant::Point:
599 Instruction::StorePoint instr;
601 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
602 instr.propertyIndex = prop->index;
603 instr.point.xp = point.x();
604 instr.point.yp = point.y();
605 output->addInstruction(instr);
608 case QVariant::PointF:
610 Instruction::StorePointF instr;
612 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
613 instr.propertyIndex = prop->index;
614 instr.point.xp = point.x();
615 instr.point.yp = point.y();
616 output->addInstruction(instr);
621 Instruction::StoreSize instr;
623 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
624 instr.propertyIndex = prop->index;
625 instr.size.wd = size.width();
626 instr.size.ht = size.height();
627 output->addInstruction(instr);
630 case QVariant::SizeF:
632 Instruction::StoreSizeF instr;
634 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
635 instr.propertyIndex = prop->index;
636 instr.size.wd = size.width();
637 instr.size.ht = size.height();
638 output->addInstruction(instr);
643 Instruction::StoreRect instr;
645 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
646 instr.propertyIndex = prop->index;
647 instr.rect.x1 = rect.left();
648 instr.rect.y1 = rect.top();
649 instr.rect.x2 = rect.right();
650 instr.rect.y2 = rect.bottom();
651 output->addInstruction(instr);
654 case QVariant::RectF:
656 Instruction::StoreRectF instr;
658 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
659 instr.propertyIndex = prop->index;
660 instr.rect.xp = rect.left();
661 instr.rect.yp = rect.top();
662 instr.rect.w = rect.width();
663 instr.rect.h = rect.height();
664 output->addInstruction(instr);
669 Instruction::StoreBool instr;
670 bool b = v->value.asBoolean();
671 instr.propertyIndex = prop->index;
673 output->addInstruction(instr);
676 case QVariant::Vector3D:
678 Instruction::StoreVector3D instr;
679 instr.propertyIndex = prop->index;
680 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
681 output->addInstruction(instr);
684 case QVariant::Vector4D:
686 Instruction::StoreVector4D instr;
687 instr.propertyIndex = prop->index;
688 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
689 output->addInstruction(instr);
694 // generate single literal value assignment to a list property if required
695 if (type == qMetaTypeId<QList<qreal> >()) {
696 Instruction::StoreDoubleQList instr;
697 instr.propertyIndex = prop->index;
698 instr.value = v->value.asNumber();
699 output->addInstruction(instr);
701 } else if (type == qMetaTypeId<QList<int> >()) {
702 Instruction::StoreIntegerQList instr;
703 instr.propertyIndex = prop->index;
704 instr.value = int(v->value.asNumber());
705 output->addInstruction(instr);
707 } else if (type == qMetaTypeId<QList<bool> >()) {
708 Instruction::StoreBoolQList instr;
709 bool b = v->value.asBoolean();
710 instr.propertyIndex = prop->index;
712 output->addInstruction(instr);
714 } else if (type == qMetaTypeId<QList<QUrl> >()) {
715 Instruction::StoreUrlQList instr;
716 QString string = v->value.asString();
717 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
718 instr.propertyIndex = prop->index;
719 instr.value = output->indexForUrl(u);
720 output->addInstruction(instr);
722 } else if (type == qMetaTypeId<QList<QString> >()) {
723 Instruction::StoreStringQList instr;
724 instr.propertyIndex = prop->index;
725 instr.value = output->indexForString(v->value.asString());
726 output->addInstruction(instr);
728 } else if (type == qMetaTypeId<QJSValue>()) {
729 if (v->value.isBoolean()) {
730 Instruction::StoreJSValueBool instr;
731 instr.propertyIndex = prop->index;
732 instr.value = v->value.asBoolean();
733 output->addInstruction(instr);
734 } else if (v->value.isNumber()) {
735 double n = v->value.asNumber();
736 if (double(int(n)) == n) {
737 Instruction::StoreJSValueInteger instr;
738 instr.propertyIndex = prop->index;
739 instr.value = int(n);
740 output->addInstruction(instr);
742 Instruction::StoreJSValueDouble instr;
743 instr.propertyIndex = prop->index;
745 output->addInstruction(instr);
748 Instruction::StoreJSValueString instr;
749 instr.propertyIndex = prop->index;
750 instr.value = output->indexForString(v->value.asString());
751 output->addInstruction(instr);
756 // otherwise, generate custom type literal assignment
757 Instruction::AssignCustomType instr;
758 instr.propertyIndex = prop->index;
759 instr.primitive = output->indexForString(v->value.asString());
761 output->addInstruction(instr);
768 Resets data by clearing the lists that the QQmlCompiler modifies.
770 void QQmlCompiler::reset(QQmlCompiledData *data)
773 data->primitives.clear();
775 data->bytecode.resize(0);
779 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
780 with which the QQmlCompiledData will be associated.
782 Returns true on success, false on failure. On failure, the compile errors
783 are available from errors().
785 If the environment variant QML_COMPILER_DUMP is set
786 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
787 on a successful compiler.
789 bool QQmlCompiler::compile(QQmlEngine *engine,
791 QQmlCompiledData *out)
798 QQmlScript::Object *root = unit->parser().tree();
801 this->engine = engine;
802 this->enginePrivate = QQmlEnginePrivate::get(engine);
804 this->unitRoot = root;
808 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
809 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
811 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
812 QQmlCompiledData::TypeReference ref;
814 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
815 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
818 ref.type = tref.type;
819 if (!ref.type->isCreatable()) {
820 QString err = ref.type->noCreationReason();
822 err = tr( "Element is not creatable.");
823 COMPILE_EXCEPTION(parserRef->firstUse, err);
826 if (ref.type->containsRevisionedAttributes()) {
827 QQmlError cacheError;
828 ref.typePropertyCache = enginePrivate->cache(ref.type,
829 resolvedTypes.at(ii).minorVersion,
831 if (!ref.typePropertyCache)
832 COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
833 ref.typePropertyCache->addref();
836 } else if (tref.typeData) {
837 ref.component = tref.typeData->compiledData();
838 ref.component->addref();
847 out->dumpInstructions();
850 Q_ASSERT(out->rootPropertyCache);
858 this->enginePrivate = 0;
860 this->cachedComponentTypeRef = -1;
861 this->cachedTranslationContextIndex = -1;
867 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
869 compileState = pool->New<ComponentCompileState>();
871 compileState->root = tree;
873 componentStats->componentStat.lineNumber = tree->location.start.line;
875 // We generate the importCache before we build the tree so that
876 // it can be used in the binding compiler. Given we "expect" the
877 // QML compilation to succeed, this isn't a waste.
878 output->importCache = new QQmlTypeNameCache();
879 foreach (const QString &ns, unit->namespaces()) {
880 output->importCache->add(ns);
884 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
885 QString qualifier = script.qualifier;
886 QString enclosingNamespace;
888 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
889 if (lastDotIndex != -1) {
890 enclosingNamespace = qualifier.left(lastDotIndex);
891 qualifier = qualifier.mid(lastDotIndex+1);
894 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
897 unit->imports().populateCache(output->importCache, engine);
899 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
902 Instruction::Init init;
903 init.bindingsSize = compileState->totalBindingsCount;
904 init.parserStatusSize = compileState->parserStatusCount;
905 init.contextCache = genContextCache();
906 init.objectStackSize = compileState->objectDepth.maxDepth();
907 init.listStackSize = compileState->listDepth.maxDepth();
908 if (compileState->compiledBindingData.isEmpty())
909 init.compiledBinding = -1;
911 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
912 output->addInstruction(init);
914 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
915 Instruction::StoreImportedScript import;
916 import.value = output->scripts.count();
918 QQmlScriptData *scriptData = script.script->scriptData();
919 scriptData->addref();
920 output->scripts << scriptData;
921 output->addInstruction(import);
924 if (!compileState->v8BindingProgram.isEmpty()) {
925 Instruction::InitV8Bindings bindings;
926 int index = output->programs.count();
928 typedef QQmlCompiledData::V8Program V8Program;
929 output->programs.append(V8Program(compileState->v8BindingProgram, output));
931 bindings.programIndex = index;
932 bindings.line = compileState->v8BindingProgramLine;
933 output->addInstruction(bindings);
938 Instruction::SetDefault def;
939 output->addInstruction(def);
941 Instruction::Done done;
942 output->addInstruction(done);
944 Q_ASSERT(tree->metatype);
945 if (!tree->synthdata.isEmpty()) {
946 enginePrivate->registerCompositeType(output);
947 } else if (output->types.at(tree->type).component) {
948 output->metaTypeId = output->types.at(tree->type).component->metaTypeId;
949 output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId;
951 Q_ASSERT(output->types.at(tree->type).type);
952 output->metaTypeId = output->types.at(tree->type).type->typeId();
953 output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId();
955 if (!tree->synthdata.isEmpty())
956 enginePrivate->registerCompositeType(output);
959 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
961 for (int ii = 0; ii < list.count(); ++ii)
962 if (string == list.at(ii))
968 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
971 componentStats->componentStat.objects++;
973 Q_ASSERT (obj->type != -1);
974 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
975 obj->metatype = tr.createPropertyCache(engine);
977 // This object is a "Component" element.
978 if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
979 COMPILE_CHECK(buildComponent(obj, ctxt));
984 typedef QQmlInstruction I;
985 const I *init = ((const I *)tr.component->bytecode.constData());
986 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
988 // Adjust stack depths to include nested components
989 compileState->objectDepth.pushPop(init->init.objectStackSize);
990 compileState->listDepth.pushPop(init->init.listStackSize);
991 compileState->parserStatusCount += init->init.parserStatusSize;
992 compileState->totalBindingsCount += init->init.bindingsSize;
995 compileState->objectDepth.push();
997 // Object instantiations reset the binding context
998 BindingContext objCtxt(obj);
1000 // Create the synthesized meta object, ignoring aliases
1001 COMPILE_CHECK(checkDynamicMeta(obj));
1002 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
1003 COMPILE_CHECK(buildDynamicMeta(obj, Normal));
1005 // Find the native type and check for the QQmlParserStatus interface
1006 QQmlType *type = toQmlType(obj);
1008 obj->parserStatusCast = type->parserStatusCast();
1009 if (obj->parserStatusCast != -1)
1010 compileState->parserStatusCount++;
1012 // Check if this is a custom parser type. Custom parser types allow
1013 // assignments to non-existent properties. These assignments are then
1014 // compiled by the type.
1015 bool isCustomParser = output->types.at(obj->type).type &&
1016 output->types.at(obj->type).type->customParser() != 0;
1017 QList<QQmlCustomParserProperty> customProps;
1019 // Fetch the list of deferred properties
1020 QStringList deferredList = deferredProperties(obj);
1022 // Must do id property first. This is to ensure that the id given to any
1023 // id reference created matches the order in which the objects are
1025 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1026 if (prop->name() == id_string) {
1027 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1033 Property *defaultProperty = 0;
1034 Property *skipProperty = 0;
1035 if (obj->defaultProperty) {
1036 defaultProperty = obj->defaultProperty;
1038 Property *explicitProperty = 0;
1040 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1041 if (!defaultPropertyName.isEmpty()) {
1042 QString *s = pool->NewString(defaultPropertyName);
1043 QHashedStringRef r(*s);
1045 if (obj->propertiesHashField.test(r.hash())) {
1046 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1047 if (ep->name() == r) {
1048 explicitProperty = ep;
1054 if (!explicitProperty)
1055 defaultProperty->setName(r);
1058 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1060 skipProperty = explicitProperty; // We merge the values into defaultProperty
1062 // Find the correct insertion point
1063 Value *insertPos = 0;
1065 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1066 if (!(v->location.start < explicitProperty->values.first()->location.start))
1071 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1075 QQmlCustomParser *cp = 0;
1077 cp = output->types.at(obj->type).type->customParser();
1079 // Build all explicit properties specified
1080 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1082 if (prop == skipProperty)
1084 if (prop->name() == id_string)
1087 bool canDefer = false;
1088 if (isCustomParser) {
1089 if (doesPropertyExist(prop, obj) &&
1090 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1091 !isAttachedPropertyName(prop->name()))) {
1092 int ids = compileState->ids.count();
1093 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1094 canDefer = ids == compileState->ids.count();
1095 } else if (isSignalPropertyName(prop->name()) &&
1096 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1097 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1099 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1102 if (isSignalPropertyName(prop->name())) {
1103 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1105 int ids = compileState->ids.count();
1106 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1107 canDefer = ids == compileState->ids.count();
1111 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1112 prop->isDeferred = true;
1116 // Build the default property
1117 if (defaultProperty) {
1118 Property *prop = defaultProperty;
1120 bool canDefer = false;
1121 if (isCustomParser) {
1122 if (doesPropertyExist(prop, obj)) {
1123 int ids = compileState->ids.count();
1124 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1125 canDefer = ids == compileState->ids.count();
1127 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1130 int ids = compileState->ids.count();
1131 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1132 canDefer = ids == compileState->ids.count();
1135 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1136 prop->isDeferred = true;
1139 // Compile custom parser parts
1140 if (isCustomParser && !customProps.isEmpty()) {
1142 cp->compiler = this;
1144 obj->custom = cp->compile(customProps);
1147 foreach (QQmlError err, cp->errors()) {
1148 err.setUrl(output->url);
1153 compileState->objectDepth.pop();
1158 void QQmlCompiler::genObject(QQmlScript::Object *obj, bool parentToSuper)
1160 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1161 if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
1166 // Create the object
1167 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1168 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1170 Instruction::CreateSimpleObject create;
1171 create.create = output->types.at(obj->type).type->createFunction();
1172 create.typeSize = output->types.at(obj->type).type->createSize();
1173 create.type = obj->type;
1174 create.line = obj->location.start.line;
1175 create.column = obj->location.start.column;
1176 create.parentToSuper = parentToSuper;
1177 output->addInstruction(create);
1181 if (output->types.at(obj->type).type) {
1182 Instruction::CreateCppObject create;
1183 create.line = obj->location.start.line;
1184 create.column = obj->location.start.column;
1186 if (!obj->custom.isEmpty())
1187 create.data = output->indexForByteArray(obj->custom);
1188 create.type = obj->type;
1189 create.isRoot = (compileState->root == obj);
1190 create.parentToSuper = parentToSuper;
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->synthdata.isEmpty()) {
1215 Instruction::StoreMetaObject meta;
1216 meta.aliasData = output->indexForByteArray(obj->synthdata);
1217 meta.propertyCache = output->propertyCaches.count();
1219 QQmlPropertyCache *propertyCache = obj->synthCache;
1220 Q_ASSERT(propertyCache);
1221 propertyCache->addref();
1223 if (obj == unitRoot) {
1224 propertyCache->addref();
1225 output->rootPropertyCache = propertyCache;
1228 output->propertyCaches << propertyCache;
1229 output->addInstruction(meta);
1230 } else if (obj == unitRoot) {
1231 output->rootPropertyCache = tr.createPropertyCache(engine);
1232 output->rootPropertyCache->addref();
1235 // Set the object id
1236 if (!obj->id.isEmpty()) {
1237 Instruction::SetId id;
1238 id.value = output->indexForString(obj->id);
1239 id.index = obj->idIndex;
1240 output->addInstruction(id);
1244 if (tr.type && obj->parserStatusCast != -1) {
1245 Instruction::BeginObject begin;
1246 begin.castValue = obj->parserStatusCast;
1247 output->addInstruction(begin);
1253 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1255 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1256 Q_ASSERT(prop->scriptStringScope != -1);
1257 const QString &script = prop->values.first()->value.asScript();
1258 Instruction::StoreScriptString ss;
1259 ss.propertyIndex = prop->index;
1260 ss.value = output->indexForString(script);
1261 ss.scope = prop->scriptStringScope;
1262 // ss.bindingId = rewriteBinding(script, prop->name());
1263 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1264 ss.line = prop->location.start.line;
1265 ss.column = prop->location.start.column;
1266 output->addInstruction(ss);
1269 bool seenDefer = false;
1270 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1271 if (prop->isDeferred) {
1276 genValueProperty(prop, obj);
1279 Instruction::Defer defer;
1280 defer.deferCount = 0;
1281 int deferIdx = output->addInstruction(defer);
1282 int nextInstructionIndex = output->nextInstructionIndex();
1284 Instruction::DeferInit dinit;
1285 // XXX - these are now massive over allocations
1286 dinit.bindingsSize = compileState->totalBindingsCount;
1287 dinit.parserStatusSize = compileState->parserStatusCount;
1288 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1289 dinit.listStackSize = compileState->listDepth.maxDepth();
1290 output->addInstruction(dinit);
1292 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1293 if (!prop->isDeferred)
1295 genValueProperty(prop, obj);
1298 Instruction::Done done;
1299 output->addInstruction(done);
1301 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1304 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1306 QQmlScript::Value *v = prop->values.first();
1308 if (v->type == Value::SignalObject) {
1310 genObject(v->object);
1312 Instruction::AssignSignalObject assign;
1313 assign.line = v->location.start.line;
1314 assign.signal = output->indexForString(prop->name().toString());
1315 output->addInstruction(assign);
1317 } else if (v->type == Value::SignalExpression) {
1319 Instruction::StoreSignal store;
1320 store.signalIndex = prop->index;
1321 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1322 store.value = output->indexForByteArray(rewrite.toUtf8());
1323 store.context = v->signalExpressionContextStack;
1324 store.line = v->location.start.line;
1325 store.column = v->location.start.column;
1326 output->addInstruction(store);
1332 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1333 Instruction::FetchAttached fetch;
1334 fetch.id = prop->index;
1335 fetch.line = prop->location.start.line;
1336 output->addInstruction(fetch);
1338 genObjectBody(prop->value);
1340 Instruction::PopFetchedObject pop;
1341 output->addInstruction(pop);
1344 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1345 Instruction::FetchObject fetch;
1346 fetch.property = prop->index;
1347 fetch.line = prop->location.start.line;
1348 output->addInstruction(fetch);
1350 if (!prop->value->synthdata.isEmpty()) {
1351 Instruction::StoreMetaObject meta;
1352 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1353 meta.propertyCache = output->propertyCaches.count();
1354 QQmlPropertyCache *propertyCache = prop->value->synthCache;
1355 Q_ASSERT(propertyCache);
1356 propertyCache->addref();
1357 output->propertyCaches << propertyCache;
1358 output->addInstruction(meta);
1361 genObjectBody(prop->value);
1363 Instruction::PopFetchedObject pop;
1364 output->addInstruction(pop);
1367 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1369 genValueTypeProperty(obj, prop);
1372 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1373 if (prop->isDeferred)
1376 genValueProperty(prop, obj);
1379 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1381 genValueTypeProperty(obj, prop);
1385 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1387 Instruction::FetchValueType fetch;
1388 fetch.property = prop->index;
1389 fetch.type = prop->type;
1390 fetch.bindingSkipList = 0;
1392 if (obj->type == -1 || output->types.at(obj->type).component) {
1393 // We only have to do this if this is a composite type. If it is a builtin
1394 // type it can't possibly already have bindings that need to be cleared.
1395 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1396 if (!vprop->values.isEmpty()) {
1397 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1398 fetch.bindingSkipList |= (1 << vprop->index);
1403 output->addInstruction(fetch);
1405 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1406 genPropertyAssignment(vprop, prop->value, prop);
1409 Instruction::PopValueType pop;
1410 pop.property = prop->index;
1411 pop.type = prop->type;
1412 pop.bindingSkipList = 0;
1413 output->addInstruction(pop);
1416 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1418 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1421 Instruction::CreateComponent create;
1422 create.line = root->location.start.line;
1423 create.column = root->location.start.column;
1424 create.endLine = root->location.end.line;
1425 create.isRoot = (compileState->root == obj);
1426 int createInstruction = output->addInstruction(create);
1427 int nextInstructionIndex = output->nextInstructionIndex();
1429 ComponentCompileState *oldCompileState = compileState;
1430 compileState = componentState(root);
1432 Instruction::Init init;
1433 init.bindingsSize = compileState->totalBindingsCount;
1434 init.parserStatusSize = compileState->parserStatusCount;
1435 init.contextCache = genContextCache();
1436 init.objectStackSize = compileState->objectDepth.maxDepth();
1437 init.listStackSize = compileState->listDepth.maxDepth();
1438 if (compileState->compiledBindingData.isEmpty())
1439 init.compiledBinding = -1;
1441 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1442 output->addInstruction(init);
1444 if (!compileState->v8BindingProgram.isEmpty()) {
1445 Instruction::InitV8Bindings bindings;
1446 int index = output->programs.count();
1448 typedef QQmlCompiledData::V8Program V8Program;
1449 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1451 bindings.programIndex = index;
1452 bindings.line = compileState->v8BindingProgramLine;
1453 output->addInstruction(bindings);
1458 Instruction::SetDefault def;
1459 output->addInstruction(def);
1461 Instruction::Done done;
1462 output->addInstruction(done);
1464 output->instruction(createInstruction)->createComponent.count =
1465 output->nextInstructionIndex() - nextInstructionIndex;
1467 compileState = oldCompileState;
1469 if (!obj->id.isEmpty()) {
1470 Instruction::SetId id;
1471 id.value = output->indexForString(obj->id);
1472 id.index = obj->idIndex;
1473 output->addInstruction(id);
1476 if (obj == unitRoot) {
1477 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1478 output->rootPropertyCache->addref();
1482 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1483 const BindingContext &ctxt)
1485 // The special "Component" element can only have the id property and a
1486 // default property, that actually defines the component's tree
1488 compileState->objectDepth.push();
1490 // Find, check and set the "id" property (if any)
1491 Property *idProp = 0;
1492 if (obj->properties.isMany() ||
1493 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1494 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1496 if (!obj->properties.isEmpty())
1497 idProp = obj->properties.first();
1500 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1501 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1502 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1504 QString idVal = idProp->values.first()->primitive();
1506 if (compileState->ids.value(idVal))
1507 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1513 // Check the Component tree is well formed
1514 if (obj->defaultProperty &&
1515 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1516 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1517 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1519 if (!obj->dynamicProperties.isEmpty())
1520 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1521 if (!obj->dynamicSignals.isEmpty())
1522 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1523 if (!obj->dynamicSlots.isEmpty())
1524 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1526 QQmlScript::Object *root = 0;
1527 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1528 root = obj->defaultProperty->values.first()->object;
1531 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1533 // Build the component tree
1534 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1536 compileState->objectDepth.pop();
1541 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1542 const BindingContext &ctxt)
1544 ComponentCompileState *oldComponentCompileState = compileState;
1545 compileState = pool->New<ComponentCompileState>();
1546 compileState->root = obj;
1547 compileState->nested = true;
1549 if (componentStats) {
1550 ComponentStat oldComponentStat = componentStats->componentStat;
1552 componentStats->componentStat = ComponentStat();
1553 componentStats->componentStat.lineNumber = obj->location.start.line;
1556 COMPILE_CHECK(buildObject(obj, ctxt));
1558 COMPILE_CHECK(completeComponentBuild());
1560 componentStats->componentStat = oldComponentStat;
1563 COMPILE_CHECK(buildObject(obj, ctxt));
1565 COMPILE_CHECK(completeComponentBuild());
1568 compileState = oldComponentCompileState;
1574 // Build a sub-object. A sub-object is one that was not created directly by
1575 // QML - such as a grouped property object, or an attached object. Sub-object's
1576 // can't have an id, involve a custom parser, have attached properties etc.
1577 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1579 Q_ASSERT(obj->metatype);
1580 Q_ASSERT(!obj->defaultProperty);
1581 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1584 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1585 if (isSignalPropertyName(prop->name())) {
1586 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1588 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1595 int QQmlCompiler::componentTypeRef()
1597 if (cachedComponentTypeRef == -1) {
1598 QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1599 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1600 if (output->types.at(ii).type == t) {
1601 cachedComponentTypeRef = ii;
1605 QQmlCompiledData::TypeReference ref;
1607 output->types << ref;
1608 cachedComponentTypeRef = output->types.count() - 1;
1610 return cachedComponentTypeRef;
1613 int QQmlCompiler::translationContextIndex()
1615 if (cachedTranslationContextIndex == -1) {
1616 // This code must match that in the qsTr() implementation
1617 const QString &path = output->name;
1618 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1619 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1621 QByteArray contextUtf8 = context.toUtf8();
1622 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1624 return cachedTranslationContextIndex;
1627 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1628 const BindingContext &ctxt)
1630 Q_ASSERT(obj->metatype);
1632 const QHashedStringRef &propName = prop->name();
1634 Q_ASSERT(propName.startsWith(on_string));
1635 QString name = propName.mid(2, -1).toString();
1637 // Note that the property name could start with any alpha or '_' or '$' character,
1638 // so we need to do the lower-casing of the first alpha character.
1639 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1640 if (name.at(firstAlphaIndex).isUpper()) {
1641 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1646 bool notInRevision = false;
1648 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1652 if (notInRevision && 0 == property(obj, propName, 0)) {
1653 Q_ASSERT(obj->type != -1);
1654 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1655 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1657 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));
1659 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1663 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1665 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1669 if (prop->value || !prop->values.isOne())
1670 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1672 prop->index = sig->coreIndex;
1675 obj->addSignalProperty(prop);
1677 if (prop->values.first()->object) {
1678 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1679 prop->values.first()->type = Value::SignalObject;
1681 prop->values.first()->type = Value::SignalExpression;
1683 if (!prop->values.first()->value.isScript())
1684 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1686 QString script = prop->values.first()->value.asScript().trimmed();
1687 if (script.isEmpty())
1688 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1690 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1699 Returns true if (value) property \a prop exists on obj, false otherwise.
1701 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1702 QQmlScript::Object *obj)
1704 if (prop->name().isEmpty())
1706 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1709 return property(obj, prop->name()) != 0;
1712 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1713 QQmlScript::Object *obj,
1714 const BindingContext &ctxt)
1716 if (prop->isEmpty())
1717 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1719 if (isAttachedPropertyName(prop->name())) {
1720 // Setup attached property data
1722 if (ctxt.isSubContext()) {
1723 // Attached properties cannot be used on sub-objects. Sub-objects
1724 // always exist in a binding sub-context, which is what we test
1726 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1730 QQmlImportNamespace *typeNamespace = 0;
1731 unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1733 if (typeNamespace) {
1734 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1737 } else if (!type || !type->attachedPropertiesType()) {
1738 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1742 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1744 Q_ASSERT(type->attachedPropertiesFunction());
1745 prop->index = type->attachedPropertiesId();
1746 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1748 // Setup regular property data
1749 bool notInRevision = false;
1750 QQmlPropertyData *d =
1751 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1753 if (d == 0 && notInRevision) {
1754 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1755 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1757 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));
1759 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1762 prop->index = d->coreIndex;
1764 } else if (prop->isDefault) {
1765 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1767 if (!defaultPropertyName.isEmpty()) {
1768 prop->setName(defaultPropertyName);
1769 prop->core = *obj->metatype->defaultProperty();
1770 prop->index = prop->core.coreIndex;
1774 // We can't error here as the "id" property does not require a
1775 // successful index resolution
1776 if (prop->index != -1)
1777 prop->type = prop->core.propType;
1779 // Check if this is an alias
1780 if (prop->index != -1 &&
1782 prop->parent->type != -1 &&
1783 output->types.at(prop->parent->type).component) {
1785 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1786 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1787 prop->isAlias = true;
1790 if (prop->index != -1 && !prop->values.isEmpty())
1791 prop->parent->setBindingBit(prop->index);
1794 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1796 // The magic "id" behavior doesn't apply when "id" is resolved as a
1797 // default property or to sub-objects (which are always in binding
1799 COMPILE_CHECK(buildIdProperty(prop, obj));
1800 if (prop->type == QVariant::String &&
1801 prop->values.first()->value.isString())
1802 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1804 } else if (isAttachedPropertyName(prop->name())) {
1806 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1808 } else if (prop->index == -1) {
1810 if (prop->isDefault) {
1811 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1813 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1816 } else if (prop->value) {
1818 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1820 } else if (prop->core.isQList()) {
1822 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1824 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1826 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1830 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1837 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1838 QQmlScript::Property *nsProp,
1839 QQmlScript::Object *obj,
1840 const BindingContext &ctxt)
1843 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1845 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1847 if (!isAttachedPropertyName(prop->name()))
1848 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1850 // Setup attached property data
1853 unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1855 if (!type || !type->attachedPropertiesType())
1856 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1859 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1861 Q_ASSERT(type->attachedPropertiesFunction());
1862 prop->index = type->index();
1863 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1865 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1871 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1872 QQmlScript::Object *obj)
1874 if (prop->core.isQList()) {
1875 genListProperty(prop, obj);
1877 genPropertyAssignment(prop, obj);
1881 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1882 QQmlScript::Object *obj)
1884 int listType = enginePrivate->listType(prop->type);
1886 Instruction::FetchQList fetch;
1887 fetch.property = prop->index;
1888 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1889 fetch.type = listType;
1890 output->addInstruction(fetch);
1892 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1894 if (v->type == Value::CreatedObject) {
1896 genObject(v->object);
1897 if (listTypeIsInterface) {
1898 Instruction::AssignObjectList assign;
1899 assign.line = prop->location.start.line;
1900 output->addInstruction(assign);
1902 Instruction::StoreObjectQList store;
1903 output->addInstruction(store);
1906 } else if (v->type == Value::PropertyBinding) {
1908 genBindingAssignment(v, prop, obj);
1914 Instruction::PopQList pop;
1915 output->addInstruction(pop);
1918 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1919 QQmlScript::Object *obj,
1920 QQmlScript::Property *valueTypeProperty)
1922 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1924 Q_ASSERT(v->type == Value::CreatedObject ||
1925 v->type == Value::PropertyBinding ||
1926 v->type == Value::Literal);
1928 if (v->type == Value::CreatedObject) {
1930 genObject(v->object);
1932 if (QQmlMetaType::isInterface(prop->type)) {
1934 Instruction::StoreInterface store;
1935 store.line = v->object->location.start.line;
1936 store.propertyIndex = prop->index;
1937 output->addInstruction(store);
1939 } else if (prop->type == QMetaType::QVariant) {
1941 if (prop->core.isVarProperty()) {
1942 Instruction::StoreVarObject store;
1943 store.line = v->object->location.start.line;
1944 store.propertyIndex = prop->index;
1945 output->addInstruction(store);
1947 Instruction::StoreVariantObject store;
1948 store.line = v->object->location.start.line;
1949 store.propertyIndex = prop->index;
1950 output->addInstruction(store);
1956 Instruction::StoreObject store;
1957 store.line = v->object->location.start.line;
1958 store.propertyIndex = prop->index;
1959 output->addInstruction(store);
1962 } else if (v->type == Value::PropertyBinding) {
1964 genBindingAssignment(v, prop, obj, valueTypeProperty);
1966 } else if (v->type == Value::Literal) {
1968 genLiteralAssignment(prop, v);
1974 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1976 Q_ASSERT(v->type == Value::ValueSource ||
1977 v->type == Value::ValueInterceptor);
1979 if (v->type == Value::ValueSource) {
1980 genObject(v->object, valueTypeProperty?true:false);
1982 Instruction::StoreValueSource store;
1983 if (valueTypeProperty)
1984 store.property = genValueTypeData(prop, valueTypeProperty);
1986 store.property = prop->core;
1987 QQmlType *valueType = toQmlType(v->object);
1988 store.castValue = valueType->propertyValueSourceCast();
1989 output->addInstruction(store);
1991 } else if (v->type == Value::ValueInterceptor) {
1992 genObject(v->object, valueTypeProperty?true:false);
1994 Instruction::StoreValueInterceptor store;
1995 if (valueTypeProperty)
1996 store.property = genValueTypeData(prop, valueTypeProperty);
1998 store.property = prop->core;
1999 QQmlType *valueType = toQmlType(v->object);
2000 store.castValue = valueType->propertyValueInterceptorCast();
2001 output->addInstruction(store);
2007 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2008 QQmlScript::Object *obj)
2011 prop->values.isMany() ||
2012 prop->values.first()->object)
2013 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2015 QQmlScript::Value *idValue = prop->values.first();
2016 QString val = idValue->primitive();
2018 COMPILE_CHECK(checkValidId(idValue, val));
2020 if (compileState->ids.value(val))
2021 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2023 prop->values.first()->type = Value::Id;
2031 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2034 Q_ASSERT(!compileState->ids.value(id));
2035 Q_ASSERT(obj->id == id);
2036 obj->idIndex = compileState->ids.count();
2037 compileState->ids.append(obj);
2040 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2042 Q_ASSERT(ref->value && !ref->value->bindingReference);
2043 ref->value->bindingReference = ref;
2044 compileState->totalBindingsCount++;
2045 compileState->bindings.prepend(ref);
2048 void QQmlCompiler::saveComponentState()
2050 Q_ASSERT(compileState->root);
2051 Q_ASSERT(compileState->root->componentCompileState == 0);
2053 compileState->root->componentCompileState = compileState;
2056 componentStats->savedComponentStats.append(componentStats->componentStat);
2059 QQmlCompilerTypes::ComponentCompileState *
2060 QQmlCompiler::componentState(QQmlScript::Object *obj)
2062 Q_ASSERT(obj->componentCompileState);
2063 return obj->componentCompileState;
2066 // Build attached property object. In this example,
2070 // GridView is an attached property object.
2071 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2072 QQmlScript::Object *obj,
2073 const BindingContext &ctxt)
2075 Q_ASSERT(prop->value);
2076 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2078 compileState->objectDepth.push();
2080 obj->addAttachedProperty(prop);
2082 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2084 compileState->objectDepth.pop();
2090 // Build "grouped" properties. In this example:
2092 // font.pointSize: 12
2093 // font.family: "Helvetica"
2095 // font is a nested property. pointSize and family are not.
2096 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2097 QQmlScript::Object *obj,
2098 const BindingContext &ctxt)
2100 Q_ASSERT(prop->type != 0);
2101 Q_ASSERT(prop->index != -1);
2103 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2104 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2106 if (!prop->values.isEmpty()) {
2107 if (prop->values.first()->location < prop->value->location) {
2108 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2110 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2114 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2115 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2119 if (prop->isAlias) {
2120 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2121 vtProp->isAlias = true;
2125 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2126 prop->value, obj, ctxt.incr()));
2127 obj->addValueTypeProperty(prop);
2129 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2133 // Load the nested property's meta type
2134 prop->value->metatype = enginePrivate->propertyCacheForType(prop->type);
2135 if (!prop->value->metatype)
2136 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2138 if (!prop->values.isEmpty())
2139 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2141 obj->addGroupedProperty(prop);
2143 compileState->objectDepth.push();
2145 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2147 compileState->objectDepth.pop();
2153 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2154 QQmlScript::Object *obj,
2155 QQmlScript::Object *baseObj,
2156 const BindingContext &ctxt)
2158 compileState->objectDepth.push();
2160 if (obj->defaultProperty)
2161 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2162 obj->metatype = enginePrivate->cache(type);
2164 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2166 QQmlPropertyData *d = property(obj, prop->name());
2168 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2170 prop->index = d->coreIndex;
2171 prop->type = d->propType;
2173 prop->isValueTypeSubProperty = true;
2176 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2178 if (prop->values.isMany()) {
2179 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2180 } else if (!prop->values.isEmpty()) {
2181 QQmlScript::Value *value = prop->values.first();
2183 if (value->object) {
2184 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2185 } else if (value->value.isScript()) {
2186 // ### Check for writability
2188 //optimization for <Type>.<EnumValue> enum assignments
2189 bool isEnumAssignment = false;
2191 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2192 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2194 if (isEnumAssignment) {
2195 value->type = Value::Literal;
2197 JSBindingReference *reference = pool->New<JSBindingReference>();
2198 reference->expression = value->value;
2199 reference->property = prop;
2200 reference->value = value;
2201 reference->bindingContext = ctxt;
2202 reference->bindingContext.owner++;
2203 addBindingReference(reference);
2204 value->type = Value::PropertyBinding;
2207 COMPILE_CHECK(testLiteralAssignment(prop, value));
2208 value->type = Value::Literal;
2212 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2213 Q_ASSERT(v->object);
2215 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2218 obj->addValueProperty(prop);
2221 compileState->objectDepth.pop();
2226 // Build assignments to QML lists. QML lists are properties of type
2227 // QQmlListProperty<T>. List properties can accept a list of
2228 // objects, or a single binding.
2229 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2230 QQmlScript::Object *obj,
2231 const BindingContext &ctxt)
2233 Q_ASSERT(prop->core.isQList());
2235 compileState->listDepth.push();
2239 obj->addValueProperty(prop);
2241 int listType = enginePrivate->listType(t);
2242 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2244 bool assignedBinding = false;
2245 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2247 v->type = Value::CreatedObject;
2248 COMPILE_CHECK(buildObject(v->object, ctxt));
2250 // We check object coercian here. We check interface assignment
2252 if (!listTypeIsInterface) {
2253 if (!canCoerce(listType, v->object)) {
2254 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2258 } else if (v->value.isScript()) {
2259 if (assignedBinding)
2260 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2262 assignedBinding = true;
2263 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2264 v->type = Value::PropertyBinding;
2266 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2270 compileState->listDepth.pop();
2275 // Compiles an assignment to a QQmlScriptString property
2276 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2277 QQmlScript::Object *obj,
2278 const BindingContext &ctxt)
2280 if (prop->values.isMany())
2281 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2283 if (prop->values.first()->object)
2284 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2286 prop->scriptStringScope = ctxt.stack;
2287 obj->addScriptStringProperty(prop);
2292 // Compile regular property assignments of the form "property: <value>"
2293 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2294 QQmlScript::Object *obj,
2295 const BindingContext &ctxt)
2297 obj->addValueProperty(prop);
2299 if (prop->values.isMany())
2300 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2302 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2305 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2309 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2314 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2315 Q_ASSERT(v->object);
2316 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2322 // Compile assigning a single object instance to a regular property
2323 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2324 QQmlScript::Object *obj,
2325 QQmlScript::Value *v,
2326 const BindingContext &ctxt)
2328 Q_ASSERT(prop->index != -1);
2329 Q_ASSERT(v->object->type != -1);
2331 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2332 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2334 if (QQmlMetaType::isInterface(prop->type)) {
2336 // Assigning an object to an interface ptr property
2337 COMPILE_CHECK(buildObject(v->object, ctxt));
2339 v->type = Value::CreatedObject;
2341 } else if (prop->type == QMetaType::QVariant) {
2343 // Assigning an object to a QVariant
2344 COMPILE_CHECK(buildObject(v->object, ctxt));
2346 v->type = Value::CreatedObject;
2348 // Normally buildObject() will set this up, but we need the static
2349 // meta object earlier to test for assignability. It doesn't matter
2350 // that there may still be outstanding synthesized meta object changes
2351 // on this type, as they are not relevant for assignability testing
2352 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2353 Q_ASSERT(v->object->metatype);
2355 // We want to raw metaObject here as the raw metaobject is the
2356 // actual property type before we applied any extensions that might
2357 // effect the properties on the type, but don't effect assignability
2358 QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type);
2360 // Will be true if the assgned type inherits propertyMetaObject
2361 bool isAssignable = false;
2362 // Determine isAssignable value
2363 if (propertyMetaObject) {
2364 QQmlPropertyCache *c = v->object->metatype;
2365 while (c && !isAssignable) {
2366 isAssignable |= c == propertyMetaObject;
2372 // Simple assignment
2373 COMPILE_CHECK(buildObject(v->object, ctxt));
2375 v->type = Value::CreatedObject;
2376 } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) {
2377 // Automatic "Component" insertion
2378 QQmlScript::Object *root = v->object;
2379 QQmlScript::Object *component = pool->New<Object>();
2380 component->type = componentTypeRef();
2381 component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject);
2382 component->location = root->location;
2383 QQmlScript::Value *componentValue = pool->New<Value>();
2384 componentValue->object = root;
2385 component->getDefaultProperty()->addValue(componentValue);
2386 v->object = component;
2387 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2389 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2396 // Compile assigning a single object instance to a regular property using the "on" syntax.
2400 // NumberAnimation on x { }
2402 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2403 QQmlScript::Object *obj,
2404 QQmlScript::Object *baseObj,
2405 QQmlScript::Value *v,
2406 const BindingContext &ctxt)
2408 Q_ASSERT(prop->index != -1);
2409 Q_ASSERT(v->object->type != -1);
2413 if (!prop->core.isWritable())
2414 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2417 // Normally buildObject() will set this up, but we need the static
2418 // meta object earlier to test for assignability. It doesn't matter
2419 // that there may still be outstanding synthesized meta object changes
2420 // on this type, as they are not relevant for assignability testing
2421 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2422 Q_ASSERT(v->object->metatype);
2424 // Will be true if the assigned type inherits QQmlPropertyValueSource
2425 bool isPropertyValue = false;
2426 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2427 bool isPropertyInterceptor = false;
2428 if (QQmlType *valueType = toQmlType(v->object)) {
2429 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2430 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2433 if (isPropertyValue || isPropertyInterceptor) {
2434 // Assign as a property value source
2435 COMPILE_CHECK(buildObject(v->object, ctxt));
2437 if (isPropertyInterceptor && baseObj->synthdata.isEmpty())
2438 buildDynamicMeta(baseObj, ForceCreation);
2439 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2441 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2447 // Compile assigning a literal or binding to a regular property
2448 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2449 QQmlScript::Object *obj,
2450 QQmlScript::Value *v,
2451 const BindingContext &ctxt)
2453 Q_ASSERT(prop->index != -1);
2455 if (v->value.isScript()) {
2457 //optimization for <Type>.<EnumValue> enum assignments
2458 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2459 bool isEnumAssignment = false;
2460 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2461 if (isEnumAssignment) {
2462 v->type = Value::Literal;
2467 // Test for other binding optimizations
2468 if (!buildLiteralBinding(v, prop, ctxt))
2469 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2471 v->type = Value::PropertyBinding;
2475 COMPILE_CHECK(testLiteralAssignment(prop, v));
2477 v->type = Value::Literal;
2483 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2484 QQmlScript::Object *obj,
2485 QQmlScript::Value *v,
2488 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2489 *isAssignment = false;
2490 if (!prop->core.isEnum() && !isIntProp)
2493 QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2495 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2496 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2498 QString string = v->value.asString();
2499 if (!string.at(0).isUpper())
2502 int dot = string.indexOf(QLatin1Char('.'));
2503 if (dot == -1 || dot == string.length()-1)
2506 if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2509 QHashedStringRef typeName(string.constData(), dot);
2510 QString enumValue = string.mid(dot+1);
2513 // Allow enum assignment to ints.
2514 int enumval = evaluateEnum(typeName, enumValue.toUtf8());
2515 if (enumval != -1) {
2516 v->type = Value::Literal;
2517 v->value = QQmlScript::Variant((double)enumval);
2518 *isAssignment = true;
2524 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2532 if (toQmlType(obj) == type) {
2533 // When these two match, we can short cut the search
2534 if (mprop.isFlagType()) {
2535 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2537 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2540 // Otherwise we have to search the whole type
2541 // This matches the logic in QV8TypeWrapper
2542 QByteArray enumName = enumValue.toUtf8();
2543 const QMetaObject *metaObject = type->baseMetaObject();
2545 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2546 QMetaEnum e = metaObject->enumerator(ii);
2547 value = e.keyToValue(enumName.constData(), &ok);
2554 v->type = Value::Literal;
2555 v->value = QQmlScript::Variant((double)value);
2556 *isAssignment = true;
2561 struct StaticQtMetaObject : public QObject
2563 static const QMetaObject *get()
2564 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2567 // Similar logic to above, but not knowing target property.
2568 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const
2571 if (scope != QLatin1String("Qt")) {
2572 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2577 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2578 int i = mo->enumeratorCount();
2581 int v = mo->enumerator(i).keyToValue(enumValue.constData(), &ok);
2588 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2590 QQmlType *qmltype = 0;
2591 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2595 return qmltype->metaObject();
2598 // similar to logic of completeComponentBuild, but also sticks data
2599 // into primitives at the end
2600 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2602 QQmlRewrite::RewriteBinding rewriteBinding;
2603 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2605 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2607 return output->indexForString(rewrite);
2610 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2612 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2613 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2616 // Ensures that the dynamic meta specification on obj is valid
2617 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2619 bool seenDefaultProperty = false;
2621 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2622 // Calculating the hash for the names is not a waste as we have to test
2623 // them against the illegalNames set anyway.
2624 QHashField propNames;
2625 QHashField methodNames;
2628 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2629 const QQmlScript::Object::DynamicProperty &prop = *p;
2631 if (prop.isDefaultProperty) {
2632 if (seenDefaultProperty)
2633 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2634 seenDefaultProperty = true;
2637 if (propNames.testAndSet(prop.name.hash())) {
2638 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2639 p2 = obj->dynamicProperties.next(p2)) {
2640 if (p2->name == prop.name) {
2641 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2642 prop.nameLocation.column,
2643 tr("Duplicate property name"));
2648 if (prop.name.at(0).isUpper()) {
2649 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2650 prop.nameLocation.column,
2651 tr("Property names cannot begin with an upper case letter"));
2654 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2655 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2656 prop.nameLocation.column,
2657 tr("Illegal property name"));
2661 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2662 const QQmlScript::Object::DynamicSignal &currSig = *s;
2664 if (methodNames.testAndSet(currSig.name.hash())) {
2665 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2666 s2 = obj->dynamicSignals.next(s2)) {
2667 if (s2->name == currSig.name)
2668 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2672 if (currSig.name.at(0).isUpper())
2673 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2674 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2675 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2678 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2679 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2681 if (methodNames.testAndSet(currSlot.name.hash())) {
2682 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2683 s2 = obj->dynamicSignals.next(s2)) {
2684 if (s2->name == currSlot.name)
2685 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2687 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2688 s2 = obj->dynamicSlots.next(s2)) {
2689 if (s2->name == currSlot.name)
2690 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2694 if (currSlot.name.at(0).isUpper())
2695 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2696 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2697 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2703 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2705 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2706 p = obj->dynamicProperties.next(p)) {
2708 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2711 Property *property = 0;
2712 if (p->isDefaultProperty) {
2713 property = obj->getDefaultProperty();
2715 property = obj->getProperty(p->name);
2716 if (!property->values.isEmpty())
2717 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2721 property->isReadOnlyDeclaration = true;
2723 if (property->value)
2724 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2726 property->values.append(p->defaultValue->values);
2731 #include <private/qqmljsparser_p.h>
2733 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2735 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2737 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2738 return QStringList() << name;
2739 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2740 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2742 QStringList rv = astNodeToStringList(expr->base);
2745 rv.append(expr->name.toString());
2748 return QStringList();
2751 static QAtomicInt classIndexCounter(0);
2753 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2756 Q_ASSERT(obj->metatype);
2758 if (mode != ForceCreation &&
2759 obj->dynamicProperties.isEmpty() &&
2760 obj->dynamicSignals.isEmpty() &&
2761 obj->dynamicSlots.isEmpty())
2764 Q_ASSERT(obj->synthCache == 0);
2767 Object::DynamicProperty::Type dtype;
2769 } builtinTypes[] = {
2770 { Object::DynamicProperty::Var, QMetaType::QVariant },
2771 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2772 { Object::DynamicProperty::Int, QMetaType::Int },
2773 { Object::DynamicProperty::Bool, QMetaType::Bool },
2774 { Object::DynamicProperty::Real, QMetaType::Double },
2775 { Object::DynamicProperty::String, QMetaType::QString },
2776 { Object::DynamicProperty::Url, QMetaType::QUrl },
2777 { Object::DynamicProperty::Color, QMetaType::QColor },
2778 { Object::DynamicProperty::Time, QMetaType::QTime },
2779 { Object::DynamicProperty::Date, QMetaType::QDate },
2780 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2781 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2783 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2785 QByteArray newClassName;
2787 if (compileState->root == obj && !compileState->nested) {
2788 QString path = output->url.path();
2789 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2790 if (lastSlash > -1) {
2791 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2792 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2793 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2794 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2797 if (newClassName.isEmpty()) {
2798 newClassName = QQmlMetaObject(obj->metatype).className();
2799 newClassName.append("_QML_");
2800 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2802 QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2803 obj->dynamicProperties.count() +
2804 obj->dynamicSignals.count() +
2805 obj->dynamicSlots.count(),
2806 obj->dynamicProperties.count() +
2807 obj->dynamicSignals.count());
2809 cache->_dynamicClassName = newClassName;
2811 int cStringNameCount = 0;
2814 int varPropCount = 0;
2816 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2817 p = obj->dynamicProperties.next(p)) {
2819 if (p->type == Object::DynamicProperty::Alias)
2821 else if (p->type == Object::DynamicProperty::Var)
2824 if (p->name.isLatin1()) {
2825 p->nameIndex = cStringNameCount;
2826 cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2829 // No point doing this for both the alias and non alias cases
2830 QQmlPropertyData *d = property(obj, p->name);
2831 if (d && d->isFinal())
2832 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2835 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2836 if (s->name.isLatin1()) {
2837 s->nameIndex = cStringNameCount;
2838 cStringNameCount += s->name.length();
2842 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2843 if (s->name.isLatin1()) {
2844 s->nameIndex = cStringNameCount;
2845 cStringNameCount += s->name.length();
2849 char *cStringData = 0;
2850 if (cStringNameCount) {
2851 cache->_dynamicStringData.resize(cStringNameCount);
2852 cStringData = cache->_dynamicStringData.data();
2854 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2855 p = obj->dynamicProperties.next(p)) {
2857 if (p->nameIndex == -1) continue;
2859 char *myData = cStringData + p->nameIndex;
2860 for (int ii = 0; ii < p->name.length(); ++ii)
2861 *myData++ = p->name.at(ii).unicode();
2862 *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2863 *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2866 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2868 if (s->nameIndex == -1) continue;
2870 char *myData = cStringData + s->nameIndex;
2871 for (int ii = 0; ii < s->name.length(); ++ii)
2872 *myData++ = s->name.at(ii).unicode();
2875 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2876 s = obj->dynamicSignals.next(s)) {
2878 if (s->nameIndex == -1) continue;
2880 char *myData = cStringData + s->nameIndex;
2881 for (int ii = 0; ii < s->name.length(); ++ii)
2882 *myData++ = s->name.at(ii).unicode();
2886 QByteArray dynamicData;
2887 typedef QQmlVMEMetaData VMD;
2889 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2890 obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2891 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2892 aliasCount * sizeof(VMD::AliasData), 0);
2894 int effectivePropertyIndex = cache->propertyIndexCacheStart;
2895 int effectiveMethodIndex = cache->methodIndexCacheStart;
2897 // First set up notify signals for properties - first normal, then var, then alias
2898 enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2899 for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2901 if (ii == NSS_Var && varPropCount == 0) continue;
2902 else if (ii == NSS_Alias && aliasCount == 0) continue;
2904 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2905 p = obj->dynamicProperties.next(p)) {
2907 if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2908 p->type == Object::DynamicProperty::Var)) ||
2909 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2910 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2913 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2914 QQmlPropertyData::IsVMESignal;
2916 if (p->nameIndex != -1) {
2917 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2918 p->name.length() + 7 /* strlen("Changed") */);
2919 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2921 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2923 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2929 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2930 int paramCount = s->parameterNames.count();
2932 QList<QByteArray> names;
2933 QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2936 paramTypes[0] = paramCount;
2938 for (int i = 0; i < paramCount; ++i) {
2939 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2940 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2941 names.append(s->parameterNames.at(i).toString().toUtf8());
2945 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2947 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2948 QQmlPropertyData::IsVMESignal;
2950 flags |= QQmlPropertyData::HasArguments;
2952 if (s->nameIndex != -1) {
2953 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2954 cache->appendSignal(name, flags, effectiveMethodIndex++,
2955 paramCount?paramTypes.constData():0, names);
2957 QString name = s->name.toString();
2958 cache->appendSignal(name, flags, effectiveMethodIndex++,
2959 paramCount?paramTypes.constData():0, names);
2965 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2966 int paramCount = s->parameterNames.count();
2968 quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
2971 flags |= QQmlPropertyData::HasArguments;
2973 if (s->nameIndex != -1) {
2974 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2975 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2977 QString name = s->name.toString();
2978 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2983 // Dynamic properties (except var and aliases)
2984 effectiveMethodIndex = cache->methodIndexCacheStart;
2985 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2986 p = obj->dynamicProperties.next(p)) {
2988 if (p->type == Object::DynamicProperty::Alias ||
2989 p->type == Object::DynamicProperty::Var)
2992 int propertyType = 0;
2993 int vmePropertyType = 0;
2994 quint32 propertyFlags = 0;
2996 if (p->type < builtinTypeCount) {
2997 propertyType = builtinTypes[p->type].metaType;
2998 vmePropertyType = propertyType;
3000 if (p->type == Object::DynamicProperty::Variant)
3001 propertyFlags |= QQmlPropertyData::IsQVariant;
3003 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3004 p->type == Object::DynamicProperty::Custom);
3006 QQmlType *qmltype = 0;
3008 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3009 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3012 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3014 Q_ASSERT(tdata->isComplete());
3016 QQmlCompiledData *data = tdata->compiledData();
3018 if (p->type == Object::DynamicProperty::Custom) {
3019 propertyType = data->metaTypeId;
3020 vmePropertyType = QMetaType::QObjectStar;
3022 propertyType = data->listMetaTypeId;
3023 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3028 if (p->type == Object::DynamicProperty::Custom) {
3029 propertyType = qmltype->typeId();
3030 vmePropertyType = QMetaType::QObjectStar;
3032 propertyType = qmltype->qListTypeId();
3033 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3037 if (p->type == Object::DynamicProperty::Custom)
3038 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3040 propertyFlags |= QQmlPropertyData::IsQList;
3043 if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3044 propertyFlags |= QQmlPropertyData::IsWritable;
3046 if (p->nameIndex != -1) {
3047 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3049 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3050 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3051 propertyType, effectiveMethodIndex);
3053 QString propertyName = p->name.toString();
3054 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3055 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3056 propertyType, effectiveMethodIndex);
3059 effectiveMethodIndex++;
3061 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3062 (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3063 vmd->propertyCount++;
3066 // Now do var properties
3067 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3068 p = obj->dynamicProperties.next(p)) {
3070 if (p->type != Object::DynamicProperty::Var)
3073 quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3075 propertyFlags |= QQmlPropertyData::IsWritable;
3077 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3078 (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3079 vmd->propertyCount++;
3080 ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3082 if (p->nameIndex != -1) {
3083 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3085 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3086 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3087 QMetaType::QVariant, effectiveMethodIndex);
3089 QString propertyName = p->name.toString();
3090 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3091 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3092 QMetaType::QVariant, effectiveMethodIndex);
3095 effectiveMethodIndex++;
3098 // Alias property count. Actual data is setup in buildDynamicMetaAliases
3099 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3101 // Dynamic slot data - comes after the property data
3102 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3103 int paramCount = s->parameterNames.count();
3107 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3108 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3109 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3110 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3111 for (int jj = 0; jj < paramCount; ++jj) {
3112 if (jj) funcScript.append(QLatin1Char(','));
3113 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3115 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3117 QByteArray utf8 = funcScript.toUtf8();
3118 VMD::MethodData methodData = { s->parameterNames.count(),
3121 s->location.start.line };
3123 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3124 VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3128 dynamicData.append((const char *)utf8.constData(), utf8.length());
3132 compileState->aliasingObjects.append(obj);
3134 obj->synthdata = dynamicData;
3135 obj->synthCache = cache;
3136 obj->metatype = cache;
3141 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3143 Q_ASSERT(obj->synthCache);
3145 QByteArray &dynamicData = obj->synthdata;
3147 QQmlPropertyCache *cache = obj->synthCache;
3148 char *cStringData = cache->_dynamicStringData.data();
3150 int effectiveMethodIndex = cache->methodIndexCacheStart + cache->propertyIndexCache.count();
3151 int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3152 int effectiveAliasIndex = 0;
3154 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3155 p = obj->dynamicProperties.next(p)) {
3157 if (p->type != Object::DynamicProperty::Alias)
3160 if (!p->defaultValue)
3161 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3163 if (!p->defaultValue->values.isOne() ||
3164 p->defaultValue->values.first()->object ||
3165 !p->defaultValue->values.first()->value.isScript())
3166 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3168 QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3171 QStringList alias = astNodeToStringList(node);
3172 if (alias.count() < 1 || alias.count() > 3)
3173 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3175 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3177 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3180 int notifySignal = -1;
3183 bool writable = false;
3184 bool resettable = false;
3186 quint32 propertyFlags = QQmlPropertyData::IsAlias;
3188 if (alias.count() == 2 || alias.count() == 3) {
3189 QQmlPropertyData *property = this->property(idObject, alias.at(1));
3191 if (!property || property->coreIndex > 0xFFFF)
3192 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3194 propIdx = property->coreIndex;
3195 type = property->propType;
3197 writable = property->isWritable();
3198 resettable = property->isResettable();
3199 notifySignal = property->notifyIndex;
3201 if (alias.count() == 3) {
3202 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3204 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3206 propIdx |= ((unsigned int)type) << 24;
3207 int valueTypeIndex =
3208 valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3209 if (valueTypeIndex == -1)
3210 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3211 Q_ASSERT(valueTypeIndex <= 0xFF);
3213 propIdx |= (valueTypeIndex << 16);
3214 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3215 type = QVariant::Int;
3217 type = valueType->metaObject()->property(valueTypeIndex).userType();
3220 if (property->isEnum()) {
3221 type = QVariant::Int;
3224 propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3226 if (property->isVarProperty())
3227 propertyFlags |= QQmlPropertyData::IsQVariant;
3229 if (property->isQObject())
3230 flags |= QML_ALIAS_FLAG_PTR;
3234 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3236 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3238 type = ref.type->typeId();
3240 type = ref.component->metaTypeId;
3242 flags |= QML_ALIAS_FLAG_PTR;
3243 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3246 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3248 typedef QQmlVMEMetaData VMD;
3249 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3250 *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3252 if (!p->isReadOnly && writable)
3253 propertyFlags |= QQmlPropertyData::IsWritable;
3255 propertyFlags &= ~QQmlPropertyData::IsWritable;
3258 propertyFlags |= QQmlPropertyData::IsResettable;
3260 propertyFlags &= ~QQmlPropertyData::IsResettable;
3262 if (p->nameIndex != -1) {
3263 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3265 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3266 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3267 type, effectiveMethodIndex++);
3269 QString propertyName = p->name.toString();
3270 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3271 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3272 type, effectiveMethodIndex++);
3279 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3282 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3284 QChar ch = val.at(0);
3285 if (ch.isLetter() && !ch.isLower())
3286 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3288 QChar u(QLatin1Char('_'));
3289 if (!ch.isLetter() && ch != u)
3290 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3292 for (int ii = 1; ii < val.count(); ++ii) {
3294 if (!ch.isLetterOrNumber() && ch != u)
3295 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3298 if (enginePrivate->v8engine()->illegalNames().contains(val))
3299 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3304 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3305 QQmlScript::Property *prop,
3306 const BindingContext &ctxt)
3308 Q_ASSERT(prop->index != -1);
3309 Q_ASSERT(prop->parent);
3310 Q_ASSERT(prop->parent->metatype);
3312 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3313 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3315 JSBindingReference *reference = pool->New<JSBindingReference>();
3316 reference->expression = value->value;
3317 reference->property = prop;
3318 reference->value = value;
3319 reference->bindingContext = ctxt;
3320 addBindingReference(reference);
3325 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3326 QQmlScript::Property *prop,
3327 const QQmlCompilerTypes::BindingContext &)
3329 Q_ASSERT(v->value.isScript());
3331 if (!prop->core.isWritable())
3334 AST::Node *binding = v->value.asAST();
3336 if (prop->type == QVariant::String) {
3337 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3338 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3339 if (i->name == qsTrId_string) {
3340 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3341 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3343 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3344 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3345 (!arg2 || !arg2->next)) {
3350 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3351 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3353 TrBindingReference *reference = pool->New<TrBindingReference>();
3354 reference->dataType = BindingReference::TrId;
3355 reference->text = text;
3357 v->bindingReference = reference;
3361 } else if (i->name == qsTr_string) {
3363 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3364 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3365 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3367 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3368 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3369 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3370 (!arg3 || !arg3->next)) {
3376 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3377 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3378 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3380 TrBindingReference *reference = pool->New<TrBindingReference>();
3381 reference->dataType = BindingReference::Tr;
3382 reference->text = text;
3383 reference->comment = comment;
3385 v->bindingReference = reference;
3398 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3399 QQmlScript::Property *prop,
3400 QQmlScript::Object *obj,
3401 QQmlScript::Property *valueTypeProperty)
3404 Q_ASSERT(binding->bindingReference);
3406 const BindingReference &ref = *binding->bindingReference;
3407 if (ref.dataType == BindingReference::TrId) {
3408 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3410 Instruction::StoreTrIdString store;
3411 store.propertyIndex = prop->core.coreIndex;
3412 store.text = output->indexForByteArray(tr.text.toUtf8());
3414 output->addInstruction(store);
3415 } else if (ref.dataType == BindingReference::Tr) {
3416 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3418 Instruction::StoreTrString store;
3419 store.propertyIndex = prop->core.coreIndex;
3420 store.context = translationContextIndex();
3421 store.text = output->indexForByteArray(tr.text.toUtf8());
3422 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3424 output->addInstruction(store);
3425 } else if (ref.dataType == BindingReference::V4) {
3426 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3428 Instruction::StoreV4Binding store;
3429 store.value = js.compiledIndex;
3430 store.context = js.bindingContext.stack;
3431 store.owner = js.bindingContext.owner;
3432 store.isAlias = prop->isAlias;
3433 if (valueTypeProperty) {
3434 store.property = (valueTypeProperty->index & 0xFFFF) |
3435 ((valueTypeProperty->type & 0xFF)) << 16 |
3436 ((prop->index & 0xFF) << 24);
3437 store.isRoot = (compileState->root == valueTypeProperty->parent);
3439 store.property = prop->index;
3440 store.isRoot = (compileState->root == obj);
3442 store.line = binding->location.start.line;
3443 store.column = binding->location.start.column;
3444 output->addInstruction(store);
3445 } else if (ref.dataType == BindingReference::V8) {
3446 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3448 Instruction::StoreV8Binding store;
3449 store.value = js.compiledIndex;
3450 store.context = js.bindingContext.stack;
3451 store.owner = js.bindingContext.owner;
3452 store.isAlias = prop->isAlias;
3453 if (valueTypeProperty) {
3454 store.isRoot = (compileState->root == valueTypeProperty->parent);
3456 store.isRoot = (compileState->root == obj);
3458 store.line = binding->location.start.line;
3459 store.column = binding->location.start.column;
3461 Q_ASSERT(js.bindingContext.owner == 0 ||
3462 (js.bindingContext.owner != 0 && valueTypeProperty));
3463 if (js.bindingContext.owner) {
3464 store.property = genValueTypeData(prop, valueTypeProperty);
3466 store.property = prop->core;
3469 output->addInstruction(store);
3470 } else if (ref.dataType == BindingReference::QtScript) {
3471 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3473 Instruction::StoreBinding store;
3474 store.value = output->indexForString(js.rewrittenExpression);
3475 store.context = js.bindingContext.stack;
3476 store.owner = js.bindingContext.owner;
3477 store.line = binding->location.start.line;
3478 store.column = binding->location.start.column;
3479 store.isAlias = prop->isAlias;
3481 if (valueTypeProperty) {
3482 store.isRoot = (compileState->root == valueTypeProperty->parent);
3484 store.isRoot = (compileState->root == obj);
3487 Q_ASSERT(js.bindingContext.owner == 0 ||
3488 (js.bindingContext.owner != 0 && valueTypeProperty));
3489 if (js.bindingContext.owner) {
3490 store.property = genValueTypeData(prop, valueTypeProperty);
3492 store.property = prop->core;
3495 output->addInstruction(store);
3497 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3501 int QQmlCompiler::genContextCache()
3503 if (compileState->ids.count() == 0)
3506 QQmlIntegerCache *cache = new QQmlIntegerCache();
3507 cache->reserve(compileState->ids.count());
3508 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3509 cache->add(o->id, o->idIndex);
3511 output->contextCaches.append(cache);
3512 return output->contextCaches.count() - 1;
3516 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3517 QQmlScript::Property *prop)
3519 typedef QQmlPropertyPrivate QDPP;
3520 return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3521 valueTypeProp->index, engine);
3524 bool QQmlCompiler::completeComponentBuild()
3527 componentStats->componentStat.ids = compileState->ids.count();
3529 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3530 aliasObject = compileState->aliasingObjects.next(aliasObject))
3531 COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3533 QV4Compiler::Expression expr(unit->imports());
3534 expr.component = compileState->root;
3535 expr.ids = &compileState->ids;
3536 expr.importCache = output->importCache;
3538 QV4Compiler bindingCompiler;
3540 QList<JSBindingReference*> sharedBindings;
3542 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3544 JSBindingReference &binding = *b;
3547 expr.context = binding.bindingContext.object;
3548 expr.property = binding.property;
3549 expr.expression = binding.expression;
3551 int index = bindingCompiler.compile(expr, enginePrivate);
3553 binding.dataType = BindingReference::V4;
3554 binding.compiledIndex = index;
3556 componentStats->componentStat.optimizedBindings.append(b->value->location);
3560 // Pre-rewrite the expression
3561 QString expression = binding.expression.asScript();
3563 QQmlRewrite::RewriteBinding rewriteBinding;
3564 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3565 bool isSharable = false;
3566 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3568 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3569 binding.dataType = BindingReference::V8;
3570 sharedBindings.append(b);
3573 componentStats->componentStat.sharedBindings.append(b->value->location);
3575 binding.dataType = BindingReference::QtScript;
3578 componentStats->componentStat.scriptBindings.append(b->value->location);
3582 if (!sharedBindings.isEmpty()) {
3584 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3586 return lhs->value->location.start.line < rhs->value->location.start.line;
3590 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3592 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3593 int lineNumber = startLineNumber;
3595 QByteArray functionArray("[", 1);
3596 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3598 JSBindingReference *reference = sharedBindings.at(ii);
3599 QQmlScript::Value *value = reference->value;
3600 const QString &expression = reference->rewrittenExpression;
3602 if (ii != 0) functionArray.append(",", 1);
3604 while (lineNumber < value->location.start.line) {
3606 functionArray.append("\n", 1);
3609 functionArray += expression.toUtf8();
3610 lineNumber += expression.count(QLatin1Char('\n'));
3611 reference->compiledIndex = ii;
3613 functionArray.append("]", 1);
3615 compileState->v8BindingProgram = functionArray;
3616 compileState->v8BindingProgramLine = startLineNumber;
3619 if (bindingCompiler.isValid())
3620 compileState->compiledBindingData = bindingCompiler.program();
3622 // Check pop()'s matched push()'s
3623 Q_ASSERT(compileState->objectDepth.depth() == 0);
3624 Q_ASSERT(compileState->listDepth.depth() == 0);
3626 saveComponentState();
3631 void QQmlCompiler::dumpStats()
3633 Q_ASSERT(componentStats);
3634 qWarning().nospace() << "QML Document: " << output->url.toString();
3635 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3636 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3637 qWarning().nospace() << " Component Line " << stat.lineNumber;
3638 qWarning().nospace() << " Total Objects: " << stat.objects;
3639 qWarning().nospace() << " IDs Used: " << stat.ids;
3640 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3644 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3645 if (0 == (ii % 10)) {
3646 if (ii) output.append("\n");
3651 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3653 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3654 output.append(") ");
3656 if (!output.isEmpty())
3657 qWarning().nospace() << output.constData();
3660 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3663 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3664 if (0 == (ii % 10)) {
3665 if (ii) output.append('\n');
3670 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3672 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3673 output.append(") ");
3675 if (!output.isEmpty())
3676 qWarning().nospace() << output.constData();
3679 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3682 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3683 if (0 == (ii % 10)) {
3684 if (ii) output.append('\n');
3689 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3691 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3692 output.append(") ");
3694 if (!output.isEmpty())
3695 qWarning().nospace() << output.constData();
3701 Returns true if from can be assigned to a (QObject) property of type
3704 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3706 QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3707 QQmlPropertyCache *fromMo = from->metatype;
3712 fromMo = fromMo->parent();
3718 Returns the element name, as written in the QML file, for o.
3720 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3723 if (o->type != -1) {
3724 return unit->parser().referencedTypes().at(o->type)->name;
3730 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3732 if (from->type != -1 && output->types.at(from->type).type)
3733 return output->types.at(from->type).type;
3735 const QMetaObject *mo = from->metatype->firstCppMetaObject();
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->firstCppMetaObject();
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::propertyCacheForObject(QQmlScript::Object *object)
3760 if (object->synthCache)
3761 return object->synthCache;
3762 else if (object->type != -1)
3763 return output->types[object->type].createPropertyCache(engine);
3765 return object->metatype;
3769 QQmlCompiler::property(QQmlScript::Object *object, int index)
3771 QQmlPropertyCache *cache = propertyCacheForObject(object);
3773 return cache->property(index);
3777 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3779 if (notInRevision) *notInRevision = false;
3781 QQmlPropertyCache *cache = propertyCacheForObject(object);
3783 QQmlPropertyData *d = cache->property(name);
3785 // Find the first property
3786 while (d && d->isFunction())
3787 d = cache->overrideData(d);
3789 if (d && !cache->isAllowedInRevision(d)) {
3790 if (notInRevision) *notInRevision = true;
3797 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3799 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3801 if (notInRevision) *notInRevision = false;
3803 QQmlPropertyCache *cache = propertyCacheForObject(object);
3806 QQmlPropertyData *d = cache->property(name);
3807 if (notInRevision) *notInRevision = false;
3809 while (d && !(d->isFunction()))
3810 d = cache->overrideData(d);
3812 if (d && !cache->isAllowedInRevision(d)) {
3813 if (notInRevision) *notInRevision = true;
3819 if (name.endsWith(Changed_string)) {
3820 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3822 d = property(object, propName, notInRevision);
3824 return cache->method(d->notifyIndex);
3830 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3831 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3832 bool *notInRevision)
3834 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3835 return d?d->coreIndex:-1;
3838 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3839 bool *notInRevision)
3841 return indexOfProperty(object, QStringRef(&name), notInRevision);
3844 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3845 bool *notInRevision)
3847 QQmlPropertyData *d = property(object, name, notInRevision);
3848 return d?d->coreIndex:-1;