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>
72 #include <QtCore/qdebug.h>
73 #include <QtCore/qdatetime.h>
74 #include <QtCore/qvarlengtharray.h>
76 Q_DECLARE_METATYPE(QList<int>)
77 Q_DECLARE_METATYPE(QList<qreal>)
78 Q_DECLARE_METATYPE(QList<bool>)
79 Q_DECLARE_METATYPE(QList<QString>)
80 Q_DECLARE_METATYPE(QList<QUrl>)
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_import_string(QLatin1String("QML/Component"));
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:
354 QQmlStringConverters::vector3DFromString(value.asString(), &ok);
355 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
358 case QVariant::Vector4D:
361 QQmlStringConverters::vector4DFromString(value.asString(), &ok);
362 if (!ok) 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"));
401 // otherwise, check for existence of string converter to custom type
402 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
404 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
411 static QUrl urlFromUserString(const QString &data)
414 // Preserve any valid percent-encoded octets supplied by the source
415 u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
420 Generate a store instruction for assigning literal \a v to property \a prop.
422 Any literal assignment that is approved in testLiteralAssignment() must have
423 a corresponding action in this method.
425 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
426 QQmlScript::Value *v)
428 if (prop->core.isEnum()) {
429 Q_ASSERT(v->value.isNumber());
431 int value = (int)v->value.asNumber();
433 Instruction::StoreInteger instr;
434 instr.propertyIndex = prop->index;
436 output->addInstruction(instr);
440 int type = prop->type;
442 case QMetaType::QVariant:
444 if (v->value.isNumber()) {
445 double n = v->value.asNumber();
446 if (double(int(n)) == n) {
447 if (prop->core.isVMEProperty()) {
448 Instruction::StoreVarInteger instr;
449 instr.propertyIndex = prop->index;
450 instr.value = int(n);
451 output->addInstruction(instr);
453 Instruction::StoreVariantInteger instr;
454 instr.propertyIndex = prop->index;
455 instr.value = int(n);
456 output->addInstruction(instr);
459 if (prop->core.isVMEProperty()) {
460 Instruction::StoreVarDouble instr;
461 instr.propertyIndex = prop->index;
463 output->addInstruction(instr);
465 Instruction::StoreVariantDouble instr;
466 instr.propertyIndex = prop->index;
468 output->addInstruction(instr);
471 } else if (v->value.isBoolean()) {
472 if (prop->core.isVMEProperty()) {
473 Instruction::StoreVarBool instr;
474 instr.propertyIndex = prop->index;
475 instr.value = v->value.asBoolean();
476 output->addInstruction(instr);
478 Instruction::StoreVariantBool instr;
479 instr.propertyIndex = prop->index;
480 instr.value = v->value.asBoolean();
481 output->addInstruction(instr);
484 if (prop->core.isVMEProperty()) {
485 Instruction::StoreVar instr;
486 instr.propertyIndex = prop->index;
487 instr.value = output->indexForString(v->value.asString());
488 output->addInstruction(instr);
490 Instruction::StoreVariant instr;
491 instr.propertyIndex = prop->index;
492 instr.value = output->indexForString(v->value.asString());
493 output->addInstruction(instr);
498 case QVariant::String:
500 Instruction::StoreString instr;
501 instr.propertyIndex = prop->index;
502 instr.value = output->indexForString(v->value.asString());
503 output->addInstruction(instr);
506 case QVariant::StringList:
508 Instruction::StoreStringList instr;
509 instr.propertyIndex = prop->index;
510 instr.value = output->indexForString(v->value.asString());
511 output->addInstruction(instr);
514 case QVariant::ByteArray:
516 Instruction::StoreByteArray instr;
517 instr.propertyIndex = prop->index;
518 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
519 output->addInstruction(instr);
524 Instruction::StoreUrl instr;
525 QString string = v->value.asString();
526 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
527 instr.propertyIndex = prop->index;
528 instr.value = output->indexForUrl(u);
529 output->addInstruction(instr);
534 Instruction::StoreInteger instr;
535 instr.propertyIndex = prop->index;
536 instr.value = uint(v->value.asNumber());
537 output->addInstruction(instr);
542 Instruction::StoreInteger instr;
543 instr.propertyIndex = prop->index;
544 instr.value = int(v->value.asNumber());
545 output->addInstruction(instr);
548 case QMetaType::Float:
550 Instruction::StoreFloat instr;
551 instr.propertyIndex = prop->index;
552 instr.value = float(v->value.asNumber());
553 output->addInstruction(instr);
556 case QVariant::Double:
558 Instruction::StoreDouble instr;
559 instr.propertyIndex = prop->index;
560 instr.value = v->value.asNumber();
561 output->addInstruction(instr);
564 case QVariant::Color:
566 Instruction::StoreColor instr;
567 QColor c = QQmlStringConverters::colorFromString(v->value.asString());
568 instr.propertyIndex = prop->index;
569 instr.value = c.rgba();
570 output->addInstruction(instr);
573 #ifndef QT_NO_DATESTRING
576 Instruction::StoreDate instr;
577 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
578 instr.propertyIndex = prop->index;
579 instr.value = d.toJulianDay();
580 output->addInstruction(instr);
585 Instruction::StoreTime instr;
586 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
587 instr.propertyIndex = prop->index;
588 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
589 ::memcpy(&instr.time, &time, sizeof(QTime));
590 output->addInstruction(instr);
593 case QVariant::DateTime:
595 Instruction::StoreDateTime instr;
596 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
597 QTime time = dateTime.time();
598 instr.propertyIndex = prop->index;
599 instr.date = dateTime.date().toJulianDay();
600 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
601 ::memcpy(&instr.time, &time, sizeof(QTime));
602 output->addInstruction(instr);
605 #endif // QT_NO_DATESTRING
606 case QVariant::Point:
608 Instruction::StorePoint instr;
610 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
611 instr.propertyIndex = prop->index;
612 instr.point.xp = point.x();
613 instr.point.yp = point.y();
614 output->addInstruction(instr);
617 case QVariant::PointF:
619 Instruction::StorePointF instr;
621 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
622 instr.propertyIndex = prop->index;
623 instr.point.xp = point.x();
624 instr.point.yp = point.y();
625 output->addInstruction(instr);
630 Instruction::StoreSize instr;
632 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
633 instr.propertyIndex = prop->index;
634 instr.size.wd = size.width();
635 instr.size.ht = size.height();
636 output->addInstruction(instr);
639 case QVariant::SizeF:
641 Instruction::StoreSizeF instr;
643 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
644 instr.propertyIndex = prop->index;
645 instr.size.wd = size.width();
646 instr.size.ht = size.height();
647 output->addInstruction(instr);
652 Instruction::StoreRect instr;
654 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
655 instr.propertyIndex = prop->index;
656 instr.rect.x1 = rect.left();
657 instr.rect.y1 = rect.top();
658 instr.rect.x2 = rect.right();
659 instr.rect.y2 = rect.bottom();
660 output->addInstruction(instr);
663 case QVariant::RectF:
665 Instruction::StoreRectF instr;
667 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
668 instr.propertyIndex = prop->index;
669 instr.rect.xp = rect.left();
670 instr.rect.yp = rect.top();
671 instr.rect.w = rect.width();
672 instr.rect.h = rect.height();
673 output->addInstruction(instr);
678 Instruction::StoreBool instr;
679 bool b = v->value.asBoolean();
680 instr.propertyIndex = prop->index;
682 output->addInstruction(instr);
685 case QVariant::Vector3D:
687 Instruction::StoreVector3D instr;
689 QVector3D vector = QQmlStringConverters::vector3DFromString(v->value.asString(), &ok);
690 instr.propertyIndex = prop->index;
691 instr.vector.xp = vector.x();
692 instr.vector.yp = vector.y();
693 instr.vector.zp = vector.z();
694 output->addInstruction(instr);
697 case QVariant::Vector4D:
699 Instruction::StoreVector4D instr;
701 QVector4D vector = QQmlStringConverters::vector4DFromString(v->value.asString(), &ok);
702 instr.propertyIndex = prop->index;
703 instr.vector.xp = vector.x();
704 instr.vector.yp = vector.y();
705 instr.vector.zp = vector.z();
706 instr.vector.wp = vector.w();
707 output->addInstruction(instr);
712 // generate single literal value assignment to a list property if required
713 if (type == qMetaTypeId<QList<qreal> >()) {
714 Instruction::StoreDoubleQList instr;
715 instr.propertyIndex = prop->index;
716 instr.value = v->value.asNumber();
717 output->addInstruction(instr);
719 } else if (type == qMetaTypeId<QList<int> >()) {
720 Instruction::StoreIntegerQList instr;
721 instr.propertyIndex = prop->index;
722 instr.value = int(v->value.asNumber());
723 output->addInstruction(instr);
725 } else if (type == qMetaTypeId<QList<bool> >()) {
726 Instruction::StoreBoolQList instr;
727 bool b = v->value.asBoolean();
728 instr.propertyIndex = prop->index;
730 output->addInstruction(instr);
732 } else if (type == qMetaTypeId<QList<QUrl> >()) {
733 Instruction::StoreUrlQList instr;
734 QString string = v->value.asString();
735 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
736 instr.propertyIndex = prop->index;
737 instr.value = output->indexForUrl(u);
738 output->addInstruction(instr);
740 } else if (type == qMetaTypeId<QList<QString> >()) {
741 Instruction::StoreStringQList instr;
742 instr.propertyIndex = prop->index;
743 instr.value = output->indexForString(v->value.asString());
744 output->addInstruction(instr);
748 // otherwise, generate custom type literal assignment
749 Instruction::AssignCustomType instr;
750 instr.propertyIndex = prop->index;
751 instr.primitive = output->indexForString(v->value.asString());
753 output->addInstruction(instr);
760 Resets data by clearing the lists that the QQmlCompiler modifies.
762 void QQmlCompiler::reset(QQmlCompiledData *data)
765 data->primitives.clear();
767 data->bytecode.resize(0);
771 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
772 with which the QQmlCompiledData will be associated.
774 Returns true on success, false on failure. On failure, the compile errors
775 are available from errors().
777 If the environment variant QML_COMPILER_DUMP is set
778 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
779 on a successful compiler.
781 bool QQmlCompiler::compile(QQmlEngine *engine,
783 QQmlCompiledData *out)
790 QQmlScript::Object *root = unit->parser().tree();
793 this->engine = engine;
794 this->enginePrivate = QQmlEnginePrivate::get(engine);
796 this->unitRoot = root;
800 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
801 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
803 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
804 QQmlCompiledData::TypeReference ref;
806 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
807 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
810 ref.type = tref.type;
811 if (!ref.type->isCreatable()) {
812 QString err = ref.type->noCreationReason();
814 err = tr( "Element is not creatable.");
815 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
818 if (ref.type->containsRevisionedAttributes()) {
819 QQmlError cacheError;
820 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
822 if (!ref.typePropertyCache)
823 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
824 ref.typePropertyCache->addref();
827 } else if (tref.typeData) {
828 ref.component = tref.typeData->compiledData();
830 ref.className = parserRef->name;
838 out->dumpInstructions();
841 Q_ASSERT(out->rootPropertyCache);
849 this->enginePrivate = 0;
851 this->cachedComponentTypeRef = -1;
852 this->cachedTranslationContextIndex = -1;
858 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
860 compileState = pool->New<ComponentCompileState>();
862 compileState->root = tree;
864 componentStats->componentStat.lineNumber = tree->location.start.line;
866 // We generate the importCache before we build the tree so that
867 // it can be used in the binding compiler. Given we "expect" the
868 // QML compilation to succeed, this isn't a waste.
869 output->importCache = new QQmlTypeNameCache();
870 foreach (const QString &ns, unit->namespaces()) {
871 output->importCache->add(ns);
875 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
876 QString qualifier = script.qualifier;
877 QString enclosingNamespace;
879 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
880 if (lastDotIndex != -1) {
881 enclosingNamespace = qualifier.left(lastDotIndex);
882 qualifier = qualifier.mid(lastDotIndex+1);
885 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
888 unit->imports().populateCache(output->importCache, engine);
890 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
893 Instruction::Init init;
894 init.bindingsSize = compileState->totalBindingsCount;
895 init.parserStatusSize = compileState->parserStatusCount;
896 init.contextCache = genContextCache();
897 init.objectStackSize = compileState->objectDepth.maxDepth();
898 init.listStackSize = compileState->listDepth.maxDepth();
899 if (compileState->compiledBindingData.isEmpty())
900 init.compiledBinding = -1;
902 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
903 output->addInstruction(init);
905 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
906 Instruction::StoreImportedScript import;
907 import.value = output->scripts.count();
909 QQmlScriptData *scriptData = script.script->scriptData();
910 scriptData->addref();
911 output->scripts << scriptData;
912 output->addInstruction(import);
915 if (!compileState->v8BindingProgram.isEmpty()) {
916 Instruction::InitV8Bindings bindings;
917 int index = output->programs.count();
919 typedef QQmlCompiledData::V8Program V8Program;
920 output->programs.append(V8Program(compileState->v8BindingProgram, output));
922 bindings.programIndex = index;
923 bindings.line = compileState->v8BindingProgramLine;
924 output->addInstruction(bindings);
929 Instruction::SetDefault def;
930 output->addInstruction(def);
932 Instruction::Done done;
933 output->addInstruction(done);
935 Q_ASSERT(tree->metatype);
937 if (tree->metadata.isEmpty()) {
938 output->root = tree->metatype;
940 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
941 output->root = &output->rootData;
943 if (!tree->metadata.isEmpty())
944 enginePrivate->registerCompositeType(output);
947 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
949 for (int ii = 0; ii < list.count(); ++ii)
950 if (string == list.at(ii))
956 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
959 componentStats->componentStat.objects++;
961 Q_ASSERT (obj->type != -1);
962 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
963 obj->metatype = tr.metaObject();
966 obj->typeName = tr.type->qmlTypeName();
968 // This object is a "Component" element
969 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
970 COMPILE_CHECK(buildComponent(obj, ctxt));
975 typedef QQmlInstruction I;
976 const I *init = ((const I *)tr.component->bytecode.constData());
977 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
979 // Adjust stack depths to include nested components
980 compileState->objectDepth.pushPop(init->init.objectStackSize);
981 compileState->listDepth.pushPop(init->init.listStackSize);
982 compileState->parserStatusCount += init->init.parserStatusSize;
983 compileState->totalBindingsCount += init->init.bindingsSize;
986 compileState->objectDepth.push();
988 // Object instantiations reset the binding context
989 BindingContext objCtxt(obj);
991 // Create the synthesized meta object, ignoring aliases
992 COMPILE_CHECK(checkDynamicMeta(obj));
993 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
994 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
996 // Find the native type and check for the QQmlParserStatus interface
997 QQmlType *type = toQmlType(obj);
999 obj->parserStatusCast = type->parserStatusCast();
1000 if (obj->parserStatusCast != -1)
1001 compileState->parserStatusCount++;
1003 // Check if this is a custom parser type. Custom parser types allow
1004 // assignments to non-existent properties. These assignments are then
1005 // compiled by the type.
1006 bool isCustomParser = output->types.at(obj->type).type &&
1007 output->types.at(obj->type).type->customParser() != 0;
1008 QList<QQmlCustomParserProperty> customProps;
1010 // Fetch the list of deferred properties
1011 QStringList deferredList = deferredProperties(obj);
1013 // Must do id property first. This is to ensure that the id given to any
1014 // id reference created matches the order in which the objects are
1016 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1017 if (prop->name() == id_string) {
1018 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1024 Property *defaultProperty = 0;
1025 Property *skipProperty = 0;
1026 if (obj->defaultProperty) {
1027 defaultProperty = obj->defaultProperty;
1029 Property *explicitProperty = 0;
1031 const QMetaObject *mo = obj->metatype;
1032 int idx = mo->indexOfClassInfo("DefaultProperty");
1034 QMetaClassInfo info = mo->classInfo(idx);
1035 const char *p = info.value();
1039 while (char c = p[plen++]) { ord |= c; };
1043 // Utf8 - unoptimal, but seldom hit
1044 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1045 QHashedStringRef r(*s);
1047 if (obj->propertiesHashField.test(r.hash())) {
1048 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1049 if (ep->name() == r) {
1050 explicitProperty = ep;
1056 if (!explicitProperty)
1057 defaultProperty->setName(r);
1060 QHashedCStringRef r(p, plen);
1062 if (obj->propertiesHashField.test(r.hash())) {
1063 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1064 if (ep->name() == r) {
1065 explicitProperty = ep;
1071 if (!explicitProperty) {
1072 // Set the default property name
1073 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1074 r.writeUtf16(buffer);
1075 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1081 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1083 skipProperty = explicitProperty; // We merge the values into defaultProperty
1085 // Find the correct insertion point
1086 Value *insertPos = 0;
1088 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1089 if (!(v->location.start < explicitProperty->values.first()->location.start))
1094 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1098 QQmlCustomParser *cp = 0;
1100 cp = output->types.at(obj->type).type->customParser();
1102 // Build all explicit properties specified
1103 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1105 if (prop == skipProperty)
1107 if (prop->name() == id_string)
1110 bool canDefer = false;
1111 if (isCustomParser) {
1112 if (doesPropertyExist(prop, obj) &&
1113 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1114 !isAttachedPropertyName(prop->name()))) {
1115 int ids = compileState->ids.count();
1116 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1117 canDefer = ids == compileState->ids.count();
1118 } else if (isSignalPropertyName(prop->name()) &&
1119 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1120 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1122 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1125 if (isSignalPropertyName(prop->name())) {
1126 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1128 int ids = compileState->ids.count();
1129 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1130 canDefer = ids == compileState->ids.count();
1134 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1135 prop->isDeferred = true;
1139 // Build the default property
1140 if (defaultProperty) {
1141 Property *prop = defaultProperty;
1143 bool canDefer = false;
1144 if (isCustomParser) {
1145 if (doesPropertyExist(prop, obj)) {
1146 int ids = compileState->ids.count();
1147 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1148 canDefer = ids == compileState->ids.count();
1150 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1153 int ids = compileState->ids.count();
1154 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1155 canDefer = ids == compileState->ids.count();
1158 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1159 prop->isDeferred = true;
1162 // Compile custom parser parts
1163 if (isCustomParser && !customProps.isEmpty()) {
1165 cp->compiler = this;
1167 obj->custom = cp->compile(customProps);
1170 foreach (QQmlError err, cp->errors()) {
1171 err.setUrl(output->url);
1176 compileState->objectDepth.pop();
1181 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1183 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1184 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1189 // Create the object
1190 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1191 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1193 Instruction::CreateSimpleObject create;
1194 create.create = output->types.at(obj->type).type->createFunction();
1195 create.typeSize = output->types.at(obj->type).type->createSize();
1196 create.type = obj->type;
1197 create.line = obj->location.start.line;
1198 create.column = obj->location.start.column;
1199 output->addInstruction(create);
1203 if (output->types.at(obj->type).type) {
1204 Instruction::CreateCppObject create;
1205 create.line = obj->location.start.line;
1206 create.column = obj->location.start.column;
1208 if (!obj->custom.isEmpty())
1209 create.data = output->indexForByteArray(obj->custom);
1210 create.type = obj->type;
1211 create.isRoot = (compileState->root == obj);
1212 output->addInstruction(create);
1214 Instruction::CreateQMLObject create;
1215 create.type = obj->type;
1216 create.isRoot = (compileState->root == obj);
1218 if (!obj->bindingBitmask.isEmpty()) {
1219 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1220 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1222 create.bindingBits = -1;
1224 output->addInstruction(create);
1226 Instruction::CompleteQMLObject complete;
1227 complete.line = obj->location.start.line;
1228 complete.column = obj->location.start.column;
1229 complete.isRoot = (compileState->root == obj);
1230 output->addInstruction(complete);
1234 // Setup the synthesized meta object if necessary
1235 if (!obj->metadata.isEmpty()) {
1236 Instruction::StoreMetaObject meta;
1237 meta.data = output->indexForByteArray(obj->metadata);
1238 meta.aliasData = output->indexForByteArray(obj->synthdata);
1239 meta.propertyCache = output->propertyCaches.count();
1241 QQmlPropertyCache *propertyCache = obj->synthCache;
1242 Q_ASSERT(propertyCache);
1243 propertyCache->addref();
1245 // Add flag for alias properties
1246 if (!obj->synthdata.isEmpty()) {
1247 const QQmlVMEMetaData *vmeMetaData =
1248 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1249 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1250 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1251 QQmlPropertyData *data = propertyCache->property(index);
1252 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1256 if (obj == unitRoot) {
1257 propertyCache->addref();
1258 output->rootPropertyCache = propertyCache;
1261 output->propertyCaches << propertyCache;
1262 output->addInstruction(meta);
1263 } else if (obj == unitRoot) {
1264 output->rootPropertyCache = tr.createPropertyCache(engine);
1265 output->rootPropertyCache->addref();
1268 // Set the object id
1269 if (!obj->id.isEmpty()) {
1270 Instruction::SetId id;
1271 id.value = output->indexForString(obj->id);
1272 id.index = obj->idIndex;
1273 output->addInstruction(id);
1277 if (tr.type && obj->parserStatusCast != -1) {
1278 Instruction::BeginObject begin;
1279 begin.castValue = obj->parserStatusCast;
1280 output->addInstruction(begin);
1286 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1288 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1289 Q_ASSERT(prop->scriptStringScope != -1);
1290 const QString &script = prop->values.first()->value.asScript();
1291 Instruction::StoreScriptString ss;
1292 ss.propertyIndex = prop->index;
1293 ss.value = output->indexForString(script);
1294 ss.scope = prop->scriptStringScope;
1295 // ss.bindingId = rewriteBinding(script, prop->name());
1296 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1297 ss.line = prop->location.start.line;
1298 ss.column = prop->location.start.column;
1299 output->addInstruction(ss);
1302 bool seenDefer = false;
1303 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1304 if (prop->isDeferred) {
1309 genValueProperty(prop, obj);
1312 Instruction::Defer defer;
1313 defer.deferCount = 0;
1314 int deferIdx = output->addInstruction(defer);
1315 int nextInstructionIndex = output->nextInstructionIndex();
1317 Instruction::DeferInit dinit;
1318 // XXX - these are now massive over allocations
1319 dinit.bindingsSize = compileState->totalBindingsCount;
1320 dinit.parserStatusSize = compileState->parserStatusCount;
1321 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1322 dinit.listStackSize = compileState->listDepth.maxDepth();
1323 output->addInstruction(dinit);
1325 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1326 if (!prop->isDeferred)
1328 genValueProperty(prop, obj);
1331 Instruction::Done done;
1332 output->addInstruction(done);
1334 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1337 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1339 QQmlScript::Value *v = prop->values.first();
1341 if (v->type == Value::SignalObject) {
1343 genObject(v->object);
1345 Instruction::AssignSignalObject assign;
1346 assign.line = v->location.start.line;
1347 assign.signal = output->indexForString(prop->name().toString());
1348 output->addInstruction(assign);
1350 } else if (v->type == Value::SignalExpression) {
1352 Instruction::StoreSignal store;
1353 store.signalIndex = prop->index;
1354 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1355 store.value = output->indexForByteArray(rewrite.toUtf8());
1356 store.context = v->signalExpressionContextStack;
1357 store.line = v->location.start.line;
1358 store.column = v->location.start.column;
1359 output->addInstruction(store);
1365 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1366 Instruction::FetchAttached fetch;
1367 fetch.id = prop->index;
1368 fetch.line = prop->location.start.line;
1369 output->addInstruction(fetch);
1371 genObjectBody(prop->value);
1373 Instruction::PopFetchedObject pop;
1374 output->addInstruction(pop);
1377 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1378 Instruction::FetchObject fetch;
1379 fetch.property = prop->index;
1380 fetch.line = prop->location.start.line;
1381 output->addInstruction(fetch);
1383 if (!prop->value->metadata.isEmpty()) {
1384 Instruction::StoreMetaObject meta;
1385 meta.data = output->indexForByteArray(prop->value->metadata);
1386 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1387 meta.propertyCache = -1;
1388 output->addInstruction(meta);
1391 genObjectBody(prop->value);
1393 Instruction::PopFetchedObject pop;
1394 output->addInstruction(pop);
1397 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1399 genValueTypeProperty(obj, prop);
1402 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1403 if (prop->isDeferred)
1406 genValueProperty(prop, obj);
1409 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1411 genValueTypeProperty(obj, prop);
1415 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1417 Instruction::FetchValueType fetch;
1418 fetch.property = prop->index;
1419 fetch.type = prop->type;
1420 fetch.bindingSkipList = 0;
1422 if (obj->type == -1 || output->types.at(obj->type).component) {
1423 // We only have to do this if this is a composite type. If it is a builtin
1424 // type it can't possibly already have bindings that need to be cleared.
1425 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1426 if (!vprop->values.isEmpty()) {
1427 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1428 fetch.bindingSkipList |= (1 << vprop->index);
1433 output->addInstruction(fetch);
1435 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1436 genPropertyAssignment(vprop, prop->value, prop);
1439 Instruction::PopValueType pop;
1440 pop.property = prop->index;
1441 pop.type = prop->type;
1442 pop.bindingSkipList = 0;
1443 output->addInstruction(pop);
1446 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1448 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1451 Instruction::CreateComponent create;
1452 create.line = root->location.start.line;
1453 create.column = root->location.start.column;
1454 create.endLine = root->location.end.line;
1455 create.isRoot = (compileState->root == obj);
1456 int createInstruction = output->addInstruction(create);
1457 int nextInstructionIndex = output->nextInstructionIndex();
1459 ComponentCompileState *oldCompileState = compileState;
1460 compileState = componentState(root);
1462 Instruction::Init init;
1463 init.bindingsSize = compileState->totalBindingsCount;
1464 init.parserStatusSize = compileState->parserStatusCount;
1465 init.contextCache = genContextCache();
1466 init.objectStackSize = compileState->objectDepth.maxDepth();
1467 init.listStackSize = compileState->listDepth.maxDepth();
1468 if (compileState->compiledBindingData.isEmpty())
1469 init.compiledBinding = -1;
1471 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1472 output->addInstruction(init);
1474 if (!compileState->v8BindingProgram.isEmpty()) {
1475 Instruction::InitV8Bindings bindings;
1476 int index = output->programs.count();
1478 typedef QQmlCompiledData::V8Program V8Program;
1479 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1481 bindings.programIndex = index;
1482 bindings.line = compileState->v8BindingProgramLine;
1483 output->addInstruction(bindings);
1488 Instruction::SetDefault def;
1489 output->addInstruction(def);
1491 Instruction::Done done;
1492 output->addInstruction(done);
1494 output->instruction(createInstruction)->createComponent.count =
1495 output->nextInstructionIndex() - nextInstructionIndex;
1497 compileState = oldCompileState;
1499 if (!obj->id.isEmpty()) {
1500 Instruction::SetId id;
1501 id.value = output->indexForString(obj->id);
1502 id.index = obj->idIndex;
1503 output->addInstruction(id);
1506 if (obj == unitRoot) {
1507 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1508 output->rootPropertyCache->addref();
1512 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1513 const BindingContext &ctxt)
1515 // The special "Component" element can only have the id property and a
1516 // default property, that actually defines the component's tree
1518 compileState->objectDepth.push();
1520 // Find, check and set the "id" property (if any)
1521 Property *idProp = 0;
1522 if (obj->properties.isMany() ||
1523 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1524 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1526 if (!obj->properties.isEmpty())
1527 idProp = obj->properties.first();
1530 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1531 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1532 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1534 QString idVal = idProp->values.first()->primitive();
1536 if (compileState->ids.value(idVal))
1537 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1543 // Check the Component tree is well formed
1544 if (obj->defaultProperty &&
1545 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1546 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1547 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1549 if (!obj->dynamicProperties.isEmpty())
1550 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1551 if (!obj->dynamicSignals.isEmpty())
1552 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1553 if (!obj->dynamicSlots.isEmpty())
1554 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1556 QQmlScript::Object *root = 0;
1557 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1558 root = obj->defaultProperty->values.first()->object;
1561 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1563 // Build the component tree
1564 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1566 compileState->objectDepth.pop();
1571 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1572 const BindingContext &ctxt)
1574 ComponentCompileState *oldComponentCompileState = compileState;
1575 compileState = pool->New<ComponentCompileState>();
1576 compileState->root = obj;
1577 compileState->nested = true;
1579 if (componentStats) {
1580 ComponentStat oldComponentStat = componentStats->componentStat;
1582 componentStats->componentStat = ComponentStat();
1583 componentStats->componentStat.lineNumber = obj->location.start.line;
1586 COMPILE_CHECK(buildObject(obj, ctxt));
1588 COMPILE_CHECK(completeComponentBuild());
1590 componentStats->componentStat = oldComponentStat;
1593 COMPILE_CHECK(buildObject(obj, ctxt));
1595 COMPILE_CHECK(completeComponentBuild());
1598 compileState = oldComponentCompileState;
1604 // Build a sub-object. A sub-object is one that was not created directly by
1605 // QML - such as a grouped property object, or an attached object. Sub-object's
1606 // can't have an id, involve a custom parser, have attached properties etc.
1607 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1609 Q_ASSERT(obj->metatype);
1610 Q_ASSERT(!obj->defaultProperty);
1611 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1614 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1615 if (isSignalPropertyName(prop->name())) {
1616 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1618 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1625 int QQmlCompiler::componentTypeRef()
1627 if (cachedComponentTypeRef == -1) {
1628 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1629 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1630 if (output->types.at(ii).type == t) {
1631 cachedComponentTypeRef = ii;
1635 QQmlCompiledData::TypeReference ref;
1636 ref.className = Component_string;
1638 output->types << ref;
1639 cachedComponentTypeRef = output->types.count() - 1;
1641 return cachedComponentTypeRef;
1644 int QQmlCompiler::translationContextIndex()
1646 if (cachedTranslationContextIndex == -1) {
1647 // This code must match that in the qsTr() implementation
1648 const QString &path = output->name;
1649 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1650 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1652 QByteArray contextUtf8 = context.toUtf8();
1653 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1655 return cachedTranslationContextIndex;
1658 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1659 const BindingContext &ctxt)
1661 Q_ASSERT(obj->metaObject());
1663 const QHashedStringRef &propName = prop->name();
1665 Q_ASSERT(propName.startsWith(on_string));
1666 QString name = propName.mid(2, -1).toString();
1668 // Note that the property name could start with any alpha or '_' or '$' character,
1669 // so we need to do the lower-casing of the first alpha character.
1670 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1671 if (name.at(firstAlphaIndex).isUpper()) {
1672 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1677 bool notInRevision = false;
1679 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1683 if (notInRevision && 0 == property(obj, propName, 0)) {
1684 Q_ASSERT(obj->type != -1);
1685 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1686 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1688 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));
1690 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1694 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1696 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1700 if (prop->value || !prop->values.isOne())
1701 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1703 prop->index = sig->coreIndex;
1706 obj->addSignalProperty(prop);
1708 if (prop->values.first()->object) {
1709 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1710 prop->values.first()->type = Value::SignalObject;
1712 prop->values.first()->type = Value::SignalExpression;
1714 if (!prop->values.first()->value.isScript())
1715 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1717 QString script = prop->values.first()->value.asScript().trimmed();
1718 if (script.isEmpty())
1719 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1721 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1730 Returns true if (value) property \a prop exists on obj, false otherwise.
1732 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1733 QQmlScript::Object *obj)
1735 if (prop->name().isEmpty())
1737 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1740 return property(obj, prop->name()) != 0;
1743 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1744 QQmlScript::Object *obj,
1745 const BindingContext &ctxt)
1747 if (prop->isEmpty())
1748 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1750 const QMetaObject *metaObject = obj->metaObject();
1751 Q_ASSERT(metaObject);
1753 if (isAttachedPropertyName(prop->name())) {
1754 // Setup attached property data
1756 if (ctxt.isSubContext()) {
1757 // Attached properties cannot be used on sub-objects. Sub-objects
1758 // always exist in a binding sub-context, which is what we test
1760 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1764 QQmlImportedNamespace *typeNamespace = 0;
1765 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1767 if (typeNamespace) {
1768 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1771 } else if (!type || !type->attachedPropertiesType()) {
1772 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1776 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1778 Q_ASSERT(type->attachedPropertiesFunction());
1779 prop->index = type->attachedPropertiesId();
1780 prop->value->metatype = type->attachedPropertiesType();
1782 // Setup regular property data
1783 bool notInRevision = false;
1784 QQmlPropertyData *d =
1785 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1787 if (d == 0 && notInRevision) {
1788 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1789 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1791 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));
1793 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1796 prop->index = d->coreIndex;
1798 } else if (prop->isDefault) {
1799 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1800 QQmlPropertyData defaultPropertyData;
1801 defaultPropertyData.load(p, engine);
1803 prop->setName(QLatin1String(p.name()));
1804 prop->core = defaultPropertyData;
1805 prop->index = prop->core.coreIndex;
1808 // We can't error here as the "id" property does not require a
1809 // successful index resolution
1810 if (prop->index != -1)
1811 prop->type = prop->core.propType;
1813 // Check if this is an alias
1814 if (prop->index != -1 &&
1816 prop->parent->type != -1 &&
1817 output->types.at(prop->parent->type).component) {
1819 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1820 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1821 prop->isAlias = true;
1824 if (prop->index != -1 && !prop->values.isEmpty())
1825 prop->parent->setBindingBit(prop->index);
1828 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1830 // The magic "id" behavior doesn't apply when "id" is resolved as a
1831 // default property or to sub-objects (which are always in binding
1833 COMPILE_CHECK(buildIdProperty(prop, obj));
1834 if (prop->type == QVariant::String &&
1835 prop->values.first()->value.isString())
1836 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1838 } else if (isAttachedPropertyName(prop->name())) {
1840 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1842 } else if (prop->index == -1) {
1844 if (prop->isDefault) {
1845 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1847 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1850 } else if (prop->value) {
1852 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1854 } else if (prop->core.isQList()) {
1856 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1858 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1860 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1864 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1871 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
1872 QQmlScript::Property *nsProp,
1873 QQmlScript::Object *obj,
1874 const BindingContext &ctxt)
1877 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1879 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1881 if (!isAttachedPropertyName(prop->name()))
1882 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1884 // Setup attached property data
1887 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1889 if (!type || !type->attachedPropertiesType())
1890 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1893 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1895 Q_ASSERT(type->attachedPropertiesFunction());
1896 prop->index = type->index();
1897 prop->value->metatype = type->attachedPropertiesType();
1899 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1905 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1906 QQmlScript::Object *obj)
1908 if (prop->core.isQList()) {
1909 genListProperty(prop, obj);
1911 genPropertyAssignment(prop, obj);
1915 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1916 QQmlScript::Object *obj)
1918 int listType = enginePrivate->listType(prop->type);
1920 Instruction::FetchQList fetch;
1921 fetch.property = prop->index;
1922 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1923 fetch.type = listType;
1924 output->addInstruction(fetch);
1926 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1928 if (v->type == Value::CreatedObject) {
1930 genObject(v->object);
1931 if (listTypeIsInterface) {
1932 Instruction::AssignObjectList assign;
1933 assign.line = prop->location.start.line;
1934 output->addInstruction(assign);
1936 Instruction::StoreObjectQList store;
1937 output->addInstruction(store);
1940 } else if (v->type == Value::PropertyBinding) {
1942 genBindingAssignment(v, prop, obj);
1948 Instruction::PopQList pop;
1949 output->addInstruction(pop);
1952 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1953 QQmlScript::Object *obj,
1954 QQmlScript::Property *valueTypeProperty)
1956 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1958 Q_ASSERT(v->type == Value::CreatedObject ||
1959 v->type == Value::PropertyBinding ||
1960 v->type == Value::Literal);
1962 if (v->type == Value::CreatedObject) {
1964 genObject(v->object);
1966 if (QQmlMetaType::isInterface(prop->type)) {
1968 Instruction::StoreInterface store;
1969 store.line = v->object->location.start.line;
1970 store.propertyIndex = prop->index;
1971 output->addInstruction(store);
1973 } else if (prop->type == QMetaType::QVariant) {
1975 if (prop->core.isVMEProperty()) {
1976 Instruction::StoreVarObject store;
1977 store.line = v->object->location.start.line;
1978 store.propertyIndex = prop->index;
1979 output->addInstruction(store);
1981 Instruction::StoreVariantObject store;
1982 store.line = v->object->location.start.line;
1983 store.propertyIndex = prop->index;
1984 output->addInstruction(store);
1990 Instruction::StoreObject store;
1991 store.line = v->object->location.start.line;
1992 store.propertyIndex = prop->index;
1993 output->addInstruction(store);
1996 } else if (v->type == Value::PropertyBinding) {
1998 genBindingAssignment(v, prop, obj, valueTypeProperty);
2000 } else if (v->type == Value::Literal) {
2002 genLiteralAssignment(prop, v);
2008 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2010 Q_ASSERT(v->type == Value::ValueSource ||
2011 v->type == Value::ValueInterceptor);
2013 if (v->type == Value::ValueSource) {
2014 genObject(v->object);
2016 Instruction::StoreValueSource store;
2017 if (valueTypeProperty) {
2018 store.property = genValueTypeData(prop, valueTypeProperty);
2021 store.property = prop->core;
2024 QQmlType *valueType = toQmlType(v->object);
2025 store.castValue = valueType->propertyValueSourceCast();
2026 output->addInstruction(store);
2028 } else if (v->type == Value::ValueInterceptor) {
2029 genObject(v->object);
2031 Instruction::StoreValueInterceptor store;
2032 if (valueTypeProperty) {
2033 store.property = genValueTypeData(prop, valueTypeProperty);
2036 store.property = prop->core;
2039 QQmlType *valueType = toQmlType(v->object);
2040 store.castValue = valueType->propertyValueInterceptorCast();
2041 output->addInstruction(store);
2047 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2048 QQmlScript::Object *obj)
2051 prop->values.isMany() ||
2052 prop->values.first()->object)
2053 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2055 QQmlScript::Value *idValue = prop->values.first();
2056 QString val = idValue->primitive();
2058 COMPILE_CHECK(checkValidId(idValue, val));
2060 if (compileState->ids.value(val))
2061 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2063 prop->values.first()->type = Value::Id;
2071 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2074 Q_ASSERT(!compileState->ids.value(id));
2075 Q_ASSERT(obj->id == id);
2076 obj->idIndex = compileState->ids.count();
2077 compileState->ids.append(obj);
2080 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2082 Q_ASSERT(ref->value && !ref->value->bindingReference);
2083 ref->value->bindingReference = ref;
2084 compileState->totalBindingsCount++;
2085 compileState->bindings.prepend(ref);
2088 void QQmlCompiler::saveComponentState()
2090 Q_ASSERT(compileState->root);
2091 Q_ASSERT(compileState->root->componentCompileState == 0);
2093 compileState->root->componentCompileState = compileState;
2096 componentStats->savedComponentStats.append(componentStats->componentStat);
2099 QQmlCompilerTypes::ComponentCompileState *
2100 QQmlCompiler::componentState(QQmlScript::Object *obj)
2102 Q_ASSERT(obj->componentCompileState);
2103 return obj->componentCompileState;
2106 // Build attached property object. In this example,
2110 // GridView is an attached property object.
2111 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2112 QQmlScript::Object *obj,
2113 const BindingContext &ctxt)
2115 Q_ASSERT(prop->value);
2116 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2118 compileState->objectDepth.push();
2120 obj->addAttachedProperty(prop);
2122 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2124 compileState->objectDepth.pop();
2130 // Build "grouped" properties. In this example:
2132 // font.pointSize: 12
2133 // font.family: "Helvetica"
2135 // font is a nested property. pointSize and family are not.
2136 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2137 QQmlScript::Object *obj,
2138 const BindingContext &ctxt)
2140 Q_ASSERT(prop->type != 0);
2141 Q_ASSERT(prop->index != -1);
2143 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2144 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2146 if (!prop->values.isEmpty()) {
2147 if (prop->values.first()->location < prop->value->location) {
2148 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2150 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2154 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2155 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2159 if (prop->isAlias) {
2160 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2161 vtProp->isAlias = true;
2165 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2166 prop->value, obj, ctxt.incr()));
2167 obj->addValueTypeProperty(prop);
2169 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2173 // Load the nested property's meta type
2174 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2175 if (!prop->value->metatype)
2176 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2178 if (!prop->values.isEmpty())
2179 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2181 obj->addGroupedProperty(prop);
2183 compileState->objectDepth.push();
2185 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2187 compileState->objectDepth.pop();
2193 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2194 QQmlScript::Object *obj,
2195 QQmlScript::Object *baseObj,
2196 const BindingContext &ctxt)
2198 compileState->objectDepth.push();
2200 if (obj->defaultProperty)
2201 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2202 obj->metatype = type->metaObject();
2204 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2206 QQmlPropertyData *d = property(obj, prop->name());
2208 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2210 prop->index = d->coreIndex;
2211 prop->type = d->propType;
2213 prop->isValueTypeSubProperty = true;
2216 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2218 if (prop->values.isMany()) {
2219 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2220 } else if (!prop->values.isEmpty()) {
2221 QQmlScript::Value *value = prop->values.first();
2223 if (value->object) {
2224 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2225 } else if (value->value.isScript()) {
2226 // ### Check for writability
2228 //optimization for <Type>.<EnumValue> enum assignments
2229 bool isEnumAssignment = false;
2231 if (prop->core.isEnum())
2232 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2234 if (isEnumAssignment) {
2235 value->type = Value::Literal;
2237 JSBindingReference *reference = pool->New<JSBindingReference>();
2238 reference->expression = value->value;
2239 reference->property = prop;
2240 reference->value = value;
2241 reference->bindingContext = ctxt;
2242 reference->bindingContext.owner++;
2243 addBindingReference(reference);
2244 value->type = Value::PropertyBinding;
2247 COMPILE_CHECK(testLiteralAssignment(prop, value));
2248 value->type = Value::Literal;
2252 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2253 Q_ASSERT(v->object);
2255 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2258 obj->addValueProperty(prop);
2261 compileState->objectDepth.pop();
2266 // Build assignments to QML lists. QML lists are properties of type
2267 // QQmlListProperty<T>. List properties can accept a list of
2268 // objects, or a single binding.
2269 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2270 QQmlScript::Object *obj,
2271 const BindingContext &ctxt)
2273 Q_ASSERT(prop->core.isQList());
2275 compileState->listDepth.push();
2279 obj->addValueProperty(prop);
2281 int listType = enginePrivate->listType(t);
2282 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2284 bool assignedBinding = false;
2285 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2287 v->type = Value::CreatedObject;
2288 COMPILE_CHECK(buildObject(v->object, ctxt));
2290 // We check object coercian here. We check interface assignment
2292 if (!listTypeIsInterface) {
2293 if (!canCoerce(listType, v->object)) {
2294 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2298 } else if (v->value.isScript()) {
2299 if (assignedBinding)
2300 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2302 assignedBinding = true;
2303 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2304 v->type = Value::PropertyBinding;
2306 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2310 compileState->listDepth.pop();
2315 // Compiles an assignment to a QQmlScriptString property
2316 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2317 QQmlScript::Object *obj,
2318 const BindingContext &ctxt)
2320 if (prop->values.isMany())
2321 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2323 if (prop->values.first()->object)
2324 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2326 prop->scriptStringScope = ctxt.stack;
2327 obj->addScriptStringProperty(prop);
2332 // Compile regular property assignments of the form "property: <value>"
2333 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2334 QQmlScript::Object *obj,
2335 const BindingContext &ctxt)
2337 obj->addValueProperty(prop);
2339 if (prop->values.isMany())
2340 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2342 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2345 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2349 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2354 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2355 Q_ASSERT(v->object);
2356 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2362 // Compile assigning a single object instance to a regular property
2363 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2364 QQmlScript::Object *obj,
2365 QQmlScript::Value *v,
2366 const BindingContext &ctxt)
2368 Q_ASSERT(prop->index != -1);
2369 Q_ASSERT(v->object->type != -1);
2371 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2372 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2374 if (QQmlMetaType::isInterface(prop->type)) {
2376 // Assigning an object to an interface ptr property
2377 COMPILE_CHECK(buildObject(v->object, ctxt));
2379 v->type = Value::CreatedObject;
2381 } else if (prop->type == QMetaType::QVariant) {
2383 // Assigning an object to a QVariant
2384 COMPILE_CHECK(buildObject(v->object, ctxt));
2386 v->type = Value::CreatedObject;
2388 // Normally buildObject() will set this up, but we need the static
2389 // meta object earlier to test for assignability. It doesn't matter
2390 // that there may still be outstanding synthesized meta object changes
2391 // on this type, as they are not relevant for assignability testing
2392 v->object->metatype = output->types.at(v->object->type).metaObject();
2393 Q_ASSERT(v->object->metaObject());
2395 // We want to raw metaObject here as the raw metaobject is the
2396 // actual property type before we applied any extensions that might
2397 // effect the properties on the type, but don't effect assignability
2398 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2400 // Will be true if the assgned type inherits propertyMetaObject
2401 bool isAssignable = false;
2402 // Determine isAssignable value
2403 if (propertyMetaObject) {
2404 const QMetaObject *c = v->object->metatype;
2406 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2407 c = c->superClass();
2412 // Simple assignment
2413 COMPILE_CHECK(buildObject(v->object, ctxt));
2415 v->type = Value::CreatedObject;
2416 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2417 // Automatic "Component" insertion
2418 QQmlScript::Object *root = v->object;
2419 QQmlScript::Object *component = pool->New<Object>();
2420 component->type = componentTypeRef();
2421 component->typeName = QStringLiteral("Qt/Component");
2422 component->metatype = &QQmlComponent::staticMetaObject;
2423 component->location = root->location;
2424 QQmlScript::Value *componentValue = pool->New<Value>();
2425 componentValue->object = root;
2426 component->getDefaultProperty()->addValue(componentValue);
2427 v->object = component;
2428 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2430 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2437 // Compile assigning a single object instance to a regular property using the "on" syntax.
2441 // NumberAnimation on x { }
2443 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2444 QQmlScript::Object *obj,
2445 QQmlScript::Object *baseObj,
2446 QQmlScript::Value *v,
2447 const BindingContext &ctxt)
2449 Q_ASSERT(prop->index != -1);
2450 Q_ASSERT(v->object->type != -1);
2454 if (!prop->core.isWritable())
2455 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2458 // Normally buildObject() will set this up, but we need the static
2459 // meta object earlier to test for assignability. It doesn't matter
2460 // that there may still be outstanding synthesized meta object changes
2461 // on this type, as they are not relevant for assignability testing
2462 v->object->metatype = output->types.at(v->object->type).metaObject();
2463 Q_ASSERT(v->object->metaObject());
2465 // Will be true if the assigned type inherits QQmlPropertyValueSource
2466 bool isPropertyValue = false;
2467 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2468 bool isPropertyInterceptor = false;
2469 if (QQmlType *valueType = toQmlType(v->object)) {
2470 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2471 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2474 if (isPropertyValue || isPropertyInterceptor) {
2475 // Assign as a property value source
2476 COMPILE_CHECK(buildObject(v->object, ctxt));
2478 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2479 buildDynamicMeta(baseObj, ForceCreation);
2480 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2482 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2488 // Compile assigning a literal or binding to a regular property
2489 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2490 QQmlScript::Object *obj,
2491 QQmlScript::Value *v,
2492 const BindingContext &ctxt)
2494 Q_ASSERT(prop->index != -1);
2496 if (v->value.isScript()) {
2498 //optimization for <Type>.<EnumValue> enum assignments
2499 if (prop->core.isEnum()) {
2500 bool isEnumAssignment = false;
2501 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2502 if (isEnumAssignment) {
2503 v->type = Value::Literal;
2508 // Test for other binding optimizations
2509 if (!buildLiteralBinding(v, prop, ctxt))
2510 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2512 v->type = Value::PropertyBinding;
2516 COMPILE_CHECK(testLiteralAssignment(prop, v));
2518 v->type = Value::Literal;
2524 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2525 QQmlScript::Object *obj,
2526 QQmlScript::Value *v,
2529 *isAssignment = false;
2530 if (!prop->core.isEnum())
2533 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2535 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2536 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2538 QString string = v->value.asString();
2539 if (!string.at(0).isUpper())
2542 QStringList parts = string.split(QLatin1Char('.'));
2543 if (parts.count() != 2)
2546 QString typeName = parts.at(0);
2548 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2550 //handle enums on value types (where obj->typeName is empty)
2551 QString objTypeName = obj->typeName;
2552 if (objTypeName.isEmpty()) {
2553 QQmlType *objType = toQmlType(obj);
2555 objTypeName = objType->qmlTypeName();
2561 QString enumValue = parts.at(1);
2565 if (objTypeName == type->qmlTypeName()) {
2566 // When these two match, we can short cut the search
2567 if (mprop.isFlagType()) {
2568 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2570 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2573 // Otherwise we have to search the whole type
2574 // This matches the logic in QV8TypeWrapper
2575 QByteArray enumName = enumValue.toUtf8();
2576 const QMetaObject *metaObject = type->baseMetaObject();
2578 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2579 QMetaEnum e = metaObject->enumerator(ii);
2580 value = e.keyToValue(enumName.constData(), &ok);
2587 v->type = Value::Literal;
2588 v->value = QQmlScript::Variant((double)value);
2589 *isAssignment = true;
2594 struct StaticQtMetaObject : public QObject
2596 static const QMetaObject *get()
2597 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2600 // Similar logic to above, but not knowing target property.
2601 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2603 int dot = script.indexOf('.');
2605 const QByteArray &scope = script.left(dot);
2607 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2608 if (!type && scope != "Qt")
2610 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2611 const char *key = script.constData() + dot+1;
2612 int i = mo->enumeratorCount();
2615 int v = mo->enumerator(i).keyToValue(key, &ok);
2623 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2625 QQmlType *qmltype = 0;
2626 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2630 return qmltype->metaObject();
2633 // similar to logic of completeComponentBuild, but also sticks data
2634 // into primitives at the end
2635 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2637 QQmlRewrite::RewriteBinding rewriteBinding;
2638 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2640 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2642 return output->indexForString(rewrite);
2645 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2647 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2648 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2651 // Ensures that the dynamic meta specification on obj is valid
2652 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2654 bool seenDefaultProperty = false;
2656 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2657 // Calculating the hash for the names is not a waste as we have to test
2658 // them against the illegalNames set anyway.
2659 QHashField propNames;
2660 QHashField methodNames;
2663 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2664 const QQmlScript::Object::DynamicProperty &prop = *p;
2666 if (prop.isDefaultProperty) {
2667 if (seenDefaultProperty)
2668 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2669 seenDefaultProperty = true;
2672 if (propNames.testAndSet(prop.name.hash())) {
2673 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2674 p2 = obj->dynamicProperties.next(p2)) {
2675 if (p2->name == prop.name) {
2676 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2677 prop.nameLocation.column,
2678 tr("Duplicate property name"));
2683 if (prop.name.at(0).isUpper()) {
2684 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2685 prop.nameLocation.column,
2686 tr("Property names cannot begin with an upper case letter"));
2689 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2690 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2691 prop.nameLocation.column,
2692 tr("Illegal property name"));
2696 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2697 const QQmlScript::Object::DynamicSignal &currSig = *s;
2699 if (methodNames.testAndSet(currSig.name.hash())) {
2700 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2701 s2 = obj->dynamicSignals.next(s2)) {
2702 if (s2->name == currSig.name)
2703 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2707 if (currSig.name.at(0).isUpper())
2708 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2709 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2710 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2713 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2714 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2716 if (methodNames.testAndSet(currSlot.name.hash())) {
2717 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2718 s2 = obj->dynamicSignals.next(s2)) {
2719 if (s2->name == currSlot.name)
2720 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2722 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2723 s2 = obj->dynamicSlots.next(s2)) {
2724 if (s2->name == currSlot.name)
2725 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2729 if (currSlot.name.at(0).isUpper())
2730 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2731 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2732 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2738 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2740 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2741 p = obj->dynamicProperties.next(p)) {
2743 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2746 Property *property = 0;
2747 if (p->isDefaultProperty) {
2748 property = obj->getDefaultProperty();
2750 property = obj->getProperty(p->name);
2751 if (!property->values.isEmpty())
2752 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2756 property->isReadOnlyDeclaration = true;
2758 if (property->value)
2759 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2761 property->values.append(p->defaultValue->values);
2766 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2768 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2771 Q_ASSERT(obj->metatype);
2773 if (mode != ForceCreation &&
2774 obj->dynamicProperties.isEmpty() &&
2775 obj->dynamicSignals.isEmpty() &&
2776 obj->dynamicSlots.isEmpty())
2779 bool resolveAlias = (mode == ResolveAliases);
2781 const Object::DynamicProperty *defaultProperty = 0;
2783 int varPropCount = 0;
2784 int totalPropCount = 0;
2785 int firstPropertyVarIndex = 0;
2787 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2789 if (p->type == Object::DynamicProperty::Alias)
2791 if (p->type == Object::DynamicProperty::Var)
2794 if (p->isDefaultProperty &&
2795 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2796 defaultProperty = p;
2798 if (!resolveAlias) {
2799 // No point doing this for both the alias and non alias cases
2800 QQmlPropertyData *d = property(obj, p->name);
2801 if (d && d->isFinal())
2802 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2806 bool buildData = resolveAlias || aliasCount == 0;
2808 QByteArray dynamicData;
2810 typedef QQmlVMEMetaData VMD;
2812 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2813 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2814 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2815 aliasCount * sizeof(VMD::AliasData), 0);
2818 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2820 QByteArray newClassName = obj->metatype->className();
2821 newClassName.append("_QML_");
2822 newClassName.append(QByteArray::number(uniqueClassId));
2824 if (compileState->root == obj && !compileState->nested) {
2825 QString path = output->url.path();
2826 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2827 if (lastSlash > -1) {
2828 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2829 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2830 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2834 // Size of the array that describes parameter types & names
2835 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2836 + obj->dynamicProperties.count() // for Changed() signals return types
2837 // Return "parameters" don't have names
2838 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2840 QFastMetaBuilder builder;
2842 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2843 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2844 obj->dynamicSlots.count(),
2845 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2846 defaultProperty?1:0, paramDataSize, ¶mIndex);
2849 Object::DynamicProperty::Type dtype;
2851 } builtinTypes[] = {
2852 { Object::DynamicProperty::Var, QMetaType::QVariant },
2853 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2854 { Object::DynamicProperty::Int, QMetaType::Int },
2855 { Object::DynamicProperty::Bool, QMetaType::Bool },
2856 { Object::DynamicProperty::Real, QMetaType::Double },
2857 { Object::DynamicProperty::String, QMetaType::QString },
2858 { Object::DynamicProperty::Url, QMetaType::QUrl },
2859 { Object::DynamicProperty::Color, QMetaType::QColor },
2860 { Object::DynamicProperty::Time, QMetaType::QTime },
2861 { Object::DynamicProperty::Date, QMetaType::QDate },
2862 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2864 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2866 // Reserve dynamic properties
2867 if (obj->dynamicProperties.count()) {
2868 typedef QQmlVMEMetaData VMD;
2870 int effectivePropertyIndex = 0;
2871 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2873 // Reserve space for name
2874 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2875 p->nameRef = builder.newString(p->name.utf8length());
2878 int propertyType = 0; // for VMD
2879 bool readonly = false;
2881 if (p->type == Object::DynamicProperty::Alias) {
2883 } else if (p->type < builtinTypeCount) {
2884 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2885 metaType = builtinTypes[p->type].metaType;
2886 propertyType = metaType;
2889 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2890 p->type == Object::DynamicProperty::Custom);
2892 // XXX don't double resolve this in the case of an alias run
2894 QByteArray customTypeName;
2895 QQmlType *qmltype = 0;
2897 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2898 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2901 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2903 Q_ASSERT(tdata->isComplete());
2905 QQmlCompiledData *data = tdata->compiledData();
2906 customTypeName = data->root->className();
2910 customTypeName = qmltype->typeName();
2913 if (p->type == Object::DynamicProperty::Custom) {
2914 customTypeName += '*';
2915 propertyType = QMetaType::QObjectStar;
2918 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2919 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2922 metaType = QMetaType::type(customTypeName);
2923 Q_ASSERT(metaType != QMetaType::UnknownType);
2924 Q_ASSERT(metaType != QMetaType::Void);
2927 if (p->type == Object::DynamicProperty::Var)
2934 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2935 vmd->propertyCount++;
2936 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2939 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2940 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2941 effectivePropertyIndex);
2943 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2944 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2947 effectivePropertyIndex++;
2951 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2953 vmd->varPropertyCount = varPropCount;
2954 firstPropertyVarIndex = effectivePropertyIndex;
2955 totalPropCount = varPropCount + effectivePropertyIndex;
2956 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2957 if (p->type == Object::DynamicProperty::Var) {
2959 vmd->propertyCount++;
2960 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2963 builder.setProperty(effectivePropertyIndex, p->nameRef,
2964 QMetaType::QVariant,
2965 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2966 effectivePropertyIndex);
2968 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2969 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2972 effectivePropertyIndex++;
2979 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2980 if (p->type == Object::DynamicProperty::Alias) {
2982 Q_ASSERT(buildData);
2983 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2984 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2987 // Even if we aren't resolving the alias, we need a fake signal so that the
2988 // metaobject remains consistent across the resolve and non-resolve alias runs
2989 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2990 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2992 effectivePropertyIndex++;
2999 // Reserve default property
3000 QFastMetaBuilder::StringRef defPropRef;
3001 if (defaultProperty) {
3002 defPropRef = builder.newString(strlen("DefaultProperty"));
3003 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3006 // Reserve dynamic signals
3007 int signalIndex = 0;
3008 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3010 s->nameRef = builder.newString(s->name.utf8length());
3012 int paramCount = s->parameterNames.count();
3013 QVarLengthArray<int, 10> paramTypes(paramCount);
3015 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3016 for (int i = 0; i < paramCount; ++i) {
3017 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3018 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3019 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3024 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3026 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3027 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3028 paramIndex += paramCount*2 + 1;
3032 // Reserve dynamic slots
3033 if (obj->dynamicSlots.count()) {
3035 typedef QQmlVMEMetaData VMD;
3037 int methodIndex = 0;
3038 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3039 s->nameRef = builder.newString(s->name.utf8length());
3040 int paramCount = s->parameterNames.count();
3042 QVarLengthArray<int, 10> paramTypes(paramCount);
3044 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3045 for (int i = 0; i < paramCount; ++i) {
3046 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3047 paramTypes[i] = QMetaType::QVariant;
3051 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3052 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3053 paramIndex += paramCount*2 + 1;
3058 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3059 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3060 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3061 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3062 for (int jj = 0; jj < paramCount; ++jj) {
3063 if (jj) funcScript.append(QLatin1Char(','));
3064 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3066 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3068 QByteArray utf8 = funcScript.toUtf8();
3069 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3071 s->location.start.line };
3073 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3076 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3078 md.bodyOffset = dynamicData.size();
3080 dynamicData.append((const char *)utf8.constData(), utf8.length());
3088 // Now allocate properties
3089 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3091 char *d = p->changedNameRef.data();
3092 p->name.writeUtf8(d);
3093 strcpy(d + p->name.utf8length(), "Changed");
3094 p->changedNameRef.loadByteArrayData();
3096 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3099 p->nameRef.load(p->name);
3102 // Allocate default property if necessary
3103 if (defaultProperty)
3104 defPropRef.load("DefaultProperty");
3106 // Now allocate signals
3107 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3109 s->nameRef.load(s->name);
3111 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3112 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3115 // Now allocate methods
3116 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3117 s->nameRef.load(s->name);
3119 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3120 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3123 // Now allocate class name
3124 classNameRef.load(newClassName);
3126 obj->metadata = builder.toData();
3127 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3129 if (mode == IgnoreAliases && aliasCount)
3130 compileState->aliasingObjects.append(obj);
3132 obj->synthdata = dynamicData;
3134 if (obj->synthCache) {
3135 obj->synthCache->release();
3136 obj->synthCache = 0;
3139 if (obj->type != -1) {
3140 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3141 QQmlPropertyCache *cache =
3142 superCache->copyAndAppend(engine, &obj->extObject,
3143 QQmlPropertyData::NoFlags,
3144 QQmlPropertyData::IsVMEFunction,
3145 QQmlPropertyData::IsVMESignal);
3147 // now we modify the flags appropriately for var properties.
3148 int propertyOffset = obj->extObject.propertyOffset();
3149 QQmlPropertyData *currPropData = 0;
3150 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3151 currPropData = cache->property(pvi + propertyOffset);
3152 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3155 obj->synthCache = cache;
3161 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3164 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3166 QChar ch = val.at(0);
3167 if (ch.isLetter() && !ch.isLower())
3168 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3170 QChar u(QLatin1Char('_'));
3171 if (!ch.isLetter() && ch != u)
3172 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3174 for (int ii = 1; ii < val.count(); ++ii) {
3176 if (!ch.isLetterOrNumber() && ch != u)
3177 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3180 if (enginePrivate->v8engine()->illegalNames().contains(val))
3181 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3186 #include <private/qqmljsparser_p.h>
3188 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3190 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3192 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3193 return QStringList() << name;
3194 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3195 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3197 QStringList rv = astNodeToStringList(expr->base);
3200 rv.append(expr->name.toString());
3203 return QStringList();
3206 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3208 QQmlScript::Object *obj,
3209 int propIndex, int aliasIndex,
3210 Object::DynamicProperty &prop)
3212 Q_ASSERT(!prop.nameRef.isEmpty());
3213 if (!prop.defaultValue)
3214 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3216 if (!prop.defaultValue->values.isOne() ||
3217 prop.defaultValue->values.first()->object ||
3218 !prop.defaultValue->values.first()->value.isScript())
3219 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3221 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3223 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3225 QStringList alias = astNodeToStringList(node);
3227 if (alias.count() < 1 || alias.count() > 3)
3228 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3230 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3232 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3234 QByteArray typeName;
3239 bool writable = false;
3240 bool resettable = false;
3241 if (alias.count() == 2 || alias.count() == 3) {
3242 propIdx = indexOfProperty(idObject, alias.at(1));
3244 if (-1 == propIdx) {
3245 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3246 } else if (propIdx > 0xFFFF) {
3247 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3250 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3251 if (!aliasProperty.isScriptable())
3252 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3254 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3255 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3257 type = aliasProperty.userType();
3259 if (alias.count() == 3) {
3260 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3262 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3264 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3266 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3267 if (valueTypeIndex == -1)
3268 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3269 Q_ASSERT(valueTypeIndex <= 0xFF);
3271 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3272 propIdx |= (valueTypeIndex << 16);
3274 // update the property type
3275 type = aliasProperty.userType();
3278 if (aliasProperty.isEnumType())
3279 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3281 typeName = aliasProperty.typeName();
3283 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3285 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3287 typeName = ref.type->typeName();
3289 typeName = ref.component->root->className();
3294 if (typeName.endsWith('*'))
3295 flags |= QML_ALIAS_FLAG_PTR;
3297 if (type == QMetaType::UnknownType) {
3298 Q_ASSERT(!typeName.isEmpty());
3299 type = QMetaType::type(typeName);
3300 Q_ASSERT(type != QMetaType::UnknownType);
3301 Q_ASSERT(type != QMetaType::Void);
3304 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3306 typedef QQmlVMEMetaData VMD;
3307 VMD *vmd = (QQmlVMEMetaData *)data.data();
3308 *(vmd->aliasData() + aliasIndex) = aliasData;
3310 int propertyFlags = 0;
3312 propertyFlags |= QFastMetaBuilder::Writable;
3314 propertyFlags |= QFastMetaBuilder::Resettable;
3316 builder.setProperty(propIndex, prop.nameRef, type,
3317 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3323 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3324 QQmlScript::Property *prop,
3325 const BindingContext &ctxt)
3327 Q_ASSERT(prop->index != -1);
3328 Q_ASSERT(prop->parent);
3329 Q_ASSERT(prop->parent->metaObject());
3331 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3332 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3334 JSBindingReference *reference = pool->New<JSBindingReference>();
3335 reference->expression = value->value;
3336 reference->property = prop;
3337 reference->value = value;
3338 reference->bindingContext = ctxt;
3339 addBindingReference(reference);
3344 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3345 QQmlScript::Property *prop,
3346 const QQmlCompilerTypes::BindingContext &)
3348 Q_ASSERT(v->value.isScript());
3350 if (!prop->core.isWritable())
3353 AST::Node *binding = v->value.asAST();
3355 if (prop->type == QVariant::String) {
3356 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3357 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3358 if (i->name == qsTrId_string) {
3359 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3360 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3362 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3363 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3364 (!arg2 || !arg2->next)) {
3369 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3370 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3372 TrBindingReference *reference = pool->New<TrBindingReference>();
3373 reference->dataType = BindingReference::TrId;
3374 reference->text = text;
3376 v->bindingReference = reference;
3380 } else if (i->name == qsTr_string) {
3382 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3383 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3384 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3386 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3387 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3388 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3389 (!arg3 || !arg3->next)) {
3395 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3396 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3397 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3399 TrBindingReference *reference = pool->New<TrBindingReference>();
3400 reference->dataType = BindingReference::Tr;
3401 reference->text = text;
3402 reference->comment = comment;
3404 v->bindingReference = reference;
3417 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3418 QQmlScript::Property *prop,
3419 QQmlScript::Object *obj,
3420 QQmlScript::Property *valueTypeProperty)
3423 Q_ASSERT(binding->bindingReference);
3425 const BindingReference &ref = *binding->bindingReference;
3426 if (ref.dataType == BindingReference::TrId) {
3427 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3429 Instruction::StoreTrIdString store;
3430 store.propertyIndex = prop->core.coreIndex;
3431 store.text = output->indexForByteArray(tr.text.toUtf8());
3433 output->addInstruction(store);
3434 } else if (ref.dataType == BindingReference::Tr) {
3435 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3437 Instruction::StoreTrString store;
3438 store.propertyIndex = prop->core.coreIndex;
3439 store.context = translationContextIndex();
3440 store.text = output->indexForByteArray(tr.text.toUtf8());
3441 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3443 output->addInstruction(store);
3444 } else if (ref.dataType == BindingReference::V4) {
3445 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3447 Instruction::StoreV4Binding store;
3448 store.value = js.compiledIndex;
3449 store.context = js.bindingContext.stack;
3450 store.owner = js.bindingContext.owner;
3451 if (valueTypeProperty) {
3452 store.property = (valueTypeProperty->index & 0xFFFF) |
3453 ((valueTypeProperty->type & 0xFF)) << 16 |
3454 ((prop->index & 0xFF) << 24);
3455 store.isRoot = (compileState->root == valueTypeProperty->parent);
3457 store.property = prop->index;
3458 store.isRoot = (compileState->root == obj);
3460 store.line = binding->location.start.line;
3461 store.column = binding->location.start.column;
3462 output->addInstruction(store);
3463 } else if (ref.dataType == BindingReference::V8) {
3464 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3466 Instruction::StoreV8Binding store;
3467 store.value = js.compiledIndex;
3468 store.context = js.bindingContext.stack;
3469 store.owner = js.bindingContext.owner;
3470 if (valueTypeProperty) {
3471 store.isRoot = (compileState->root == valueTypeProperty->parent);
3473 store.isRoot = (compileState->root == obj);
3475 store.line = binding->location.start.line;
3476 store.column = binding->location.start.column;
3478 Q_ASSERT(js.bindingContext.owner == 0 ||
3479 (js.bindingContext.owner != 0 && valueTypeProperty));
3480 if (js.bindingContext.owner) {
3481 store.property = genValueTypeData(prop, valueTypeProperty);
3483 store.property = prop->core;
3486 output->addInstruction(store);
3487 } else if (ref.dataType == BindingReference::QtScript) {
3488 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3490 QQmlInstruction store;
3491 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3492 store.assignBinding.context = js.bindingContext.stack;
3493 store.assignBinding.owner = js.bindingContext.owner;
3494 store.assignBinding.line = binding->location.start.line;
3495 store.assignBinding.column = binding->location.start.column;
3497 if (valueTypeProperty) {
3498 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3500 store.assignBinding.isRoot = (compileState->root == obj);
3503 Q_ASSERT(js.bindingContext.owner == 0 ||
3504 (js.bindingContext.owner != 0 && valueTypeProperty));
3505 if (js.bindingContext.owner) {
3506 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3508 store.assignBinding.property = prop->core;
3510 output->addInstructionHelper(
3511 !prop->isAlias ? QQmlInstruction::StoreBinding
3512 : QQmlInstruction::StoreBindingOnAlias
3515 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3519 int QQmlCompiler::genContextCache()
3521 if (compileState->ids.count() == 0)
3524 QQmlIntegerCache *cache = new QQmlIntegerCache();
3525 cache->reserve(compileState->ids.count());
3526 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3527 cache->add(o->id, o->idIndex);
3529 output->contextCaches.append(cache);
3530 return output->contextCaches.count() - 1;
3534 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3535 QQmlScript::Property *prop)
3537 typedef QQmlPropertyPrivate QDPP;
3538 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3539 enginePrivate->valueTypes[prop->type]->metaObject(),
3540 valueTypeProp->index, engine);
3543 bool QQmlCompiler::completeComponentBuild()
3546 componentStats->componentStat.ids = compileState->ids.count();
3548 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3549 aliasObject = compileState->aliasingObjects.next(aliasObject))
3550 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3552 QV4Compiler::Expression expr(unit->imports());
3553 expr.component = compileState->root;
3554 expr.ids = &compileState->ids;
3555 expr.importCache = output->importCache;
3557 QV4Compiler bindingCompiler;
3559 QList<JSBindingReference*> sharedBindings;
3561 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3563 JSBindingReference &binding = *b;
3565 // ### We don't currently optimize for bindings on alias's - because
3566 // of the solution to QTBUG-13719
3567 if (!binding.property->isAlias) {
3568 expr.context = binding.bindingContext.object;
3569 expr.property = binding.property;
3570 expr.expression = binding.expression;
3572 int index = bindingCompiler.compile(expr, enginePrivate);
3574 binding.dataType = BindingReference::V4;
3575 binding.compiledIndex = index;
3577 componentStats->componentStat.optimizedBindings.append(b->value->location);
3582 // Pre-rewrite the expression
3583 QString expression = binding.expression.asScript();
3585 QQmlRewrite::RewriteBinding rewriteBinding;
3586 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3587 bool isSharable = false;
3588 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3590 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3591 binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3592 binding.dataType = BindingReference::V8;
3593 sharedBindings.append(b);
3596 componentStats->componentStat.sharedBindings.append(b->value->location);
3598 binding.dataType = BindingReference::QtScript;
3601 componentStats->componentStat.scriptBindings.append(b->value->location);
3605 if (!sharedBindings.isEmpty()) {
3607 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3609 return lhs->value->location.start.line < rhs->value->location.start.line;
3613 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3615 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3616 int lineNumber = startLineNumber;
3618 QByteArray functionArray("[", 1);
3619 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3621 JSBindingReference *reference = sharedBindings.at(ii);
3622 QQmlScript::Value *value = reference->value;
3623 const QString &expression = reference->rewrittenExpression;
3625 if (ii != 0) functionArray.append(",", 1);
3627 while (lineNumber < value->location.start.line) {
3629 functionArray.append("\n", 1);
3632 functionArray += expression.toUtf8();
3633 lineNumber += expression.count(QLatin1Char('\n'));
3634 reference->compiledIndex = ii;
3636 functionArray.append("]", 1);
3638 compileState->v8BindingProgram = functionArray;
3639 compileState->v8BindingProgramLine = startLineNumber;
3642 if (bindingCompiler.isValid())
3643 compileState->compiledBindingData = bindingCompiler.program();
3645 // Check pop()'s matched push()'s
3646 Q_ASSERT(compileState->objectDepth.depth() == 0);
3647 Q_ASSERT(compileState->listDepth.depth() == 0);
3649 saveComponentState();
3654 void QQmlCompiler::dumpStats()
3656 Q_ASSERT(componentStats);
3657 qWarning().nospace() << "QML Document: " << output->url.toString();
3658 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3659 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3660 qWarning().nospace() << " Component Line " << stat.lineNumber;
3661 qWarning().nospace() << " Total Objects: " << stat.objects;
3662 qWarning().nospace() << " IDs Used: " << stat.ids;
3663 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3667 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3668 if (0 == (ii % 10)) {
3669 if (ii) output.append("\n");
3674 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3676 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3677 output.append(") ");
3679 if (!output.isEmpty())
3680 qWarning().nospace() << output.constData();
3683 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3686 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3687 if (0 == (ii % 10)) {
3688 if (ii) output.append("\n");
3693 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3695 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3696 output.append(") ");
3698 if (!output.isEmpty())
3699 qWarning().nospace() << output.constData();
3702 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3705 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3706 if (0 == (ii % 10)) {
3707 if (ii) output.append("\n");
3712 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3714 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3715 output.append(") ");
3717 if (!output.isEmpty())
3718 qWarning().nospace() << output.constData();
3724 Returns true if from can be assigned to a (QObject) property of type
3727 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3729 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3730 const QMetaObject *fromMo = from->metaObject();
3733 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3735 fromMo = fromMo->superClass();
3741 Returns the element name, as written in the QML file, for o.
3743 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3746 if (o->type != -1) {
3747 return output->types.at(o->type).className;
3753 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3756 const QMetaObject *mo = from->metatype;
3758 while (!type && mo) {
3759 type = QQmlMetaType::qmlType(mo);
3760 mo = mo->superClass();
3765 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3767 const QMetaObject *mo = obj->metatype;
3769 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3771 return QStringList();
3773 QMetaClassInfo classInfo = mo->classInfo(idx);
3774 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3779 QQmlCompiler::property(QQmlScript::Object *object, int index)
3781 QQmlPropertyCache *cache = 0;
3783 if (object->synthCache)
3784 cache = object->synthCache;
3785 else if (object->type != -1)
3786 cache = output->types[object->type].createPropertyCache(engine);
3788 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3790 return cache->property(index);
3794 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3796 if (notInRevision) *notInRevision = false;
3798 QQmlPropertyCache *cache = 0;
3800 if (object->synthCache)
3801 cache = object->synthCache;
3802 else if (object->type != -1)
3803 cache = output->types[object->type].createPropertyCache(engine);
3805 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3807 QQmlPropertyData *d = cache->property(name);
3809 // Find the first property
3810 while (d && d->isFunction())
3811 d = cache->overrideData(d);
3813 if (d && !cache->isAllowedInRevision(d)) {
3814 if (notInRevision) *notInRevision = true;
3821 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3823 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3825 if (notInRevision) *notInRevision = false;
3827 QQmlPropertyCache *cache = 0;
3829 if (object->synthCache)
3830 cache = object->synthCache;
3831 else if (object->type != -1)
3832 cache = output->types[object->type].createPropertyCache(engine);
3834 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3837 QQmlPropertyData *d = cache->property(name);
3838 if (notInRevision) *notInRevision = false;
3840 while (d && !(d->isFunction()))
3841 d = cache->overrideData(d);
3843 if (d && !cache->isAllowedInRevision(d)) {
3844 if (notInRevision) *notInRevision = true;
3850 if (name.endsWith(Changed_string)) {
3851 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3853 d = property(object, propName, notInRevision);
3855 return cache->method(d->notifyIndex);
3861 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3862 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3863 bool *notInRevision)
3865 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3866 return d?d->coreIndex:-1;
3869 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3870 bool *notInRevision)
3872 return indexOfProperty(object, QStringRef(&name), notInRevision);
3875 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3876 bool *notInRevision)
3878 QQmlPropertyData *d = property(object, name, notInRevision);
3879 return d?d->coreIndex:-1;