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())
2549 int dot = string.indexOf(QLatin1Char('.'));
2550 if (dot == -1 || dot == string.length()-1)
2553 if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2556 QHashedStringRef typeName(string.constData(), dot);
2557 QString enumValue = string.mid(dot+1);
2560 // Allow enum assignment to ints.
2561 int enumval = evaluateEnum(typeName, enumValue.toUtf8());
2562 if (enumval != -1) {
2563 v->type = Value::Literal;
2564 v->value = QQmlScript::Variant((double)enumval);
2565 *isAssignment = true;
2571 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2579 if (toQmlType(obj) == type) {
2580 // When these two match, we can short cut the search
2581 if (mprop.isFlagType()) {
2582 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2584 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2587 // Otherwise we have to search the whole type
2588 // This matches the logic in QV8TypeWrapper
2589 QByteArray enumName = enumValue.toUtf8();
2590 const QMetaObject *metaObject = type->baseMetaObject();
2592 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2593 QMetaEnum e = metaObject->enumerator(ii);
2594 value = e.keyToValue(enumName.constData(), &ok);
2601 v->type = Value::Literal;
2602 v->value = QQmlScript::Variant((double)value);
2603 *isAssignment = true;
2608 struct StaticQtMetaObject : public QObject
2610 static const QMetaObject *get()
2611 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2614 // Similar logic to above, but not knowing target property.
2615 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const
2618 if (scope != QLatin1String("Qt")) {
2619 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2624 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2625 int i = mo->enumeratorCount();
2628 int v = mo->enumerator(i).keyToValue(enumValue.constData(), &ok);
2635 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2637 QQmlType *qmltype = 0;
2638 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2642 return qmltype->metaObject();
2645 // similar to logic of completeComponentBuild, but also sticks data
2646 // into primitives at the end
2647 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2649 QQmlRewrite::RewriteBinding rewriteBinding;
2650 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2652 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2654 return output->indexForString(rewrite);
2657 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2659 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2660 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2663 // Ensures that the dynamic meta specification on obj is valid
2664 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2666 bool seenDefaultProperty = false;
2668 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2669 // Calculating the hash for the names is not a waste as we have to test
2670 // them against the illegalNames set anyway.
2671 QHashField propNames;
2672 QHashField methodNames;
2675 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2676 const QQmlScript::Object::DynamicProperty &prop = *p;
2678 if (prop.isDefaultProperty) {
2679 if (seenDefaultProperty)
2680 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2681 seenDefaultProperty = true;
2684 if (propNames.testAndSet(prop.name.hash())) {
2685 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2686 p2 = obj->dynamicProperties.next(p2)) {
2687 if (p2->name == prop.name) {
2688 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2689 prop.nameLocation.column,
2690 tr("Duplicate property name"));
2695 if (prop.name.at(0).isUpper()) {
2696 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2697 prop.nameLocation.column,
2698 tr("Property names cannot begin with an upper case letter"));
2701 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2702 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2703 prop.nameLocation.column,
2704 tr("Illegal property name"));
2708 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2709 const QQmlScript::Object::DynamicSignal &currSig = *s;
2711 if (methodNames.testAndSet(currSig.name.hash())) {
2712 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2713 s2 = obj->dynamicSignals.next(s2)) {
2714 if (s2->name == currSig.name)
2715 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2719 if (currSig.name.at(0).isUpper())
2720 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2721 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2722 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2725 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2726 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2728 if (methodNames.testAndSet(currSlot.name.hash())) {
2729 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2730 s2 = obj->dynamicSignals.next(s2)) {
2731 if (s2->name == currSlot.name)
2732 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2734 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2735 s2 = obj->dynamicSlots.next(s2)) {
2736 if (s2->name == currSlot.name)
2737 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2741 if (currSlot.name.at(0).isUpper())
2742 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2743 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2744 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2750 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2752 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2753 p = obj->dynamicProperties.next(p)) {
2755 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2758 Property *property = 0;
2759 if (p->isDefaultProperty) {
2760 property = obj->getDefaultProperty();
2762 property = obj->getProperty(p->name);
2763 if (!property->values.isEmpty())
2764 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2768 property->isReadOnlyDeclaration = true;
2770 if (property->value)
2771 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2773 property->values.append(p->defaultValue->values);
2778 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2780 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2783 Q_ASSERT(obj->metatype);
2785 if (mode != ForceCreation &&
2786 obj->dynamicProperties.isEmpty() &&
2787 obj->dynamicSignals.isEmpty() &&
2788 obj->dynamicSlots.isEmpty())
2791 bool resolveAlias = (mode == ResolveAliases);
2793 const Object::DynamicProperty *defaultProperty = 0;
2795 int varPropCount = 0;
2796 int totalPropCount = 0;
2797 int firstPropertyVarIndex = 0;
2799 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2801 if (p->type == Object::DynamicProperty::Alias)
2803 if (p->type == Object::DynamicProperty::Var)
2806 if (p->isDefaultProperty &&
2807 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2808 defaultProperty = p;
2810 if (!resolveAlias) {
2811 // No point doing this for both the alias and non alias cases
2812 QQmlPropertyData *d = property(obj, p->name);
2813 if (d && d->isFinal())
2814 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2818 bool buildData = resolveAlias || aliasCount == 0;
2820 QByteArray dynamicData;
2822 typedef QQmlVMEMetaData VMD;
2824 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2825 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2826 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2827 aliasCount * sizeof(VMD::AliasData), 0);
2830 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2832 QByteArray newClassName = obj->metatype->className();
2833 newClassName.append("_QML_");
2834 newClassName.append(QByteArray::number(uniqueClassId));
2836 if (compileState->root == obj && !compileState->nested) {
2837 QString path = output->url.path();
2838 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2839 if (lastSlash > -1) {
2840 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2841 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2842 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2846 // Size of the array that describes parameter types & names
2847 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2848 + obj->dynamicProperties.count() // for Changed() signals return types
2849 // Return "parameters" don't have names
2850 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2852 QFastMetaBuilder builder;
2854 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2855 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2856 obj->dynamicSlots.count(),
2857 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2858 defaultProperty?1:0, paramDataSize, ¶mIndex);
2861 Object::DynamicProperty::Type dtype;
2863 } builtinTypes[] = {
2864 { Object::DynamicProperty::Var, QMetaType::QVariant },
2865 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2866 { Object::DynamicProperty::Int, QMetaType::Int },
2867 { Object::DynamicProperty::Bool, QMetaType::Bool },
2868 { Object::DynamicProperty::Real, QMetaType::Double },
2869 { Object::DynamicProperty::String, QMetaType::QString },
2870 { Object::DynamicProperty::Url, QMetaType::QUrl },
2871 { Object::DynamicProperty::Color, QMetaType::QColor },
2872 { Object::DynamicProperty::Time, QMetaType::QTime },
2873 { Object::DynamicProperty::Date, QMetaType::QDate },
2874 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2875 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2877 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2879 // Reserve dynamic properties
2880 if (obj->dynamicProperties.count()) {
2881 typedef QQmlVMEMetaData VMD;
2883 int effectivePropertyIndex = 0;
2884 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2886 // Reserve space for name
2887 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2888 p->nameRef = builder.newString(p->name.utf8length());
2891 int propertyType = 0; // for VMD
2892 bool readonly = false;
2894 if (p->type == Object::DynamicProperty::Alias) {
2896 } else if (p->type < builtinTypeCount) {
2897 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2898 metaType = builtinTypes[p->type].metaType;
2899 propertyType = metaType;
2902 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2903 p->type == Object::DynamicProperty::Custom);
2905 // XXX don't double resolve this in the case of an alias run
2907 QByteArray customTypeName;
2908 QQmlType *qmltype = 0;
2910 if (!unit->imports().resolveType(p->customType, &qmltype, &url, 0, 0, 0))
2911 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2914 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
2916 Q_ASSERT(tdata->isComplete());
2917 customTypeName = tdata->compiledData()->root->className();
2920 customTypeName = qmltype->typeName();
2923 if (p->type == Object::DynamicProperty::Custom) {
2924 customTypeName += '*';
2925 propertyType = QMetaType::QObjectStar;
2928 customTypeName = QByteArrayLiteral("QQmlListProperty<") + customTypeName + '>';
2929 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2932 metaType = QMetaType::type(customTypeName);
2933 Q_ASSERT(metaType != QMetaType::UnknownType);
2934 Q_ASSERT(metaType != QMetaType::Void);
2937 if (p->type == Object::DynamicProperty::Var)
2944 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2945 vmd->propertyCount++;
2946 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2949 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2950 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2951 effectivePropertyIndex);
2953 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2954 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2957 effectivePropertyIndex++;
2961 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2963 vmd->varPropertyCount = varPropCount;
2964 firstPropertyVarIndex = effectivePropertyIndex;
2965 totalPropCount = varPropCount + effectivePropertyIndex;
2966 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2967 if (p->type == Object::DynamicProperty::Var) {
2969 vmd->propertyCount++;
2970 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2973 builder.setProperty(effectivePropertyIndex, p->nameRef,
2974 QMetaType::QVariant,
2975 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2976 effectivePropertyIndex);
2978 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2979 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2982 effectivePropertyIndex++;
2989 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2990 if (p->type == Object::DynamicProperty::Alias) {
2992 Q_ASSERT(buildData);
2993 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2994 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2997 // Even if we aren't resolving the alias, we need a fake signal so that the
2998 // metaobject remains consistent across the resolve and non-resolve alias runs
2999 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
3000 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
3002 effectivePropertyIndex++;
3009 // Reserve default property
3010 QFastMetaBuilder::StringRef defPropRef;
3011 if (defaultProperty) {
3012 defPropRef = builder.newString(int(sizeof("DefaultProperty")) - 1);
3013 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3016 // Reserve dynamic signals
3017 int signalIndex = 0;
3018 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3020 s->nameRef = builder.newString(s->name.utf8length());
3022 int paramCount = s->parameterNames.count();
3023 QVarLengthArray<int, 10> paramTypes(paramCount);
3025 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3026 for (int i = 0; i < paramCount; ++i) {
3027 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3028 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3029 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3034 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3036 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3037 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3038 paramIndex += paramCount*2 + 1;
3042 // Reserve dynamic slots
3043 if (obj->dynamicSlots.count()) {
3045 typedef QQmlVMEMetaData VMD;
3047 int methodIndex = 0;
3048 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3049 s->nameRef = builder.newString(s->name.utf8length());
3050 int paramCount = s->parameterNames.count();
3052 QVarLengthArray<int, 10> paramTypes(paramCount);
3054 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3055 for (int i = 0; i < paramCount; ++i) {
3056 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3057 paramTypes[i] = QMetaType::QVariant;
3061 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3062 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3063 paramIndex += paramCount*2 + 1;
3068 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3069 funcScript.reserve(int(sizeof("(function ")) - 1 + s->name.length() + 1 /* lparen */ +
3070 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3071 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3072 for (int jj = 0; jj < paramCount; ++jj) {
3073 if (jj) funcScript.append(QLatin1Char(','));
3074 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3076 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3078 QByteArray utf8 = funcScript.toUtf8();
3079 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3081 s->location.start.line };
3083 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3086 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3088 md.bodyOffset = dynamicData.size();
3090 dynamicData.append((const char *)utf8.constData(), utf8.length());
3098 // Now allocate properties
3099 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3101 char *d = p->changedNameRef.data();
3102 p->name.writeUtf8(d);
3103 strcpy(d + p->name.utf8length(), "Changed");
3104 p->changedNameRef.loadByteArrayData();
3106 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3109 p->nameRef.load(p->name);
3112 // Allocate default property if necessary
3113 if (defaultProperty)
3114 defPropRef.load("DefaultProperty");
3116 // Now allocate signals
3117 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3119 s->nameRef.load(s->name);
3121 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3122 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3125 // Now allocate methods
3126 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3127 s->nameRef.load(s->name);
3129 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3130 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3133 // Now allocate class name
3134 classNameRef.load(newClassName);
3136 obj->metadata = builder.toData();
3137 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3139 if (mode == IgnoreAliases && aliasCount)
3140 compileState->aliasingObjects.append(obj);
3142 obj->synthdata = dynamicData;
3144 if (obj->synthCache) {
3145 obj->synthCache->release();
3146 obj->synthCache = 0;
3149 if (obj->type != -1) {
3150 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3151 QQmlPropertyCache *cache =
3152 superCache->copyAndAppend(engine, &obj->extObject,
3153 QQmlPropertyData::NoFlags,
3154 QQmlPropertyData::IsVMEFunction,
3155 QQmlPropertyData::IsVMESignal);
3157 // now we modify the flags appropriately for var properties.
3158 int propertyOffset = obj->extObject.propertyOffset();
3159 QQmlPropertyData *currPropData = 0;
3160 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3161 currPropData = cache->property(pvi + propertyOffset);
3162 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3165 obj->synthCache = cache;
3171 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3174 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3176 QChar ch = val.at(0);
3177 if (ch.isLetter() && !ch.isLower())
3178 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3180 QChar u(QLatin1Char('_'));
3181 if (!ch.isLetter() && ch != u)
3182 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3184 for (int ii = 1; ii < val.count(); ++ii) {
3186 if (!ch.isLetterOrNumber() && ch != u)
3187 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3190 if (enginePrivate->v8engine()->illegalNames().contains(val))
3191 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3196 #include <private/qqmljsparser_p.h>
3198 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3200 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3202 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3203 return QStringList() << name;
3204 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3205 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3207 QStringList rv = astNodeToStringList(expr->base);
3210 rv.append(expr->name.toString());
3213 return QStringList();
3216 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3218 QQmlScript::Object *obj,
3219 int propIndex, int aliasIndex,
3220 Object::DynamicProperty &prop)
3222 Q_ASSERT(!prop.nameRef.isEmpty());
3223 if (!prop.defaultValue)
3224 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3226 if (!prop.defaultValue->values.isOne() ||
3227 prop.defaultValue->values.first()->object ||
3228 !prop.defaultValue->values.first()->value.isScript())
3229 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3231 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3233 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3235 QStringList alias = astNodeToStringList(node);
3237 if (alias.count() < 1 || alias.count() > 3)
3238 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3240 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3242 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3244 QByteArray typeName;
3249 bool writable = false;
3250 bool resettable = false;
3251 if (alias.count() == 2 || alias.count() == 3) {
3252 propIdx = indexOfProperty(idObject, alias.at(1));
3254 if (-1 == propIdx) {
3255 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3256 } else if (propIdx > 0xFFFF) {
3257 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3260 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3261 if (!aliasProperty.isScriptable())
3262 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3264 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3265 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3267 type = aliasProperty.userType();
3269 if (alias.count() == 3) {
3270 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3272 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3274 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3276 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3277 if (valueTypeIndex == -1)
3278 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3279 Q_ASSERT(valueTypeIndex <= 0xFF);
3281 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3282 propIdx |= (valueTypeIndex << 16);
3284 // update the property type
3285 type = aliasProperty.userType();
3288 if (aliasProperty.isEnumType())
3289 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3291 typeName = aliasProperty.typeName();
3293 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3295 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3297 typeName = ref.type->typeName();
3299 typeName = ref.component->root->className();
3304 if (typeName.endsWith('*'))
3305 flags |= QML_ALIAS_FLAG_PTR;
3307 if (type == QMetaType::UnknownType) {
3308 Q_ASSERT(!typeName.isEmpty());
3309 type = QMetaType::type(typeName);
3310 Q_ASSERT(type != QMetaType::UnknownType);
3311 Q_ASSERT(type != QMetaType::Void);
3314 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3316 typedef QQmlVMEMetaData VMD;
3317 VMD *vmd = (QQmlVMEMetaData *)data.data();
3318 *(vmd->aliasData() + aliasIndex) = aliasData;
3320 int propertyFlags = 0;
3322 propertyFlags |= QFastMetaBuilder::Writable;
3324 propertyFlags |= QFastMetaBuilder::Resettable;
3326 builder.setProperty(propIndex, prop.nameRef, type,
3327 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3333 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3334 QQmlScript::Property *prop,
3335 const BindingContext &ctxt)
3337 Q_ASSERT(prop->index != -1);
3338 Q_ASSERT(prop->parent);
3339 Q_ASSERT(prop->parent->metaObject());
3341 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3342 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3344 JSBindingReference *reference = pool->New<JSBindingReference>();
3345 reference->expression = value->value;
3346 reference->property = prop;
3347 reference->value = value;
3348 reference->bindingContext = ctxt;
3349 addBindingReference(reference);
3354 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3355 QQmlScript::Property *prop,
3356 const QQmlCompilerTypes::BindingContext &)
3358 Q_ASSERT(v->value.isScript());
3360 if (!prop->core.isWritable())
3363 AST::Node *binding = v->value.asAST();
3365 if (prop->type == QVariant::String) {
3366 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3367 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3368 if (i->name == qsTrId_string) {
3369 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3370 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3372 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3373 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3374 (!arg2 || !arg2->next)) {
3379 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3380 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3382 TrBindingReference *reference = pool->New<TrBindingReference>();
3383 reference->dataType = BindingReference::TrId;
3384 reference->text = text;
3386 v->bindingReference = reference;
3390 } else if (i->name == qsTr_string) {
3392 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3393 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3394 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3396 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3397 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3398 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3399 (!arg3 || !arg3->next)) {
3405 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3406 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3407 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3409 TrBindingReference *reference = pool->New<TrBindingReference>();
3410 reference->dataType = BindingReference::Tr;
3411 reference->text = text;
3412 reference->comment = comment;
3414 v->bindingReference = reference;
3427 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3428 QQmlScript::Property *prop,
3429 QQmlScript::Object *obj,
3430 QQmlScript::Property *valueTypeProperty)
3433 Q_ASSERT(binding->bindingReference);
3435 const BindingReference &ref = *binding->bindingReference;
3436 if (ref.dataType == BindingReference::TrId) {
3437 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3439 Instruction::StoreTrIdString store;
3440 store.propertyIndex = prop->core.coreIndex;
3441 store.text = output->indexForByteArray(tr.text.toUtf8());
3443 output->addInstruction(store);
3444 } else if (ref.dataType == BindingReference::Tr) {
3445 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3447 Instruction::StoreTrString store;
3448 store.propertyIndex = prop->core.coreIndex;
3449 store.context = translationContextIndex();
3450 store.text = output->indexForByteArray(tr.text.toUtf8());
3451 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3453 output->addInstruction(store);
3454 } else if (ref.dataType == BindingReference::V4) {
3455 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3457 Instruction::StoreV4Binding store;
3458 store.value = js.compiledIndex;
3459 store.context = js.bindingContext.stack;
3460 store.owner = js.bindingContext.owner;
3461 store.isAlias = prop->isAlias;
3462 if (valueTypeProperty) {
3463 store.property = (valueTypeProperty->index & 0xFFFF) |
3464 ((valueTypeProperty->type & 0xFF)) << 16 |
3465 ((prop->index & 0xFF) << 24);
3466 store.isRoot = (compileState->root == valueTypeProperty->parent);
3468 store.property = prop->index;
3469 store.isRoot = (compileState->root == obj);
3471 store.line = binding->location.start.line;
3472 store.column = binding->location.start.column;
3473 output->addInstruction(store);
3474 } else if (ref.dataType == BindingReference::V8) {
3475 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3477 Instruction::StoreV8Binding store;
3478 store.value = js.compiledIndex;
3479 store.context = js.bindingContext.stack;
3480 store.owner = js.bindingContext.owner;
3481 store.isAlias = prop->isAlias;
3482 if (valueTypeProperty) {
3483 store.isRoot = (compileState->root == valueTypeProperty->parent);
3485 store.isRoot = (compileState->root == obj);
3487 store.line = binding->location.start.line;
3488 store.column = binding->location.start.column;
3490 Q_ASSERT(js.bindingContext.owner == 0 ||
3491 (js.bindingContext.owner != 0 && valueTypeProperty));
3492 if (js.bindingContext.owner) {
3493 store.property = genValueTypeData(prop, valueTypeProperty);
3495 store.property = prop->core;
3498 output->addInstruction(store);
3499 } else if (ref.dataType == BindingReference::QtScript) {
3500 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3502 Instruction::StoreBinding store;
3503 store.value = output->indexForString(js.rewrittenExpression);
3504 store.context = js.bindingContext.stack;
3505 store.owner = js.bindingContext.owner;
3506 store.line = binding->location.start.line;
3507 store.column = binding->location.start.column;
3508 store.isAlias = prop->isAlias;
3510 if (valueTypeProperty) {
3511 store.isRoot = (compileState->root == valueTypeProperty->parent);
3513 store.isRoot = (compileState->root == obj);
3516 Q_ASSERT(js.bindingContext.owner == 0 ||
3517 (js.bindingContext.owner != 0 && valueTypeProperty));
3518 if (js.bindingContext.owner) {
3519 store.property = genValueTypeData(prop, valueTypeProperty);
3521 store.property = prop->core;
3524 output->addInstruction(store);
3526 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3530 int QQmlCompiler::genContextCache()
3532 if (compileState->ids.count() == 0)
3535 QQmlIntegerCache *cache = new QQmlIntegerCache();
3536 cache->reserve(compileState->ids.count());
3537 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3538 cache->add(o->id, o->idIndex);
3540 output->contextCaches.append(cache);
3541 return output->contextCaches.count() - 1;
3545 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3546 QQmlScript::Property *prop)
3548 typedef QQmlPropertyPrivate QDPP;
3549 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3550 enginePrivate->valueTypes[prop->type]->metaObject(),
3551 valueTypeProp->index, engine);
3554 bool QQmlCompiler::completeComponentBuild()
3557 componentStats->componentStat.ids = compileState->ids.count();
3559 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3560 aliasObject = compileState->aliasingObjects.next(aliasObject))
3561 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3563 QV4Compiler::Expression expr(unit->imports());
3564 expr.component = compileState->root;
3565 expr.ids = &compileState->ids;
3566 expr.importCache = output->importCache;
3568 QV4Compiler bindingCompiler;
3570 QList<JSBindingReference*> sharedBindings;
3572 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3574 JSBindingReference &binding = *b;
3577 expr.context = binding.bindingContext.object;
3578 expr.property = binding.property;
3579 expr.expression = binding.expression;
3581 int index = bindingCompiler.compile(expr, enginePrivate);
3583 binding.dataType = BindingReference::V4;
3584 binding.compiledIndex = index;
3586 componentStats->componentStat.optimizedBindings.append(b->value->location);
3590 // Pre-rewrite the expression
3591 QString expression = binding.expression.asScript();
3593 QQmlRewrite::RewriteBinding rewriteBinding;
3594 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3595 bool isSharable = false;
3596 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3598 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3599 binding.dataType = BindingReference::V8;
3600 sharedBindings.append(b);
3603 componentStats->componentStat.sharedBindings.append(b->value->location);
3605 binding.dataType = BindingReference::QtScript;
3608 componentStats->componentStat.scriptBindings.append(b->value->location);
3612 if (!sharedBindings.isEmpty()) {
3614 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3616 return lhs->value->location.start.line < rhs->value->location.start.line;
3620 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3622 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3623 int lineNumber = startLineNumber;
3625 QByteArray functionArray("[", 1);
3626 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3628 JSBindingReference *reference = sharedBindings.at(ii);
3629 QQmlScript::Value *value = reference->value;
3630 const QString &expression = reference->rewrittenExpression;
3632 if (ii != 0) functionArray.append(",", 1);
3634 while (lineNumber < value->location.start.line) {
3636 functionArray.append("\n", 1);
3639 functionArray += expression.toUtf8();
3640 lineNumber += expression.count(QLatin1Char('\n'));
3641 reference->compiledIndex = ii;
3643 functionArray.append("]", 1);
3645 compileState->v8BindingProgram = functionArray;
3646 compileState->v8BindingProgramLine = startLineNumber;
3649 if (bindingCompiler.isValid())
3650 compileState->compiledBindingData = bindingCompiler.program();
3652 // Check pop()'s matched push()'s
3653 Q_ASSERT(compileState->objectDepth.depth() == 0);
3654 Q_ASSERT(compileState->listDepth.depth() == 0);
3656 saveComponentState();
3661 void QQmlCompiler::dumpStats()
3663 Q_ASSERT(componentStats);
3664 qWarning().nospace() << "QML Document: " << output->url.toString();
3665 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3666 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3667 qWarning().nospace() << " Component Line " << stat.lineNumber;
3668 qWarning().nospace() << " Total Objects: " << stat.objects;
3669 qWarning().nospace() << " IDs Used: " << stat.ids;
3670 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3674 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3675 if (0 == (ii % 10)) {
3676 if (ii) output.append("\n");
3681 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3683 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3684 output.append(") ");
3686 if (!output.isEmpty())
3687 qWarning().nospace() << output.constData();
3690 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3693 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3694 if (0 == (ii % 10)) {
3695 if (ii) output.append('\n');
3700 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3702 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3703 output.append(") ");
3705 if (!output.isEmpty())
3706 qWarning().nospace() << output.constData();
3709 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3712 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3713 if (0 == (ii % 10)) {
3714 if (ii) output.append('\n');
3719 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3721 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3722 output.append(") ");
3724 if (!output.isEmpty())
3725 qWarning().nospace() << output.constData();
3731 Returns true if from can be assigned to a (QObject) property of type
3734 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3736 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3737 const QMetaObject *fromMo = from->metaObject();
3740 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3742 fromMo = fromMo->superClass();
3748 Returns the element name, as written in the QML file, for o.
3750 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3753 if (o->type != -1) {
3754 return unit->parser().referencedTypes().at(o->type)->name;
3760 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3762 if (from->type != -1 && output->types.at(from->type).type)
3763 return output->types.at(from->type).type;
3766 const QMetaObject *mo = from->metatype;
3768 while (!type && mo) {
3769 type = QQmlMetaType::qmlType(mo);
3770 mo = mo->superClass();
3775 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3777 const QMetaObject *mo = obj->metatype;
3779 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3781 return QStringList();
3783 QMetaClassInfo classInfo = mo->classInfo(idx);
3784 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3789 QQmlCompiler::property(QQmlScript::Object *object, int index)
3791 QQmlPropertyCache *cache = 0;
3793 if (object->synthCache)
3794 cache = object->synthCache;
3795 else if (object->type != -1)
3796 cache = output->types[object->type].createPropertyCache(engine);
3798 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3800 return cache->property(index);
3804 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3806 if (notInRevision) *notInRevision = false;
3808 QQmlPropertyCache *cache = 0;
3810 if (object->synthCache)
3811 cache = object->synthCache;
3812 else if (object->type != -1)
3813 cache = output->types[object->type].createPropertyCache(engine);
3815 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3817 QQmlPropertyData *d = cache->property(name);
3819 // Find the first property
3820 while (d && d->isFunction())
3821 d = cache->overrideData(d);
3823 if (d && !cache->isAllowedInRevision(d)) {
3824 if (notInRevision) *notInRevision = true;
3831 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3833 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3835 if (notInRevision) *notInRevision = false;
3837 QQmlPropertyCache *cache = 0;
3839 if (object->synthCache)
3840 cache = object->synthCache;
3841 else if (object->type != -1)
3842 cache = output->types[object->type].createPropertyCache(engine);
3844 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3847 QQmlPropertyData *d = cache->property(name);
3848 if (notInRevision) *notInRevision = false;
3850 while (d && !(d->isFunction()))
3851 d = cache->overrideData(d);
3853 if (d && !cache->isAllowedInRevision(d)) {
3854 if (notInRevision) *notInRevision = true;
3860 if (name.endsWith(Changed_string)) {
3861 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3863 d = property(object, propName, notInRevision);
3865 return cache->method(d->notifyIndex);
3871 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3872 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3873 bool *notInRevision)
3875 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3876 return d?d->coreIndex:-1;
3879 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3880 bool *notInRevision)
3882 return indexOfProperty(object, QStringRef(&name), notInRevision);
3885 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3886 bool *notInRevision)
3888 QQmlPropertyData *d = property(object, name, notInRevision);
3889 return d?d->coreIndex:-1;