1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcompiler_p.h"
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qqmlstringconverters_p.h"
49 #include "qqmlengine_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlcontext.h"
52 #include "qqmlmetatype_p.h"
53 #include "qqmlcustomparser_p_p.h"
54 #include "qqmlcontext_p.h"
55 #include "qqmlcomponent_p.h"
56 #include <private/qqmljsast_p.h>
57 #include "qqmlvmemetaobject_p.h"
58 #include "qqmlexpression_p.h"
59 #include "qqmlproperty_p.h"
60 #include "qqmlrewrite_p.h"
61 #include "qqmlscriptstring.h"
62 #include "qqmlglobal_p.h"
63 #include "qqmlbinding_p.h"
64 #include <private/qv4compiler_p.h>
71 #include <QtCore/qdebug.h>
72 #include <QtCore/qdatetime.h>
73 #include <QtCore/qvarlengtharray.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QQmlJS;
87 using namespace QQmlScript;
88 using namespace QQmlCompilerTypes;
90 static QString id_string(QLatin1String("id"));
91 static QString on_string(QLatin1String("on"));
92 static QString Changed_string(QLatin1String("Changed"));
93 static QString Component_import_string(QLatin1String("QML/Component"));
94 static QString qsTr_string(QLatin1String("qsTr"));
95 static QString qsTrId_string(QLatin1String("qsTrId"));
98 Instantiate a new QQmlCompiler.
100 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
101 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
102 cachedTranslationContextIndex(-1), componentStats(0)
104 if (compilerStatDump())
105 componentStats = pool->New<ComponentStats>();
109 Returns true if the last call to compile() caused errors.
113 bool QQmlCompiler::isError() const
115 return !exceptions.isEmpty();
119 Return the list of errors from the last call to compile(), or an empty list
120 if there were no errors.
122 QList<QQmlError> QQmlCompiler::errors() const
128 Returns true if \a name refers to an attached property, false otherwise.
130 Attached property names are those that start with a capital letter.
132 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
134 return isAttachedPropertyName(QHashedStringRef(&name));
137 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
139 return !name.isEmpty() && name.at(0).isUpper();
143 Returns true if \a name refers to a signal property, false otherwise.
145 Signal property names are those that start with "on", followed by a first
146 character which is either a capital letter or one or more underscores followed
147 by a capital letter, which is then followed by other allowed characters.
149 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
150 character codes in property names, for simplicity and performance reasons
151 QML only supports letters, numbers and underscores.
153 bool QQmlCompiler::isSignalPropertyName(const QString &name)
155 return isSignalPropertyName(QStringRef(&name));
158 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
160 if (name.length() < 3) return false;
161 if (!name.startsWith(on_string)) return false;
162 int ns = name.length();
163 for (int i = 2; i < ns; ++i) {
164 const QChar curr = name.at(i);
165 if (curr.unicode() == '_') continue;
166 if (curr.isUpper()) return true;
169 return false; // consists solely of underscores - invalid.
173 \macro COMPILE_EXCEPTION
175 Inserts an error into the QQmlCompiler error list, and returns false
178 \a token is used to source the error line and column, and \a desc is the
179 error itself. \a desc can be an expression that can be piped into QDebug.
184 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
187 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
190 error.setUrl(output->url); \
191 error.setLine(line); \
192 error.setColumn(column); \
193 error.setDescription(desc.trimmed()); \
194 exceptions << error; \
198 #define COMPILE_EXCEPTION(token, desc) \
199 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
204 Returns false if \a is false, otherwise does nothing.
206 #define COMPILE_CHECK(a) \
208 if (!a) return false; \
212 Returns true if literal \a v can be assigned to property \a prop, otherwise
215 This test corresponds to action taken by genLiteralAssignment(). Any change
216 made here, must have a corresponding action in genLiteralAssigment().
218 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
219 QQmlScript::Value *v)
221 const QQmlScript::Variant &value = v->value;
223 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
224 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
226 if (prop->core.isEnum()) {
227 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
230 if (p.isFlagType()) {
231 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
233 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
236 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
238 v->value = QQmlScript::Variant((double)enumValue);
242 int type = prop->type;
245 case QMetaType::QVariant:
247 case QVariant::String:
248 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
250 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
251 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
253 case QVariant::ByteArray:
254 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
257 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
259 case QVariant::RegExp:
260 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
264 bool ok = v->value.isNumber();
266 double n = v->value.asNumber();
267 if (double(uint(n)) != n)
270 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
275 bool ok = v->value.isNumber();
277 double n = v->value.asNumber();
278 if (double(int(n)) != n)
281 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
284 case QMetaType::Float:
285 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
287 case QVariant::Double:
288 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
290 case QVariant::Color:
293 QQmlStringConverters::colorFromString(value.asString(), &ok);
294 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
297 #ifndef QT_NO_DATESTRING
301 QQmlStringConverters::dateFromString(value.asString(), &ok);
302 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
308 QQmlStringConverters::timeFromString(value.asString(), &ok);
309 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
312 case QVariant::DateTime:
315 QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
316 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
319 #endif // QT_NO_DATESTRING
320 case QVariant::Point:
321 case QVariant::PointF:
324 QQmlStringConverters::pointFFromString(value.asString(), &ok);
325 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
329 case QVariant::SizeF:
332 QQmlStringConverters::sizeFFromString(value.asString(), &ok);
333 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
337 case QVariant::RectF:
340 QQmlStringConverters::rectFFromString(value.asString(), &ok);
341 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
346 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
349 case QVariant::Vector3D:
351 QQmlInstruction::instr_storeVector3D::QVector3D v3;
352 if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, value.asString(), &v3, sizeof(v3)))
353 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
356 case QVariant::Vector4D:
358 QQmlInstruction::instr_storeVector4D::QVector4D v4;
359 if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, value.asString(), &v4, sizeof(v4)))
360 COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
365 // check if assigning a literal value to a list property.
366 // in each case, check the singular, since an Array of the specified type
367 // will not go via this literal assignment codepath.
368 if (type == qMetaTypeId<QList<qreal> >()) {
369 if (!v->value.isNumber()) {
370 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
373 } else if (type == qMetaTypeId<QList<int> >()) {
374 bool ok = v->value.isNumber();
376 double n = v->value.asNumber();
377 if (double(int(n)) != n)
380 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
382 } else if (type == qMetaTypeId<QList<bool> >()) {
383 if (!v->value.isBoolean()) {
384 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
387 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
388 if (!v->value.isString()) {
389 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
392 } else if (type == qMetaTypeId<QList<QUrl> >()) {
393 if (!v->value.isString()) {
394 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
399 // otherwise, check for existence of string converter to custom type
400 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
402 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
410 Generate a store instruction for assigning literal \a v to property \a prop.
412 Any literal assignment that is approved in testLiteralAssignment() must have
413 a corresponding action in this method.
415 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
416 QQmlScript::Value *v)
418 if (prop->core.isEnum()) {
419 Q_ASSERT(v->value.isNumber());
421 int value = (int)v->value.asNumber();
423 Instruction::StoreInteger instr;
424 instr.propertyIndex = prop->index;
426 output->addInstruction(instr);
430 int type = prop->type;
432 case QMetaType::QVariant:
434 if (v->value.isNumber()) {
435 double n = v->value.asNumber();
436 if (double(int(n)) == n) {
437 if (prop->core.isVMEProperty()) {
438 Instruction::StoreVarInteger instr;
439 instr.propertyIndex = prop->index;
440 instr.value = int(n);
441 output->addInstruction(instr);
443 Instruction::StoreVariantInteger instr;
444 instr.propertyIndex = prop->index;
445 instr.value = int(n);
446 output->addInstruction(instr);
449 if (prop->core.isVMEProperty()) {
450 Instruction::StoreVarDouble instr;
451 instr.propertyIndex = prop->index;
453 output->addInstruction(instr);
455 Instruction::StoreVariantDouble instr;
456 instr.propertyIndex = prop->index;
458 output->addInstruction(instr);
461 } else if (v->value.isBoolean()) {
462 if (prop->core.isVMEProperty()) {
463 Instruction::StoreVarBool instr;
464 instr.propertyIndex = prop->index;
465 instr.value = v->value.asBoolean();
466 output->addInstruction(instr);
468 Instruction::StoreVariantBool instr;
469 instr.propertyIndex = prop->index;
470 instr.value = v->value.asBoolean();
471 output->addInstruction(instr);
474 if (prop->core.isVMEProperty()) {
475 Instruction::StoreVar instr;
476 instr.propertyIndex = prop->index;
477 instr.value = output->indexForString(v->value.asString());
478 output->addInstruction(instr);
480 Instruction::StoreVariant instr;
481 instr.propertyIndex = prop->index;
482 instr.value = output->indexForString(v->value.asString());
483 output->addInstruction(instr);
488 case QVariant::String:
490 Instruction::StoreString instr;
491 instr.propertyIndex = prop->index;
492 instr.value = output->indexForString(v->value.asString());
493 output->addInstruction(instr);
496 case QVariant::StringList:
498 Instruction::StoreStringList instr;
499 instr.propertyIndex = prop->index;
500 instr.value = output->indexForString(v->value.asString());
501 output->addInstruction(instr);
504 case QVariant::ByteArray:
506 Instruction::StoreByteArray instr;
507 instr.propertyIndex = prop->index;
508 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
509 output->addInstruction(instr);
514 Instruction::StoreUrl instr;
515 QString string = v->value.asString();
516 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
517 instr.propertyIndex = prop->index;
518 instr.value = output->indexForUrl(u);
519 output->addInstruction(instr);
524 Instruction::StoreInteger instr;
525 instr.propertyIndex = prop->index;
526 instr.value = uint(v->value.asNumber());
527 output->addInstruction(instr);
532 Instruction::StoreInteger instr;
533 instr.propertyIndex = prop->index;
534 instr.value = int(v->value.asNumber());
535 output->addInstruction(instr);
538 case QMetaType::Float:
540 Instruction::StoreFloat instr;
541 instr.propertyIndex = prop->index;
542 instr.value = float(v->value.asNumber());
543 output->addInstruction(instr);
546 case QVariant::Double:
548 Instruction::StoreDouble instr;
549 instr.propertyIndex = prop->index;
550 instr.value = v->value.asNumber();
551 output->addInstruction(instr);
554 case QVariant::Color:
556 Instruction::StoreColor instr;
557 instr.propertyIndex = prop->index;
558 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
559 output->addInstruction(instr);
562 #ifndef QT_NO_DATESTRING
565 Instruction::StoreDate instr;
566 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
567 instr.propertyIndex = prop->index;
568 instr.value = d.toJulianDay();
569 output->addInstruction(instr);
574 Instruction::StoreTime instr;
575 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
576 instr.propertyIndex = prop->index;
577 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
578 ::memcpy(&instr.time, &time, sizeof(QTime));
579 output->addInstruction(instr);
582 case QVariant::DateTime:
584 Instruction::StoreDateTime instr;
585 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
586 QTime time = dateTime.time();
587 instr.propertyIndex = prop->index;
588 instr.date = dateTime.date().toJulianDay();
589 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
590 ::memcpy(&instr.time, &time, sizeof(QTime));
591 output->addInstruction(instr);
594 #endif // QT_NO_DATESTRING
595 case QVariant::Point:
597 Instruction::StorePoint instr;
599 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
600 instr.propertyIndex = prop->index;
601 instr.point.xp = point.x();
602 instr.point.yp = point.y();
603 output->addInstruction(instr);
606 case QVariant::PointF:
608 Instruction::StorePointF instr;
610 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
611 instr.propertyIndex = prop->index;
612 instr.point.xp = point.x();
613 instr.point.yp = point.y();
614 output->addInstruction(instr);
619 Instruction::StoreSize instr;
621 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
622 instr.propertyIndex = prop->index;
623 instr.size.wd = size.width();
624 instr.size.ht = size.height();
625 output->addInstruction(instr);
628 case QVariant::SizeF:
630 Instruction::StoreSizeF instr;
632 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
633 instr.propertyIndex = prop->index;
634 instr.size.wd = size.width();
635 instr.size.ht = size.height();
636 output->addInstruction(instr);
641 Instruction::StoreRect instr;
643 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
644 instr.propertyIndex = prop->index;
645 instr.rect.x1 = rect.left();
646 instr.rect.y1 = rect.top();
647 instr.rect.x2 = rect.right();
648 instr.rect.y2 = rect.bottom();
649 output->addInstruction(instr);
652 case QVariant::RectF:
654 Instruction::StoreRectF instr;
656 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
657 instr.propertyIndex = prop->index;
658 instr.rect.xp = rect.left();
659 instr.rect.yp = rect.top();
660 instr.rect.w = rect.width();
661 instr.rect.h = rect.height();
662 output->addInstruction(instr);
667 Instruction::StoreBool instr;
668 bool b = v->value.asBoolean();
669 instr.propertyIndex = prop->index;
671 output->addInstruction(instr);
674 case QVariant::Vector3D:
676 Instruction::StoreVector3D instr;
677 instr.propertyIndex = prop->index;
678 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
679 output->addInstruction(instr);
682 case QVariant::Vector4D:
684 Instruction::StoreVector4D instr;
685 instr.propertyIndex = prop->index;
686 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
687 output->addInstruction(instr);
692 // generate single literal value assignment to a list property if required
693 if (type == qMetaTypeId<QList<qreal> >()) {
694 Instruction::StoreDoubleQList instr;
695 instr.propertyIndex = prop->index;
696 instr.value = v->value.asNumber();
697 output->addInstruction(instr);
699 } else if (type == qMetaTypeId<QList<int> >()) {
700 Instruction::StoreIntegerQList instr;
701 instr.propertyIndex = prop->index;
702 instr.value = int(v->value.asNumber());
703 output->addInstruction(instr);
705 } else if (type == qMetaTypeId<QList<bool> >()) {
706 Instruction::StoreBoolQList instr;
707 bool b = v->value.asBoolean();
708 instr.propertyIndex = prop->index;
710 output->addInstruction(instr);
712 } else if (type == qMetaTypeId<QList<QUrl> >()) {
713 Instruction::StoreUrlQList instr;
714 QString string = v->value.asString();
715 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
716 instr.propertyIndex = prop->index;
717 instr.value = output->indexForUrl(u);
718 output->addInstruction(instr);
720 } else if (type == qMetaTypeId<QList<QString> >()) {
721 Instruction::StoreStringQList instr;
722 instr.propertyIndex = prop->index;
723 instr.value = output->indexForString(v->value.asString());
724 output->addInstruction(instr);
728 // otherwise, generate custom type literal assignment
729 Instruction::AssignCustomType instr;
730 instr.propertyIndex = prop->index;
731 instr.primitive = output->indexForString(v->value.asString());
733 output->addInstruction(instr);
740 Resets data by clearing the lists that the QQmlCompiler modifies.
742 void QQmlCompiler::reset(QQmlCompiledData *data)
745 data->primitives.clear();
747 data->bytecode.resize(0);
751 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
752 with which the QQmlCompiledData will be associated.
754 Returns true on success, false on failure. On failure, the compile errors
755 are available from errors().
757 If the environment variant QML_COMPILER_DUMP is set
758 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
759 on a successful compiler.
761 bool QQmlCompiler::compile(QQmlEngine *engine,
763 QQmlCompiledData *out)
770 QQmlScript::Object *root = unit->parser().tree();
773 this->engine = engine;
774 this->enginePrivate = QQmlEnginePrivate::get(engine);
776 this->unitRoot = root;
780 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
781 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
783 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
784 QQmlCompiledData::TypeReference ref;
786 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
787 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
790 ref.type = tref.type;
791 if (!ref.type->isCreatable()) {
792 QString err = ref.type->noCreationReason();
794 err = tr( "Element is not creatable.");
795 COMPILE_EXCEPTION(parserRef->firstUse, err);
798 if (ref.type->containsRevisionedAttributes()) {
799 QQmlError cacheError;
800 ref.typePropertyCache = enginePrivate->cache(ref.type,
801 resolvedTypes.at(ii).minorVersion,
803 if (!ref.typePropertyCache)
804 COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
805 ref.typePropertyCache->addref();
808 } else if (tref.typeData) {
809 ref.component = tref.typeData->compiledData();
818 out->dumpInstructions();
821 Q_ASSERT(out->rootPropertyCache);
829 this->enginePrivate = 0;
831 this->cachedComponentTypeRef = -1;
832 this->cachedTranslationContextIndex = -1;
838 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
840 compileState = pool->New<ComponentCompileState>();
842 compileState->root = tree;
844 componentStats->componentStat.lineNumber = tree->location.start.line;
846 // We generate the importCache before we build the tree so that
847 // it can be used in the binding compiler. Given we "expect" the
848 // QML compilation to succeed, this isn't a waste.
849 output->importCache = new QQmlTypeNameCache();
850 foreach (const QString &ns, unit->namespaces()) {
851 output->importCache->add(ns);
855 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
856 QString qualifier = script.qualifier;
857 QString enclosingNamespace;
859 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
860 if (lastDotIndex != -1) {
861 enclosingNamespace = qualifier.left(lastDotIndex);
862 qualifier = qualifier.mid(lastDotIndex+1);
865 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
868 unit->imports().populateCache(output->importCache, engine);
870 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
873 Instruction::Init init;
874 init.bindingsSize = compileState->totalBindingsCount;
875 init.parserStatusSize = compileState->parserStatusCount;
876 init.contextCache = genContextCache();
877 init.objectStackSize = compileState->objectDepth.maxDepth();
878 init.listStackSize = compileState->listDepth.maxDepth();
879 if (compileState->compiledBindingData.isEmpty())
880 init.compiledBinding = -1;
882 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
883 output->addInstruction(init);
885 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
886 Instruction::StoreImportedScript import;
887 import.value = output->scripts.count();
889 QQmlScriptData *scriptData = script.script->scriptData();
890 scriptData->addref();
891 output->scripts << scriptData;
892 output->addInstruction(import);
895 if (!compileState->v8BindingProgram.isEmpty()) {
896 Instruction::InitV8Bindings bindings;
897 int index = output->programs.count();
899 typedef QQmlCompiledData::V8Program V8Program;
900 output->programs.append(V8Program(compileState->v8BindingProgram, output));
902 bindings.programIndex = index;
903 bindings.line = compileState->v8BindingProgramLine;
904 output->addInstruction(bindings);
909 Instruction::SetDefault def;
910 output->addInstruction(def);
912 Instruction::Done done;
913 output->addInstruction(done);
915 Q_ASSERT(tree->metatype);
917 if (tree->metadata.isEmpty()) {
918 output->root = tree->metatype;
920 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
921 output->root = &output->rootData;
923 if (!tree->metadata.isEmpty())
924 enginePrivate->registerCompositeType(output);
927 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
929 for (int ii = 0; ii < list.count(); ++ii)
930 if (string == list.at(ii))
936 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
939 componentStats->componentStat.objects++;
941 Q_ASSERT (obj->type != -1);
942 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
943 obj->metatype = tr.metaObject();
945 // This object is a "Component" element
946 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
947 COMPILE_CHECK(buildComponent(obj, ctxt));
952 typedef QQmlInstruction I;
953 const I *init = ((const I *)tr.component->bytecode.constData());
954 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
956 // Adjust stack depths to include nested components
957 compileState->objectDepth.pushPop(init->init.objectStackSize);
958 compileState->listDepth.pushPop(init->init.listStackSize);
959 compileState->parserStatusCount += init->init.parserStatusSize;
960 compileState->totalBindingsCount += init->init.bindingsSize;
963 compileState->objectDepth.push();
965 // Object instantiations reset the binding context
966 BindingContext objCtxt(obj);
968 // Create the synthesized meta object, ignoring aliases
969 COMPILE_CHECK(checkDynamicMeta(obj));
970 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
971 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
973 // Find the native type and check for the QQmlParserStatus interface
974 QQmlType *type = toQmlType(obj);
976 obj->parserStatusCast = type->parserStatusCast();
977 if (obj->parserStatusCast != -1)
978 compileState->parserStatusCount++;
980 // Check if this is a custom parser type. Custom parser types allow
981 // assignments to non-existent properties. These assignments are then
982 // compiled by the type.
983 bool isCustomParser = output->types.at(obj->type).type &&
984 output->types.at(obj->type).type->customParser() != 0;
985 QList<QQmlCustomParserProperty> customProps;
987 // Fetch the list of deferred properties
988 QStringList deferredList = deferredProperties(obj);
990 // Must do id property first. This is to ensure that the id given to any
991 // id reference created matches the order in which the objects are
993 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
994 if (prop->name() == id_string) {
995 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1001 Property *defaultProperty = 0;
1002 Property *skipProperty = 0;
1003 if (obj->defaultProperty) {
1004 defaultProperty = obj->defaultProperty;
1006 Property *explicitProperty = 0;
1008 const QMetaObject *mo = obj->metatype;
1009 int idx = mo->indexOfClassInfo("DefaultProperty");
1011 QMetaClassInfo info = mo->classInfo(idx);
1012 const char *p = info.value();
1016 while (char c = p[plen++]) { ord |= c; };
1020 // Utf8 - unoptimal, but seldom hit
1021 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1022 QHashedStringRef r(*s);
1024 if (obj->propertiesHashField.test(r.hash())) {
1025 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1026 if (ep->name() == r) {
1027 explicitProperty = ep;
1033 if (!explicitProperty)
1034 defaultProperty->setName(r);
1037 QHashedCStringRef r(p, plen);
1039 if (obj->propertiesHashField.test(r.hash())) {
1040 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1041 if (ep->name() == r) {
1042 explicitProperty = ep;
1048 if (!explicitProperty) {
1049 // Set the default property name
1050 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1051 r.writeUtf16(buffer);
1052 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1058 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1060 skipProperty = explicitProperty; // We merge the values into defaultProperty
1062 // Find the correct insertion point
1063 Value *insertPos = 0;
1065 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1066 if (!(v->location.start < explicitProperty->values.first()->location.start))
1071 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1075 QQmlCustomParser *cp = 0;
1077 cp = output->types.at(obj->type).type->customParser();
1079 // Build all explicit properties specified
1080 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1082 if (prop == skipProperty)
1084 if (prop->name() == id_string)
1087 bool canDefer = false;
1088 if (isCustomParser) {
1089 if (doesPropertyExist(prop, obj) &&
1090 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1091 !isAttachedPropertyName(prop->name()))) {
1092 int ids = compileState->ids.count();
1093 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1094 canDefer = ids == compileState->ids.count();
1095 } else if (isSignalPropertyName(prop->name()) &&
1096 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1097 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1099 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1102 if (isSignalPropertyName(prop->name())) {
1103 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1105 int ids = compileState->ids.count();
1106 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1107 canDefer = ids == compileState->ids.count();
1111 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1112 prop->isDeferred = true;
1116 // Build the default property
1117 if (defaultProperty) {
1118 Property *prop = defaultProperty;
1120 bool canDefer = false;
1121 if (isCustomParser) {
1122 if (doesPropertyExist(prop, obj)) {
1123 int ids = compileState->ids.count();
1124 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1125 canDefer = ids == compileState->ids.count();
1127 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1130 int ids = compileState->ids.count();
1131 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1132 canDefer = ids == compileState->ids.count();
1135 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1136 prop->isDeferred = true;
1139 // Compile custom parser parts
1140 if (isCustomParser && !customProps.isEmpty()) {
1142 cp->compiler = this;
1144 obj->custom = cp->compile(customProps);
1147 foreach (QQmlError err, cp->errors()) {
1148 err.setUrl(output->url);
1153 compileState->objectDepth.pop();
1158 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1160 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1161 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1166 // Create the object
1167 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1168 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1170 Instruction::CreateSimpleObject create;
1171 create.create = output->types.at(obj->type).type->createFunction();
1172 create.typeSize = output->types.at(obj->type).type->createSize();
1173 create.type = obj->type;
1174 create.line = obj->location.start.line;
1175 create.column = obj->location.start.column;
1176 output->addInstruction(create);
1180 if (output->types.at(obj->type).type) {
1181 Instruction::CreateCppObject create;
1182 create.line = obj->location.start.line;
1183 create.column = obj->location.start.column;
1185 if (!obj->custom.isEmpty())
1186 create.data = output->indexForByteArray(obj->custom);
1187 create.type = obj->type;
1188 create.isRoot = (compileState->root == obj);
1189 output->addInstruction(create);
1191 Instruction::CreateQMLObject create;
1192 create.type = obj->type;
1193 create.isRoot = (compileState->root == obj);
1195 if (!obj->bindingBitmask.isEmpty()) {
1196 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1197 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1199 create.bindingBits = -1;
1201 output->addInstruction(create);
1203 Instruction::CompleteQMLObject complete;
1204 complete.line = obj->location.start.line;
1205 complete.column = obj->location.start.column;
1206 complete.isRoot = (compileState->root == obj);
1207 output->addInstruction(complete);
1211 // Setup the synthesized meta object if necessary
1212 if (!obj->metadata.isEmpty()) {
1213 Instruction::StoreMetaObject meta;
1214 meta.data = output->indexForByteArray(obj->metadata);
1215 meta.aliasData = output->indexForByteArray(obj->synthdata);
1216 meta.propertyCache = output->propertyCaches.count();
1218 QQmlPropertyCache *propertyCache = obj->synthCache;
1219 Q_ASSERT(propertyCache);
1220 propertyCache->addref();
1222 // Add flag for alias properties
1223 if (!obj->synthdata.isEmpty()) {
1224 const QQmlVMEMetaData *vmeMetaData =
1225 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1226 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1227 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1228 QQmlPropertyData *data = propertyCache->property(index);
1229 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1233 if (obj == unitRoot) {
1234 propertyCache->addref();
1235 output->rootPropertyCache = propertyCache;
1238 output->propertyCaches << propertyCache;
1239 output->addInstruction(meta);
1240 } else if (obj == unitRoot) {
1241 output->rootPropertyCache = tr.createPropertyCache(engine);
1242 output->rootPropertyCache->addref();
1245 // Set the object id
1246 if (!obj->id.isEmpty()) {
1247 Instruction::SetId id;
1248 id.value = output->indexForString(obj->id);
1249 id.index = obj->idIndex;
1250 output->addInstruction(id);
1254 if (tr.type && obj->parserStatusCast != -1) {
1255 Instruction::BeginObject begin;
1256 begin.castValue = obj->parserStatusCast;
1257 output->addInstruction(begin);
1263 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1265 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1266 Q_ASSERT(prop->scriptStringScope != -1);
1267 const QString &script = prop->values.first()->value.asScript();
1268 Instruction::StoreScriptString ss;
1269 ss.propertyIndex = prop->index;
1270 ss.value = output->indexForString(script);
1271 ss.scope = prop->scriptStringScope;
1272 // ss.bindingId = rewriteBinding(script, prop->name());
1273 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1274 ss.line = prop->location.start.line;
1275 ss.column = prop->location.start.column;
1276 output->addInstruction(ss);
1279 bool seenDefer = false;
1280 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1281 if (prop->isDeferred) {
1286 genValueProperty(prop, obj);
1289 Instruction::Defer defer;
1290 defer.deferCount = 0;
1291 int deferIdx = output->addInstruction(defer);
1292 int nextInstructionIndex = output->nextInstructionIndex();
1294 Instruction::DeferInit dinit;
1295 // XXX - these are now massive over allocations
1296 dinit.bindingsSize = compileState->totalBindingsCount;
1297 dinit.parserStatusSize = compileState->parserStatusCount;
1298 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1299 dinit.listStackSize = compileState->listDepth.maxDepth();
1300 output->addInstruction(dinit);
1302 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1303 if (!prop->isDeferred)
1305 genValueProperty(prop, obj);
1308 Instruction::Done done;
1309 output->addInstruction(done);
1311 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1314 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1316 QQmlScript::Value *v = prop->values.first();
1318 if (v->type == Value::SignalObject) {
1320 genObject(v->object);
1322 Instruction::AssignSignalObject assign;
1323 assign.line = v->location.start.line;
1324 assign.signal = output->indexForString(prop->name().toString());
1325 output->addInstruction(assign);
1327 } else if (v->type == Value::SignalExpression) {
1329 Instruction::StoreSignal store;
1330 store.signalIndex = prop->index;
1331 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1332 store.value = output->indexForByteArray(rewrite.toUtf8());
1333 store.context = v->signalExpressionContextStack;
1334 store.line = v->location.start.line;
1335 store.column = v->location.start.column;
1336 output->addInstruction(store);
1342 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1343 Instruction::FetchAttached fetch;
1344 fetch.id = prop->index;
1345 fetch.line = prop->location.start.line;
1346 output->addInstruction(fetch);
1348 genObjectBody(prop->value);
1350 Instruction::PopFetchedObject pop;
1351 output->addInstruction(pop);
1354 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1355 Instruction::FetchObject fetch;
1356 fetch.property = prop->index;
1357 fetch.line = prop->location.start.line;
1358 output->addInstruction(fetch);
1360 if (!prop->value->metadata.isEmpty()) {
1361 Instruction::StoreMetaObject meta;
1362 meta.data = output->indexForByteArray(prop->value->metadata);
1363 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1364 meta.propertyCache = -1;
1365 output->addInstruction(meta);
1368 genObjectBody(prop->value);
1370 Instruction::PopFetchedObject pop;
1371 output->addInstruction(pop);
1374 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1376 genValueTypeProperty(obj, prop);
1379 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1380 if (prop->isDeferred)
1383 genValueProperty(prop, obj);
1386 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1388 genValueTypeProperty(obj, prop);
1392 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1394 Instruction::FetchValueType fetch;
1395 fetch.property = prop->index;
1396 fetch.type = prop->type;
1397 fetch.bindingSkipList = 0;
1399 if (obj->type == -1 || output->types.at(obj->type).component) {
1400 // We only have to do this if this is a composite type. If it is a builtin
1401 // type it can't possibly already have bindings that need to be cleared.
1402 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1403 if (!vprop->values.isEmpty()) {
1404 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1405 fetch.bindingSkipList |= (1 << vprop->index);
1410 output->addInstruction(fetch);
1412 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1413 genPropertyAssignment(vprop, prop->value, prop);
1416 Instruction::PopValueType pop;
1417 pop.property = prop->index;
1418 pop.type = prop->type;
1419 pop.bindingSkipList = 0;
1420 output->addInstruction(pop);
1423 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1425 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1428 Instruction::CreateComponent create;
1429 create.line = root->location.start.line;
1430 create.column = root->location.start.column;
1431 create.endLine = root->location.end.line;
1432 create.isRoot = (compileState->root == obj);
1433 int createInstruction = output->addInstruction(create);
1434 int nextInstructionIndex = output->nextInstructionIndex();
1436 ComponentCompileState *oldCompileState = compileState;
1437 compileState = componentState(root);
1439 Instruction::Init init;
1440 init.bindingsSize = compileState->totalBindingsCount;
1441 init.parserStatusSize = compileState->parserStatusCount;
1442 init.contextCache = genContextCache();
1443 init.objectStackSize = compileState->objectDepth.maxDepth();
1444 init.listStackSize = compileState->listDepth.maxDepth();
1445 if (compileState->compiledBindingData.isEmpty())
1446 init.compiledBinding = -1;
1448 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1449 output->addInstruction(init);
1451 if (!compileState->v8BindingProgram.isEmpty()) {
1452 Instruction::InitV8Bindings bindings;
1453 int index = output->programs.count();
1455 typedef QQmlCompiledData::V8Program V8Program;
1456 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1458 bindings.programIndex = index;
1459 bindings.line = compileState->v8BindingProgramLine;
1460 output->addInstruction(bindings);
1465 Instruction::SetDefault def;
1466 output->addInstruction(def);
1468 Instruction::Done done;
1469 output->addInstruction(done);
1471 output->instruction(createInstruction)->createComponent.count =
1472 output->nextInstructionIndex() - nextInstructionIndex;
1474 compileState = oldCompileState;
1476 if (!obj->id.isEmpty()) {
1477 Instruction::SetId id;
1478 id.value = output->indexForString(obj->id);
1479 id.index = obj->idIndex;
1480 output->addInstruction(id);
1483 if (obj == unitRoot) {
1484 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1485 output->rootPropertyCache->addref();
1489 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1490 const BindingContext &ctxt)
1492 // The special "Component" element can only have the id property and a
1493 // default property, that actually defines the component's tree
1495 compileState->objectDepth.push();
1497 // Find, check and set the "id" property (if any)
1498 Property *idProp = 0;
1499 if (obj->properties.isMany() ||
1500 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1501 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1503 if (!obj->properties.isEmpty())
1504 idProp = obj->properties.first();
1507 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1508 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1509 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1511 QString idVal = idProp->values.first()->primitive();
1513 if (compileState->ids.value(idVal))
1514 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1520 // Check the Component tree is well formed
1521 if (obj->defaultProperty &&
1522 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1523 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1524 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1526 if (!obj->dynamicProperties.isEmpty())
1527 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1528 if (!obj->dynamicSignals.isEmpty())
1529 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1530 if (!obj->dynamicSlots.isEmpty())
1531 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1533 QQmlScript::Object *root = 0;
1534 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1535 root = obj->defaultProperty->values.first()->object;
1538 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1540 // Build the component tree
1541 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1543 compileState->objectDepth.pop();
1548 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1549 const BindingContext &ctxt)
1551 ComponentCompileState *oldComponentCompileState = compileState;
1552 compileState = pool->New<ComponentCompileState>();
1553 compileState->root = obj;
1554 compileState->nested = true;
1556 if (componentStats) {
1557 ComponentStat oldComponentStat = componentStats->componentStat;
1559 componentStats->componentStat = ComponentStat();
1560 componentStats->componentStat.lineNumber = obj->location.start.line;
1563 COMPILE_CHECK(buildObject(obj, ctxt));
1565 COMPILE_CHECK(completeComponentBuild());
1567 componentStats->componentStat = oldComponentStat;
1570 COMPILE_CHECK(buildObject(obj, ctxt));
1572 COMPILE_CHECK(completeComponentBuild());
1575 compileState = oldComponentCompileState;
1581 // Build a sub-object. A sub-object is one that was not created directly by
1582 // QML - such as a grouped property object, or an attached object. Sub-object's
1583 // can't have an id, involve a custom parser, have attached properties etc.
1584 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1586 Q_ASSERT(obj->metatype);
1587 Q_ASSERT(!obj->defaultProperty);
1588 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1591 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1592 if (isSignalPropertyName(prop->name())) {
1593 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1595 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1602 int QQmlCompiler::componentTypeRef()
1604 if (cachedComponentTypeRef == -1) {
1605 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1606 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1607 if (output->types.at(ii).type == t) {
1608 cachedComponentTypeRef = ii;
1612 QQmlCompiledData::TypeReference ref;
1614 output->types << ref;
1615 cachedComponentTypeRef = output->types.count() - 1;
1617 return cachedComponentTypeRef;
1620 int QQmlCompiler::translationContextIndex()
1622 if (cachedTranslationContextIndex == -1) {
1623 // This code must match that in the qsTr() implementation
1624 const QString &path = output->name;
1625 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1626 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1628 QByteArray contextUtf8 = context.toUtf8();
1629 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1631 return cachedTranslationContextIndex;
1634 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1635 const BindingContext &ctxt)
1637 Q_ASSERT(obj->metaObject());
1639 const QHashedStringRef &propName = prop->name();
1641 Q_ASSERT(propName.startsWith(on_string));
1642 QString name = propName.mid(2, -1).toString();
1644 // Note that the property name could start with any alpha or '_' or '$' character,
1645 // so we need to do the lower-casing of the first alpha character.
1646 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1647 if (name.at(firstAlphaIndex).isUpper()) {
1648 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1653 bool notInRevision = false;
1655 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1659 if (notInRevision && 0 == property(obj, propName, 0)) {
1660 Q_ASSERT(obj->type != -1);
1661 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1662 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1664 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));
1666 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1670 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1672 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1676 if (prop->value || !prop->values.isOne())
1677 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1679 prop->index = sig->coreIndex;
1682 obj->addSignalProperty(prop);
1684 if (prop->values.first()->object) {
1685 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1686 prop->values.first()->type = Value::SignalObject;
1688 prop->values.first()->type = Value::SignalExpression;
1690 if (!prop->values.first()->value.isScript())
1691 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1693 QString script = prop->values.first()->value.asScript().trimmed();
1694 if (script.isEmpty())
1695 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1697 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1706 Returns true if (value) property \a prop exists on obj, false otherwise.
1708 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1709 QQmlScript::Object *obj)
1711 if (prop->name().isEmpty())
1713 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1716 return property(obj, prop->name()) != 0;
1719 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1720 QQmlScript::Object *obj,
1721 const BindingContext &ctxt)
1723 if (prop->isEmpty())
1724 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1726 const QMetaObject *metaObject = obj->metaObject();
1727 Q_ASSERT(metaObject);
1729 if (isAttachedPropertyName(prop->name())) {
1730 // Setup attached property data
1732 if (ctxt.isSubContext()) {
1733 // Attached properties cannot be used on sub-objects. Sub-objects
1734 // always exist in a binding sub-context, which is what we test
1736 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1740 QQmlImportNamespace *typeNamespace = 0;
1741 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1743 if (typeNamespace) {
1744 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1747 } else if (!type || !type->attachedPropertiesType()) {
1748 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1752 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1754 Q_ASSERT(type->attachedPropertiesFunction());
1755 prop->index = type->attachedPropertiesId();
1756 prop->value->metatype = type->attachedPropertiesType();
1758 // Setup regular property data
1759 bool notInRevision = false;
1760 QQmlPropertyData *d =
1761 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1763 if (d == 0 && notInRevision) {
1764 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1765 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1767 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));
1769 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1772 prop->index = d->coreIndex;
1774 } else if (prop->isDefault) {
1775 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1776 QQmlPropertyData defaultPropertyData;
1777 defaultPropertyData.load(p, engine);
1779 prop->setName(QLatin1String(p.name()));
1780 prop->core = defaultPropertyData;
1781 prop->index = prop->core.coreIndex;
1784 // We can't error here as the "id" property does not require a
1785 // successful index resolution
1786 if (prop->index != -1)
1787 prop->type = prop->core.propType;
1789 // Check if this is an alias
1790 if (prop->index != -1 &&
1792 prop->parent->type != -1 &&
1793 output->types.at(prop->parent->type).component) {
1795 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1796 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1797 prop->isAlias = true;
1800 if (prop->index != -1 && !prop->values.isEmpty())
1801 prop->parent->setBindingBit(prop->index);
1804 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1806 // The magic "id" behavior doesn't apply when "id" is resolved as a
1807 // default property or to sub-objects (which are always in binding
1809 COMPILE_CHECK(buildIdProperty(prop, obj));
1810 if (prop->type == QVariant::String &&
1811 prop->values.first()->value.isString())
1812 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1814 } else if (isAttachedPropertyName(prop->name())) {
1816 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1818 } else if (prop->index == -1) {
1820 if (prop->isDefault) {
1821 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1823 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1826 } else if (prop->value) {
1828 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1830 } else if (prop->core.isQList()) {
1832 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1834 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1836 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1840 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1847 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1848 QQmlScript::Property *nsProp,
1849 QQmlScript::Object *obj,
1850 const BindingContext &ctxt)
1853 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1855 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1857 if (!isAttachedPropertyName(prop->name()))
1858 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1860 // Setup attached property data
1863 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1865 if (!type || !type->attachedPropertiesType())
1866 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1869 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1871 Q_ASSERT(type->attachedPropertiesFunction());
1872 prop->index = type->index();
1873 prop->value->metatype = type->attachedPropertiesType();
1875 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1881 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1882 QQmlScript::Object *obj)
1884 if (prop->core.isQList()) {
1885 genListProperty(prop, obj);
1887 genPropertyAssignment(prop, obj);
1891 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1892 QQmlScript::Object *obj)
1894 int listType = enginePrivate->listType(prop->type);
1896 Instruction::FetchQList fetch;
1897 fetch.property = prop->index;
1898 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1899 fetch.type = listType;
1900 output->addInstruction(fetch);
1902 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1904 if (v->type == Value::CreatedObject) {
1906 genObject(v->object);
1907 if (listTypeIsInterface) {
1908 Instruction::AssignObjectList assign;
1909 assign.line = prop->location.start.line;
1910 output->addInstruction(assign);
1912 Instruction::StoreObjectQList store;
1913 output->addInstruction(store);
1916 } else if (v->type == Value::PropertyBinding) {
1918 genBindingAssignment(v, prop, obj);
1924 Instruction::PopQList pop;
1925 output->addInstruction(pop);
1928 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1929 QQmlScript::Object *obj,
1930 QQmlScript::Property *valueTypeProperty)
1932 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1934 Q_ASSERT(v->type == Value::CreatedObject ||
1935 v->type == Value::PropertyBinding ||
1936 v->type == Value::Literal);
1938 if (v->type == Value::CreatedObject) {
1940 genObject(v->object);
1942 if (QQmlMetaType::isInterface(prop->type)) {
1944 Instruction::StoreInterface store;
1945 store.line = v->object->location.start.line;
1946 store.propertyIndex = prop->index;
1947 output->addInstruction(store);
1949 } else if (prop->type == QMetaType::QVariant) {
1951 if (prop->core.isVMEProperty()) {
1952 Instruction::StoreVarObject store;
1953 store.line = v->object->location.start.line;
1954 store.propertyIndex = prop->index;
1955 output->addInstruction(store);
1957 Instruction::StoreVariantObject store;
1958 store.line = v->object->location.start.line;
1959 store.propertyIndex = prop->index;
1960 output->addInstruction(store);
1966 Instruction::StoreObject store;
1967 store.line = v->object->location.start.line;
1968 store.propertyIndex = prop->index;
1969 output->addInstruction(store);
1972 } else if (v->type == Value::PropertyBinding) {
1974 genBindingAssignment(v, prop, obj, valueTypeProperty);
1976 } else if (v->type == Value::Literal) {
1978 genLiteralAssignment(prop, v);
1984 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1986 Q_ASSERT(v->type == Value::ValueSource ||
1987 v->type == Value::ValueInterceptor);
1989 if (v->type == Value::ValueSource) {
1990 genObject(v->object);
1992 Instruction::StoreValueSource store;
1993 if (valueTypeProperty) {
1994 store.property = genValueTypeData(prop, valueTypeProperty);
1997 store.property = prop->core;
2000 QQmlType *valueType = toQmlType(v->object);
2001 store.castValue = valueType->propertyValueSourceCast();
2002 output->addInstruction(store);
2004 } else if (v->type == Value::ValueInterceptor) {
2005 genObject(v->object);
2007 Instruction::StoreValueInterceptor store;
2008 if (valueTypeProperty) {
2009 store.property = genValueTypeData(prop, valueTypeProperty);
2012 store.property = prop->core;
2015 QQmlType *valueType = toQmlType(v->object);
2016 store.castValue = valueType->propertyValueInterceptorCast();
2017 output->addInstruction(store);
2023 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2024 QQmlScript::Object *obj)
2027 prop->values.isMany() ||
2028 prop->values.first()->object)
2029 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2031 QQmlScript::Value *idValue = prop->values.first();
2032 QString val = idValue->primitive();
2034 COMPILE_CHECK(checkValidId(idValue, val));
2036 if (compileState->ids.value(val))
2037 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2039 prop->values.first()->type = Value::Id;
2047 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2050 Q_ASSERT(!compileState->ids.value(id));
2051 Q_ASSERT(obj->id == id);
2052 obj->idIndex = compileState->ids.count();
2053 compileState->ids.append(obj);
2056 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2058 Q_ASSERT(ref->value && !ref->value->bindingReference);
2059 ref->value->bindingReference = ref;
2060 compileState->totalBindingsCount++;
2061 compileState->bindings.prepend(ref);
2064 void QQmlCompiler::saveComponentState()
2066 Q_ASSERT(compileState->root);
2067 Q_ASSERT(compileState->root->componentCompileState == 0);
2069 compileState->root->componentCompileState = compileState;
2072 componentStats->savedComponentStats.append(componentStats->componentStat);
2075 QQmlCompilerTypes::ComponentCompileState *
2076 QQmlCompiler::componentState(QQmlScript::Object *obj)
2078 Q_ASSERT(obj->componentCompileState);
2079 return obj->componentCompileState;
2082 // Build attached property object. In this example,
2086 // GridView is an attached property object.
2087 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2088 QQmlScript::Object *obj,
2089 const BindingContext &ctxt)
2091 Q_ASSERT(prop->value);
2092 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2094 compileState->objectDepth.push();
2096 obj->addAttachedProperty(prop);
2098 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2100 compileState->objectDepth.pop();
2106 // Build "grouped" properties. In this example:
2108 // font.pointSize: 12
2109 // font.family: "Helvetica"
2111 // font is a nested property. pointSize and family are not.
2112 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2113 QQmlScript::Object *obj,
2114 const BindingContext &ctxt)
2116 Q_ASSERT(prop->type != 0);
2117 Q_ASSERT(prop->index != -1);
2119 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2120 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2122 if (!prop->values.isEmpty()) {
2123 if (prop->values.first()->location < prop->value->location) {
2124 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2126 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2130 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2131 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2135 if (prop->isAlias) {
2136 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2137 vtProp->isAlias = true;
2141 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2142 prop->value, obj, ctxt.incr()));
2143 obj->addValueTypeProperty(prop);
2145 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2149 // Load the nested property's meta type
2150 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2151 if (!prop->value->metatype)
2152 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2154 if (!prop->values.isEmpty())
2155 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2157 obj->addGroupedProperty(prop);
2159 compileState->objectDepth.push();
2161 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2163 compileState->objectDepth.pop();
2169 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2170 QQmlScript::Object *obj,
2171 QQmlScript::Object *baseObj,
2172 const BindingContext &ctxt)
2174 compileState->objectDepth.push();
2176 if (obj->defaultProperty)
2177 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2178 obj->metatype = type->metaObject();
2180 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2182 QQmlPropertyData *d = property(obj, prop->name());
2184 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2186 prop->index = d->coreIndex;
2187 prop->type = d->propType;
2189 prop->isValueTypeSubProperty = true;
2192 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2194 if (prop->values.isMany()) {
2195 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2196 } else if (!prop->values.isEmpty()) {
2197 QQmlScript::Value *value = prop->values.first();
2199 if (value->object) {
2200 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2201 } else if (value->value.isScript()) {
2202 // ### Check for writability
2204 //optimization for <Type>.<EnumValue> enum assignments
2205 bool isEnumAssignment = false;
2207 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2208 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2210 if (isEnumAssignment) {
2211 value->type = Value::Literal;
2213 JSBindingReference *reference = pool->New<JSBindingReference>();
2214 reference->expression = value->value;
2215 reference->property = prop;
2216 reference->value = value;
2217 reference->bindingContext = ctxt;
2218 reference->bindingContext.owner++;
2219 addBindingReference(reference);
2220 value->type = Value::PropertyBinding;
2223 COMPILE_CHECK(testLiteralAssignment(prop, value));
2224 value->type = Value::Literal;
2228 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2229 Q_ASSERT(v->object);
2231 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2234 obj->addValueProperty(prop);
2237 compileState->objectDepth.pop();
2242 // Build assignments to QML lists. QML lists are properties of type
2243 // QQmlListProperty<T>. List properties can accept a list of
2244 // objects, or a single binding.
2245 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2246 QQmlScript::Object *obj,
2247 const BindingContext &ctxt)
2249 Q_ASSERT(prop->core.isQList());
2251 compileState->listDepth.push();
2255 obj->addValueProperty(prop);
2257 int listType = enginePrivate->listType(t);
2258 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2260 bool assignedBinding = false;
2261 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2263 v->type = Value::CreatedObject;
2264 COMPILE_CHECK(buildObject(v->object, ctxt));
2266 // We check object coercian here. We check interface assignment
2268 if (!listTypeIsInterface) {
2269 if (!canCoerce(listType, v->object)) {
2270 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2274 } else if (v->value.isScript()) {
2275 if (assignedBinding)
2276 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2278 assignedBinding = true;
2279 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2280 v->type = Value::PropertyBinding;
2282 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2286 compileState->listDepth.pop();
2291 // Compiles an assignment to a QQmlScriptString property
2292 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2293 QQmlScript::Object *obj,
2294 const BindingContext &ctxt)
2296 if (prop->values.isMany())
2297 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2299 if (prop->values.first()->object)
2300 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2302 prop->scriptStringScope = ctxt.stack;
2303 obj->addScriptStringProperty(prop);
2308 // Compile regular property assignments of the form "property: <value>"
2309 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2310 QQmlScript::Object *obj,
2311 const BindingContext &ctxt)
2313 obj->addValueProperty(prop);
2315 if (prop->values.isMany())
2316 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2318 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2321 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2325 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2330 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2331 Q_ASSERT(v->object);
2332 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2338 // Compile assigning a single object instance to a regular property
2339 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2340 QQmlScript::Object *obj,
2341 QQmlScript::Value *v,
2342 const BindingContext &ctxt)
2344 Q_ASSERT(prop->index != -1);
2345 Q_ASSERT(v->object->type != -1);
2347 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2348 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2350 if (QQmlMetaType::isInterface(prop->type)) {
2352 // Assigning an object to an interface ptr property
2353 COMPILE_CHECK(buildObject(v->object, ctxt));
2355 v->type = Value::CreatedObject;
2357 } else if (prop->type == QMetaType::QVariant) {
2359 // Assigning an object to a QVariant
2360 COMPILE_CHECK(buildObject(v->object, ctxt));
2362 v->type = Value::CreatedObject;
2364 // Normally buildObject() will set this up, but we need the static
2365 // meta object earlier to test for assignability. It doesn't matter
2366 // that there may still be outstanding synthesized meta object changes
2367 // on this type, as they are not relevant for assignability testing
2368 v->object->metatype = output->types.at(v->object->type).metaObject();
2369 Q_ASSERT(v->object->metaObject());
2371 // We want to raw metaObject here as the raw metaobject is the
2372 // actual property type before we applied any extensions that might
2373 // effect the properties on the type, but don't effect assignability
2374 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2376 // Will be true if the assgned type inherits propertyMetaObject
2377 bool isAssignable = false;
2378 // Determine isAssignable value
2379 if (propertyMetaObject) {
2380 const QMetaObject *c = v->object->metatype;
2382 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2383 c = c->superClass();
2388 // Simple assignment
2389 COMPILE_CHECK(buildObject(v->object, ctxt));
2391 v->type = Value::CreatedObject;
2392 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2393 // Automatic "Component" insertion
2394 QQmlScript::Object *root = v->object;
2395 QQmlScript::Object *component = pool->New<Object>();
2396 component->type = componentTypeRef();
2397 component->metatype = &QQmlComponent::staticMetaObject;
2398 component->location = root->location;
2399 QQmlScript::Value *componentValue = pool->New<Value>();
2400 componentValue->object = root;
2401 component->getDefaultProperty()->addValue(componentValue);
2402 v->object = component;
2403 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2405 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2412 // Compile assigning a single object instance to a regular property using the "on" syntax.
2416 // NumberAnimation on x { }
2418 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2419 QQmlScript::Object *obj,
2420 QQmlScript::Object *baseObj,
2421 QQmlScript::Value *v,
2422 const BindingContext &ctxt)
2424 Q_ASSERT(prop->index != -1);
2425 Q_ASSERT(v->object->type != -1);
2429 if (!prop->core.isWritable())
2430 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2433 // Normally buildObject() will set this up, but we need the static
2434 // meta object earlier to test for assignability. It doesn't matter
2435 // that there may still be outstanding synthesized meta object changes
2436 // on this type, as they are not relevant for assignability testing
2437 v->object->metatype = output->types.at(v->object->type).metaObject();
2438 Q_ASSERT(v->object->metaObject());
2440 // Will be true if the assigned type inherits QQmlPropertyValueSource
2441 bool isPropertyValue = false;
2442 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2443 bool isPropertyInterceptor = false;
2444 if (QQmlType *valueType = toQmlType(v->object)) {
2445 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2446 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2449 if (isPropertyValue || isPropertyInterceptor) {
2450 // Assign as a property value source
2451 COMPILE_CHECK(buildObject(v->object, ctxt));
2453 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2454 buildDynamicMeta(baseObj, ForceCreation);
2455 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2457 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2463 // Compile assigning a literal or binding to a regular property
2464 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2465 QQmlScript::Object *obj,
2466 QQmlScript::Value *v,
2467 const BindingContext &ctxt)
2469 Q_ASSERT(prop->index != -1);
2471 if (v->value.isScript()) {
2473 //optimization for <Type>.<EnumValue> enum assignments
2474 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2475 bool isEnumAssignment = false;
2476 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2477 if (isEnumAssignment) {
2478 v->type = Value::Literal;
2483 // Test for other binding optimizations
2484 if (!buildLiteralBinding(v, prop, ctxt))
2485 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2487 v->type = Value::PropertyBinding;
2491 COMPILE_CHECK(testLiteralAssignment(prop, v));
2493 v->type = Value::Literal;
2499 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2500 QQmlScript::Object *obj,
2501 QQmlScript::Value *v,
2504 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2505 *isAssignment = false;
2506 if (!prop->core.isEnum() && !isIntProp)
2509 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2511 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2512 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2514 QString string = v->value.asString();
2515 if (!string.at(0).isUpper())
2519 // Allow enum assignment to ints.
2520 int enumval = evaluateEnum(string.toUtf8());
2521 if (enumval != -1) {
2522 v->type = Value::Literal;
2523 v->value = QQmlScript::Variant((double)enumval);
2524 *isAssignment = true;
2529 QStringList parts = string.split(QLatin1Char('.'));
2530 if (parts.count() != 2)
2533 QString typeName = parts.at(0);
2535 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2540 QString enumValue = parts.at(1);
2544 if (toQmlType(obj) == type) {
2545 // When these two match, we can short cut the search
2546 if (mprop.isFlagType()) {
2547 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2549 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2552 // Otherwise we have to search the whole type
2553 // This matches the logic in QV8TypeWrapper
2554 QByteArray enumName = enumValue.toUtf8();
2555 const QMetaObject *metaObject = type->baseMetaObject();
2557 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2558 QMetaEnum e = metaObject->enumerator(ii);
2559 value = e.keyToValue(enumName.constData(), &ok);
2566 v->type = Value::Literal;
2567 v->value = QQmlScript::Variant((double)value);
2568 *isAssignment = true;
2573 struct StaticQtMetaObject : public QObject
2575 static const QMetaObject *get()
2576 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2579 // Similar logic to above, but not knowing target property.
2580 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2582 int dot = script.indexOf('.');
2584 const QByteArray &scope = script.left(dot);
2586 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2587 if (!type && scope != "Qt")
2589 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2590 const char *key = script.constData() + dot+1;
2591 int i = mo->enumeratorCount();
2594 int v = mo->enumerator(i).keyToValue(key, &ok);
2602 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2604 QQmlType *qmltype = 0;
2605 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2609 return qmltype->metaObject();
2612 // similar to logic of completeComponentBuild, but also sticks data
2613 // into primitives at the end
2614 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2616 QQmlRewrite::RewriteBinding rewriteBinding;
2617 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2619 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2621 return output->indexForString(rewrite);
2624 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2626 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2627 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2630 // Ensures that the dynamic meta specification on obj is valid
2631 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2633 bool seenDefaultProperty = false;
2635 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2636 // Calculating the hash for the names is not a waste as we have to test
2637 // them against the illegalNames set anyway.
2638 QHashField propNames;
2639 QHashField methodNames;
2642 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2643 const QQmlScript::Object::DynamicProperty &prop = *p;
2645 if (prop.isDefaultProperty) {
2646 if (seenDefaultProperty)
2647 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2648 seenDefaultProperty = true;
2651 if (propNames.testAndSet(prop.name.hash())) {
2652 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2653 p2 = obj->dynamicProperties.next(p2)) {
2654 if (p2->name == prop.name) {
2655 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2656 prop.nameLocation.column,
2657 tr("Duplicate property name"));
2662 if (prop.name.at(0).isUpper()) {
2663 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2664 prop.nameLocation.column,
2665 tr("Property names cannot begin with an upper case letter"));
2668 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2669 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2670 prop.nameLocation.column,
2671 tr("Illegal property name"));
2675 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2676 const QQmlScript::Object::DynamicSignal &currSig = *s;
2678 if (methodNames.testAndSet(currSig.name.hash())) {
2679 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2680 s2 = obj->dynamicSignals.next(s2)) {
2681 if (s2->name == currSig.name)
2682 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2686 if (currSig.name.at(0).isUpper())
2687 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2688 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2689 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2692 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2693 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2695 if (methodNames.testAndSet(currSlot.name.hash())) {
2696 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2697 s2 = obj->dynamicSignals.next(s2)) {
2698 if (s2->name == currSlot.name)
2699 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2701 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2702 s2 = obj->dynamicSlots.next(s2)) {
2703 if (s2->name == currSlot.name)
2704 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2708 if (currSlot.name.at(0).isUpper())
2709 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2710 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2711 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2717 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2719 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2720 p = obj->dynamicProperties.next(p)) {
2722 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2725 Property *property = 0;
2726 if (p->isDefaultProperty) {
2727 property = obj->getDefaultProperty();
2729 property = obj->getProperty(p->name);
2730 if (!property->values.isEmpty())
2731 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2735 property->isReadOnlyDeclaration = true;
2737 if (property->value)
2738 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2740 property->values.append(p->defaultValue->values);
2745 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2747 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2750 Q_ASSERT(obj->metatype);
2752 if (mode != ForceCreation &&
2753 obj->dynamicProperties.isEmpty() &&
2754 obj->dynamicSignals.isEmpty() &&
2755 obj->dynamicSlots.isEmpty())
2758 bool resolveAlias = (mode == ResolveAliases);
2760 const Object::DynamicProperty *defaultProperty = 0;
2762 int varPropCount = 0;
2763 int totalPropCount = 0;
2764 int firstPropertyVarIndex = 0;
2766 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2768 if (p->type == Object::DynamicProperty::Alias)
2770 if (p->type == Object::DynamicProperty::Var)
2773 if (p->isDefaultProperty &&
2774 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2775 defaultProperty = p;
2777 if (!resolveAlias) {
2778 // No point doing this for both the alias and non alias cases
2779 QQmlPropertyData *d = property(obj, p->name);
2780 if (d && d->isFinal())
2781 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2785 bool buildData = resolveAlias || aliasCount == 0;
2787 QByteArray dynamicData;
2789 typedef QQmlVMEMetaData VMD;
2791 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2792 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2793 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2794 aliasCount * sizeof(VMD::AliasData), 0);
2797 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2799 QByteArray newClassName = obj->metatype->className();
2800 newClassName.append("_QML_");
2801 newClassName.append(QByteArray::number(uniqueClassId));
2803 if (compileState->root == obj && !compileState->nested) {
2804 QString path = output->url.path();
2805 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2806 if (lastSlash > -1) {
2807 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2808 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2809 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2813 // Size of the array that describes parameter types & names
2814 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2815 + obj->dynamicProperties.count() // for Changed() signals return types
2816 // Return "parameters" don't have names
2817 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2819 QFastMetaBuilder builder;
2821 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2822 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2823 obj->dynamicSlots.count(),
2824 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2825 defaultProperty?1:0, paramDataSize, ¶mIndex);
2828 Object::DynamicProperty::Type dtype;
2830 } builtinTypes[] = {
2831 { Object::DynamicProperty::Var, QMetaType::QVariant },
2832 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2833 { Object::DynamicProperty::Int, QMetaType::Int },
2834 { Object::DynamicProperty::Bool, QMetaType::Bool },
2835 { Object::DynamicProperty::Real, QMetaType::Double },
2836 { Object::DynamicProperty::String, QMetaType::QString },
2837 { Object::DynamicProperty::Url, QMetaType::QUrl },
2838 { Object::DynamicProperty::Color, QMetaType::QColor },
2839 { Object::DynamicProperty::Time, QMetaType::QTime },
2840 { Object::DynamicProperty::Date, QMetaType::QDate },
2841 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2843 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2845 // Reserve dynamic properties
2846 if (obj->dynamicProperties.count()) {
2847 typedef QQmlVMEMetaData VMD;
2849 int effectivePropertyIndex = 0;
2850 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2852 // Reserve space for name
2853 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2854 p->nameRef = builder.newString(p->name.utf8length());
2857 int propertyType = 0; // for VMD
2858 bool readonly = false;
2860 if (p->type == Object::DynamicProperty::Alias) {
2862 } else if (p->type < builtinTypeCount) {
2863 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2864 metaType = builtinTypes[p->type].metaType;
2865 propertyType = metaType;
2868 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2869 p->type == Object::DynamicProperty::Custom);
2871 // XXX don't double resolve this in the case of an alias run
2873 QByteArray customTypeName;
2874 QQmlType *qmltype = 0;
2876 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2877 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2880 QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2882 Q_ASSERT(tdata->isComplete());
2884 QQmlCompiledData *data = tdata->compiledData();
2885 customTypeName = data->root->className();
2889 customTypeName = qmltype->typeName();
2892 if (p->type == Object::DynamicProperty::Custom) {
2893 customTypeName += '*';
2894 propertyType = QMetaType::QObjectStar;
2897 customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2898 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2901 metaType = QMetaType::type(customTypeName);
2902 Q_ASSERT(metaType != QMetaType::UnknownType);
2903 Q_ASSERT(metaType != QMetaType::Void);
2906 if (p->type == Object::DynamicProperty::Var)
2913 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2914 vmd->propertyCount++;
2915 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2918 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2919 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2920 effectivePropertyIndex);
2922 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2923 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2926 effectivePropertyIndex++;
2930 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2932 vmd->varPropertyCount = varPropCount;
2933 firstPropertyVarIndex = effectivePropertyIndex;
2934 totalPropCount = varPropCount + effectivePropertyIndex;
2935 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2936 if (p->type == Object::DynamicProperty::Var) {
2938 vmd->propertyCount++;
2939 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2942 builder.setProperty(effectivePropertyIndex, p->nameRef,
2943 QMetaType::QVariant,
2944 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2945 effectivePropertyIndex);
2947 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2948 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2951 effectivePropertyIndex++;
2958 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2959 if (p->type == Object::DynamicProperty::Alias) {
2961 Q_ASSERT(buildData);
2962 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2963 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2966 // Even if we aren't resolving the alias, we need a fake signal so that the
2967 // metaobject remains consistent across the resolve and non-resolve alias runs
2968 p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2969 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2971 effectivePropertyIndex++;
2978 // Reserve default property
2979 QFastMetaBuilder::StringRef defPropRef;
2980 if (defaultProperty) {
2981 defPropRef = builder.newString(strlen("DefaultProperty"));
2982 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2985 // Reserve dynamic signals
2986 int signalIndex = 0;
2987 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2989 s->nameRef = builder.newString(s->name.utf8length());
2991 int paramCount = s->parameterNames.count();
2992 QVarLengthArray<int, 10> paramTypes(paramCount);
2994 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
2995 for (int i = 0; i < paramCount; ++i) {
2996 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
2997 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2998 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3003 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3005 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3006 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3007 paramIndex += paramCount*2 + 1;
3011 // Reserve dynamic slots
3012 if (obj->dynamicSlots.count()) {
3014 typedef QQmlVMEMetaData VMD;
3016 int methodIndex = 0;
3017 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3018 s->nameRef = builder.newString(s->name.utf8length());
3019 int paramCount = s->parameterNames.count();
3021 QVarLengthArray<int, 10> paramTypes(paramCount);
3023 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3024 for (int i = 0; i < paramCount; ++i) {
3025 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3026 paramTypes[i] = QMetaType::QVariant;
3030 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3031 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3032 paramIndex += paramCount*2 + 1;
3037 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3038 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3039 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3040 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3041 for (int jj = 0; jj < paramCount; ++jj) {
3042 if (jj) funcScript.append(QLatin1Char(','));
3043 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3045 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3047 QByteArray utf8 = funcScript.toUtf8();
3048 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3050 s->location.start.line };
3052 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3055 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3057 md.bodyOffset = dynamicData.size();
3059 dynamicData.append((const char *)utf8.constData(), utf8.length());
3067 // Now allocate properties
3068 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3070 char *d = p->changedNameRef.data();
3071 p->name.writeUtf8(d);
3072 strcpy(d + p->name.utf8length(), "Changed");
3073 p->changedNameRef.loadByteArrayData();
3075 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3078 p->nameRef.load(p->name);
3081 // Allocate default property if necessary
3082 if (defaultProperty)
3083 defPropRef.load("DefaultProperty");
3085 // Now allocate signals
3086 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3088 s->nameRef.load(s->name);
3090 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3091 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3094 // Now allocate methods
3095 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3096 s->nameRef.load(s->name);
3098 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3099 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3102 // Now allocate class name
3103 classNameRef.load(newClassName);
3105 obj->metadata = builder.toData();
3106 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3108 if (mode == IgnoreAliases && aliasCount)
3109 compileState->aliasingObjects.append(obj);
3111 obj->synthdata = dynamicData;
3113 if (obj->synthCache) {
3114 obj->synthCache->release();
3115 obj->synthCache = 0;
3118 if (obj->type != -1) {
3119 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3120 QQmlPropertyCache *cache =
3121 superCache->copyAndAppend(engine, &obj->extObject,
3122 QQmlPropertyData::NoFlags,
3123 QQmlPropertyData::IsVMEFunction,
3124 QQmlPropertyData::IsVMESignal);
3126 // now we modify the flags appropriately for var properties.
3127 int propertyOffset = obj->extObject.propertyOffset();
3128 QQmlPropertyData *currPropData = 0;
3129 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3130 currPropData = cache->property(pvi + propertyOffset);
3131 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3134 obj->synthCache = cache;
3140 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3143 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3145 QChar ch = val.at(0);
3146 if (ch.isLetter() && !ch.isLower())
3147 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3149 QChar u(QLatin1Char('_'));
3150 if (!ch.isLetter() && ch != u)
3151 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3153 for (int ii = 1; ii < val.count(); ++ii) {
3155 if (!ch.isLetterOrNumber() && ch != u)
3156 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3159 if (enginePrivate->v8engine()->illegalNames().contains(val))
3160 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3165 #include <private/qqmljsparser_p.h>
3167 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3169 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3171 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3172 return QStringList() << name;
3173 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3174 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3176 QStringList rv = astNodeToStringList(expr->base);
3179 rv.append(expr->name.toString());
3182 return QStringList();
3185 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3187 QQmlScript::Object *obj,
3188 int propIndex, int aliasIndex,
3189 Object::DynamicProperty &prop)
3191 Q_ASSERT(!prop.nameRef.isEmpty());
3192 if (!prop.defaultValue)
3193 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3195 if (!prop.defaultValue->values.isOne() ||
3196 prop.defaultValue->values.first()->object ||
3197 !prop.defaultValue->values.first()->value.isScript())
3198 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3200 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3202 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3204 QStringList alias = astNodeToStringList(node);
3206 if (alias.count() < 1 || alias.count() > 3)
3207 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3209 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3211 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3213 QByteArray typeName;
3218 bool writable = false;
3219 bool resettable = false;
3220 if (alias.count() == 2 || alias.count() == 3) {
3221 propIdx = indexOfProperty(idObject, alias.at(1));
3223 if (-1 == propIdx) {
3224 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3225 } else if (propIdx > 0xFFFF) {
3226 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3229 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3230 if (!aliasProperty.isScriptable())
3231 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3233 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3234 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3236 type = aliasProperty.userType();
3238 if (alias.count() == 3) {
3239 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3241 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3243 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3245 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3246 if (valueTypeIndex == -1)
3247 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3248 Q_ASSERT(valueTypeIndex <= 0xFF);
3250 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3251 propIdx |= (valueTypeIndex << 16);
3253 // update the property type
3254 type = aliasProperty.userType();
3257 if (aliasProperty.isEnumType())
3258 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3260 typeName = aliasProperty.typeName();
3262 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3264 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3266 typeName = ref.type->typeName();
3268 typeName = ref.component->root->className();
3273 if (typeName.endsWith('*'))
3274 flags |= QML_ALIAS_FLAG_PTR;
3276 if (type == QMetaType::UnknownType) {
3277 Q_ASSERT(!typeName.isEmpty());
3278 type = QMetaType::type(typeName);
3279 Q_ASSERT(type != QMetaType::UnknownType);
3280 Q_ASSERT(type != QMetaType::Void);
3283 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3285 typedef QQmlVMEMetaData VMD;
3286 VMD *vmd = (QQmlVMEMetaData *)data.data();
3287 *(vmd->aliasData() + aliasIndex) = aliasData;
3289 int propertyFlags = 0;
3291 propertyFlags |= QFastMetaBuilder::Writable;
3293 propertyFlags |= QFastMetaBuilder::Resettable;
3295 builder.setProperty(propIndex, prop.nameRef, type,
3296 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3302 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3303 QQmlScript::Property *prop,
3304 const BindingContext &ctxt)
3306 Q_ASSERT(prop->index != -1);
3307 Q_ASSERT(prop->parent);
3308 Q_ASSERT(prop->parent->metaObject());
3310 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3311 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3313 JSBindingReference *reference = pool->New<JSBindingReference>();
3314 reference->expression = value->value;
3315 reference->property = prop;
3316 reference->value = value;
3317 reference->bindingContext = ctxt;
3318 addBindingReference(reference);
3323 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3324 QQmlScript::Property *prop,
3325 const QQmlCompilerTypes::BindingContext &)
3327 Q_ASSERT(v->value.isScript());
3329 if (!prop->core.isWritable())
3332 AST::Node *binding = v->value.asAST();
3334 if (prop->type == QVariant::String) {
3335 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3336 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3337 if (i->name == qsTrId_string) {
3338 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3339 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3341 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3342 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3343 (!arg2 || !arg2->next)) {
3348 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3349 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3351 TrBindingReference *reference = pool->New<TrBindingReference>();
3352 reference->dataType = BindingReference::TrId;
3353 reference->text = text;
3355 v->bindingReference = reference;
3359 } else if (i->name == qsTr_string) {
3361 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3362 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3363 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3365 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3366 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3367 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3368 (!arg3 || !arg3->next)) {
3374 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3375 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3376 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3378 TrBindingReference *reference = pool->New<TrBindingReference>();
3379 reference->dataType = BindingReference::Tr;
3380 reference->text = text;
3381 reference->comment = comment;
3383 v->bindingReference = reference;
3396 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3397 QQmlScript::Property *prop,
3398 QQmlScript::Object *obj,
3399 QQmlScript::Property *valueTypeProperty)
3402 Q_ASSERT(binding->bindingReference);
3404 const BindingReference &ref = *binding->bindingReference;
3405 if (ref.dataType == BindingReference::TrId) {
3406 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3408 Instruction::StoreTrIdString store;
3409 store.propertyIndex = prop->core.coreIndex;
3410 store.text = output->indexForByteArray(tr.text.toUtf8());
3412 output->addInstruction(store);
3413 } else if (ref.dataType == BindingReference::Tr) {
3414 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3416 Instruction::StoreTrString store;
3417 store.propertyIndex = prop->core.coreIndex;
3418 store.context = translationContextIndex();
3419 store.text = output->indexForByteArray(tr.text.toUtf8());
3420 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3422 output->addInstruction(store);
3423 } else if (ref.dataType == BindingReference::V4) {
3424 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3426 Instruction::StoreV4Binding store;
3427 store.value = js.compiledIndex;
3428 store.context = js.bindingContext.stack;
3429 store.owner = js.bindingContext.owner;
3430 if (valueTypeProperty) {
3431 store.property = (valueTypeProperty->index & 0xFFFF) |
3432 ((valueTypeProperty->type & 0xFF)) << 16 |
3433 ((prop->index & 0xFF) << 24);
3434 store.isRoot = (compileState->root == valueTypeProperty->parent);
3436 store.property = prop->index;
3437 store.isRoot = (compileState->root == obj);
3439 store.line = binding->location.start.line;
3440 store.column = binding->location.start.column;
3441 output->addInstruction(store);
3442 } else if (ref.dataType == BindingReference::V8) {
3443 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3445 Instruction::StoreV8Binding store;
3446 store.value = js.compiledIndex;
3447 store.context = js.bindingContext.stack;
3448 store.owner = js.bindingContext.owner;
3449 store.isAlias = prop->isAlias;
3450 if (valueTypeProperty) {
3451 store.isRoot = (compileState->root == valueTypeProperty->parent);
3453 store.isRoot = (compileState->root == obj);
3455 store.line = binding->location.start.line;
3456 store.column = binding->location.start.column;
3458 Q_ASSERT(js.bindingContext.owner == 0 ||
3459 (js.bindingContext.owner != 0 && valueTypeProperty));
3460 if (js.bindingContext.owner) {
3461 store.property = genValueTypeData(prop, valueTypeProperty);
3463 store.property = prop->core;
3466 output->addInstruction(store);
3467 } else if (ref.dataType == BindingReference::QtScript) {
3468 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3470 Instruction::StoreBinding store;
3471 store.value = output->indexForString(js.rewrittenExpression);
3472 store.context = js.bindingContext.stack;
3473 store.owner = js.bindingContext.owner;
3474 store.line = binding->location.start.line;
3475 store.column = binding->location.start.column;
3476 store.isAlias = prop->isAlias;
3478 if (valueTypeProperty) {
3479 store.isRoot = (compileState->root == valueTypeProperty->parent);
3481 store.isRoot = (compileState->root == obj);
3484 Q_ASSERT(js.bindingContext.owner == 0 ||
3485 (js.bindingContext.owner != 0 && valueTypeProperty));
3486 if (js.bindingContext.owner) {
3487 store.property = genValueTypeData(prop, valueTypeProperty);
3489 store.property = prop->core;
3492 output->addInstruction(store);
3494 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3498 int QQmlCompiler::genContextCache()
3500 if (compileState->ids.count() == 0)
3503 QQmlIntegerCache *cache = new QQmlIntegerCache();
3504 cache->reserve(compileState->ids.count());
3505 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3506 cache->add(o->id, o->idIndex);
3508 output->contextCaches.append(cache);
3509 return output->contextCaches.count() - 1;
3513 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3514 QQmlScript::Property *prop)
3516 typedef QQmlPropertyPrivate QDPP;
3517 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3518 enginePrivate->valueTypes[prop->type]->metaObject(),
3519 valueTypeProp->index, engine);
3522 bool QQmlCompiler::completeComponentBuild()
3525 componentStats->componentStat.ids = compileState->ids.count();
3527 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3528 aliasObject = compileState->aliasingObjects.next(aliasObject))
3529 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3531 QV4Compiler::Expression expr(unit->imports());
3532 expr.component = compileState->root;
3533 expr.ids = &compileState->ids;
3534 expr.importCache = output->importCache;
3536 QV4Compiler bindingCompiler;
3538 QList<JSBindingReference*> sharedBindings;
3540 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3542 JSBindingReference &binding = *b;
3544 // ### We don't currently optimize for bindings on alias's - because
3545 // of the solution to QTBUG-13719
3546 if (!binding.property->isAlias) {
3547 expr.context = binding.bindingContext.object;
3548 expr.property = binding.property;
3549 expr.expression = binding.expression;
3551 int index = bindingCompiler.compile(expr, enginePrivate);
3553 binding.dataType = BindingReference::V4;
3554 binding.compiledIndex = index;
3556 componentStats->componentStat.optimizedBindings.append(b->value->location);
3561 // Pre-rewrite the expression
3562 QString expression = binding.expression.asScript();
3564 QQmlRewrite::RewriteBinding rewriteBinding;
3565 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3566 bool isSharable = false;
3567 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3569 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3570 binding.dataType = BindingReference::V8;
3571 sharedBindings.append(b);
3574 componentStats->componentStat.sharedBindings.append(b->value->location);
3576 binding.dataType = BindingReference::QtScript;
3579 componentStats->componentStat.scriptBindings.append(b->value->location);
3583 if (!sharedBindings.isEmpty()) {
3585 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3587 return lhs->value->location.start.line < rhs->value->location.start.line;
3591 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3593 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3594 int lineNumber = startLineNumber;
3596 QByteArray functionArray("[", 1);
3597 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3599 JSBindingReference *reference = sharedBindings.at(ii);
3600 QQmlScript::Value *value = reference->value;
3601 const QString &expression = reference->rewrittenExpression;
3603 if (ii != 0) functionArray.append(",", 1);
3605 while (lineNumber < value->location.start.line) {
3607 functionArray.append("\n", 1);
3610 functionArray += expression.toUtf8();
3611 lineNumber += expression.count(QLatin1Char('\n'));
3612 reference->compiledIndex = ii;
3614 functionArray.append("]", 1);
3616 compileState->v8BindingProgram = functionArray;
3617 compileState->v8BindingProgramLine = startLineNumber;
3620 if (bindingCompiler.isValid())
3621 compileState->compiledBindingData = bindingCompiler.program();
3623 // Check pop()'s matched push()'s
3624 Q_ASSERT(compileState->objectDepth.depth() == 0);
3625 Q_ASSERT(compileState->listDepth.depth() == 0);
3627 saveComponentState();
3632 void QQmlCompiler::dumpStats()
3634 Q_ASSERT(componentStats);
3635 qWarning().nospace() << "QML Document: " << output->url.toString();
3636 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3637 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3638 qWarning().nospace() << " Component Line " << stat.lineNumber;
3639 qWarning().nospace() << " Total Objects: " << stat.objects;
3640 qWarning().nospace() << " IDs Used: " << stat.ids;
3641 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3645 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3646 if (0 == (ii % 10)) {
3647 if (ii) output.append("\n");
3652 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3654 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3655 output.append(") ");
3657 if (!output.isEmpty())
3658 qWarning().nospace() << output.constData();
3661 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3664 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3665 if (0 == (ii % 10)) {
3666 if (ii) output.append("\n");
3671 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3673 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3674 output.append(") ");
3676 if (!output.isEmpty())
3677 qWarning().nospace() << output.constData();
3680 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3683 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3684 if (0 == (ii % 10)) {
3685 if (ii) output.append("\n");
3690 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3692 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3693 output.append(") ");
3695 if (!output.isEmpty())
3696 qWarning().nospace() << output.constData();
3702 Returns true if from can be assigned to a (QObject) property of type
3705 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3707 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3708 const QMetaObject *fromMo = from->metaObject();
3711 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3713 fromMo = fromMo->superClass();
3719 Returns the element name, as written in the QML file, for o.
3721 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3724 if (o->type != -1) {
3725 return unit->parser().referencedTypes().at(o->type)->name;
3731 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3733 if (from->type != -1 && output->types.at(from->type).type)
3734 return output->types.at(from->type).type;
3737 const QMetaObject *mo = from->metatype;
3739 while (!type && mo) {
3740 type = QQmlMetaType::qmlType(mo);
3741 mo = mo->superClass();
3746 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3748 const QMetaObject *mo = obj->metatype;
3750 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3752 return QStringList();
3754 QMetaClassInfo classInfo = mo->classInfo(idx);
3755 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3760 QQmlCompiler::property(QQmlScript::Object *object, int index)
3762 QQmlPropertyCache *cache = 0;
3764 if (object->synthCache)
3765 cache = object->synthCache;
3766 else if (object->type != -1)
3767 cache = output->types[object->type].createPropertyCache(engine);
3769 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3771 return cache->property(index);
3775 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3777 if (notInRevision) *notInRevision = false;
3779 QQmlPropertyCache *cache = 0;
3781 if (object->synthCache)
3782 cache = object->synthCache;
3783 else if (object->type != -1)
3784 cache = output->types[object->type].createPropertyCache(engine);
3786 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3788 QQmlPropertyData *d = cache->property(name);
3790 // Find the first property
3791 while (d && d->isFunction())
3792 d = cache->overrideData(d);
3794 if (d && !cache->isAllowedInRevision(d)) {
3795 if (notInRevision) *notInRevision = true;
3802 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3804 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3806 if (notInRevision) *notInRevision = false;
3808 QQmlPropertyCache *cache = 0;
3810 if (object->synthCache)
3811 cache = object->synthCache;
3812 else if (object->type != -1)
3813 cache = output->types[object->type].createPropertyCache(engine);
3815 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3818 QQmlPropertyData *d = cache->property(name);
3819 if (notInRevision) *notInRevision = false;
3821 while (d && !(d->isFunction()))
3822 d = cache->overrideData(d);
3824 if (d && !cache->isAllowedInRevision(d)) {
3825 if (notInRevision) *notInRevision = true;
3831 if (name.endsWith(Changed_string)) {
3832 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3834 d = property(object, propName, notInRevision);
3836 return cache->method(d->notifyIndex);
3842 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3843 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3844 bool *notInRevision)
3846 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3847 return d?d->coreIndex:-1;
3850 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3851 bool *notInRevision)
3853 return indexOfProperty(object, QStringRef(&name), notInRevision);
3856 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3857 bool *notInRevision)
3859 QQmlPropertyData *d = property(object, name, notInRevision);
3860 return d?d->coreIndex:-1;