1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcompiler_p.h"
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qqmlstringconverters_p.h"
49 #include "qqmlengine_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlcontext.h"
52 #include "qqmlmetatype_p.h"
53 #include "qqmlcustomparser_p_p.h"
54 #include "qqmlcontext_p.h"
55 #include "qqmlcomponent_p.h"
56 #include <private/qqmljsast_p.h>
57 #include "qqmlvmemetaobject_p.h"
58 #include "qqmlexpression_p.h"
59 #include "qqmlproperty_p.h"
60 #include "qqmlrewrite_p.h"
61 #include "qqmlscriptstring.h"
62 #include "qqmlglobal_p.h"
63 #include "qqmlbinding_p.h"
64 #include <private/qv4compiler_p.h>
71 #include <QtCore/qdebug.h>
72 #include <QtCore/qdatetime.h>
73 #include <QtCore/qvarlengtharray.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
80 Q_DECLARE_METATYPE(QJSValue)
84 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
85 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
87 using namespace QQmlJS;
88 using namespace QQmlScript;
89 using namespace QQmlCompilerTypes;
91 static QString id_string(QLatin1String("id"));
92 static QString on_string(QLatin1String("on"));
93 static QString Changed_string(QLatin1String("Changed"));
94 static QString Component_string(QLatin1String("Component"));
95 static QString Component_module_string(QLatin1String("QML"));
96 static QString qsTr_string(QLatin1String("qsTr"));
97 static QString qsTrId_string(QLatin1String("qsTrId"));
100 Instantiate a new QQmlCompiler.
102 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
103 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
104 cachedTranslationContextIndex(-1), componentStats(0)
106 if (compilerStatDump())
107 componentStats = pool->New<ComponentStats>();
111 Returns true if the last call to compile() caused errors.
115 bool QQmlCompiler::isError() const
117 return !exceptions.isEmpty();
121 Return the list of errors from the last call to compile(), or an empty list
122 if there were no errors.
124 QList<QQmlError> QQmlCompiler::errors() const
130 Returns true if \a name refers to an attached property, false otherwise.
132 Attached property names are those that start with a capital letter.
134 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
136 return isAttachedPropertyName(QHashedStringRef(&name));
139 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
141 return !name.isEmpty() && name.at(0).isUpper();
145 Returns true if \a name refers to a signal property, false otherwise.
147 Signal property names are those that start with "on", followed by a first
148 character which is either a capital letter or one or more underscores followed
149 by a capital letter, which is then followed by other allowed characters.
151 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
152 character codes in property names, for simplicity and performance reasons
153 QML only supports letters, numbers and underscores.
155 bool QQmlCompiler::isSignalPropertyName(const QString &name)
157 return isSignalPropertyName(QStringRef(&name));
160 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
162 if (name.length() < 3) return false;
163 if (!name.startsWith(on_string)) return false;
164 int ns = name.length();
165 for (int i = 2; i < ns; ++i) {
166 const QChar curr = name.at(i);
167 if (curr.unicode() == '_') continue;
168 if (curr.isUpper()) return true;
171 return false; // consists solely of underscores - invalid.
175 \macro COMPILE_EXCEPTION
177 Inserts an error into the QQmlCompiler error list, and returns false
180 \a token is used to source the error line and column, and \a desc is the
181 error itself. \a desc can be an expression that can be piped into QDebug.
186 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
189 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
192 error.setUrl(output->url); \
193 error.setLine(line); \
194 error.setColumn(column); \
195 error.setDescription(desc.trimmed()); \
196 exceptions << error; \
200 #define COMPILE_EXCEPTION(token, desc) \
201 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
206 Returns false if \a is false, otherwise does nothing.
208 #define COMPILE_CHECK(a) \
210 if (!a) return false; \
214 Returns true if literal \a v can be assigned to property \a prop, otherwise
217 This test corresponds to action taken by genLiteralAssignment(). Any change
218 made here, must have a corresponding action in genLiteralAssigment().
220 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
221 QQmlScript::Value *v)
223 const QQmlScript::Variant &value = v->value;
225 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
226 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
228 if (prop->core.isEnum()) {
229 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
232 if (p.isFlagType()) {
233 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
235 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
238 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
240 v->value = QQmlScript::Variant((double)enumValue);
244 int type = prop->type;
247 case QMetaType::QVariant:
249 case QVariant::String:
250 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
252 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
253 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
255 case QVariant::ByteArray:
256 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
259 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
261 case QVariant::RegExp:
262 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
266 bool ok = v->value.isNumber();
268 double n = v->value.asNumber();
269 if (double(uint(n)) != n)
272 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
277 bool ok = v->value.isNumber();
279 double n = v->value.asNumber();
280 if (double(int(n)) != n)
283 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
286 case QMetaType::Float:
287 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
289 case QVariant::Double:
290 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
292 case QVariant::Color:
295 QQmlStringConverters::colorFromString(value.asString(), &ok);
296 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
299 #ifndef QT_NO_DATESTRING
303 QQmlStringConverters::dateFromString(value.asString(), &ok);
304 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
310 QQmlStringConverters::timeFromString(value.asString(), &ok);
311 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
314 case QVariant::DateTime:
317 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
318 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
321 #endif // QT_NO_DATESTRING
322 case QVariant::Point:
323 case QVariant::PointF:
326 QQmlStringConverters::pointFFromString(value.asString(), &ok);
327 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
331 case QVariant::SizeF:
334 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
335 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
339 case QVariant::RectF:
342 QQmlStringConverters::rectFFromString(value.asString(), &ok);
343 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
348 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
351 case QVariant::Vector3D:
353 QQmlInstruction::instr_storeVector3D::QVector3D v3;
354 if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3)))
355 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
358 case QVariant::Vector4D:
360 QQmlInstruction::instr_storeVector4D::QVector4D v4;
361 if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4)))
362 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
367 // check if assigning a literal value to a list property.
368 // in each case, check the singular, since an Array of the specified type
369 // will not go via this literal assignment codepath.
370 if (type == qMetaTypeId<QList<qreal> >()) {
371 if (!v->value.isNumber()) {
372 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
375 } else if (type == qMetaTypeId<QList<int> >()) {
376 bool ok = v->value.isNumber();
378 double n = v->value.asNumber();
379 if (double(int(n)) != n)
382 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
384 } else if (type == qMetaTypeId<QList<bool> >()) {
385 if (!v->value.isBoolean()) {
386 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
389 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
390 if (!v->value.isString()) {
391 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
394 } else if (type == qMetaTypeId<QList<QUrl> >()) {
395 if (!v->value.isString()) {
396 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
399 } else if (type == qMetaTypeId<QJSValue>()) {
403 // otherwise, check for existence of string converter to custom type
404 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
406 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(type))));
414 Generate a store instruction for assigning literal \a v to property \a prop.
416 Any literal assignment that is approved in testLiteralAssignment() must have
417 a corresponding action in this method.
419 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
420 QQmlScript::Value *v)
422 if (prop->core.isEnum()) {
423 Q_ASSERT(v->value.isNumber());
425 int value = (int)v->value.asNumber();
427 Instruction::StoreInteger instr;
428 instr.propertyIndex = prop->index;
430 output->addInstruction(instr);
434 int type = prop->type;
436 case QMetaType::QVariant:
438 if (v->value.isNumber()) {
439 double n = v->value.asNumber();
440 if (double(int(n)) == n) {
441 if (prop->core.isVMEProperty()) {
442 Instruction::StoreVarInteger instr;
443 instr.propertyIndex = prop->index;
444 instr.value = int(n);
445 output->addInstruction(instr);
447 Instruction::StoreVariantInteger instr;
448 instr.propertyIndex = prop->index;
449 instr.value = int(n);
450 output->addInstruction(instr);
453 if (prop->core.isVMEProperty()) {
454 Instruction::StoreVarDouble instr;
455 instr.propertyIndex = prop->index;
457 output->addInstruction(instr);
459 Instruction::StoreVariantDouble instr;
460 instr.propertyIndex = prop->index;
462 output->addInstruction(instr);
465 } else if (v->value.isBoolean()) {
466 if (prop->core.isVMEProperty()) {
467 Instruction::StoreVarBool instr;
468 instr.propertyIndex = prop->index;
469 instr.value = v->value.asBoolean();
470 output->addInstruction(instr);
472 Instruction::StoreVariantBool instr;
473 instr.propertyIndex = prop->index;
474 instr.value = v->value.asBoolean();
475 output->addInstruction(instr);
478 if (prop->core.isVMEProperty()) {
479 Instruction::StoreVar instr;
480 instr.propertyIndex = prop->index;
481 instr.value = output->indexForString(v->value.asString());
482 output->addInstruction(instr);
484 Instruction::StoreVariant instr;
485 instr.propertyIndex = prop->index;
486 instr.value = output->indexForString(v->value.asString());
487 output->addInstruction(instr);
492 case QVariant::String:
494 Instruction::StoreString instr;
495 instr.propertyIndex = prop->index;
496 instr.value = output->indexForString(v->value.asString());
497 output->addInstruction(instr);
500 case QVariant::StringList:
502 Instruction::StoreStringList instr;
503 instr.propertyIndex = prop->index;
504 instr.value = output->indexForString(v->value.asString());
505 output->addInstruction(instr);
508 case QVariant::ByteArray:
510 Instruction::StoreByteArray instr;
511 instr.propertyIndex = prop->index;
512 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
513 output->addInstruction(instr);
518 Instruction::StoreUrl instr;
519 QString string = v->value.asString();
520 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
521 instr.propertyIndex = prop->index;
522 instr.value = output->indexForUrl(u);
523 output->addInstruction(instr);
528 Instruction::StoreInteger instr;
529 instr.propertyIndex = prop->index;
530 instr.value = uint(v->value.asNumber());
531 output->addInstruction(instr);
536 Instruction::StoreInteger instr;
537 instr.propertyIndex = prop->index;
538 instr.value = int(v->value.asNumber());
539 output->addInstruction(instr);
542 case QMetaType::Float:
544 Instruction::StoreFloat instr;
545 instr.propertyIndex = prop->index;
546 instr.value = float(v->value.asNumber());
547 output->addInstruction(instr);
550 case QVariant::Double:
552 Instruction::StoreDouble instr;
553 instr.propertyIndex = prop->index;
554 instr.value = v->value.asNumber();
555 output->addInstruction(instr);
558 case QVariant::Color:
560 Instruction::StoreColor instr;
561 instr.propertyIndex = prop->index;
562 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
563 output->addInstruction(instr);
566 #ifndef QT_NO_DATESTRING
569 Instruction::StoreDate instr;
570 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
571 instr.propertyIndex = prop->index;
572 instr.value = d.toJulianDay();
573 output->addInstruction(instr);
578 Instruction::StoreTime instr;
579 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
580 instr.propertyIndex = prop->index;
581 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
582 ::memcpy(&instr.time, &time, sizeof(QTime));
583 output->addInstruction(instr);
586 case QVariant::DateTime:
588 Instruction::StoreDateTime instr;
589 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
590 QTime time = dateTime.time();
591 instr.propertyIndex = prop->index;
592 instr.date = dateTime.date().toJulianDay();
593 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
594 ::memcpy(&instr.time, &time, sizeof(QTime));
595 output->addInstruction(instr);
598 #endif // QT_NO_DATESTRING
599 case QVariant::Point:
601 Instruction::StorePoint instr;
603 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
604 instr.propertyIndex = prop->index;
605 instr.point.xp = point.x();
606 instr.point.yp = point.y();
607 output->addInstruction(instr);
610 case QVariant::PointF:
612 Instruction::StorePointF instr;
614 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
615 instr.propertyIndex = prop->index;
616 instr.point.xp = point.x();
617 instr.point.yp = point.y();
618 output->addInstruction(instr);
623 Instruction::StoreSize instr;
625 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
626 instr.propertyIndex = prop->index;
627 instr.size.wd = size.width();
628 instr.size.ht = size.height();
629 output->addInstruction(instr);
632 case QVariant::SizeF:
634 Instruction::StoreSizeF instr;
636 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
637 instr.propertyIndex = prop->index;
638 instr.size.wd = size.width();
639 instr.size.ht = size.height();
640 output->addInstruction(instr);
645 Instruction::StoreRect instr;
647 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
648 instr.propertyIndex = prop->index;
649 instr.rect.x1 = rect.left();
650 instr.rect.y1 = rect.top();
651 instr.rect.x2 = rect.right();
652 instr.rect.y2 = rect.bottom();
653 output->addInstruction(instr);
656 case QVariant::RectF:
658 Instruction::StoreRectF instr;
660 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
661 instr.propertyIndex = prop->index;
662 instr.rect.xp = rect.left();
663 instr.rect.yp = rect.top();
664 instr.rect.w = rect.width();
665 instr.rect.h = rect.height();
666 output->addInstruction(instr);
671 Instruction::StoreBool instr;
672 bool b = v->value.asBoolean();
673 instr.propertyIndex = prop->index;
675 output->addInstruction(instr);
678 case QVariant::Vector3D:
680 Instruction::StoreVector3D instr;
681 instr.propertyIndex = prop->index;
682 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
683 output->addInstruction(instr);
686 case QVariant::Vector4D:
688 Instruction::StoreVector4D instr;
689 instr.propertyIndex = prop->index;
690 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
691 output->addInstruction(instr);
696 // generate single literal value assignment to a list property if required
697 if (type == qMetaTypeId<QList<qreal> >()) {
698 Instruction::StoreDoubleQList instr;
699 instr.propertyIndex = prop->index;
700 instr.value = v->value.asNumber();
701 output->addInstruction(instr);
703 } else if (type == qMetaTypeId<QList<int> >()) {
704 Instruction::StoreIntegerQList instr;
705 instr.propertyIndex = prop->index;
706 instr.value = int(v->value.asNumber());
707 output->addInstruction(instr);
709 } else if (type == qMetaTypeId<QList<bool> >()) {
710 Instruction::StoreBoolQList instr;
711 bool b = v->value.asBoolean();
712 instr.propertyIndex = prop->index;
714 output->addInstruction(instr);
716 } else if (type == qMetaTypeId<QList<QUrl> >()) {
717 Instruction::StoreUrlQList instr;
718 QString string = v->value.asString();
719 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
720 instr.propertyIndex = prop->index;
721 instr.value = output->indexForUrl(u);
722 output->addInstruction(instr);
724 } else if (type == qMetaTypeId<QList<QString> >()) {
725 Instruction::StoreStringQList instr;
726 instr.propertyIndex = prop->index;
727 instr.value = output->indexForString(v->value.asString());
728 output->addInstruction(instr);
730 } else if (type == qMetaTypeId<QJSValue>()) {
731 if (v->value.isBoolean()) {
732 Instruction::StoreJSValueBool instr;
733 instr.propertyIndex = prop->index;
734 instr.value = v->value.asBoolean();
735 output->addInstruction(instr);
736 } else if (v->value.isNumber()) {
737 double n = v->value.asNumber();
738 if (double(int(n)) == n) {
739 Instruction::StoreJSValueInteger instr;
740 instr.propertyIndex = prop->index;
741 instr.value = int(n);
742 output->addInstruction(instr);
744 Instruction::StoreJSValueDouble instr;
745 instr.propertyIndex = prop->index;
747 output->addInstruction(instr);
750 Instruction::StoreJSValueString instr;
751 instr.propertyIndex = prop->index;
752 instr.value = output->indexForString(v->value.asString());
753 output->addInstruction(instr);
758 // otherwise, generate custom type literal assignment
759 Instruction::AssignCustomType instr;
760 instr.propertyIndex = prop->index;
761 instr.primitive = output->indexForString(v->value.asString());
763 output->addInstruction(instr);
770 Resets data by clearing the lists that the QQmlCompiler modifies.
772 void QQmlCompiler::reset(QQmlCompiledData *data)
775 data->primitives.clear();
777 data->bytecode.resize(0);
781 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
782 with which the QQmlCompiledData will be associated.
784 Returns true on success, false on failure. On failure, the compile errors
785 are available from errors().
787 If the environment variant QML_COMPILER_DUMP is set
788 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
789 on a successful compiler.
791 bool QQmlCompiler::compile(QQmlEngine *engine,
793 QQmlCompiledData *out)
800 QQmlScript::Object *root = unit->parser().tree();
803 this->engine = engine;
804 this->enginePrivate = QQmlEnginePrivate::get(engine);
806 this->unitRoot = root;
810 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
811 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
813 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
814 QQmlCompiledData::TypeReference ref;
816 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
817 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
820 ref.type = tref.type;
821 if (!ref.type->isCreatable()) {
822 QString err = ref.type->noCreationReason();
824 err = tr( "Element is not creatable.");
825 COMPILE_EXCEPTION(parserRef->firstUse, err);
828 if (ref.type->containsRevisionedAttributes()) {
829 QQmlError cacheError;
830 ref.typePropertyCache = enginePrivate->cache(ref.type,
831 resolvedTypes.at(ii).minorVersion,
833 if (!ref.typePropertyCache)
834 COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
835 ref.typePropertyCache->addref();
838 } else if (tref.typeData) {
839 ref.component = tref.typeData->compiledData();
840 ref.component->addref();
849 out->dumpInstructions();
852 Q_ASSERT(out->rootPropertyCache);
860 this->enginePrivate = 0;
862 this->cachedComponentTypeRef = -1;
863 this->cachedTranslationContextIndex = -1;
869 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
871 compileState = pool->New<ComponentCompileState>();
873 compileState->root = tree;
875 componentStats->componentStat.lineNumber = tree->location.start.line;
877 // We generate the importCache before we build the tree so that
878 // it can be used in the binding compiler. Given we "expect" the
879 // QML compilation to succeed, this isn't a waste.
880 output->importCache = new QQmlTypeNameCache();
881 foreach (const QString &ns, unit->namespaces()) {
882 output->importCache->add(ns);
886 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
887 QString qualifier = script.qualifier;
888 QString enclosingNamespace;
890 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
891 if (lastDotIndex != -1) {
892 enclosingNamespace = qualifier.left(lastDotIndex);
893 qualifier = qualifier.mid(lastDotIndex+1);
896 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
899 unit->imports().populateCache(output->importCache, engine);
901 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
904 Instruction::Init init;
905 init.bindingsSize = compileState->totalBindingsCount;
906 init.parserStatusSize = compileState->parserStatusCount;
907 init.contextCache = genContextCache();
908 init.objectStackSize = compileState->objectDepth.maxDepth();
909 init.listStackSize = compileState->listDepth.maxDepth();
910 if (compileState->compiledBindingData.isEmpty())
911 init.compiledBinding = -1;
913 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
914 output->addInstruction(init);
916 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
917 Instruction::StoreImportedScript import;
918 import.value = output->scripts.count();
920 QQmlScriptData *scriptData = script.script->scriptData();
921 scriptData->addref();
922 output->scripts << scriptData;
923 output->addInstruction(import);
926 if (!compileState->v8BindingProgram.isEmpty()) {
927 Instruction::InitV8Bindings bindings;
928 int index = output->programs.count();
930 typedef QQmlCompiledData::V8Program V8Program;
931 output->programs.append(V8Program(compileState->v8BindingProgram, output));
933 bindings.programIndex = index;
934 bindings.line = compileState->v8BindingProgramLine;
935 output->addInstruction(bindings);
940 Instruction::SetDefault def;
941 output->addInstruction(def);
943 Instruction::Done done;
944 output->addInstruction(done);
946 Q_ASSERT(tree->metatype);
948 if (tree->metadata.isEmpty()) {
949 output->root = tree->metatype;
951 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
952 output->root = &output->rootData;
954 if (!tree->metadata.isEmpty())
955 enginePrivate->registerCompositeType(output->root);
958 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
960 for (int ii = 0; ii < list.count(); ++ii)
961 if (string == list.at(ii))
967 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
970 componentStats->componentStat.objects++;
972 Q_ASSERT (obj->type != -1);
973 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
974 obj->metatype = tr.metaObject();
976 // This object is a "Component" element
977 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
978 COMPILE_CHECK(buildComponent(obj, ctxt));
983 typedef QQmlInstruction I;
984 const I *init = ((const I *)tr.component->bytecode.constData());
985 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
987 // Adjust stack depths to include nested components
988 compileState->objectDepth.pushPop(init->init.objectStackSize);
989 compileState->listDepth.pushPop(init->init.listStackSize);
990 compileState->parserStatusCount += init->init.parserStatusSize;
991 compileState->totalBindingsCount += init->init.bindingsSize;
994 compileState->objectDepth.push();
996 // Object instantiations reset the binding context
997 BindingContext objCtxt(obj);
999 // Create the synthesized meta object, ignoring aliases
1000 COMPILE_CHECK(checkDynamicMeta(obj));
1001 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
1002 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
1004 // Find the native type and check for the QQmlParserStatus interface
1005 QQmlType *type = toQmlType(obj);
1007 obj->parserStatusCast = type->parserStatusCast();
1008 if (obj->parserStatusCast != -1)
1009 compileState->parserStatusCount++;
1011 // Check if this is a custom parser type. Custom parser types allow
1012 // assignments to non-existent properties. These assignments are then
1013 // compiled by the type.
1014 bool isCustomParser = output->types.at(obj->type).type &&
1015 output->types.at(obj->type).type->customParser() != 0;
1016 QList<QQmlCustomParserProperty> customProps;
1018 // Fetch the list of deferred properties
1019 QStringList deferredList = deferredProperties(obj);
1021 // Must do id property first. This is to ensure that the id given to any
1022 // id reference created matches the order in which the objects are
1024 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1025 if (prop->name() == id_string) {
1026 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1032 Property *defaultProperty = 0;
1033 Property *skipProperty = 0;
1034 if (obj->defaultProperty) {
1035 defaultProperty = obj->defaultProperty;
1037 Property *explicitProperty = 0;
1039 const QMetaObject *mo = obj->metatype;
1040 int idx = mo->indexOfClassInfo("DefaultProperty");
1042 QMetaClassInfo info = mo->classInfo(idx);
1043 const char *p = info.value();
1047 while (char c = p[plen++]) { ord |= c; };
1051 // Utf8 - unoptimal, but seldom hit
1052 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1053 QHashedStringRef r(*s);
1055 if (obj->propertiesHashField.test(r.hash())) {
1056 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1057 if (ep->name() == r) {
1058 explicitProperty = ep;
1064 if (!explicitProperty)
1065 defaultProperty->setName(r);
1068 QHashedCStringRef r(p, plen);
1070 if (obj->propertiesHashField.test(r.hash())) {
1071 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1072 if (ep->name() == r) {
1073 explicitProperty = ep;
1079 if (!explicitProperty) {
1080 // Set the default property name
1081 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1082 r.writeUtf16(buffer);
1083 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1089 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1091 skipProperty = explicitProperty; // We merge the values into defaultProperty
1093 // Find the correct insertion point
1094 Value *insertPos = 0;
1096 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1097 if (!(v->location.start < explicitProperty->values.first()->location.start))
1102 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1106 QQmlCustomParser *cp = 0;
1108 cp = output->types.at(obj->type).type->customParser();
1110 // Build all explicit properties specified
1111 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1113 if (prop == skipProperty)
1115 if (prop->name() == id_string)
1118 bool canDefer = false;
1119 if (isCustomParser) {
1120 if (doesPropertyExist(prop, obj) &&
1121 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1122 !isAttachedPropertyName(prop->name()))) {
1123 int ids = compileState->ids.count();
1124 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1125 canDefer = ids == compileState->ids.count();
1126 } else if (isSignalPropertyName(prop->name()) &&
1127 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1128 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1130 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1133 if (isSignalPropertyName(prop->name())) {
1134 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1136 int ids = compileState->ids.count();
1137 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1138 canDefer = ids == compileState->ids.count();
1142 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1143 prop->isDeferred = true;
1147 // Build the default property
1148 if (defaultProperty) {
1149 Property *prop = defaultProperty;
1151 bool canDefer = false;
1152 if (isCustomParser) {
1153 if (doesPropertyExist(prop, obj)) {
1154 int ids = compileState->ids.count();
1155 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1156 canDefer = ids == compileState->ids.count();
1158 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1161 int ids = compileState->ids.count();
1162 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1163 canDefer = ids == compileState->ids.count();
1166 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1167 prop->isDeferred = true;
1170 // Compile custom parser parts
1171 if (isCustomParser && !customProps.isEmpty()) {
1173 cp->compiler = this;
1175 obj->custom = cp->compile(customProps);
1178 foreach (QQmlError err, cp->errors()) {
1179 err.setUrl(output->url);
1184 compileState->objectDepth.pop();
1189 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1191 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1192 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1197 // Create the object
1198 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1199 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1201 Instruction::CreateSimpleObject create;
1202 create.create = output->types.at(obj->type).type->createFunction();
1203 create.typeSize = output->types.at(obj->type).type->createSize();
1204 create.type = obj->type;
1205 create.line = obj->location.start.line;
1206 create.column = obj->location.start.column;
1207 output->addInstruction(create);
1211 if (output->types.at(obj->type).type) {
1212 Instruction::CreateCppObject create;
1213 create.line = obj->location.start.line;
1214 create.column = obj->location.start.column;
1216 if (!obj->custom.isEmpty())
1217 create.data = output->indexForByteArray(obj->custom);
1218 create.type = obj->type;
1219 create.isRoot = (compileState->root == obj);
1220 output->addInstruction(create);
1222 Instruction::CreateQMLObject create;
1223 create.type = obj->type;
1224 create.isRoot = (compileState->root == obj);
1226 if (!obj->bindingBitmask.isEmpty()) {
1227 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1228 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1230 create.bindingBits = -1;
1232 output->addInstruction(create);
1234 Instruction::CompleteQMLObject complete;
1235 complete.line = obj->location.start.line;
1236 complete.column = obj->location.start.column;
1237 complete.isRoot = (compileState->root == obj);
1238 output->addInstruction(complete);
1242 // Setup the synthesized meta object if necessary
1243 if (!obj->metadata.isEmpty()) {
1244 Instruction::StoreMetaObject meta;
1245 meta.data = output->indexForByteArray(obj->metadata);
1246 meta.aliasData = output->indexForByteArray(obj->synthdata);
1247 meta.propertyCache = output->propertyCaches.count();
1249 QQmlPropertyCache *propertyCache = obj->synthCache;
1250 Q_ASSERT(propertyCache);
1251 propertyCache->addref();
1253 // Add flag for alias properties
1254 if (!obj->synthdata.isEmpty()) {
1255 const QQmlVMEMetaData *vmeMetaData =
1256 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1257 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1258 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1259 QQmlPropertyData *data = propertyCache->property(index);
1260 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1264 if (obj == unitRoot) {
1265 propertyCache->addref();
1266 output->rootPropertyCache = propertyCache;
1269 output->propertyCaches << propertyCache;
1270 output->addInstruction(meta);
1271 } else if (obj == unitRoot) {
1272 output->rootPropertyCache = tr.createPropertyCache(engine);
1273 output->rootPropertyCache->addref();
1276 // Set the object id
1277 if (!obj->id.isEmpty()) {
1278 Instruction::SetId id;
1279 id.value = output->indexForString(obj->id);
1280 id.index = obj->idIndex;
1281 output->addInstruction(id);
1285 if (tr.type && obj->parserStatusCast != -1) {
1286 Instruction::BeginObject begin;
1287 begin.castValue = obj->parserStatusCast;
1288 output->addInstruction(begin);
1294 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1296 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1297 Q_ASSERT(prop->scriptStringScope != -1);
1298 const QString &script = prop->values.first()->value.asScript();
1299 Instruction::StoreScriptString ss;
1300 ss.propertyIndex = prop->index;
1301 ss.value = output->indexForString(script);
1302 ss.scope = prop->scriptStringScope;
1303 // ss.bindingId = rewriteBinding(script, prop->name());
1304 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1305 ss.line = prop->location.start.line;
1306 ss.column = prop->location.start.column;
1307 output->addInstruction(ss);
1310 bool seenDefer = false;
1311 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1312 if (prop->isDeferred) {
1317 genValueProperty(prop, obj);
1320 Instruction::Defer defer;
1321 defer.deferCount = 0;
1322 int deferIdx = output->addInstruction(defer);
1323 int nextInstructionIndex = output->nextInstructionIndex();
1325 Instruction::DeferInit dinit;
1326 // XXX - these are now massive over allocations
1327 dinit.bindingsSize = compileState->totalBindingsCount;
1328 dinit.parserStatusSize = compileState->parserStatusCount;
1329 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1330 dinit.listStackSize = compileState->listDepth.maxDepth();
1331 output->addInstruction(dinit);
1333 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1334 if (!prop->isDeferred)
1336 genValueProperty(prop, obj);
1339 Instruction::Done done;
1340 output->addInstruction(done);
1342 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1345 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1347 QQmlScript::Value *v = prop->values.first();
1349 if (v->type == Value::SignalObject) {
1351 genObject(v->object);
1353 Instruction::AssignSignalObject assign;
1354 assign.line = v->location.start.line;
1355 assign.signal = output->indexForString(prop->name().toString());
1356 output->addInstruction(assign);
1358 } else if (v->type == Value::SignalExpression) {
1360 Instruction::StoreSignal store;
1361 store.signalIndex = prop->index;
1362 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1363 store.value = output->indexForByteArray(rewrite.toUtf8());
1364 store.context = v->signalExpressionContextStack;
1365 store.line = v->location.start.line;
1366 store.column = v->location.start.column;
1367 output->addInstruction(store);
1373 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1374 Instruction::FetchAttached fetch;
1375 fetch.id = prop->index;
1376 fetch.line = prop->location.start.line;
1377 output->addInstruction(fetch);
1379 genObjectBody(prop->value);
1381 Instruction::PopFetchedObject pop;
1382 output->addInstruction(pop);
1385 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1386 Instruction::FetchObject fetch;
1387 fetch.property = prop->index;
1388 fetch.line = prop->location.start.line;
1389 output->addInstruction(fetch);
1391 if (!prop->value->metadata.isEmpty()) {
1392 Instruction::StoreMetaObject meta;
1393 meta.data = output->indexForByteArray(prop->value->metadata);
1394 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1395 meta.propertyCache = -1;
1396 output->addInstruction(meta);
1399 genObjectBody(prop->value);
1401 Instruction::PopFetchedObject pop;
1402 output->addInstruction(pop);
1405 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1407 genValueTypeProperty(obj, prop);
1410 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1411 if (prop->isDeferred)
1414 genValueProperty(prop, obj);
1417 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1419 genValueTypeProperty(obj, prop);
1423 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1425 Instruction::FetchValueType fetch;
1426 fetch.property = prop->index;
1427 fetch.type = prop->type;
1428 fetch.bindingSkipList = 0;
1430 if (obj->type == -1 || output->types.at(obj->type).component) {
1431 // We only have to do this if this is a composite type. If it is a builtin
1432 // type it can't possibly already have bindings that need to be cleared.
1433 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1434 if (!vprop->values.isEmpty()) {
1435 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1436 fetch.bindingSkipList |= (1 << vprop->index);
1441 output->addInstruction(fetch);
1443 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1444 genPropertyAssignment(vprop, prop->value, prop);
1447 Instruction::PopValueType pop;
1448 pop.property = prop->index;
1449 pop.type = prop->type;
1450 pop.bindingSkipList = 0;
1451 output->addInstruction(pop);
1454 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1456 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1459 Instruction::CreateComponent create;
1460 create.line = root->location.start.line;
1461 create.column = root->location.start.column;
1462 create.endLine = root->location.end.line;
1463 create.isRoot = (compileState->root == obj);
1464 int createInstruction = output->addInstruction(create);
1465 int nextInstructionIndex = output->nextInstructionIndex();
1467 ComponentCompileState *oldCompileState = compileState;
1468 compileState = componentState(root);
1470 Instruction::Init init;
1471 init.bindingsSize = compileState->totalBindingsCount;
1472 init.parserStatusSize = compileState->parserStatusCount;
1473 init.contextCache = genContextCache();
1474 init.objectStackSize = compileState->objectDepth.maxDepth();
1475 init.listStackSize = compileState->listDepth.maxDepth();
1476 if (compileState->compiledBindingData.isEmpty())
1477 init.compiledBinding = -1;
1479 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1480 output->addInstruction(init);
1482 if (!compileState->v8BindingProgram.isEmpty()) {
1483 Instruction::InitV8Bindings bindings;
1484 int index = output->programs.count();
1486 typedef QQmlCompiledData::V8Program V8Program;
1487 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1489 bindings.programIndex = index;
1490 bindings.line = compileState->v8BindingProgramLine;
1491 output->addInstruction(bindings);
1496 Instruction::SetDefault def;
1497 output->addInstruction(def);
1499 Instruction::Done done;
1500 output->addInstruction(done);
1502 output->instruction(createInstruction)->createComponent.count =
1503 output->nextInstructionIndex() - nextInstructionIndex;
1505 compileState = oldCompileState;
1507 if (!obj->id.isEmpty()) {
1508 Instruction::SetId id;
1509 id.value = output->indexForString(obj->id);
1510 id.index = obj->idIndex;
1511 output->addInstruction(id);
1514 if (obj == unitRoot) {
1515 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1516 output->rootPropertyCache->addref();
1520 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1521 const BindingContext &ctxt)
1523 // The special "Component" element can only have the id property and a
1524 // default property, that actually defines the component's tree
1526 compileState->objectDepth.push();
1528 // Find, check and set the "id" property (if any)
1529 Property *idProp = 0;
1530 if (obj->properties.isMany() ||
1531 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1532 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1534 if (!obj->properties.isEmpty())
1535 idProp = obj->properties.first();
1538 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1539 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1540 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1542 QString idVal = idProp->values.first()->primitive();
1544 if (compileState->ids.value(idVal))
1545 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1551 // Check the Component tree is well formed
1552 if (obj->defaultProperty &&
1553 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1554 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1555 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1557 if (!obj->dynamicProperties.isEmpty())
1558 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1559 if (!obj->dynamicSignals.isEmpty())
1560 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1561 if (!obj->dynamicSlots.isEmpty())
1562 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1564 QQmlScript::Object *root = 0;
1565 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1566 root = obj->defaultProperty->values.first()->object;
1569 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1571 // Build the component tree
1572 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1574 compileState->objectDepth.pop();
1579 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1580 const BindingContext &ctxt)
1582 ComponentCompileState *oldComponentCompileState = compileState;
1583 compileState = pool->New<ComponentCompileState>();
1584 compileState->root = obj;
1585 compileState->nested = true;
1587 if (componentStats) {
1588 ComponentStat oldComponentStat = componentStats->componentStat;
1590 componentStats->componentStat = ComponentStat();
1591 componentStats->componentStat.lineNumber = obj->location.start.line;
1594 COMPILE_CHECK(buildObject(obj, ctxt));
1596 COMPILE_CHECK(completeComponentBuild());
1598 componentStats->componentStat = oldComponentStat;
1601 COMPILE_CHECK(buildObject(obj, ctxt));
1603 COMPILE_CHECK(completeComponentBuild());
1606 compileState = oldComponentCompileState;
1612 // Build a sub-object. A sub-object is one that was not created directly by
1613 // QML - such as a grouped property object, or an attached object. Sub-object's
1614 // can't have an id, involve a custom parser, have attached properties etc.
1615 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1617 Q_ASSERT(obj->metatype);
1618 Q_ASSERT(!obj->defaultProperty);
1619 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1622 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1623 if (isSignalPropertyName(prop->name())) {
1624 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1626 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1633 int QQmlCompiler::componentTypeRef()
1635 if (cachedComponentTypeRef == -1) {
1636 QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1637 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1638 if (output->types.at(ii).type == t) {
1639 cachedComponentTypeRef = ii;
1643 QQmlCompiledData::TypeReference ref;
1645 output->types << ref;
1646 cachedComponentTypeRef = output->types.count() - 1;
1648 return cachedComponentTypeRef;
1651 int QQmlCompiler::translationContextIndex()
1653 if (cachedTranslationContextIndex == -1) {
1654 // This code must match that in the qsTr() implementation
1655 const QString &path = output->name;
1656 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1657 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1659 QByteArray contextUtf8 = context.toUtf8();
1660 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1662 return cachedTranslationContextIndex;
1665 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1666 const BindingContext &ctxt)
1668 Q_ASSERT(obj->metaObject());
1670 const QHashedStringRef &propName = prop->name();
1672 Q_ASSERT(propName.startsWith(on_string));
1673 QString name = propName.mid(2, -1).toString();
1675 // Note that the property name could start with any alpha or '_' or '$' character,
1676 // so we need to do the lower-casing of the first alpha character.
1677 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1678 if (name.at(firstAlphaIndex).isUpper()) {
1679 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1684 bool notInRevision = false;
1686 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1690 if (notInRevision && 0 == property(obj, propName, 0)) {
1691 Q_ASSERT(obj->type != -1);
1692 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1693 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1695 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));
1697 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1701 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1703 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1707 if (prop->value || !prop->values.isOne())
1708 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1710 prop->index = sig->coreIndex;
1713 obj->addSignalProperty(prop);
1715 if (prop->values.first()->object) {
1716 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1717 prop->values.first()->type = Value::SignalObject;
1719 prop->values.first()->type = Value::SignalExpression;
1721 if (!prop->values.first()->value.isScript())
1722 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1724 QString script = prop->values.first()->value.asScript().trimmed();
1725 if (script.isEmpty())
1726 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1728 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1737 Returns true if (value) property \a prop exists on obj, false otherwise.
1739 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1740 QQmlScript::Object *obj)
1742 if (prop->name().isEmpty())
1744 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1747 return property(obj, prop->name()) != 0;
1750 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1751 QQmlScript::Object *obj,
1752 const BindingContext &ctxt)
1754 if (prop->isEmpty())
1755 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1757 const QMetaObject *metaObject = obj->metaObject();
1758 Q_ASSERT(metaObject);
1760 if (isAttachedPropertyName(prop->name())) {
1761 // Setup attached property data
1763 if (ctxt.isSubContext()) {
1764 // Attached properties cannot be used on sub-objects. Sub-objects
1765 // always exist in a binding sub-context, which is what we test
1767 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1771 QQmlImportNamespace *typeNamespace = 0;
1772 unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1774 if (typeNamespace) {
1775 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1778 } else if (!type || !type->attachedPropertiesType()) {
1779 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1783 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1785 Q_ASSERT(type->attachedPropertiesFunction());
1786 prop->index = type->attachedPropertiesId();
1787 prop->value->metatype = type->attachedPropertiesType();
1789 // Setup regular property data
1790 bool notInRevision = false;
1791 QQmlPropertyData *d =
1792 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1794 if (d == 0 && notInRevision) {
1795 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1796 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1798 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));
1800 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1803 prop->index = d->coreIndex;
1805 } else if (prop->isDefault) {
1806 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1807 QQmlPropertyData defaultPropertyData;
1808 defaultPropertyData.load(p, engine);
1810 prop->setName(QLatin1String(p.name()));
1811 prop->core = defaultPropertyData;
1812 prop->index = prop->core.coreIndex;
1815 // We can't error here as the "id" property does not require a
1816 // successful index resolution
1817 if (prop->index != -1)
1818 prop->type = prop->core.propType;
1820 // Check if this is an alias
1821 if (prop->index != -1 &&
1823 prop->parent->type != -1 &&
1824 output->types.at(prop->parent->type).component) {
1826 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1827 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1828 prop->isAlias = true;
1831 if (prop->index != -1 && !prop->values.isEmpty())
1832 prop->parent->setBindingBit(prop->index);
1835 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1837 // The magic "id" behavior doesn't apply when "id" is resolved as a
1838 // default property or to sub-objects (which are always in binding
1840 COMPILE_CHECK(buildIdProperty(prop, obj));
1841 if (prop->type == QVariant::String &&
1842 prop->values.first()->value.isString())
1843 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1845 } else if (isAttachedPropertyName(prop->name())) {
1847 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1849 } else if (prop->index == -1) {
1851 if (prop->isDefault) {
1852 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1854 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1857 } else if (prop->value) {
1859 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1861 } else if (prop->core.isQList()) {
1863 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1865 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1867 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1871 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1878 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1879 QQmlScript::Property *nsProp,
1880 QQmlScript::Object *obj,
1881 const BindingContext &ctxt)
1884 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1886 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1888 if (!isAttachedPropertyName(prop->name()))
1889 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1891 // Setup attached property data
1894 unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1896 if (!type || !type->attachedPropertiesType())
1897 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1900 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1902 Q_ASSERT(type->attachedPropertiesFunction());
1903 prop->index = type->index();
1904 prop->value->metatype = type->attachedPropertiesType();
1906 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1912 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1913 QQmlScript::Object *obj)
1915 if (prop->core.isQList()) {
1916 genListProperty(prop, obj);
1918 genPropertyAssignment(prop, obj);
1922 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1923 QQmlScript::Object *obj)
1925 int listType = enginePrivate->listType(prop->type);
1927 Instruction::FetchQList fetch;
1928 fetch.property = prop->index;
1929 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1930 fetch.type = listType;
1931 output->addInstruction(fetch);
1933 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1935 if (v->type == Value::CreatedObject) {
1937 genObject(v->object);
1938 if (listTypeIsInterface) {
1939 Instruction::AssignObjectList assign;
1940 assign.line = prop->location.start.line;
1941 output->addInstruction(assign);
1943 Instruction::StoreObjectQList store;
1944 output->addInstruction(store);
1947 } else if (v->type == Value::PropertyBinding) {
1949 genBindingAssignment(v, prop, obj);
1955 Instruction::PopQList pop;
1956 output->addInstruction(pop);
1959 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1960 QQmlScript::Object *obj,
1961 QQmlScript::Property *valueTypeProperty)
1963 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1965 Q_ASSERT(v->type == Value::CreatedObject ||
1966 v->type == Value::PropertyBinding ||
1967 v->type == Value::Literal);
1969 if (v->type == Value::CreatedObject) {
1971 genObject(v->object);
1973 if (QQmlMetaType::isInterface(prop->type)) {
1975 Instruction::StoreInterface store;
1976 store.line = v->object->location.start.line;
1977 store.propertyIndex = prop->index;
1978 output->addInstruction(store);
1980 } else if (prop->type == QMetaType::QVariant) {
1982 if (prop->core.isVMEProperty()) {
1983 Instruction::StoreVarObject store;
1984 store.line = v->object->location.start.line;
1985 store.propertyIndex = prop->index;
1986 output->addInstruction(store);
1988 Instruction::StoreVariantObject store;
1989 store.line = v->object->location.start.line;
1990 store.propertyIndex = prop->index;
1991 output->addInstruction(store);
1997 Instruction::StoreObject store;
1998 store.line = v->object->location.start.line;
1999 store.propertyIndex = prop->index;
2000 output->addInstruction(store);
2003 } else if (v->type == Value::PropertyBinding) {
2005 genBindingAssignment(v, prop, obj, valueTypeProperty);
2007 } else if (v->type == Value::Literal) {
2009 genLiteralAssignment(prop, v);
2015 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2017 Q_ASSERT(v->type == Value::ValueSource ||
2018 v->type == Value::ValueInterceptor);
2020 if (v->type == Value::ValueSource) {
2021 genObject(v->object);
2023 Instruction::StoreValueSource store;
2024 if (valueTypeProperty) {
2025 store.property = genValueTypeData(prop, valueTypeProperty);
2028 store.property = prop->core;
2031 QQmlType *valueType = toQmlType(v->object);
2032 store.castValue = valueType->propertyValueSourceCast();
2033 output->addInstruction(store);
2035 } else if (v->type == Value::ValueInterceptor) {
2036 genObject(v->object);
2038 Instruction::StoreValueInterceptor store;
2039 if (valueTypeProperty) {
2040 store.property = genValueTypeData(prop, valueTypeProperty);
2043 store.property = prop->core;
2046 QQmlType *valueType = toQmlType(v->object);
2047 store.castValue = valueType->propertyValueInterceptorCast();
2048 output->addInstruction(store);
2054 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2055 QQmlScript::Object *obj)
2058 prop->values.isMany() ||
2059 prop->values.first()->object)
2060 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2062 QQmlScript::Value *idValue = prop->values.first();
2063 QString val = idValue->primitive();
2065 COMPILE_CHECK(checkValidId(idValue, val));
2067 if (compileState->ids.value(val))
2068 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2070 prop->values.first()->type = Value::Id;
2078 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2081 Q_ASSERT(!compileState->ids.value(id));
2082 Q_ASSERT(obj->id == id);
2083 obj->idIndex = compileState->ids.count();
2084 compileState->ids.append(obj);
2087 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2089 Q_ASSERT(ref->value && !ref->value->bindingReference);
2090 ref->value->bindingReference = ref;
2091 compileState->totalBindingsCount++;
2092 compileState->bindings.prepend(ref);
2095 void QQmlCompiler::saveComponentState()
2097 Q_ASSERT(compileState->root);
2098 Q_ASSERT(compileState->root->componentCompileState == 0);
2100 compileState->root->componentCompileState = compileState;
2103 componentStats->savedComponentStats.append(componentStats->componentStat);
2106 QQmlCompilerTypes::ComponentCompileState *
2107 QQmlCompiler::componentState(QQmlScript::Object *obj)
2109 Q_ASSERT(obj->componentCompileState);
2110 return obj->componentCompileState;
2113 // Build attached property object. In this example,
2117 // GridView is an attached property object.
2118 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2119 QQmlScript::Object *obj,
2120 const BindingContext &ctxt)
2122 Q_ASSERT(prop->value);
2123 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2125 compileState->objectDepth.push();
2127 obj->addAttachedProperty(prop);
2129 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2131 compileState->objectDepth.pop();
2137 // Build "grouped" properties. In this example:
2139 // font.pointSize: 12
2140 // font.family: "Helvetica"
2142 // font is a nested property. pointSize and family are not.
2143 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2144 QQmlScript::Object *obj,
2145 const BindingContext &ctxt)
2147 Q_ASSERT(prop->type != 0);
2148 Q_ASSERT(prop->index != -1);
2150 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2151 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2153 if (!prop->values.isEmpty()) {
2154 if (prop->values.first()->location < prop->value->location) {
2155 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2157 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2161 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2162 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2166 if (prop->isAlias) {
2167 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2168 vtProp->isAlias = true;
2172 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2173 prop->value, obj, ctxt.incr()));
2174 obj->addValueTypeProperty(prop);
2176 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2180 // Load the nested property's meta type
2181 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2182 if (!prop->value->metatype)
2183 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2185 if (!prop->values.isEmpty())
2186 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2188 obj->addGroupedProperty(prop);
2190 compileState->objectDepth.push();
2192 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2194 compileState->objectDepth.pop();
2200 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2201 QQmlScript::Object *obj,
2202 QQmlScript::Object *baseObj,
2203 const BindingContext &ctxt)
2205 compileState->objectDepth.push();
2207 if (obj->defaultProperty)
2208 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2209 obj->metatype = type->metaObject();
2211 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2213 QQmlPropertyData *d = property(obj, prop->name());
2215 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2217 prop->index = d->coreIndex;
2218 prop->type = d->propType;
2220 prop->isValueTypeSubProperty = true;
2223 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2225 if (prop->values.isMany()) {
2226 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2227 } else if (!prop->values.isEmpty()) {
2228 QQmlScript::Value *value = prop->values.first();
2230 if (value->object) {
2231 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2232 } else if (value->value.isScript()) {
2233 // ### Check for writability
2235 //optimization for <Type>.<EnumValue> enum assignments
2236 bool isEnumAssignment = false;
2238 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2239 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2241 if (isEnumAssignment) {
2242 value->type = Value::Literal;
2244 JSBindingReference *reference = pool->New<JSBindingReference>();
2245 reference->expression = value->value;
2246 reference->property = prop;
2247 reference->value = value;
2248 reference->bindingContext = ctxt;
2249 reference->bindingContext.owner++;
2250 addBindingReference(reference);
2251 value->type = Value::PropertyBinding;
2254 COMPILE_CHECK(testLiteralAssignment(prop, value));
2255 value->type = Value::Literal;
2259 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2260 Q_ASSERT(v->object);
2262 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2265 obj->addValueProperty(prop);
2268 compileState->objectDepth.pop();
2273 // Build assignments to QML lists. QML lists are properties of type
2274 // QQmlListProperty<T>. List properties can accept a list of
2275 // objects, or a single binding.
2276 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2277 QQmlScript::Object *obj,
2278 const BindingContext &ctxt)
2280 Q_ASSERT(prop->core.isQList());
2282 compileState->listDepth.push();
2286 obj->addValueProperty(prop);
2288 int listType = enginePrivate->listType(t);
2289 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2291 bool assignedBinding = false;
2292 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2294 v->type = Value::CreatedObject;
2295 COMPILE_CHECK(buildObject(v->object, ctxt));
2297 // We check object coercian here. We check interface assignment
2299 if (!listTypeIsInterface) {
2300 if (!canCoerce(listType, v->object)) {
2301 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2305 } else if (v->value.isScript()) {
2306 if (assignedBinding)
2307 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2309 assignedBinding = true;
2310 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2311 v->type = Value::PropertyBinding;
2313 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2317 compileState->listDepth.pop();
2322 // Compiles an assignment to a QQmlScriptString property
2323 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2324 QQmlScript::Object *obj,
2325 const BindingContext &ctxt)
2327 if (prop->values.isMany())
2328 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2330 if (prop->values.first()->object)
2331 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2333 prop->scriptStringScope = ctxt.stack;
2334 obj->addScriptStringProperty(prop);
2339 // Compile regular property assignments of the form "property: <value>"
2340 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2341 QQmlScript::Object *obj,
2342 const BindingContext &ctxt)
2344 obj->addValueProperty(prop);
2346 if (prop->values.isMany())
2347 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2349 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2352 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2356 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2361 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2362 Q_ASSERT(v->object);
2363 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2369 // Compile assigning a single object instance to a regular property
2370 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2371 QQmlScript::Object *obj,
2372 QQmlScript::Value *v,
2373 const BindingContext &ctxt)
2375 Q_ASSERT(prop->index != -1);
2376 Q_ASSERT(v->object->type != -1);
2378 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2379 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2381 if (QQmlMetaType::isInterface(prop->type)) {
2383 // Assigning an object to an interface ptr property
2384 COMPILE_CHECK(buildObject(v->object, ctxt));
2386 v->type = Value::CreatedObject;
2388 } else if (prop->type == QMetaType::QVariant) {
2390 // Assigning an object to a QVariant
2391 COMPILE_CHECK(buildObject(v->object, ctxt));
2393 v->type = Value::CreatedObject;
2395 // Normally buildObject() will set this up, but we need the static
2396 // meta object earlier to test for assignability. It doesn't matter
2397 // that there may still be outstanding synthesized meta object changes
2398 // on this type, as they are not relevant for assignability testing
2399 v->object->metatype = output->types.at(v->object->type).metaObject();
2400 Q_ASSERT(v->object->metaObject());
2402 // We want to raw metaObject here as the raw metaobject is the
2403 // actual property type before we applied any extensions that might
2404 // effect the properties on the type, but don't effect assignability
2405 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2407 // Will be true if the assgned type inherits propertyMetaObject
2408 bool isAssignable = false;
2409 // Determine isAssignable value
2410 if (propertyMetaObject) {
2411 const QMetaObject *c = v->object->metatype;
2413 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2414 c = c->superClass();
2419 // Simple assignment
2420 COMPILE_CHECK(buildObject(v->object, ctxt));
2422 v->type = Value::CreatedObject;
2423 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2424 // Automatic "Component" insertion
2425 QQmlScript::Object *root = v->object;
2426 QQmlScript::Object *component = pool->New<Object>();
2427 component->type = componentTypeRef();
2428 component->metatype = &QQmlComponent::staticMetaObject;
2429 component->location = root->location;
2430 QQmlScript::Value *componentValue = pool->New<Value>();
2431 componentValue->object = root;
2432 component->getDefaultProperty()->addValue(componentValue);
2433 v->object = component;
2434 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2436 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2443 // Compile assigning a single object instance to a regular property using the "on" syntax.
2447 // NumberAnimation on x { }
2449 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2450 QQmlScript::Object *obj,
2451 QQmlScript::Object *baseObj,
2452 QQmlScript::Value *v,
2453 const BindingContext &ctxt)
2455 Q_ASSERT(prop->index != -1);
2456 Q_ASSERT(v->object->type != -1);
2460 if (!prop->core.isWritable())
2461 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2464 // Normally buildObject() will set this up, but we need the static
2465 // meta object earlier to test for assignability. It doesn't matter
2466 // that there may still be outstanding synthesized meta object changes
2467 // on this type, as they are not relevant for assignability testing
2468 v->object->metatype = output->types.at(v->object->type).metaObject();
2469 Q_ASSERT(v->object->metaObject());
2471 // Will be true if the assigned type inherits QQmlPropertyValueSource
2472 bool isPropertyValue = false;
2473 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2474 bool isPropertyInterceptor = false;
2475 if (QQmlType *valueType = toQmlType(v->object)) {
2476 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2477 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2480 if (isPropertyValue || isPropertyInterceptor) {
2481 // Assign as a property value source
2482 COMPILE_CHECK(buildObject(v->object, ctxt));
2484 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2485 buildDynamicMeta(baseObj, ForceCreation);
2486 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2488 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2494 // Compile assigning a literal or binding to a regular property
2495 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2496 QQmlScript::Object *obj,
2497 QQmlScript::Value *v,
2498 const BindingContext &ctxt)
2500 Q_ASSERT(prop->index != -1);
2502 if (v->value.isScript()) {
2504 //optimization for <Type>.<EnumValue> enum assignments
2505 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2506 bool isEnumAssignment = false;
2507 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2508 if (isEnumAssignment) {
2509 v->type = Value::Literal;
2514 // Test for other binding optimizations
2515 if (!buildLiteralBinding(v, prop, ctxt))
2516 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2518 v->type = Value::PropertyBinding;
2522 COMPILE_CHECK(testLiteralAssignment(prop, v));
2524 v->type = Value::Literal;
2530 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2531 QQmlScript::Object *obj,
2532 QQmlScript::Value *v,
2535 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2536 *isAssignment = false;
2537 if (!prop->core.isEnum() && !isIntProp)
2540 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2542 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2543 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2545 QString string = v->value.asString();
2546 if (!string.at(0).isUpper())
2550 // Allow enum assignment to ints.
2551 int enumval = evaluateEnum(string.toUtf8());
2552 if (enumval != -1) {
2553 v->type = Value::Literal;
2554 v->value = QQmlScript::Variant((double)enumval);
2555 *isAssignment = true;
2560 QStringList parts = string.split(QLatin1Char('.'));
2561 if (parts.count() != 2)
2564 QString typeName = parts.at(0);
2566 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2571 QString enumValue = parts.at(1);
2575 if (toQmlType(obj) == type) {
2576 // When these two match, we can short cut the search
2577 if (mprop.isFlagType()) {
2578 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2580 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2583 // Otherwise we have to search the whole type
2584 // This matches the logic in QV8TypeWrapper
2585 QByteArray enumName = enumValue.toUtf8();
2586 const QMetaObject *metaObject = type->baseMetaObject();
2588 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2589 QMetaEnum e = metaObject->enumerator(ii);
2590 value = e.keyToValue(enumName.constData(), &ok);
2597 v->type = Value::Literal;
2598 v->value = QQmlScript::Variant((double)value);
2599 *isAssignment = true;
2604 struct StaticQtMetaObject : public QObject
2606 static const QMetaObject *get()
2607 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2610 // Similar logic to above, but not knowing target property.
2611 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2613 int dot = script.indexOf('.');
2615 const QByteArray &scope = script.left(dot);
2617 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2618 if (!type && scope != "Qt")
2620 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2621 const char *key = script.constData() + dot+1;
2622 int i = mo->enumeratorCount();
2625 int v = mo->enumerator(i).keyToValue(key, &ok);
2633 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2635 QQmlType *qmltype = 0;
2636 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2640 return qmltype->metaObject();
2643 // similar to logic of completeComponentBuild, but also sticks data
2644 // into primitives at the end
2645 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2647 QQmlRewrite::RewriteBinding rewriteBinding;
2648 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2650 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2652 return output->indexForString(rewrite);
2655 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2657 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2658 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2661 // Ensures that the dynamic meta specification on obj is valid
2662 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2664 bool seenDefaultProperty = false;
2666 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2667 // Calculating the hash for the names is not a waste as we have to test
2668 // them against the illegalNames set anyway.
2669 QHashField propNames;
2670 QHashField methodNames;
2673 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2674 const QQmlScript::Object::DynamicProperty &prop = *p;
2676 if (prop.isDefaultProperty) {
2677 if (seenDefaultProperty)
2678 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2679 seenDefaultProperty = true;
2682 if (propNames.testAndSet(prop.name.hash())) {
2683 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2684 p2 = obj->dynamicProperties.next(p2)) {
2685 if (p2->name == prop.name) {
2686 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2687 prop.nameLocation.column,
2688 tr("Duplicate property name"));
2693 if (prop.name.at(0).isUpper()) {
2694 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2695 prop.nameLocation.column,
2696 tr("Property names cannot begin with an upper case letter"));
2699 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2700 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2701 prop.nameLocation.column,
2702 tr("Illegal property name"));
2706 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2707 const QQmlScript::Object::DynamicSignal &currSig = *s;
2709 if (methodNames.testAndSet(currSig.name.hash())) {
2710 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2711 s2 = obj->dynamicSignals.next(s2)) {
2712 if (s2->name == currSig.name)
2713 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2717 if (currSig.name.at(0).isUpper())
2718 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2719 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2720 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2723 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2724 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2726 if (methodNames.testAndSet(currSlot.name.hash())) {
2727 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2728 s2 = obj->dynamicSignals.next(s2)) {
2729 if (s2->name == currSlot.name)
2730 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2732 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2733 s2 = obj->dynamicSlots.next(s2)) {
2734 if (s2->name == currSlot.name)
2735 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2739 if (currSlot.name.at(0).isUpper())
2740 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2741 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2742 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2748 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2750 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2751 p = obj->dynamicProperties.next(p)) {
2753 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2756 Property *property = 0;
2757 if (p->isDefaultProperty) {
2758 property = obj->getDefaultProperty();
2760 property = obj->getProperty(p->name);
2761 if (!property->values.isEmpty())
2762 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2766 property->isReadOnlyDeclaration = true;
2768 if (property->value)
2769 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2771 property->values.append(p->defaultValue->values);
2776 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2778 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2781 Q_ASSERT(obj->metatype);
2783 if (mode != ForceCreation &&
2784 obj->dynamicProperties.isEmpty() &&
2785 obj->dynamicSignals.isEmpty() &&
2786 obj->dynamicSlots.isEmpty())
2789 bool resolveAlias = (mode == ResolveAliases);
2791 const Object::DynamicProperty *defaultProperty = 0;
2793 int varPropCount = 0;
2794 int totalPropCount = 0;
2795 int firstPropertyVarIndex = 0;
2797 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2799 if (p->type == Object::DynamicProperty::Alias)
2801 if (p->type == Object::DynamicProperty::Var)
2804 if (p->isDefaultProperty &&
2805 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2806 defaultProperty = p;
2808 if (!resolveAlias) {
2809 // No point doing this for both the alias and non alias cases
2810 QQmlPropertyData *d = property(obj, p->name);
2811 if (d && d->isFinal())
2812 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2816 bool buildData = resolveAlias || aliasCount == 0;
2818 QByteArray dynamicData;
2820 typedef QQmlVMEMetaData VMD;
2822 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2823 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2824 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2825 aliasCount * sizeof(VMD::AliasData), 0);
2828 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2830 QByteArray newClassName = obj->metatype->className();
2831 newClassName.append("_QML_");
2832 newClassName.append(QByteArray::number(uniqueClassId));
2834 if (compileState->root == obj && !compileState->nested) {
2835 QString path = output->url.path();
2836 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2837 if (lastSlash > -1) {
2838 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2839 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2840 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2844 // Size of the array that describes parameter types & names
2845 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2846 + obj->dynamicProperties.count() // for Changed() signals return types
2847 // Return "parameters" don't have names
2848 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2850 QFastMetaBuilder builder;
2852 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2853 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2854 obj->dynamicSlots.count(),
2855 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2856 defaultProperty?1:0, paramDataSize, ¶mIndex);
2859 Object::DynamicProperty::Type dtype;
2861 } builtinTypes[] = {
2862 { Object::DynamicProperty::Var, QMetaType::QVariant },
2863 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2864 { Object::DynamicProperty::Int, QMetaType::Int },
2865 { Object::DynamicProperty::Bool, QMetaType::Bool },
2866 { Object::DynamicProperty::Real, QMetaType::Double },
2867 { Object::DynamicProperty::String, QMetaType::QString },
2868 { Object::DynamicProperty::Url, QMetaType::QUrl },
2869 { Object::DynamicProperty::Color, QMetaType::QColor },
2870 { Object::DynamicProperty::Time, QMetaType::QTime },
2871 { Object::DynamicProperty::Date, QMetaType::QDate },
2872 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2873 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2875 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2877 // Reserve dynamic properties
2878 if (obj->dynamicProperties.count()) {
2879 typedef QQmlVMEMetaData VMD;
2881 int effectivePropertyIndex = 0;
2882 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2884 // Reserve space for name
2885 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2886 p->nameRef = builder.newString(p->name.utf8length());
2889 int propertyType = 0; // for VMD
2890 bool readonly = false;
2892 if (p->type == Object::DynamicProperty::Alias) {
2894 } else if (p->type < builtinTypeCount) {
2895 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2896 metaType = builtinTypes[p->type].metaType;
2897 propertyType = metaType;
2900 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2901 p->type == Object::DynamicProperty::Custom);
2903 // XXX don't double resolve this in the case of an alias run
2905 QByteArray customTypeName;
2906 QQmlType *qmltype = 0;
2908 if (!unit->imports().resolveType(p->customType, &qmltype, &url, 0, 0, 0))
2909 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2912 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
2914 Q_ASSERT(tdata->isComplete());
2915 customTypeName = tdata->compiledData()->root->className();
2918 customTypeName = qmltype->typeName();
2921 if (p->type == Object::DynamicProperty::Custom) {
2922 customTypeName += '*';
2923 propertyType = QMetaType::QObjectStar;
2926 customTypeName = QByteArrayLiteral("QQmlListProperty<") + customTypeName + '>';
2927 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2930 metaType = QMetaType::type(customTypeName);
2931 Q_ASSERT(metaType != QMetaType::UnknownType);
2932 Q_ASSERT(metaType != QMetaType::Void);
2935 if (p->type == Object::DynamicProperty::Var)
2942 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2943 vmd->propertyCount++;
2944 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2947 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2948 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2949 effectivePropertyIndex);
2951 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2952 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2955 effectivePropertyIndex++;
2959 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2961 vmd->varPropertyCount = varPropCount;
2962 firstPropertyVarIndex = effectivePropertyIndex;
2963 totalPropCount = varPropCount + effectivePropertyIndex;
2964 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2965 if (p->type == Object::DynamicProperty::Var) {
2967 vmd->propertyCount++;
2968 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2971 builder.setProperty(effectivePropertyIndex, p->nameRef,
2972 QMetaType::QVariant,
2973 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2974 effectivePropertyIndex);
2976 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2977 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2980 effectivePropertyIndex++;
2987 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2988 if (p->type == Object::DynamicProperty::Alias) {
2990 Q_ASSERT(buildData);
2991 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2992 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2995 // Even if we aren't resolving the alias, we need a fake signal so that the
2996 // metaobject remains consistent across the resolve and non-resolve alias runs
2997 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2998 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
3000 effectivePropertyIndex++;
3007 // Reserve default property
3008 QFastMetaBuilder::StringRef defPropRef;
3009 if (defaultProperty) {
3010 defPropRef = builder.newString(int(sizeof("DefaultProperty")) - 1);
3011 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3014 // Reserve dynamic signals
3015 int signalIndex = 0;
3016 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3018 s->nameRef = builder.newString(s->name.utf8length());
3020 int paramCount = s->parameterNames.count();
3021 QVarLengthArray<int, 10> paramTypes(paramCount);
3023 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3024 for (int i = 0; i < paramCount; ++i) {
3025 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3026 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3027 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3032 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3034 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3035 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3036 paramIndex += paramCount*2 + 1;
3040 // Reserve dynamic slots
3041 if (obj->dynamicSlots.count()) {
3043 typedef QQmlVMEMetaData VMD;
3045 int methodIndex = 0;
3046 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3047 s->nameRef = builder.newString(s->name.utf8length());
3048 int paramCount = s->parameterNames.count();
3050 QVarLengthArray<int, 10> paramTypes(paramCount);
3052 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3053 for (int i = 0; i < paramCount; ++i) {
3054 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3055 paramTypes[i] = QMetaType::QVariant;
3059 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3060 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3061 paramIndex += paramCount*2 + 1;
3066 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3067 funcScript.reserve(int(sizeof("(function ")) - 1 + s->name.length() + 1 /* lparen */ +
3068 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3069 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3070 for (int jj = 0; jj < paramCount; ++jj) {
3071 if (jj) funcScript.append(QLatin1Char(','));
3072 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3074 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3076 QByteArray utf8 = funcScript.toUtf8();
3077 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3079 s->location.start.line };
3081 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3084 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3086 md.bodyOffset = dynamicData.size();
3088 dynamicData.append((const char *)utf8.constData(), utf8.length());
3096 // Now allocate properties
3097 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3099 char *d = p->changedNameRef.data();
3100 p->name.writeUtf8(d);
3101 strcpy(d + p->name.utf8length(), "Changed");
3102 p->changedNameRef.loadByteArrayData();
3104 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3107 p->nameRef.load(p->name);
3110 // Allocate default property if necessary
3111 if (defaultProperty)
3112 defPropRef.load("DefaultProperty");
3114 // Now allocate signals
3115 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3117 s->nameRef.load(s->name);
3119 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3120 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3123 // Now allocate methods
3124 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3125 s->nameRef.load(s->name);
3127 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3128 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3131 // Now allocate class name
3132 classNameRef.load(newClassName);
3134 obj->metadata = builder.toData();
3135 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3137 if (mode == IgnoreAliases && aliasCount)
3138 compileState->aliasingObjects.append(obj);
3140 obj->synthdata = dynamicData;
3142 if (obj->synthCache) {
3143 obj->synthCache->release();
3144 obj->synthCache = 0;
3147 if (obj->type != -1) {
3148 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3149 QQmlPropertyCache *cache =
3150 superCache->copyAndAppend(engine, &obj->extObject,
3151 QQmlPropertyData::NoFlags,
3152 QQmlPropertyData::IsVMEFunction,
3153 QQmlPropertyData::IsVMESignal);
3155 // now we modify the flags appropriately for var properties.
3156 int propertyOffset = obj->extObject.propertyOffset();
3157 QQmlPropertyData *currPropData = 0;
3158 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3159 currPropData = cache->property(pvi + propertyOffset);
3160 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3163 obj->synthCache = cache;
3169 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3172 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3174 QChar ch = val.at(0);
3175 if (ch.isLetter() && !ch.isLower())
3176 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3178 QChar u(QLatin1Char('_'));
3179 if (!ch.isLetter() && ch != u)
3180 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3182 for (int ii = 1; ii < val.count(); ++ii) {
3184 if (!ch.isLetterOrNumber() && ch != u)
3185 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3188 if (enginePrivate->v8engine()->illegalNames().contains(val))
3189 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3194 #include <private/qqmljsparser_p.h>
3196 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3198 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3200 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3201 return QStringList() << name;
3202 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3203 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3205 QStringList rv = astNodeToStringList(expr->base);
3208 rv.append(expr->name.toString());
3211 return QStringList();
3214 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3216 QQmlScript::Object *obj,
3217 int propIndex, int aliasIndex,
3218 Object::DynamicProperty &prop)
3220 Q_ASSERT(!prop.nameRef.isEmpty());
3221 if (!prop.defaultValue)
3222 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3224 if (!prop.defaultValue->values.isOne() ||
3225 prop.defaultValue->values.first()->object ||
3226 !prop.defaultValue->values.first()->value.isScript())
3227 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3229 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3231 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3233 QStringList alias = astNodeToStringList(node);
3235 if (alias.count() < 1 || alias.count() > 3)
3236 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3238 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3240 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3242 QByteArray typeName;
3247 bool writable = false;
3248 bool resettable = false;
3249 if (alias.count() == 2 || alias.count() == 3) {
3250 propIdx = indexOfProperty(idObject, alias.at(1));
3252 if (-1 == propIdx) {
3253 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3254 } else if (propIdx > 0xFFFF) {
3255 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3258 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3259 if (!aliasProperty.isScriptable())
3260 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3262 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3263 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3265 type = aliasProperty.userType();
3267 if (alias.count() == 3) {
3268 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3270 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3272 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3274 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3275 if (valueTypeIndex == -1)
3276 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3277 Q_ASSERT(valueTypeIndex <= 0xFF);
3279 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3280 propIdx |= (valueTypeIndex << 16);
3282 // update the property type
3283 type = aliasProperty.userType();
3286 if (aliasProperty.isEnumType())
3287 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3289 typeName = aliasProperty.typeName();
3291 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3293 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3295 typeName = ref.type->typeName();
3297 typeName = ref.component->root->className();
3302 if (typeName.endsWith('*'))
3303 flags |= QML_ALIAS_FLAG_PTR;
3305 if (type == QMetaType::UnknownType) {
3306 Q_ASSERT(!typeName.isEmpty());
3307 type = QMetaType::type(typeName);
3308 Q_ASSERT(type != QMetaType::UnknownType);
3309 Q_ASSERT(type != QMetaType::Void);
3312 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3314 typedef QQmlVMEMetaData VMD;
3315 VMD *vmd = (QQmlVMEMetaData *)data.data();
3316 *(vmd->aliasData() + aliasIndex) = aliasData;
3318 int propertyFlags = 0;
3320 propertyFlags |= QFastMetaBuilder::Writable;
3322 propertyFlags |= QFastMetaBuilder::Resettable;
3324 builder.setProperty(propIndex, prop.nameRef, type,
3325 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3331 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3332 QQmlScript::Property *prop,
3333 const BindingContext &ctxt)
3335 Q_ASSERT(prop->index != -1);
3336 Q_ASSERT(prop->parent);
3337 Q_ASSERT(prop->parent->metaObject());
3339 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3340 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3342 JSBindingReference *reference = pool->New<JSBindingReference>();
3343 reference->expression = value->value;
3344 reference->property = prop;
3345 reference->value = value;
3346 reference->bindingContext = ctxt;
3347 addBindingReference(reference);
3352 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3353 QQmlScript::Property *prop,
3354 const QQmlCompilerTypes::BindingContext &)
3356 Q_ASSERT(v->value.isScript());
3358 if (!prop->core.isWritable())
3361 AST::Node *binding = v->value.asAST();
3363 if (prop->type == QVariant::String) {
3364 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3365 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3366 if (i->name == qsTrId_string) {
3367 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3368 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3370 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3371 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3372 (!arg2 || !arg2->next)) {
3377 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3378 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3380 TrBindingReference *reference = pool->New<TrBindingReference>();
3381 reference->dataType = BindingReference::TrId;
3382 reference->text = text;
3384 v->bindingReference = reference;
3388 } else if (i->name == qsTr_string) {
3390 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3391 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3392 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3394 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3395 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3396 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3397 (!arg3 || !arg3->next)) {
3403 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3404 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3405 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3407 TrBindingReference *reference = pool->New<TrBindingReference>();
3408 reference->dataType = BindingReference::Tr;
3409 reference->text = text;
3410 reference->comment = comment;
3412 v->bindingReference = reference;
3425 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3426 QQmlScript::Property *prop,
3427 QQmlScript::Object *obj,
3428 QQmlScript::Property *valueTypeProperty)
3431 Q_ASSERT(binding->bindingReference);
3433 const BindingReference &ref = *binding->bindingReference;
3434 if (ref.dataType == BindingReference::TrId) {
3435 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3437 Instruction::StoreTrIdString store;
3438 store.propertyIndex = prop->core.coreIndex;
3439 store.text = output->indexForByteArray(tr.text.toUtf8());
3441 output->addInstruction(store);
3442 } else if (ref.dataType == BindingReference::Tr) {
3443 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3445 Instruction::StoreTrString store;
3446 store.propertyIndex = prop->core.coreIndex;
3447 store.context = translationContextIndex();
3448 store.text = output->indexForByteArray(tr.text.toUtf8());
3449 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3451 output->addInstruction(store);
3452 } else if (ref.dataType == BindingReference::V4) {
3453 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3455 Instruction::StoreV4Binding store;
3456 store.value = js.compiledIndex;
3457 store.context = js.bindingContext.stack;
3458 store.owner = js.bindingContext.owner;
3459 store.isAlias = prop->isAlias;
3460 if (valueTypeProperty) {
3461 store.property = (valueTypeProperty->index & 0xFFFF) |
3462 ((valueTypeProperty->type & 0xFF)) << 16 |
3463 ((prop->index & 0xFF) << 24);
3464 store.isRoot = (compileState->root == valueTypeProperty->parent);
3466 store.property = prop->index;
3467 store.isRoot = (compileState->root == obj);
3469 store.line = binding->location.start.line;
3470 store.column = binding->location.start.column;
3471 output->addInstruction(store);
3472 } else if (ref.dataType == BindingReference::V8) {
3473 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3475 Instruction::StoreV8Binding store;
3476 store.value = js.compiledIndex;
3477 store.context = js.bindingContext.stack;
3478 store.owner = js.bindingContext.owner;
3479 store.isAlias = prop->isAlias;
3480 if (valueTypeProperty) {
3481 store.isRoot = (compileState->root == valueTypeProperty->parent);
3483 store.isRoot = (compileState->root == obj);
3485 store.line = binding->location.start.line;
3486 store.column = binding->location.start.column;
3488 Q_ASSERT(js.bindingContext.owner == 0 ||
3489 (js.bindingContext.owner != 0 && valueTypeProperty));
3490 if (js.bindingContext.owner) {
3491 store.property = genValueTypeData(prop, valueTypeProperty);
3493 store.property = prop->core;
3496 output->addInstruction(store);
3497 } else if (ref.dataType == BindingReference::QtScript) {
3498 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3500 Instruction::StoreBinding store;
3501 store.value = output->indexForString(js.rewrittenExpression);
3502 store.context = js.bindingContext.stack;
3503 store.owner = js.bindingContext.owner;
3504 store.line = binding->location.start.line;
3505 store.column = binding->location.start.column;
3506 store.isAlias = prop->isAlias;
3508 if (valueTypeProperty) {
3509 store.isRoot = (compileState->root == valueTypeProperty->parent);
3511 store.isRoot = (compileState->root == obj);
3514 Q_ASSERT(js.bindingContext.owner == 0 ||
3515 (js.bindingContext.owner != 0 && valueTypeProperty));
3516 if (js.bindingContext.owner) {
3517 store.property = genValueTypeData(prop, valueTypeProperty);
3519 store.property = prop->core;
3522 output->addInstruction(store);
3524 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3528 int QQmlCompiler::genContextCache()
3530 if (compileState->ids.count() == 0)
3533 QQmlIntegerCache *cache = new QQmlIntegerCache();
3534 cache->reserve(compileState->ids.count());
3535 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3536 cache->add(o->id, o->idIndex);
3538 output->contextCaches.append(cache);
3539 return output->contextCaches.count() - 1;
3543 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3544 QQmlScript::Property *prop)
3546 typedef QQmlPropertyPrivate QDPP;
3547 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3548 enginePrivate->valueTypes[prop->type]->metaObject(),
3549 valueTypeProp->index, engine);
3552 bool QQmlCompiler::completeComponentBuild()
3555 componentStats->componentStat.ids = compileState->ids.count();
3557 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3558 aliasObject = compileState->aliasingObjects.next(aliasObject))
3559 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3561 QV4Compiler::Expression expr(unit->imports());
3562 expr.component = compileState->root;
3563 expr.ids = &compileState->ids;
3564 expr.importCache = output->importCache;
3566 QV4Compiler bindingCompiler;
3568 QList<JSBindingReference*> sharedBindings;
3570 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3572 JSBindingReference &binding = *b;
3575 expr.context = binding.bindingContext.object;
3576 expr.property = binding.property;
3577 expr.expression = binding.expression;
3579 int index = bindingCompiler.compile(expr, enginePrivate);
3581 binding.dataType = BindingReference::V4;
3582 binding.compiledIndex = index;
3584 componentStats->componentStat.optimizedBindings.append(b->value->location);
3588 // Pre-rewrite the expression
3589 QString expression = binding.expression.asScript();
3591 QQmlRewrite::RewriteBinding rewriteBinding;
3592 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3593 bool isSharable = false;
3594 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3596 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3597 binding.dataType = BindingReference::V8;
3598 sharedBindings.append(b);
3601 componentStats->componentStat.sharedBindings.append(b->value->location);
3603 binding.dataType = BindingReference::QtScript;
3606 componentStats->componentStat.scriptBindings.append(b->value->location);
3610 if (!sharedBindings.isEmpty()) {
3612 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3614 return lhs->value->location.start.line < rhs->value->location.start.line;
3618 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3620 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3621 int lineNumber = startLineNumber;
3623 QByteArray functionArray("[", 1);
3624 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3626 JSBindingReference *reference = sharedBindings.at(ii);
3627 QQmlScript::Value *value = reference->value;
3628 const QString &expression = reference->rewrittenExpression;
3630 if (ii != 0) functionArray.append(",", 1);
3632 while (lineNumber < value->location.start.line) {
3634 functionArray.append("\n", 1);
3637 functionArray += expression.toUtf8();
3638 lineNumber += expression.count(QLatin1Char('\n'));
3639 reference->compiledIndex = ii;
3641 functionArray.append("]", 1);
3643 compileState->v8BindingProgram = functionArray;
3644 compileState->v8BindingProgramLine = startLineNumber;
3647 if (bindingCompiler.isValid())
3648 compileState->compiledBindingData = bindingCompiler.program();
3650 // Check pop()'s matched push()'s
3651 Q_ASSERT(compileState->objectDepth.depth() == 0);
3652 Q_ASSERT(compileState->listDepth.depth() == 0);
3654 saveComponentState();
3659 void QQmlCompiler::dumpStats()
3661 Q_ASSERT(componentStats);
3662 qWarning().nospace() << "QML Document: " << output->url.toString();
3663 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3664 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3665 qWarning().nospace() << " Component Line " << stat.lineNumber;
3666 qWarning().nospace() << " Total Objects: " << stat.objects;
3667 qWarning().nospace() << " IDs Used: " << stat.ids;
3668 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3672 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3673 if (0 == (ii % 10)) {
3674 if (ii) output.append("\n");
3679 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3681 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3682 output.append(") ");
3684 if (!output.isEmpty())
3685 qWarning().nospace() << output.constData();
3688 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3691 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3692 if (0 == (ii % 10)) {
3693 if (ii) output.append('\n');
3698 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3700 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3701 output.append(") ");
3703 if (!output.isEmpty())
3704 qWarning().nospace() << output.constData();
3707 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3710 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3711 if (0 == (ii % 10)) {
3712 if (ii) output.append('\n');
3717 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3719 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3720 output.append(") ");
3722 if (!output.isEmpty())
3723 qWarning().nospace() << output.constData();
3729 Returns true if from can be assigned to a (QObject) property of type
3732 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3734 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3735 const QMetaObject *fromMo = from->metaObject();
3738 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3740 fromMo = fromMo->superClass();
3746 Returns the element name, as written in the QML file, for o.
3748 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3751 if (o->type != -1) {
3752 return unit->parser().referencedTypes().at(o->type)->name;
3758 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3760 if (from->type != -1 && output->types.at(from->type).type)
3761 return output->types.at(from->type).type;
3764 const QMetaObject *mo = from->metatype;
3766 while (!type && mo) {
3767 type = QQmlMetaType::qmlType(mo);
3768 mo = mo->superClass();
3773 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3775 const QMetaObject *mo = obj->metatype;
3777 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3779 return QStringList();
3781 QMetaClassInfo classInfo = mo->classInfo(idx);
3782 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3787 QQmlCompiler::property(QQmlScript::Object *object, int index)
3789 QQmlPropertyCache *cache = 0;
3791 if (object->synthCache)
3792 cache = object->synthCache;
3793 else if (object->type != -1)
3794 cache = output->types[object->type].createPropertyCache(engine);
3796 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3798 return cache->property(index);
3802 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3804 if (notInRevision) *notInRevision = false;
3806 QQmlPropertyCache *cache = 0;
3808 if (object->synthCache)
3809 cache = object->synthCache;
3810 else if (object->type != -1)
3811 cache = output->types[object->type].createPropertyCache(engine);
3813 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3815 QQmlPropertyData *d = cache->property(name);
3817 // Find the first property
3818 while (d && d->isFunction())
3819 d = cache->overrideData(d);
3821 if (d && !cache->isAllowedInRevision(d)) {
3822 if (notInRevision) *notInRevision = true;
3829 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3831 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3833 if (notInRevision) *notInRevision = false;
3835 QQmlPropertyCache *cache = 0;
3837 if (object->synthCache)
3838 cache = object->synthCache;
3839 else if (object->type != -1)
3840 cache = output->types[object->type].createPropertyCache(engine);
3842 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3845 QQmlPropertyData *d = cache->property(name);
3846 if (notInRevision) *notInRevision = false;
3848 while (d && !(d->isFunction()))
3849 d = cache->overrideData(d);
3851 if (d && !cache->isAllowedInRevision(d)) {
3852 if (notInRevision) *notInRevision = true;
3858 if (name.endsWith(Changed_string)) {
3859 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3861 d = property(object, propName, notInRevision);
3863 return cache->method(d->notifyIndex);
3869 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3870 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3871 bool *notInRevision)
3873 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3874 return d?d->coreIndex:-1;
3877 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3878 bool *notInRevision)
3880 return indexOfProperty(object, QStringRef(&name), notInRevision);
3883 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3884 bool *notInRevision)
3886 QQmlPropertyData *d = property(object, name, notInRevision);
3887 return d?d->coreIndex:-1;