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 = propertyCacheForObject(obj)->methodIndexToSignalIndex(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 struct StaticQtMetaObject : public QObject
2485 static const QMetaObject *get()
2486 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2489 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2490 QQmlScript::Object *obj,
2491 QQmlScript::Value *v,
2494 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2495 *isAssignment = false;
2496 if (!prop->core.isEnum() && !isIntProp)
2499 QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2501 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2502 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2504 QString string = v->value.asString();
2505 if (!string.at(0).isUpper())
2508 int dot = string.indexOf(QLatin1Char('.'));
2509 if (dot == -1 || dot == string.length()-1)
2512 if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2515 QHashedStringRef typeName(string.constData(), dot);
2516 QString enumValue = string.mid(dot+1);
2519 // Allow enum assignment to ints.
2521 int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
2523 v->type = Value::Literal;
2524 v->value = QQmlScript::Variant((double)enumval);
2525 *isAssignment = true;
2531 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2533 if (!type && typeName != QLatin1String("Qt"))
2539 if (type && toQmlType(obj) == type) {
2540 // When these two match, we can short cut the search
2541 if (mprop.isFlagType()) {
2542 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2544 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2547 // Otherwise we have to search the whole type
2548 // This matches the logic in QV8TypeWrapper
2549 QByteArray enumName = enumValue.toUtf8();
2550 const QMetaObject *metaObject = type ? type->baseMetaObject() : StaticQtMetaObject::get();
2552 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2553 QMetaEnum e = metaObject->enumerator(ii);
2554 value = e.keyToValue(enumName.constData(), &ok);
2561 v->type = Value::Literal;
2562 v->value = QQmlScript::Variant((double)value);
2563 *isAssignment = true;
2568 // Similar logic to above, but not knowing target property.
2569 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
2571 Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
2574 if (scope != QLatin1String("Qt")) {
2575 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2580 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2581 int i = mo->enumeratorCount();
2583 int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
2590 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2592 QQmlType *qmltype = 0;
2593 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2597 return qmltype->metaObject();
2600 // similar to logic of completeComponentBuild, but also sticks data
2601 // into primitives at the end
2602 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2604 QQmlRewrite::RewriteBinding rewriteBinding;
2605 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2607 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2609 return output->indexForString(rewrite);
2612 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2614 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2615 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2618 // Ensures that the dynamic meta specification on obj is valid
2619 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2621 bool seenDefaultProperty = false;
2623 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2624 // Calculating the hash for the names is not a waste as we have to test
2625 // them against the illegalNames set anyway.
2626 QHashField propNames;
2627 QHashField methodNames;
2630 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2631 const QQmlScript::Object::DynamicProperty &prop = *p;
2633 if (prop.isDefaultProperty) {
2634 if (seenDefaultProperty)
2635 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2636 seenDefaultProperty = true;
2639 if (propNames.testAndSet(prop.name.hash())) {
2640 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2641 p2 = obj->dynamicProperties.next(p2)) {
2642 if (p2->name == prop.name) {
2643 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2644 prop.nameLocation.column,
2645 tr("Duplicate property name"));
2650 if (prop.name.at(0).isUpper()) {
2651 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2652 prop.nameLocation.column,
2653 tr("Property names cannot begin with an upper case letter"));
2656 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2657 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2658 prop.nameLocation.column,
2659 tr("Illegal property name"));
2663 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2664 const QQmlScript::Object::DynamicSignal &currSig = *s;
2666 if (methodNames.testAndSet(currSig.name.hash())) {
2667 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2668 s2 = obj->dynamicSignals.next(s2)) {
2669 if (s2->name == currSig.name)
2670 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2674 if (currSig.name.at(0).isUpper())
2675 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2676 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2677 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2680 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2681 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2683 if (methodNames.testAndSet(currSlot.name.hash())) {
2684 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2685 s2 = obj->dynamicSignals.next(s2)) {
2686 if (s2->name == currSlot.name)
2687 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2689 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2690 s2 = obj->dynamicSlots.next(s2)) {
2691 if (s2->name == currSlot.name)
2692 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2696 if (currSlot.name.at(0).isUpper())
2697 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2698 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2699 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2705 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2707 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2708 p = obj->dynamicProperties.next(p)) {
2710 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2713 Property *property = 0;
2714 if (p->isDefaultProperty) {
2715 property = obj->getDefaultProperty();
2717 property = obj->getProperty(p->name);
2718 if (!property->values.isEmpty())
2719 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2723 property->isReadOnlyDeclaration = true;
2725 if (property->value)
2726 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2728 property->values.append(p->defaultValue->values);
2733 #include <private/qqmljsparser_p.h>
2735 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2737 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2739 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2740 return QStringList() << name;
2741 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2742 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2744 QStringList rv = astNodeToStringList(expr->base);
2747 rv.append(expr->name.toString());
2750 return QStringList();
2753 static QAtomicInt classIndexCounter(0);
2755 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2758 Q_ASSERT(obj->metatype);
2760 if (mode != ForceCreation &&
2761 obj->dynamicProperties.isEmpty() &&
2762 obj->dynamicSignals.isEmpty() &&
2763 obj->dynamicSlots.isEmpty())
2766 Q_ASSERT(obj->synthCache == 0);
2769 Object::DynamicProperty::Type dtype;
2771 } builtinTypes[] = {
2772 { Object::DynamicProperty::Var, QMetaType::QVariant },
2773 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2774 { Object::DynamicProperty::Int, QMetaType::Int },
2775 { Object::DynamicProperty::Bool, QMetaType::Bool },
2776 { Object::DynamicProperty::Real, QMetaType::Double },
2777 { Object::DynamicProperty::String, QMetaType::QString },
2778 { Object::DynamicProperty::Url, QMetaType::QUrl },
2779 { Object::DynamicProperty::Color, QMetaType::QColor },
2780 { Object::DynamicProperty::Time, QMetaType::QTime },
2781 { Object::DynamicProperty::Date, QMetaType::QDate },
2782 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2783 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2785 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2787 QByteArray newClassName;
2789 if (compileState->root == obj && !compileState->nested) {
2790 QString path = output->url.path();
2791 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2792 if (lastSlash > -1) {
2793 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2794 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2795 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2796 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2799 if (newClassName.isEmpty()) {
2800 newClassName = QQmlMetaObject(obj->metatype).className();
2801 newClassName.append("_QML_");
2802 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2804 QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2805 obj->dynamicProperties.count() +
2806 obj->dynamicSignals.count() +
2807 obj->dynamicSlots.count(),
2808 obj->dynamicProperties.count() +
2809 obj->dynamicSignals.count());
2811 cache->_dynamicClassName = newClassName;
2813 int cStringNameCount = 0;
2816 int varPropCount = 0;
2818 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2819 p = obj->dynamicProperties.next(p)) {
2821 if (p->type == Object::DynamicProperty::Alias)
2823 else if (p->type == Object::DynamicProperty::Var)
2826 if (p->name.isLatin1()) {
2827 p->nameIndex = cStringNameCount;
2828 cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2831 // No point doing this for both the alias and non alias cases
2832 QQmlPropertyData *d = property(obj, p->name);
2833 if (d && d->isFinal())
2834 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2837 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2838 if (s->name.isLatin1()) {
2839 s->nameIndex = cStringNameCount;
2840 cStringNameCount += s->name.length();
2844 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2845 if (s->name.isLatin1()) {
2846 s->nameIndex = cStringNameCount;
2847 cStringNameCount += s->name.length();
2851 char *cStringData = 0;
2852 if (cStringNameCount) {
2853 cache->_dynamicStringData.resize(cStringNameCount);
2854 cStringData = cache->_dynamicStringData.data();
2856 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2857 p = obj->dynamicProperties.next(p)) {
2859 if (p->nameIndex == -1) continue;
2861 char *myData = cStringData + p->nameIndex;
2862 for (int ii = 0; ii < p->name.length(); ++ii)
2863 *myData++ = p->name.at(ii).unicode();
2864 *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2865 *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2868 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2870 if (s->nameIndex == -1) continue;
2872 char *myData = cStringData + s->nameIndex;
2873 for (int ii = 0; ii < s->name.length(); ++ii)
2874 *myData++ = s->name.at(ii).unicode();
2877 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2878 s = obj->dynamicSignals.next(s)) {
2880 if (s->nameIndex == -1) continue;
2882 char *myData = cStringData + s->nameIndex;
2883 for (int ii = 0; ii < s->name.length(); ++ii)
2884 *myData++ = s->name.at(ii).unicode();
2888 QByteArray dynamicData;
2889 typedef QQmlVMEMetaData VMD;
2891 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2892 obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2893 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2894 aliasCount * sizeof(VMD::AliasData), 0);
2896 int effectivePropertyIndex = cache->propertyIndexCacheStart;
2897 int effectiveMethodIndex = cache->methodIndexCacheStart;
2899 // First set up notify signals for properties - first normal, then var, then alias
2900 enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2901 for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2903 if (ii == NSS_Var && varPropCount == 0) continue;
2904 else if (ii == NSS_Alias && aliasCount == 0) continue;
2906 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2907 p = obj->dynamicProperties.next(p)) {
2909 if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2910 p->type == Object::DynamicProperty::Var)) ||
2911 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2912 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2915 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2916 QQmlPropertyData::IsVMESignal;
2918 if (p->nameIndex != -1) {
2919 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2920 p->name.length() + 7 /* strlen("Changed") */);
2921 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2923 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2925 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2931 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2932 int paramCount = s->parameterNames.count();
2934 QList<QByteArray> names;
2935 QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2938 paramTypes[0] = paramCount;
2940 for (int i = 0; i < paramCount; ++i) {
2941 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2942 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2943 names.append(s->parameterNames.at(i).toString().toUtf8());
2947 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2949 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2950 QQmlPropertyData::IsVMESignal;
2952 flags |= QQmlPropertyData::HasArguments;
2954 if (s->nameIndex != -1) {
2955 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2956 cache->appendSignal(name, flags, effectiveMethodIndex++,
2957 paramCount?paramTypes.constData():0, names);
2959 QString name = s->name.toString();
2960 cache->appendSignal(name, flags, effectiveMethodIndex++,
2961 paramCount?paramTypes.constData():0, names);
2967 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2968 int paramCount = s->parameterNames.count();
2970 quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
2973 flags |= QQmlPropertyData::HasArguments;
2975 if (s->nameIndex != -1) {
2976 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2977 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2979 QString name = s->name.toString();
2980 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2985 // Dynamic properties (except var and aliases)
2986 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
2987 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2988 p = obj->dynamicProperties.next(p)) {
2990 if (p->type == Object::DynamicProperty::Alias ||
2991 p->type == Object::DynamicProperty::Var)
2994 int propertyType = 0;
2995 int vmePropertyType = 0;
2996 quint32 propertyFlags = 0;
2998 if (p->type < builtinTypeCount) {
2999 propertyType = builtinTypes[p->type].metaType;
3000 vmePropertyType = propertyType;
3002 if (p->type == Object::DynamicProperty::Variant)
3003 propertyFlags |= QQmlPropertyData::IsQVariant;
3005 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3006 p->type == Object::DynamicProperty::Custom);
3008 QQmlType *qmltype = 0;
3010 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3011 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3014 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3016 Q_ASSERT(tdata->isComplete());
3018 QQmlCompiledData *data = tdata->compiledData();
3020 if (p->type == Object::DynamicProperty::Custom) {
3021 propertyType = data->metaTypeId;
3022 vmePropertyType = QMetaType::QObjectStar;
3024 propertyType = data->listMetaTypeId;
3025 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3030 if (p->type == Object::DynamicProperty::Custom) {
3031 propertyType = qmltype->typeId();
3032 vmePropertyType = QMetaType::QObjectStar;
3034 propertyType = qmltype->qListTypeId();
3035 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3039 if (p->type == Object::DynamicProperty::Custom)
3040 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3042 propertyFlags |= QQmlPropertyData::IsQList;
3045 if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3046 propertyFlags |= QQmlPropertyData::IsWritable;
3048 if (p->nameIndex != -1) {
3049 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3051 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3052 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3053 propertyType, effectiveSignalIndex);
3055 QString propertyName = p->name.toString();
3056 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3057 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3058 propertyType, effectiveSignalIndex);
3061 effectiveSignalIndex++;
3063 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3064 (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3065 vmd->propertyCount++;
3068 // Now do var properties
3069 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3070 p = obj->dynamicProperties.next(p)) {
3072 if (p->type != Object::DynamicProperty::Var)
3075 quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3077 propertyFlags |= QQmlPropertyData::IsWritable;
3079 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3080 (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3081 vmd->propertyCount++;
3082 ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3084 if (p->nameIndex != -1) {
3085 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3087 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3088 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3089 QMetaType::QVariant, effectiveSignalIndex);
3091 QString propertyName = p->name.toString();
3092 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3093 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3094 QMetaType::QVariant, effectiveSignalIndex);
3097 effectiveSignalIndex++;
3100 // Alias property count. Actual data is setup in buildDynamicMetaAliases
3101 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3103 // Dynamic slot data - comes after the property data
3104 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3105 int paramCount = s->parameterNames.count();
3109 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3110 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3111 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3112 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3113 for (int jj = 0; jj < paramCount; ++jj) {
3114 if (jj) funcScript.append(QLatin1Char(','));
3115 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3117 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3119 QByteArray utf8 = funcScript.toUtf8();
3120 VMD::MethodData methodData = { s->parameterNames.count(),
3123 s->location.start.line };
3125 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3126 VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3130 dynamicData.append((const char *)utf8.constData(), utf8.length());
3134 compileState->aliasingObjects.append(obj);
3136 obj->synthdata = dynamicData;
3137 obj->synthCache = cache;
3138 obj->metatype = cache;
3143 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3145 Q_ASSERT(obj->synthCache);
3147 QByteArray &dynamicData = obj->synthdata;
3149 QQmlPropertyCache *cache = obj->synthCache;
3150 char *cStringData = cache->_dynamicStringData.data();
3152 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
3153 int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3154 int effectiveAliasIndex = 0;
3156 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3157 p = obj->dynamicProperties.next(p)) {
3159 if (p->type != Object::DynamicProperty::Alias)
3162 if (!p->defaultValue)
3163 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3165 if (!p->defaultValue->values.isOne() ||
3166 p->defaultValue->values.first()->object ||
3167 !p->defaultValue->values.first()->value.isScript())
3168 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3170 QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3173 QStringList alias = astNodeToStringList(node);
3174 if (alias.count() < 1 || alias.count() > 3)
3175 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3177 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3179 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3182 int notifySignal = -1;
3185 bool writable = false;
3186 bool resettable = false;
3188 quint32 propertyFlags = QQmlPropertyData::IsAlias;
3190 if (alias.count() == 2 || alias.count() == 3) {
3191 QQmlPropertyData *property = this->property(idObject, alias.at(1));
3193 if (!property || property->coreIndex > 0xFFFF)
3194 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3196 propIdx = property->coreIndex;
3197 type = property->propType;
3199 writable = property->isWritable();
3200 resettable = property->isResettable();
3201 notifySignal = property->notifyIndex;
3203 if (alias.count() == 3) {
3204 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3206 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3208 propIdx |= ((unsigned int)type) << 24;
3209 int valueTypeIndex =
3210 valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3211 if (valueTypeIndex == -1)
3212 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3213 Q_ASSERT(valueTypeIndex <= 0xFF);
3215 propIdx |= (valueTypeIndex << 16);
3216 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3217 type = QVariant::Int;
3219 type = valueType->metaObject()->property(valueTypeIndex).userType();
3222 if (property->isEnum()) {
3223 type = QVariant::Int;
3226 propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3228 if (property->isVarProperty())
3229 propertyFlags |= QQmlPropertyData::IsQVariant;
3231 if (property->isQObject())
3232 flags |= QML_ALIAS_FLAG_PTR;
3236 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3238 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3240 type = ref.type->typeId();
3242 type = ref.component->metaTypeId;
3244 flags |= QML_ALIAS_FLAG_PTR;
3245 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3248 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3250 typedef QQmlVMEMetaData VMD;
3251 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3252 *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3254 if (!p->isReadOnly && writable)
3255 propertyFlags |= QQmlPropertyData::IsWritable;
3257 propertyFlags &= ~QQmlPropertyData::IsWritable;
3260 propertyFlags |= QQmlPropertyData::IsResettable;
3262 propertyFlags &= ~QQmlPropertyData::IsResettable;
3264 if (p->nameIndex != -1) {
3265 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3267 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3268 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3269 type, effectiveSignalIndex++);
3271 QString propertyName = p->name.toString();
3272 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3273 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3274 type, effectiveSignalIndex++);
3281 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3284 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3286 QChar ch = val.at(0);
3287 if (ch.isLetter() && !ch.isLower())
3288 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3290 QChar u(QLatin1Char('_'));
3291 if (!ch.isLetter() && ch != u)
3292 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3294 for (int ii = 1; ii < val.count(); ++ii) {
3296 if (!ch.isLetterOrNumber() && ch != u)
3297 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3300 if (enginePrivate->v8engine()->illegalNames().contains(val))
3301 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3306 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3307 QQmlScript::Property *prop,
3308 const BindingContext &ctxt)
3310 Q_ASSERT(prop->index != -1);
3311 Q_ASSERT(prop->parent);
3312 Q_ASSERT(prop->parent->metatype);
3314 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3315 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3317 JSBindingReference *reference = pool->New<JSBindingReference>();
3318 reference->expression = value->value;
3319 reference->property = prop;
3320 reference->value = value;
3321 reference->bindingContext = ctxt;
3322 addBindingReference(reference);
3327 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3328 QQmlScript::Property *prop,
3329 const QQmlCompilerTypes::BindingContext &)
3331 Q_ASSERT(v->value.isScript());
3333 if (!prop->core.isWritable())
3336 AST::Node *binding = v->value.asAST();
3338 if (prop->type == QVariant::String) {
3339 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3340 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3341 if (i->name == qsTrId_string) {
3342 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3343 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3345 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3346 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3347 (!arg2 || !arg2->next)) {
3352 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3353 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3355 TrBindingReference *reference = pool->New<TrBindingReference>();
3356 reference->dataType = BindingReference::TrId;
3357 reference->text = text;
3359 v->bindingReference = reference;
3363 } else if (i->name == qsTr_string) {
3365 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3366 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3367 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3369 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3370 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3371 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3372 (!arg3 || !arg3->next)) {
3378 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3379 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3380 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3382 TrBindingReference *reference = pool->New<TrBindingReference>();
3383 reference->dataType = BindingReference::Tr;
3384 reference->text = text;
3385 reference->comment = comment;
3387 v->bindingReference = reference;
3400 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3401 QQmlScript::Property *prop,
3402 QQmlScript::Object *obj,
3403 QQmlScript::Property *valueTypeProperty)
3406 Q_ASSERT(binding->bindingReference);
3408 const BindingReference &ref = *binding->bindingReference;
3409 if (ref.dataType == BindingReference::TrId) {
3410 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3412 Instruction::StoreTrIdString store;
3413 store.propertyIndex = prop->core.coreIndex;
3414 store.text = output->indexForByteArray(tr.text.toUtf8());
3416 output->addInstruction(store);
3417 } else if (ref.dataType == BindingReference::Tr) {
3418 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3420 Instruction::StoreTrString store;
3421 store.propertyIndex = prop->core.coreIndex;
3422 store.context = translationContextIndex();
3423 store.text = output->indexForByteArray(tr.text.toUtf8());
3424 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3426 output->addInstruction(store);
3427 } else if (ref.dataType == BindingReference::V4) {
3428 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3430 Instruction::StoreV4Binding store;
3431 store.value = js.compiledIndex;
3432 store.context = js.bindingContext.stack;
3433 store.owner = js.bindingContext.owner;
3434 store.isAlias = prop->isAlias;
3435 if (valueTypeProperty) {
3436 store.property = (valueTypeProperty->index & 0xFFFF) |
3437 ((valueTypeProperty->type & 0xFF)) << 16 |
3438 ((prop->index & 0xFF) << 24);
3439 store.isRoot = (compileState->root == valueTypeProperty->parent);
3441 store.property = prop->index;
3442 store.isRoot = (compileState->root == obj);
3444 store.line = binding->location.start.line;
3445 store.column = binding->location.start.column;
3446 output->addInstruction(store);
3447 } else if (ref.dataType == BindingReference::V8) {
3448 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3450 Instruction::StoreV8Binding store;
3451 store.value = js.compiledIndex;
3452 store.context = js.bindingContext.stack;
3453 store.owner = js.bindingContext.owner;
3454 store.isAlias = prop->isAlias;
3455 if (valueTypeProperty) {
3456 store.isRoot = (compileState->root == valueTypeProperty->parent);
3458 store.isRoot = (compileState->root == obj);
3460 store.line = binding->location.start.line;
3461 store.column = binding->location.start.column;
3463 Q_ASSERT(js.bindingContext.owner == 0 ||
3464 (js.bindingContext.owner != 0 && valueTypeProperty));
3465 if (js.bindingContext.owner) {
3466 store.property = genValueTypeData(prop, valueTypeProperty);
3468 store.property = prop->core;
3471 output->addInstruction(store);
3472 } else if (ref.dataType == BindingReference::QtScript) {
3473 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3475 Instruction::StoreBinding store;
3476 store.value = output->indexForString(js.rewrittenExpression);
3477 store.context = js.bindingContext.stack;
3478 store.owner = js.bindingContext.owner;
3479 store.line = binding->location.start.line;
3480 store.column = binding->location.start.column;
3481 store.isAlias = prop->isAlias;
3483 if (valueTypeProperty) {
3484 store.isRoot = (compileState->root == valueTypeProperty->parent);
3486 store.isRoot = (compileState->root == obj);
3489 Q_ASSERT(js.bindingContext.owner == 0 ||
3490 (js.bindingContext.owner != 0 && valueTypeProperty));
3491 if (js.bindingContext.owner) {
3492 store.property = genValueTypeData(prop, valueTypeProperty);
3494 store.property = prop->core;
3497 output->addInstruction(store);
3499 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3503 int QQmlCompiler::genContextCache()
3505 if (compileState->ids.count() == 0)
3508 QQmlIntegerCache *cache = new QQmlIntegerCache();
3509 cache->reserve(compileState->ids.count());
3510 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3511 cache->add(o->id, o->idIndex);
3513 output->contextCaches.append(cache);
3514 return output->contextCaches.count() - 1;
3518 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3519 QQmlScript::Property *prop)
3521 typedef QQmlPropertyPrivate QDPP;
3522 return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3523 valueTypeProp->index, engine);
3526 bool QQmlCompiler::completeComponentBuild()
3529 componentStats->componentStat.ids = compileState->ids.count();
3531 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3532 aliasObject = compileState->aliasingObjects.next(aliasObject))
3533 COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3535 QV4Compiler::Expression expr(unit->imports());
3536 expr.component = compileState->root;
3537 expr.ids = &compileState->ids;
3538 expr.importCache = output->importCache;
3540 QV4Compiler bindingCompiler;
3542 QList<JSBindingReference*> sharedBindings;
3544 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3546 JSBindingReference &binding = *b;
3549 expr.context = binding.bindingContext.object;
3550 expr.property = binding.property;
3551 expr.expression = binding.expression;
3553 int index = bindingCompiler.compile(expr, enginePrivate);
3555 binding.dataType = BindingReference::V4;
3556 binding.compiledIndex = index;
3558 componentStats->componentStat.optimizedBindings.append(b->value->location);
3562 // Pre-rewrite the expression
3563 QString expression = binding.expression.asScript();
3565 QQmlRewrite::RewriteBinding rewriteBinding;
3566 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3567 bool isSharable = false;
3568 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3570 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3571 binding.dataType = BindingReference::V8;
3572 sharedBindings.append(b);
3575 componentStats->componentStat.sharedBindings.append(b->value->location);
3577 binding.dataType = BindingReference::QtScript;
3580 componentStats->componentStat.scriptBindings.append(b->value->location);
3584 if (!sharedBindings.isEmpty()) {
3586 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3588 return lhs->value->location.start.line < rhs->value->location.start.line;
3592 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3594 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3595 int lineNumber = startLineNumber;
3597 QByteArray functionArray("[", 1);
3598 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3600 JSBindingReference *reference = sharedBindings.at(ii);
3601 QQmlScript::Value *value = reference->value;
3602 const QString &expression = reference->rewrittenExpression;
3604 if (ii != 0) functionArray.append(",", 1);
3606 while (lineNumber < value->location.start.line) {
3608 functionArray.append("\n", 1);
3611 functionArray += expression.toUtf8();
3612 lineNumber += expression.count(QLatin1Char('\n'));
3613 reference->compiledIndex = ii;
3615 functionArray.append("]", 1);
3617 compileState->v8BindingProgram = functionArray;
3618 compileState->v8BindingProgramLine = startLineNumber;
3621 if (bindingCompiler.isValid())
3622 compileState->compiledBindingData = bindingCompiler.program();
3624 // Check pop()'s matched push()'s
3625 Q_ASSERT(compileState->objectDepth.depth() == 0);
3626 Q_ASSERT(compileState->listDepth.depth() == 0);
3628 saveComponentState();
3633 void QQmlCompiler::dumpStats()
3635 Q_ASSERT(componentStats);
3636 qWarning().nospace() << "QML Document: " << output->url.toString();
3637 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3638 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3639 qWarning().nospace() << " Component Line " << stat.lineNumber;
3640 qWarning().nospace() << " Total Objects: " << stat.objects;
3641 qWarning().nospace() << " IDs Used: " << stat.ids;
3642 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3646 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3647 if (0 == (ii % 10)) {
3648 if (ii) output.append("\n");
3653 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3655 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3656 output.append(") ");
3658 if (!output.isEmpty())
3659 qWarning().nospace() << output.constData();
3662 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3665 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3666 if (0 == (ii % 10)) {
3667 if (ii) output.append('\n');
3672 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3674 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3675 output.append(") ");
3677 if (!output.isEmpty())
3678 qWarning().nospace() << output.constData();
3681 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3684 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3685 if (0 == (ii % 10)) {
3686 if (ii) output.append('\n');
3691 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3693 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3694 output.append(") ");
3696 if (!output.isEmpty())
3697 qWarning().nospace() << output.constData();
3703 Returns true if from can be assigned to a (QObject) property of type
3706 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3708 QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3709 QQmlPropertyCache *fromMo = from->metatype;
3714 fromMo = fromMo->parent();
3720 Returns the element name, as written in the QML file, for o.
3722 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3725 if (o->type != -1) {
3726 return unit->parser().referencedTypes().at(o->type)->name;
3732 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3734 if (from->type != -1 && output->types.at(from->type).type)
3735 return output->types.at(from->type).type;
3737 const QMetaObject *mo = from->metatype->firstCppMetaObject();
3739 while (!type && mo) {
3740 type = QQmlMetaType::qmlType(mo);
3741 mo = mo->superClass();
3746 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3748 const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3750 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3752 return QStringList();
3754 QMetaClassInfo classInfo = mo->classInfo(idx);
3755 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3760 QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
3762 if (object->synthCache)
3763 return object->synthCache;
3764 else if (object->type != -1)
3765 return output->types[object->type].createPropertyCache(engine);
3767 return object->metatype;
3771 QQmlCompiler::property(QQmlScript::Object *object, int index)
3773 QQmlPropertyCache *cache = propertyCacheForObject(object);
3775 return cache->property(index);
3779 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3781 if (notInRevision) *notInRevision = false;
3783 QQmlPropertyCache *cache = propertyCacheForObject(object);
3785 QQmlPropertyData *d = cache->property(name);
3787 // Find the first property
3788 while (d && d->isFunction())
3789 d = cache->overrideData(d);
3791 if (d && !cache->isAllowedInRevision(d)) {
3792 if (notInRevision) *notInRevision = true;
3799 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3801 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3803 if (notInRevision) *notInRevision = false;
3805 QQmlPropertyCache *cache = propertyCacheForObject(object);
3808 QQmlPropertyData *d = cache->property(name);
3809 if (notInRevision) *notInRevision = false;
3811 while (d && !(d->isFunction()))
3812 d = cache->overrideData(d);
3814 if (d && !cache->isAllowedInRevision(d)) {
3815 if (notInRevision) *notInRevision = true;
3817 } else if (d && d->isSignal()) {
3821 if (name.endsWith(Changed_string)) {
3822 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3824 d = property(object, propName, notInRevision);
3826 return cache->signal(d->notifyIndex);
3832 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3833 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3834 bool *notInRevision)
3836 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3837 return d?d->coreIndex:-1;
3840 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3841 bool *notInRevision)
3843 return indexOfProperty(object, QStringRef(&name), notInRevision);
3846 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3847 bool *notInRevision)
3849 QQmlPropertyData *d = property(object, name, notInRevision);
3850 return d?d->coreIndex:-1;