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();
810 ref.component->addref();
819 out->dumpInstructions();
822 Q_ASSERT(out->rootPropertyCache);
830 this->enginePrivate = 0;
832 this->cachedComponentTypeRef = -1;
833 this->cachedTranslationContextIndex = -1;
839 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
841 compileState = pool->New<ComponentCompileState>();
843 compileState->root = tree;
845 componentStats->componentStat.lineNumber = tree->location.start.line;
847 // We generate the importCache before we build the tree so that
848 // it can be used in the binding compiler. Given we "expect" the
849 // QML compilation to succeed, this isn't a waste.
850 output->importCache = new QQmlTypeNameCache();
851 foreach (const QString &ns, unit->namespaces()) {
852 output->importCache->add(ns);
856 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
857 QString qualifier = script.qualifier;
858 QString enclosingNamespace;
860 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
861 if (lastDotIndex != -1) {
862 enclosingNamespace = qualifier.left(lastDotIndex);
863 qualifier = qualifier.mid(lastDotIndex+1);
866 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
869 unit->imports().populateCache(output->importCache, engine);
871 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
874 Instruction::Init init;
875 init.bindingsSize = compileState->totalBindingsCount;
876 init.parserStatusSize = compileState->parserStatusCount;
877 init.contextCache = genContextCache();
878 init.objectStackSize = compileState->objectDepth.maxDepth();
879 init.listStackSize = compileState->listDepth.maxDepth();
880 if (compileState->compiledBindingData.isEmpty())
881 init.compiledBinding = -1;
883 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
884 output->addInstruction(init);
886 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
887 Instruction::StoreImportedScript import;
888 import.value = output->scripts.count();
890 QQmlScriptData *scriptData = script.script->scriptData();
891 scriptData->addref();
892 output->scripts << scriptData;
893 output->addInstruction(import);
896 if (!compileState->v8BindingProgram.isEmpty()) {
897 Instruction::InitV8Bindings bindings;
898 int index = output->programs.count();
900 typedef QQmlCompiledData::V8Program V8Program;
901 output->programs.append(V8Program(compileState->v8BindingProgram, output));
903 bindings.programIndex = index;
904 bindings.line = compileState->v8BindingProgramLine;
905 output->addInstruction(bindings);
910 Instruction::SetDefault def;
911 output->addInstruction(def);
913 Instruction::Done done;
914 output->addInstruction(done);
916 Q_ASSERT(tree->metatype);
918 if (tree->metadata.isEmpty()) {
919 output->root = tree->metatype;
921 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
922 output->root = &output->rootData;
924 if (!tree->metadata.isEmpty())
925 enginePrivate->registerCompositeType(output->root);
928 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
930 for (int ii = 0; ii < list.count(); ++ii)
931 if (string == list.at(ii))
937 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
940 componentStats->componentStat.objects++;
942 Q_ASSERT (obj->type != -1);
943 const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
944 obj->metatype = tr.metaObject();
946 // This object is a "Component" element
947 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
948 COMPILE_CHECK(buildComponent(obj, ctxt));
953 typedef QQmlInstruction I;
954 const I *init = ((const I *)tr.component->bytecode.constData());
955 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
957 // Adjust stack depths to include nested components
958 compileState->objectDepth.pushPop(init->init.objectStackSize);
959 compileState->listDepth.pushPop(init->init.listStackSize);
960 compileState->parserStatusCount += init->init.parserStatusSize;
961 compileState->totalBindingsCount += init->init.bindingsSize;
964 compileState->objectDepth.push();
966 // Object instantiations reset the binding context
967 BindingContext objCtxt(obj);
969 // Create the synthesized meta object, ignoring aliases
970 COMPILE_CHECK(checkDynamicMeta(obj));
971 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
972 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
974 // Find the native type and check for the QQmlParserStatus interface
975 QQmlType *type = toQmlType(obj);
977 obj->parserStatusCast = type->parserStatusCast();
978 if (obj->parserStatusCast != -1)
979 compileState->parserStatusCount++;
981 // Check if this is a custom parser type. Custom parser types allow
982 // assignments to non-existent properties. These assignments are then
983 // compiled by the type.
984 bool isCustomParser = output->types.at(obj->type).type &&
985 output->types.at(obj->type).type->customParser() != 0;
986 QList<QQmlCustomParserProperty> customProps;
988 // Fetch the list of deferred properties
989 QStringList deferredList = deferredProperties(obj);
991 // Must do id property first. This is to ensure that the id given to any
992 // id reference created matches the order in which the objects are
994 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
995 if (prop->name() == id_string) {
996 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1002 Property *defaultProperty = 0;
1003 Property *skipProperty = 0;
1004 if (obj->defaultProperty) {
1005 defaultProperty = obj->defaultProperty;
1007 Property *explicitProperty = 0;
1009 const QMetaObject *mo = obj->metatype;
1010 int idx = mo->indexOfClassInfo("DefaultProperty");
1012 QMetaClassInfo info = mo->classInfo(idx);
1013 const char *p = info.value();
1017 while (char c = p[plen++]) { ord |= c; };
1021 // Utf8 - unoptimal, but seldom hit
1022 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1023 QHashedStringRef r(*s);
1025 if (obj->propertiesHashField.test(r.hash())) {
1026 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1027 if (ep->name() == r) {
1028 explicitProperty = ep;
1034 if (!explicitProperty)
1035 defaultProperty->setName(r);
1038 QHashedCStringRef r(p, plen);
1040 if (obj->propertiesHashField.test(r.hash())) {
1041 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1042 if (ep->name() == r) {
1043 explicitProperty = ep;
1049 if (!explicitProperty) {
1050 // Set the default property name
1051 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1052 r.writeUtf16(buffer);
1053 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1059 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1061 skipProperty = explicitProperty; // We merge the values into defaultProperty
1063 // Find the correct insertion point
1064 Value *insertPos = 0;
1066 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1067 if (!(v->location.start < explicitProperty->values.first()->location.start))
1072 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1076 QQmlCustomParser *cp = 0;
1078 cp = output->types.at(obj->type).type->customParser();
1080 // Build all explicit properties specified
1081 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1083 if (prop == skipProperty)
1085 if (prop->name() == id_string)
1088 bool canDefer = false;
1089 if (isCustomParser) {
1090 if (doesPropertyExist(prop, obj) &&
1091 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1092 !isAttachedPropertyName(prop->name()))) {
1093 int ids = compileState->ids.count();
1094 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1095 canDefer = ids == compileState->ids.count();
1096 } else if (isSignalPropertyName(prop->name()) &&
1097 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1098 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1100 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1103 if (isSignalPropertyName(prop->name())) {
1104 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1106 int ids = compileState->ids.count();
1107 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1108 canDefer = ids == compileState->ids.count();
1112 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1113 prop->isDeferred = true;
1117 // Build the default property
1118 if (defaultProperty) {
1119 Property *prop = defaultProperty;
1121 bool canDefer = false;
1122 if (isCustomParser) {
1123 if (doesPropertyExist(prop, obj)) {
1124 int ids = compileState->ids.count();
1125 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1126 canDefer = ids == compileState->ids.count();
1128 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1131 int ids = compileState->ids.count();
1132 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1133 canDefer = ids == compileState->ids.count();
1136 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1137 prop->isDeferred = true;
1140 // Compile custom parser parts
1141 if (isCustomParser && !customProps.isEmpty()) {
1143 cp->compiler = this;
1145 obj->custom = cp->compile(customProps);
1148 foreach (QQmlError err, cp->errors()) {
1149 err.setUrl(output->url);
1154 compileState->objectDepth.pop();
1159 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1161 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1162 if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1167 // Create the object
1168 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1169 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1171 Instruction::CreateSimpleObject create;
1172 create.create = output->types.at(obj->type).type->createFunction();
1173 create.typeSize = output->types.at(obj->type).type->createSize();
1174 create.type = obj->type;
1175 create.line = obj->location.start.line;
1176 create.column = obj->location.start.column;
1177 output->addInstruction(create);
1181 if (output->types.at(obj->type).type) {
1182 Instruction::CreateCppObject create;
1183 create.line = obj->location.start.line;
1184 create.column = obj->location.start.column;
1186 if (!obj->custom.isEmpty())
1187 create.data = output->indexForByteArray(obj->custom);
1188 create.type = obj->type;
1189 create.isRoot = (compileState->root == obj);
1190 output->addInstruction(create);
1192 Instruction::CreateQMLObject create;
1193 create.type = obj->type;
1194 create.isRoot = (compileState->root == obj);
1196 if (!obj->bindingBitmask.isEmpty()) {
1197 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1198 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1200 create.bindingBits = -1;
1202 output->addInstruction(create);
1204 Instruction::CompleteQMLObject complete;
1205 complete.line = obj->location.start.line;
1206 complete.column = obj->location.start.column;
1207 complete.isRoot = (compileState->root == obj);
1208 output->addInstruction(complete);
1212 // Setup the synthesized meta object if necessary
1213 if (!obj->metadata.isEmpty()) {
1214 Instruction::StoreMetaObject meta;
1215 meta.data = output->indexForByteArray(obj->metadata);
1216 meta.aliasData = output->indexForByteArray(obj->synthdata);
1217 meta.propertyCache = output->propertyCaches.count();
1219 QQmlPropertyCache *propertyCache = obj->synthCache;
1220 Q_ASSERT(propertyCache);
1221 propertyCache->addref();
1223 // Add flag for alias properties
1224 if (!obj->synthdata.isEmpty()) {
1225 const QQmlVMEMetaData *vmeMetaData =
1226 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1227 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1228 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1229 QQmlPropertyData *data = propertyCache->property(index);
1230 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1234 if (obj == unitRoot) {
1235 propertyCache->addref();
1236 output->rootPropertyCache = propertyCache;
1239 output->propertyCaches << propertyCache;
1240 output->addInstruction(meta);
1241 } else if (obj == unitRoot) {
1242 output->rootPropertyCache = tr.createPropertyCache(engine);
1243 output->rootPropertyCache->addref();
1246 // Set the object id
1247 if (!obj->id.isEmpty()) {
1248 Instruction::SetId id;
1249 id.value = output->indexForString(obj->id);
1250 id.index = obj->idIndex;
1251 output->addInstruction(id);
1255 if (tr.type && obj->parserStatusCast != -1) {
1256 Instruction::BeginObject begin;
1257 begin.castValue = obj->parserStatusCast;
1258 output->addInstruction(begin);
1264 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1266 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1267 Q_ASSERT(prop->scriptStringScope != -1);
1268 const QString &script = prop->values.first()->value.asScript();
1269 Instruction::StoreScriptString ss;
1270 ss.propertyIndex = prop->index;
1271 ss.value = output->indexForString(script);
1272 ss.scope = prop->scriptStringScope;
1273 // ss.bindingId = rewriteBinding(script, prop->name());
1274 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1275 ss.line = prop->location.start.line;
1276 ss.column = prop->location.start.column;
1277 output->addInstruction(ss);
1280 bool seenDefer = false;
1281 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1282 if (prop->isDeferred) {
1287 genValueProperty(prop, obj);
1290 Instruction::Defer defer;
1291 defer.deferCount = 0;
1292 int deferIdx = output->addInstruction(defer);
1293 int nextInstructionIndex = output->nextInstructionIndex();
1295 Instruction::DeferInit dinit;
1296 // XXX - these are now massive over allocations
1297 dinit.bindingsSize = compileState->totalBindingsCount;
1298 dinit.parserStatusSize = compileState->parserStatusCount;
1299 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1300 dinit.listStackSize = compileState->listDepth.maxDepth();
1301 output->addInstruction(dinit);
1303 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1304 if (!prop->isDeferred)
1306 genValueProperty(prop, obj);
1309 Instruction::Done done;
1310 output->addInstruction(done);
1312 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1315 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1317 QQmlScript::Value *v = prop->values.first();
1319 if (v->type == Value::SignalObject) {
1321 genObject(v->object);
1323 Instruction::AssignSignalObject assign;
1324 assign.line = v->location.start.line;
1325 assign.signal = output->indexForString(prop->name().toString());
1326 output->addInstruction(assign);
1328 } else if (v->type == Value::SignalExpression) {
1330 Instruction::StoreSignal store;
1331 store.signalIndex = prop->index;
1332 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1333 store.value = output->indexForByteArray(rewrite.toUtf8());
1334 store.context = v->signalExpressionContextStack;
1335 store.line = v->location.start.line;
1336 store.column = v->location.start.column;
1337 output->addInstruction(store);
1343 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1344 Instruction::FetchAttached fetch;
1345 fetch.id = prop->index;
1346 fetch.line = prop->location.start.line;
1347 output->addInstruction(fetch);
1349 genObjectBody(prop->value);
1351 Instruction::PopFetchedObject pop;
1352 output->addInstruction(pop);
1355 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1356 Instruction::FetchObject fetch;
1357 fetch.property = prop->index;
1358 fetch.line = prop->location.start.line;
1359 output->addInstruction(fetch);
1361 if (!prop->value->metadata.isEmpty()) {
1362 Instruction::StoreMetaObject meta;
1363 meta.data = output->indexForByteArray(prop->value->metadata);
1364 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1365 meta.propertyCache = -1;
1366 output->addInstruction(meta);
1369 genObjectBody(prop->value);
1371 Instruction::PopFetchedObject pop;
1372 output->addInstruction(pop);
1375 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1377 genValueTypeProperty(obj, prop);
1380 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1381 if (prop->isDeferred)
1384 genValueProperty(prop, obj);
1387 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1389 genValueTypeProperty(obj, prop);
1393 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1395 Instruction::FetchValueType fetch;
1396 fetch.property = prop->index;
1397 fetch.type = prop->type;
1398 fetch.bindingSkipList = 0;
1400 if (obj->type == -1 || output->types.at(obj->type).component) {
1401 // We only have to do this if this is a composite type. If it is a builtin
1402 // type it can't possibly already have bindings that need to be cleared.
1403 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1404 if (!vprop->values.isEmpty()) {
1405 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1406 fetch.bindingSkipList |= (1 << vprop->index);
1411 output->addInstruction(fetch);
1413 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1414 genPropertyAssignment(vprop, prop->value, prop);
1417 Instruction::PopValueType pop;
1418 pop.property = prop->index;
1419 pop.type = prop->type;
1420 pop.bindingSkipList = 0;
1421 output->addInstruction(pop);
1424 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1426 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1429 Instruction::CreateComponent create;
1430 create.line = root->location.start.line;
1431 create.column = root->location.start.column;
1432 create.endLine = root->location.end.line;
1433 create.isRoot = (compileState->root == obj);
1434 int createInstruction = output->addInstruction(create);
1435 int nextInstructionIndex = output->nextInstructionIndex();
1437 ComponentCompileState *oldCompileState = compileState;
1438 compileState = componentState(root);
1440 Instruction::Init init;
1441 init.bindingsSize = compileState->totalBindingsCount;
1442 init.parserStatusSize = compileState->parserStatusCount;
1443 init.contextCache = genContextCache();
1444 init.objectStackSize = compileState->objectDepth.maxDepth();
1445 init.listStackSize = compileState->listDepth.maxDepth();
1446 if (compileState->compiledBindingData.isEmpty())
1447 init.compiledBinding = -1;
1449 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1450 output->addInstruction(init);
1452 if (!compileState->v8BindingProgram.isEmpty()) {
1453 Instruction::InitV8Bindings bindings;
1454 int index = output->programs.count();
1456 typedef QQmlCompiledData::V8Program V8Program;
1457 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1459 bindings.programIndex = index;
1460 bindings.line = compileState->v8BindingProgramLine;
1461 output->addInstruction(bindings);
1466 Instruction::SetDefault def;
1467 output->addInstruction(def);
1469 Instruction::Done done;
1470 output->addInstruction(done);
1472 output->instruction(createInstruction)->createComponent.count =
1473 output->nextInstructionIndex() - nextInstructionIndex;
1475 compileState = oldCompileState;
1477 if (!obj->id.isEmpty()) {
1478 Instruction::SetId id;
1479 id.value = output->indexForString(obj->id);
1480 id.index = obj->idIndex;
1481 output->addInstruction(id);
1484 if (obj == unitRoot) {
1485 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1486 output->rootPropertyCache->addref();
1490 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1491 const BindingContext &ctxt)
1493 // The special "Component" element can only have the id property and a
1494 // default property, that actually defines the component's tree
1496 compileState->objectDepth.push();
1498 // Find, check and set the "id" property (if any)
1499 Property *idProp = 0;
1500 if (obj->properties.isMany() ||
1501 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1502 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1504 if (!obj->properties.isEmpty())
1505 idProp = obj->properties.first();
1508 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1509 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1510 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1512 QString idVal = idProp->values.first()->primitive();
1514 if (compileState->ids.value(idVal))
1515 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1521 // Check the Component tree is well formed
1522 if (obj->defaultProperty &&
1523 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1524 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1525 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1527 if (!obj->dynamicProperties.isEmpty())
1528 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1529 if (!obj->dynamicSignals.isEmpty())
1530 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1531 if (!obj->dynamicSlots.isEmpty())
1532 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1534 QQmlScript::Object *root = 0;
1535 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1536 root = obj->defaultProperty->values.first()->object;
1539 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1541 // Build the component tree
1542 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1544 compileState->objectDepth.pop();
1549 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1550 const BindingContext &ctxt)
1552 ComponentCompileState *oldComponentCompileState = compileState;
1553 compileState = pool->New<ComponentCompileState>();
1554 compileState->root = obj;
1555 compileState->nested = true;
1557 if (componentStats) {
1558 ComponentStat oldComponentStat = componentStats->componentStat;
1560 componentStats->componentStat = ComponentStat();
1561 componentStats->componentStat.lineNumber = obj->location.start.line;
1564 COMPILE_CHECK(buildObject(obj, ctxt));
1566 COMPILE_CHECK(completeComponentBuild());
1568 componentStats->componentStat = oldComponentStat;
1571 COMPILE_CHECK(buildObject(obj, ctxt));
1573 COMPILE_CHECK(completeComponentBuild());
1576 compileState = oldComponentCompileState;
1582 // Build a sub-object. A sub-object is one that was not created directly by
1583 // QML - such as a grouped property object, or an attached object. Sub-object's
1584 // can't have an id, involve a custom parser, have attached properties etc.
1585 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1587 Q_ASSERT(obj->metatype);
1588 Q_ASSERT(!obj->defaultProperty);
1589 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1592 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1593 if (isSignalPropertyName(prop->name())) {
1594 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1596 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1603 int QQmlCompiler::componentTypeRef()
1605 if (cachedComponentTypeRef == -1) {
1606 QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1607 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1608 if (output->types.at(ii).type == t) {
1609 cachedComponentTypeRef = ii;
1613 QQmlCompiledData::TypeReference ref;
1615 output->types << ref;
1616 cachedComponentTypeRef = output->types.count() - 1;
1618 return cachedComponentTypeRef;
1621 int QQmlCompiler::translationContextIndex()
1623 if (cachedTranslationContextIndex == -1) {
1624 // This code must match that in the qsTr() implementation
1625 const QString &path = output->name;
1626 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1627 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1629 QByteArray contextUtf8 = context.toUtf8();
1630 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1632 return cachedTranslationContextIndex;
1635 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1636 const BindingContext &ctxt)
1638 Q_ASSERT(obj->metaObject());
1640 const QHashedStringRef &propName = prop->name();
1642 Q_ASSERT(propName.startsWith(on_string));
1643 QString name = propName.mid(2, -1).toString();
1645 // Note that the property name could start with any alpha or '_' or '$' character,
1646 // so we need to do the lower-casing of the first alpha character.
1647 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1648 if (name.at(firstAlphaIndex).isUpper()) {
1649 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1654 bool notInRevision = false;
1656 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1660 if (notInRevision && 0 == property(obj, propName, 0)) {
1661 Q_ASSERT(obj->type != -1);
1662 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1663 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1665 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));
1667 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1671 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1673 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1677 if (prop->value || !prop->values.isOne())
1678 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1680 prop->index = sig->coreIndex;
1683 obj->addSignalProperty(prop);
1685 if (prop->values.first()->object) {
1686 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1687 prop->values.first()->type = Value::SignalObject;
1689 prop->values.first()->type = Value::SignalExpression;
1691 if (!prop->values.first()->value.isScript())
1692 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1694 QString script = prop->values.first()->value.asScript().trimmed();
1695 if (script.isEmpty())
1696 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1698 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1707 Returns true if (value) property \a prop exists on obj, false otherwise.
1709 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1710 QQmlScript::Object *obj)
1712 if (prop->name().isEmpty())
1714 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1717 return property(obj, prop->name()) != 0;
1720 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1721 QQmlScript::Object *obj,
1722 const BindingContext &ctxt)
1724 if (prop->isEmpty())
1725 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1727 const QMetaObject *metaObject = obj->metaObject();
1728 Q_ASSERT(metaObject);
1730 if (isAttachedPropertyName(prop->name())) {
1731 // Setup attached property data
1733 if (ctxt.isSubContext()) {
1734 // Attached properties cannot be used on sub-objects. Sub-objects
1735 // always exist in a binding sub-context, which is what we test
1737 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1741 QQmlImportNamespace *typeNamespace = 0;
1742 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1744 if (typeNamespace) {
1745 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1748 } else if (!type || !type->attachedPropertiesType()) {
1749 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1753 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1755 Q_ASSERT(type->attachedPropertiesFunction());
1756 prop->index = type->attachedPropertiesId();
1757 prop->value->metatype = type->attachedPropertiesType();
1759 // Setup regular property data
1760 bool notInRevision = false;
1761 QQmlPropertyData *d =
1762 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1764 if (d == 0 && notInRevision) {
1765 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1766 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1768 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));
1770 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1773 prop->index = d->coreIndex;
1775 } else if (prop->isDefault) {
1776 QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1777 QQmlPropertyData defaultPropertyData;
1778 defaultPropertyData.load(p, engine);
1780 prop->setName(QLatin1String(p.name()));
1781 prop->core = defaultPropertyData;
1782 prop->index = prop->core.coreIndex;
1785 // We can't error here as the "id" property does not require a
1786 // successful index resolution
1787 if (prop->index != -1)
1788 prop->type = prop->core.propType;
1790 // Check if this is an alias
1791 if (prop->index != -1 &&
1793 prop->parent->type != -1 &&
1794 output->types.at(prop->parent->type).component) {
1796 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1797 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1798 prop->isAlias = true;
1801 if (prop->index != -1 && !prop->values.isEmpty())
1802 prop->parent->setBindingBit(prop->index);
1805 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1807 // The magic "id" behavior doesn't apply when "id" is resolved as a
1808 // default property or to sub-objects (which are always in binding
1810 COMPILE_CHECK(buildIdProperty(prop, obj));
1811 if (prop->type == QVariant::String &&
1812 prop->values.first()->value.isString())
1813 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1815 } else if (isAttachedPropertyName(prop->name())) {
1817 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1819 } else if (prop->index == -1) {
1821 if (prop->isDefault) {
1822 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1824 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1827 } else if (prop->value) {
1829 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1831 } else if (prop->core.isQList()) {
1833 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1835 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1837 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1841 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1848 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1849 QQmlScript::Property *nsProp,
1850 QQmlScript::Object *obj,
1851 const BindingContext &ctxt)
1854 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1856 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1858 if (!isAttachedPropertyName(prop->name()))
1859 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1861 // Setup attached property data
1864 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1866 if (!type || !type->attachedPropertiesType())
1867 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1870 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1872 Q_ASSERT(type->attachedPropertiesFunction());
1873 prop->index = type->index();
1874 prop->value->metatype = type->attachedPropertiesType();
1876 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1882 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1883 QQmlScript::Object *obj)
1885 if (prop->core.isQList()) {
1886 genListProperty(prop, obj);
1888 genPropertyAssignment(prop, obj);
1892 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1893 QQmlScript::Object *obj)
1895 int listType = enginePrivate->listType(prop->type);
1897 Instruction::FetchQList fetch;
1898 fetch.property = prop->index;
1899 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1900 fetch.type = listType;
1901 output->addInstruction(fetch);
1903 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1905 if (v->type == Value::CreatedObject) {
1907 genObject(v->object);
1908 if (listTypeIsInterface) {
1909 Instruction::AssignObjectList assign;
1910 assign.line = prop->location.start.line;
1911 output->addInstruction(assign);
1913 Instruction::StoreObjectQList store;
1914 output->addInstruction(store);
1917 } else if (v->type == Value::PropertyBinding) {
1919 genBindingAssignment(v, prop, obj);
1925 Instruction::PopQList pop;
1926 output->addInstruction(pop);
1929 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1930 QQmlScript::Object *obj,
1931 QQmlScript::Property *valueTypeProperty)
1933 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1935 Q_ASSERT(v->type == Value::CreatedObject ||
1936 v->type == Value::PropertyBinding ||
1937 v->type == Value::Literal);
1939 if (v->type == Value::CreatedObject) {
1941 genObject(v->object);
1943 if (QQmlMetaType::isInterface(prop->type)) {
1945 Instruction::StoreInterface store;
1946 store.line = v->object->location.start.line;
1947 store.propertyIndex = prop->index;
1948 output->addInstruction(store);
1950 } else if (prop->type == QMetaType::QVariant) {
1952 if (prop->core.isVMEProperty()) {
1953 Instruction::StoreVarObject store;
1954 store.line = v->object->location.start.line;
1955 store.propertyIndex = prop->index;
1956 output->addInstruction(store);
1958 Instruction::StoreVariantObject store;
1959 store.line = v->object->location.start.line;
1960 store.propertyIndex = prop->index;
1961 output->addInstruction(store);
1967 Instruction::StoreObject store;
1968 store.line = v->object->location.start.line;
1969 store.propertyIndex = prop->index;
1970 output->addInstruction(store);
1973 } else if (v->type == Value::PropertyBinding) {
1975 genBindingAssignment(v, prop, obj, valueTypeProperty);
1977 } else if (v->type == Value::Literal) {
1979 genLiteralAssignment(prop, v);
1985 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1987 Q_ASSERT(v->type == Value::ValueSource ||
1988 v->type == Value::ValueInterceptor);
1990 if (v->type == Value::ValueSource) {
1991 genObject(v->object);
1993 Instruction::StoreValueSource store;
1994 if (valueTypeProperty) {
1995 store.property = genValueTypeData(prop, valueTypeProperty);
1998 store.property = prop->core;
2001 QQmlType *valueType = toQmlType(v->object);
2002 store.castValue = valueType->propertyValueSourceCast();
2003 output->addInstruction(store);
2005 } else if (v->type == Value::ValueInterceptor) {
2006 genObject(v->object);
2008 Instruction::StoreValueInterceptor store;
2009 if (valueTypeProperty) {
2010 store.property = genValueTypeData(prop, valueTypeProperty);
2013 store.property = prop->core;
2016 QQmlType *valueType = toQmlType(v->object);
2017 store.castValue = valueType->propertyValueInterceptorCast();
2018 output->addInstruction(store);
2024 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2025 QQmlScript::Object *obj)
2028 prop->values.isMany() ||
2029 prop->values.first()->object)
2030 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2032 QQmlScript::Value *idValue = prop->values.first();
2033 QString val = idValue->primitive();
2035 COMPILE_CHECK(checkValidId(idValue, val));
2037 if (compileState->ids.value(val))
2038 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2040 prop->values.first()->type = Value::Id;
2048 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2051 Q_ASSERT(!compileState->ids.value(id));
2052 Q_ASSERT(obj->id == id);
2053 obj->idIndex = compileState->ids.count();
2054 compileState->ids.append(obj);
2057 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2059 Q_ASSERT(ref->value && !ref->value->bindingReference);
2060 ref->value->bindingReference = ref;
2061 compileState->totalBindingsCount++;
2062 compileState->bindings.prepend(ref);
2065 void QQmlCompiler::saveComponentState()
2067 Q_ASSERT(compileState->root);
2068 Q_ASSERT(compileState->root->componentCompileState == 0);
2070 compileState->root->componentCompileState = compileState;
2073 componentStats->savedComponentStats.append(componentStats->componentStat);
2076 QQmlCompilerTypes::ComponentCompileState *
2077 QQmlCompiler::componentState(QQmlScript::Object *obj)
2079 Q_ASSERT(obj->componentCompileState);
2080 return obj->componentCompileState;
2083 // Build attached property object. In this example,
2087 // GridView is an attached property object.
2088 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2089 QQmlScript::Object *obj,
2090 const BindingContext &ctxt)
2092 Q_ASSERT(prop->value);
2093 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2095 compileState->objectDepth.push();
2097 obj->addAttachedProperty(prop);
2099 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2101 compileState->objectDepth.pop();
2107 // Build "grouped" properties. In this example:
2109 // font.pointSize: 12
2110 // font.family: "Helvetica"
2112 // font is a nested property. pointSize and family are not.
2113 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2114 QQmlScript::Object *obj,
2115 const BindingContext &ctxt)
2117 Q_ASSERT(prop->type != 0);
2118 Q_ASSERT(prop->index != -1);
2120 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2121 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2123 if (!prop->values.isEmpty()) {
2124 if (prop->values.first()->location < prop->value->location) {
2125 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2127 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2131 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2132 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2136 if (prop->isAlias) {
2137 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2138 vtProp->isAlias = true;
2142 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2143 prop->value, obj, ctxt.incr()));
2144 obj->addValueTypeProperty(prop);
2146 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2150 // Load the nested property's meta type
2151 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2152 if (!prop->value->metatype)
2153 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2155 if (!prop->values.isEmpty())
2156 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2158 obj->addGroupedProperty(prop);
2160 compileState->objectDepth.push();
2162 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2164 compileState->objectDepth.pop();
2170 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2171 QQmlScript::Object *obj,
2172 QQmlScript::Object *baseObj,
2173 const BindingContext &ctxt)
2175 compileState->objectDepth.push();
2177 if (obj->defaultProperty)
2178 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2179 obj->metatype = type->metaObject();
2181 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2183 QQmlPropertyData *d = property(obj, prop->name());
2185 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2187 prop->index = d->coreIndex;
2188 prop->type = d->propType;
2190 prop->isValueTypeSubProperty = true;
2193 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2195 if (prop->values.isMany()) {
2196 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2197 } else if (!prop->values.isEmpty()) {
2198 QQmlScript::Value *value = prop->values.first();
2200 if (value->object) {
2201 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2202 } else if (value->value.isScript()) {
2203 // ### Check for writability
2205 //optimization for <Type>.<EnumValue> enum assignments
2206 bool isEnumAssignment = false;
2208 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2209 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2211 if (isEnumAssignment) {
2212 value->type = Value::Literal;
2214 JSBindingReference *reference = pool->New<JSBindingReference>();
2215 reference->expression = value->value;
2216 reference->property = prop;
2217 reference->value = value;
2218 reference->bindingContext = ctxt;
2219 reference->bindingContext.owner++;
2220 addBindingReference(reference);
2221 value->type = Value::PropertyBinding;
2224 COMPILE_CHECK(testLiteralAssignment(prop, value));
2225 value->type = Value::Literal;
2229 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2230 Q_ASSERT(v->object);
2232 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2235 obj->addValueProperty(prop);
2238 compileState->objectDepth.pop();
2243 // Build assignments to QML lists. QML lists are properties of type
2244 // QQmlListProperty<T>. List properties can accept a list of
2245 // objects, or a single binding.
2246 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2247 QQmlScript::Object *obj,
2248 const BindingContext &ctxt)
2250 Q_ASSERT(prop->core.isQList());
2252 compileState->listDepth.push();
2256 obj->addValueProperty(prop);
2258 int listType = enginePrivate->listType(t);
2259 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2261 bool assignedBinding = false;
2262 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2264 v->type = Value::CreatedObject;
2265 COMPILE_CHECK(buildObject(v->object, ctxt));
2267 // We check object coercian here. We check interface assignment
2269 if (!listTypeIsInterface) {
2270 if (!canCoerce(listType, v->object)) {
2271 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2275 } else if (v->value.isScript()) {
2276 if (assignedBinding)
2277 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2279 assignedBinding = true;
2280 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2281 v->type = Value::PropertyBinding;
2283 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2287 compileState->listDepth.pop();
2292 // Compiles an assignment to a QQmlScriptString property
2293 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2294 QQmlScript::Object *obj,
2295 const BindingContext &ctxt)
2297 if (prop->values.isMany())
2298 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2300 if (prop->values.first()->object)
2301 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2303 prop->scriptStringScope = ctxt.stack;
2304 obj->addScriptStringProperty(prop);
2309 // Compile regular property assignments of the form "property: <value>"
2310 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2311 QQmlScript::Object *obj,
2312 const BindingContext &ctxt)
2314 obj->addValueProperty(prop);
2316 if (prop->values.isMany())
2317 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2319 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2322 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2326 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2331 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2332 Q_ASSERT(v->object);
2333 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2339 // Compile assigning a single object instance to a regular property
2340 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2341 QQmlScript::Object *obj,
2342 QQmlScript::Value *v,
2343 const BindingContext &ctxt)
2345 Q_ASSERT(prop->index != -1);
2346 Q_ASSERT(v->object->type != -1);
2348 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2349 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2351 if (QQmlMetaType::isInterface(prop->type)) {
2353 // Assigning an object to an interface ptr property
2354 COMPILE_CHECK(buildObject(v->object, ctxt));
2356 v->type = Value::CreatedObject;
2358 } else if (prop->type == QMetaType::QVariant) {
2360 // Assigning an object to a QVariant
2361 COMPILE_CHECK(buildObject(v->object, ctxt));
2363 v->type = Value::CreatedObject;
2365 // Normally buildObject() will set this up, but we need the static
2366 // meta object earlier to test for assignability. It doesn't matter
2367 // that there may still be outstanding synthesized meta object changes
2368 // on this type, as they are not relevant for assignability testing
2369 v->object->metatype = output->types.at(v->object->type).metaObject();
2370 Q_ASSERT(v->object->metaObject());
2372 // We want to raw metaObject here as the raw metaobject is the
2373 // actual property type before we applied any extensions that might
2374 // effect the properties on the type, but don't effect assignability
2375 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2377 // Will be true if the assgned type inherits propertyMetaObject
2378 bool isAssignable = false;
2379 // Determine isAssignable value
2380 if (propertyMetaObject) {
2381 const QMetaObject *c = v->object->metatype;
2383 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2384 c = c->superClass();
2389 // Simple assignment
2390 COMPILE_CHECK(buildObject(v->object, ctxt));
2392 v->type = Value::CreatedObject;
2393 } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2394 // Automatic "Component" insertion
2395 QQmlScript::Object *root = v->object;
2396 QQmlScript::Object *component = pool->New<Object>();
2397 component->type = componentTypeRef();
2398 component->metatype = &QQmlComponent::staticMetaObject;
2399 component->location = root->location;
2400 QQmlScript::Value *componentValue = pool->New<Value>();
2401 componentValue->object = root;
2402 component->getDefaultProperty()->addValue(componentValue);
2403 v->object = component;
2404 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2406 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2413 // Compile assigning a single object instance to a regular property using the "on" syntax.
2417 // NumberAnimation on x { }
2419 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2420 QQmlScript::Object *obj,
2421 QQmlScript::Object *baseObj,
2422 QQmlScript::Value *v,
2423 const BindingContext &ctxt)
2425 Q_ASSERT(prop->index != -1);
2426 Q_ASSERT(v->object->type != -1);
2430 if (!prop->core.isWritable())
2431 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2434 // Normally buildObject() will set this up, but we need the static
2435 // meta object earlier to test for assignability. It doesn't matter
2436 // that there may still be outstanding synthesized meta object changes
2437 // on this type, as they are not relevant for assignability testing
2438 v->object->metatype = output->types.at(v->object->type).metaObject();
2439 Q_ASSERT(v->object->metaObject());
2441 // Will be true if the assigned type inherits QQmlPropertyValueSource
2442 bool isPropertyValue = false;
2443 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2444 bool isPropertyInterceptor = false;
2445 if (QQmlType *valueType = toQmlType(v->object)) {
2446 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2447 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2450 if (isPropertyValue || isPropertyInterceptor) {
2451 // Assign as a property value source
2452 COMPILE_CHECK(buildObject(v->object, ctxt));
2454 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2455 buildDynamicMeta(baseObj, ForceCreation);
2456 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2458 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2464 // Compile assigning a literal or binding to a regular property
2465 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2466 QQmlScript::Object *obj,
2467 QQmlScript::Value *v,
2468 const BindingContext &ctxt)
2470 Q_ASSERT(prop->index != -1);
2472 if (v->value.isScript()) {
2474 //optimization for <Type>.<EnumValue> enum assignments
2475 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2476 bool isEnumAssignment = false;
2477 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2478 if (isEnumAssignment) {
2479 v->type = Value::Literal;
2484 // Test for other binding optimizations
2485 if (!buildLiteralBinding(v, prop, ctxt))
2486 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2488 v->type = Value::PropertyBinding;
2492 COMPILE_CHECK(testLiteralAssignment(prop, v));
2494 v->type = Value::Literal;
2500 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2501 QQmlScript::Object *obj,
2502 QQmlScript::Value *v,
2505 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2506 *isAssignment = false;
2507 if (!prop->core.isEnum() && !isIntProp)
2510 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2512 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2513 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2515 QString string = v->value.asString();
2516 if (!string.at(0).isUpper())
2520 // Allow enum assignment to ints.
2521 int enumval = evaluateEnum(string.toUtf8());
2522 if (enumval != -1) {
2523 v->type = Value::Literal;
2524 v->value = QQmlScript::Variant((double)enumval);
2525 *isAssignment = true;
2530 QStringList parts = string.split(QLatin1Char('.'));
2531 if (parts.count() != 2)
2534 QString typeName = parts.at(0);
2536 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2541 QString enumValue = parts.at(1);
2545 if (toQmlType(obj) == type) {
2546 // When these two match, we can short cut the search
2547 if (mprop.isFlagType()) {
2548 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2550 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2553 // Otherwise we have to search the whole type
2554 // This matches the logic in QV8TypeWrapper
2555 QByteArray enumName = enumValue.toUtf8();
2556 const QMetaObject *metaObject = type->baseMetaObject();
2558 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2559 QMetaEnum e = metaObject->enumerator(ii);
2560 value = e.keyToValue(enumName.constData(), &ok);
2567 v->type = Value::Literal;
2568 v->value = QQmlScript::Variant((double)value);
2569 *isAssignment = true;
2574 struct StaticQtMetaObject : public QObject
2576 static const QMetaObject *get()
2577 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2580 // Similar logic to above, but not knowing target property.
2581 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2583 int dot = script.indexOf('.');
2585 const QByteArray &scope = script.left(dot);
2587 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2588 if (!type && scope != "Qt")
2590 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2591 const char *key = script.constData() + dot+1;
2592 int i = mo->enumeratorCount();
2595 int v = mo->enumerator(i).keyToValue(key, &ok);
2603 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2605 QQmlType *qmltype = 0;
2606 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2610 return qmltype->metaObject();
2613 // similar to logic of completeComponentBuild, but also sticks data
2614 // into primitives at the end
2615 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2617 QQmlRewrite::RewriteBinding rewriteBinding;
2618 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2620 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2622 return output->indexForString(rewrite);
2625 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2627 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2628 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2631 // Ensures that the dynamic meta specification on obj is valid
2632 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2634 bool seenDefaultProperty = false;
2636 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2637 // Calculating the hash for the names is not a waste as we have to test
2638 // them against the illegalNames set anyway.
2639 QHashField propNames;
2640 QHashField methodNames;
2643 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2644 const QQmlScript::Object::DynamicProperty &prop = *p;
2646 if (prop.isDefaultProperty) {
2647 if (seenDefaultProperty)
2648 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2649 seenDefaultProperty = true;
2652 if (propNames.testAndSet(prop.name.hash())) {
2653 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2654 p2 = obj->dynamicProperties.next(p2)) {
2655 if (p2->name == prop.name) {
2656 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2657 prop.nameLocation.column,
2658 tr("Duplicate property name"));
2663 if (prop.name.at(0).isUpper()) {
2664 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2665 prop.nameLocation.column,
2666 tr("Property names cannot begin with an upper case letter"));
2669 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2670 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2671 prop.nameLocation.column,
2672 tr("Illegal property name"));
2676 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2677 const QQmlScript::Object::DynamicSignal &currSig = *s;
2679 if (methodNames.testAndSet(currSig.name.hash())) {
2680 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2681 s2 = obj->dynamicSignals.next(s2)) {
2682 if (s2->name == currSig.name)
2683 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2687 if (currSig.name.at(0).isUpper())
2688 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2689 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2690 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2693 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2694 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2696 if (methodNames.testAndSet(currSlot.name.hash())) {
2697 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2698 s2 = obj->dynamicSignals.next(s2)) {
2699 if (s2->name == currSlot.name)
2700 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2702 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2703 s2 = obj->dynamicSlots.next(s2)) {
2704 if (s2->name == currSlot.name)
2705 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2709 if (currSlot.name.at(0).isUpper())
2710 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2711 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2712 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2718 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2720 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2721 p = obj->dynamicProperties.next(p)) {
2723 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2726 Property *property = 0;
2727 if (p->isDefaultProperty) {
2728 property = obj->getDefaultProperty();
2730 property = obj->getProperty(p->name);
2731 if (!property->values.isEmpty())
2732 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2736 property->isReadOnlyDeclaration = true;
2738 if (property->value)
2739 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2741 property->values.append(p->defaultValue->values);
2746 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2748 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2751 Q_ASSERT(obj->metatype);
2753 if (mode != ForceCreation &&
2754 obj->dynamicProperties.isEmpty() &&
2755 obj->dynamicSignals.isEmpty() &&
2756 obj->dynamicSlots.isEmpty())
2759 bool resolveAlias = (mode == ResolveAliases);
2761 const Object::DynamicProperty *defaultProperty = 0;
2763 int varPropCount = 0;
2764 int totalPropCount = 0;
2765 int firstPropertyVarIndex = 0;
2767 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2769 if (p->type == Object::DynamicProperty::Alias)
2771 if (p->type == Object::DynamicProperty::Var)
2774 if (p->isDefaultProperty &&
2775 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2776 defaultProperty = p;
2778 if (!resolveAlias) {
2779 // No point doing this for both the alias and non alias cases
2780 QQmlPropertyData *d = property(obj, p->name);
2781 if (d && d->isFinal())
2782 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2786 bool buildData = resolveAlias || aliasCount == 0;
2788 QByteArray dynamicData;
2790 typedef QQmlVMEMetaData VMD;
2792 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2793 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2794 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2795 aliasCount * sizeof(VMD::AliasData), 0);
2798 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2800 QByteArray newClassName = obj->metatype->className();
2801 newClassName.append("_QML_");
2802 newClassName.append(QByteArray::number(uniqueClassId));
2804 if (compileState->root == obj && !compileState->nested) {
2805 QString path = output->url.path();
2806 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2807 if (lastSlash > -1) {
2808 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2809 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2810 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2814 // Size of the array that describes parameter types & names
2815 int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2816 + obj->dynamicProperties.count() // for Changed() signals return types
2817 // Return "parameters" don't have names
2818 - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2820 QFastMetaBuilder builder;
2822 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2823 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2824 obj->dynamicSlots.count(),
2825 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2826 defaultProperty?1:0, paramDataSize, ¶mIndex);
2829 Object::DynamicProperty::Type dtype;
2831 } builtinTypes[] = {
2832 { Object::DynamicProperty::Var, QMetaType::QVariant },
2833 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2834 { Object::DynamicProperty::Int, QMetaType::Int },
2835 { Object::DynamicProperty::Bool, QMetaType::Bool },
2836 { Object::DynamicProperty::Real, QMetaType::Double },
2837 { Object::DynamicProperty::String, QMetaType::QString },
2838 { Object::DynamicProperty::Url, QMetaType::QUrl },
2839 { Object::DynamicProperty::Color, QMetaType::QColor },
2840 { Object::DynamicProperty::Time, QMetaType::QTime },
2841 { Object::DynamicProperty::Date, QMetaType::QDate },
2842 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2843 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2845 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2847 // Reserve dynamic properties
2848 if (obj->dynamicProperties.count()) {
2849 typedef QQmlVMEMetaData VMD;
2851 int effectivePropertyIndex = 0;
2852 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2854 // Reserve space for name
2855 if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2856 p->nameRef = builder.newString(p->name.utf8length());
2859 int propertyType = 0; // for VMD
2860 bool readonly = false;
2862 if (p->type == Object::DynamicProperty::Alias) {
2864 } else if (p->type < builtinTypeCount) {
2865 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2866 metaType = builtinTypes[p->type].metaType;
2867 propertyType = metaType;
2870 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2871 p->type == Object::DynamicProperty::Custom);
2873 // XXX don't double resolve this in the case of an alias run
2875 QByteArray customTypeName;
2876 QQmlType *qmltype = 0;
2878 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2879 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2882 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
2884 Q_ASSERT(tdata->isComplete());
2885 customTypeName = tdata->compiledData()->root->className();
2888 customTypeName = qmltype->typeName();
2891 if (p->type == Object::DynamicProperty::Custom) {
2892 customTypeName += '*';
2893 propertyType = QMetaType::QObjectStar;
2896 customTypeName = QByteArrayLiteral("QQmlListProperty<") + customTypeName + '>';
2897 propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2900 metaType = QMetaType::type(customTypeName);
2901 Q_ASSERT(metaType != QMetaType::UnknownType);
2902 Q_ASSERT(metaType != QMetaType::Void);
2905 if (p->type == Object::DynamicProperty::Var)
2912 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2913 vmd->propertyCount++;
2914 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2917 builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2918 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2919 effectivePropertyIndex);
2921 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2922 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2925 effectivePropertyIndex++;
2929 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2931 vmd->varPropertyCount = varPropCount;
2932 firstPropertyVarIndex = effectivePropertyIndex;
2933 totalPropCount = varPropCount + effectivePropertyIndex;
2934 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2935 if (p->type == Object::DynamicProperty::Var) {
2937 vmd->propertyCount++;
2938 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2941 builder.setProperty(effectivePropertyIndex, p->nameRef,
2942 QMetaType::QVariant,
2943 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2944 effectivePropertyIndex);
2946 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2947 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2950 effectivePropertyIndex++;
2957 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2958 if (p->type == Object::DynamicProperty::Alias) {
2960 Q_ASSERT(buildData);
2961 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2962 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2965 // Even if we aren't resolving the alias, we need a fake signal so that the
2966 // metaobject remains consistent across the resolve and non-resolve alias runs
2967 p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size());
2968 builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2970 effectivePropertyIndex++;
2977 // Reserve default property
2978 QFastMetaBuilder::StringRef defPropRef;
2979 if (defaultProperty) {
2980 defPropRef = builder.newString(int(sizeof("DefaultProperty")) - 1);
2981 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2984 // Reserve dynamic signals
2985 int signalIndex = 0;
2986 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2988 s->nameRef = builder.newString(s->name.utf8length());
2990 int paramCount = s->parameterNames.count();
2991 QVarLengthArray<int, 10> paramTypes(paramCount);
2993 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
2994 for (int i = 0; i < paramCount; ++i) {
2995 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
2996 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2997 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3002 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3004 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3005 paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3006 paramIndex += paramCount*2 + 1;
3010 // Reserve dynamic slots
3011 if (obj->dynamicSlots.count()) {
3013 typedef QQmlVMEMetaData VMD;
3015 int methodIndex = 0;
3016 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3017 s->nameRef = builder.newString(s->name.utf8length());
3018 int paramCount = s->parameterNames.count();
3020 QVarLengthArray<int, 10> paramTypes(paramCount);
3022 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3023 for (int i = 0; i < paramCount; ++i) {
3024 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3025 paramTypes[i] = QMetaType::QVariant;
3029 builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3030 paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3031 paramIndex += paramCount*2 + 1;
3036 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3037 funcScript.reserve(int(sizeof("(function ")) - 1 + s->name.length() + 1 /* lparen */ +
3038 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3039 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3040 for (int jj = 0; jj < paramCount; ++jj) {
3041 if (jj) funcScript.append(QLatin1Char(','));
3042 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3044 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3046 QByteArray utf8 = funcScript.toUtf8();
3047 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3049 s->location.start.line };
3051 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3054 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3056 md.bodyOffset = dynamicData.size();
3058 dynamicData.append((const char *)utf8.constData(), utf8.length());
3066 // Now allocate properties
3067 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3069 char *d = p->changedNameRef.data();
3070 p->name.writeUtf8(d);
3071 strcpy(d + p->name.utf8length(), "Changed");
3072 p->changedNameRef.loadByteArrayData();
3074 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3077 p->nameRef.load(p->name);
3080 // Allocate default property if necessary
3081 if (defaultProperty)
3082 defPropRef.load("DefaultProperty");
3084 // Now allocate signals
3085 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3087 s->nameRef.load(s->name);
3089 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3090 s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3093 // Now allocate methods
3094 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3095 s->nameRef.load(s->name);
3097 for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3098 s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3101 // Now allocate class name
3102 classNameRef.load(newClassName);
3104 obj->metadata = builder.toData();
3105 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3107 if (mode == IgnoreAliases && aliasCount)
3108 compileState->aliasingObjects.append(obj);
3110 obj->synthdata = dynamicData;
3112 if (obj->synthCache) {
3113 obj->synthCache->release();
3114 obj->synthCache = 0;
3117 if (obj->type != -1) {
3118 QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3119 QQmlPropertyCache *cache =
3120 superCache->copyAndAppend(engine, &obj->extObject,
3121 QQmlPropertyData::NoFlags,
3122 QQmlPropertyData::IsVMEFunction,
3123 QQmlPropertyData::IsVMESignal);
3125 // now we modify the flags appropriately for var properties.
3126 int propertyOffset = obj->extObject.propertyOffset();
3127 QQmlPropertyData *currPropData = 0;
3128 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3129 currPropData = cache->property(pvi + propertyOffset);
3130 currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3133 obj->synthCache = cache;
3139 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3142 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3144 QChar ch = val.at(0);
3145 if (ch.isLetter() && !ch.isLower())
3146 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3148 QChar u(QLatin1Char('_'));
3149 if (!ch.isLetter() && ch != u)
3150 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3152 for (int ii = 1; ii < val.count(); ++ii) {
3154 if (!ch.isLetterOrNumber() && ch != u)
3155 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3158 if (enginePrivate->v8engine()->illegalNames().contains(val))
3159 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3164 #include <private/qqmljsparser_p.h>
3166 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3168 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3170 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3171 return QStringList() << name;
3172 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3173 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3175 QStringList rv = astNodeToStringList(expr->base);
3178 rv.append(expr->name.toString());
3181 return QStringList();
3184 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3186 QQmlScript::Object *obj,
3187 int propIndex, int aliasIndex,
3188 Object::DynamicProperty &prop)
3190 Q_ASSERT(!prop.nameRef.isEmpty());
3191 if (!prop.defaultValue)
3192 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3194 if (!prop.defaultValue->values.isOne() ||
3195 prop.defaultValue->values.first()->object ||
3196 !prop.defaultValue->values.first()->value.isScript())
3197 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3199 QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3201 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3203 QStringList alias = astNodeToStringList(node);
3205 if (alias.count() < 1 || alias.count() > 3)
3206 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3208 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3210 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3212 QByteArray typeName;
3217 bool writable = false;
3218 bool resettable = false;
3219 if (alias.count() == 2 || alias.count() == 3) {
3220 propIdx = indexOfProperty(idObject, alias.at(1));
3222 if (-1 == propIdx) {
3223 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3224 } else if (propIdx > 0xFFFF) {
3225 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3228 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3229 if (!aliasProperty.isScriptable())
3230 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3232 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3233 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3235 type = aliasProperty.userType();
3237 if (alias.count() == 3) {
3238 QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3240 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3242 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3244 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3245 if (valueTypeIndex == -1)
3246 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3247 Q_ASSERT(valueTypeIndex <= 0xFF);
3249 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3250 propIdx |= (valueTypeIndex << 16);
3252 // update the property type
3253 type = aliasProperty.userType();
3256 if (aliasProperty.isEnumType())
3257 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3259 typeName = aliasProperty.typeName();
3261 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3263 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3265 typeName = ref.type->typeName();
3267 typeName = ref.component->root->className();
3272 if (typeName.endsWith('*'))
3273 flags |= QML_ALIAS_FLAG_PTR;
3275 if (type == QMetaType::UnknownType) {
3276 Q_ASSERT(!typeName.isEmpty());
3277 type = QMetaType::type(typeName);
3278 Q_ASSERT(type != QMetaType::UnknownType);
3279 Q_ASSERT(type != QMetaType::Void);
3282 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3284 typedef QQmlVMEMetaData VMD;
3285 VMD *vmd = (QQmlVMEMetaData *)data.data();
3286 *(vmd->aliasData() + aliasIndex) = aliasData;
3288 int propertyFlags = 0;
3290 propertyFlags |= QFastMetaBuilder::Writable;
3292 propertyFlags |= QFastMetaBuilder::Resettable;
3294 builder.setProperty(propIndex, prop.nameRef, type,
3295 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3301 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3302 QQmlScript::Property *prop,
3303 const BindingContext &ctxt)
3305 Q_ASSERT(prop->index != -1);
3306 Q_ASSERT(prop->parent);
3307 Q_ASSERT(prop->parent->metaObject());
3309 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3310 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3312 JSBindingReference *reference = pool->New<JSBindingReference>();
3313 reference->expression = value->value;
3314 reference->property = prop;
3315 reference->value = value;
3316 reference->bindingContext = ctxt;
3317 addBindingReference(reference);
3322 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3323 QQmlScript::Property *prop,
3324 const QQmlCompilerTypes::BindingContext &)
3326 Q_ASSERT(v->value.isScript());
3328 if (!prop->core.isWritable())
3331 AST::Node *binding = v->value.asAST();
3333 if (prop->type == QVariant::String) {
3334 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3335 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3336 if (i->name == qsTrId_string) {
3337 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3338 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3340 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3341 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3342 (!arg2 || !arg2->next)) {
3347 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3348 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3350 TrBindingReference *reference = pool->New<TrBindingReference>();
3351 reference->dataType = BindingReference::TrId;
3352 reference->text = text;
3354 v->bindingReference = reference;
3358 } else if (i->name == qsTr_string) {
3360 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3361 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3362 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3364 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3365 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3366 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3367 (!arg3 || !arg3->next)) {
3373 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3374 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3375 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3377 TrBindingReference *reference = pool->New<TrBindingReference>();
3378 reference->dataType = BindingReference::Tr;
3379 reference->text = text;
3380 reference->comment = comment;
3382 v->bindingReference = reference;
3395 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3396 QQmlScript::Property *prop,
3397 QQmlScript::Object *obj,
3398 QQmlScript::Property *valueTypeProperty)
3401 Q_ASSERT(binding->bindingReference);
3403 const BindingReference &ref = *binding->bindingReference;
3404 if (ref.dataType == BindingReference::TrId) {
3405 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3407 Instruction::StoreTrIdString store;
3408 store.propertyIndex = prop->core.coreIndex;
3409 store.text = output->indexForByteArray(tr.text.toUtf8());
3411 output->addInstruction(store);
3412 } else if (ref.dataType == BindingReference::Tr) {
3413 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3415 Instruction::StoreTrString store;
3416 store.propertyIndex = prop->core.coreIndex;
3417 store.context = translationContextIndex();
3418 store.text = output->indexForByteArray(tr.text.toUtf8());
3419 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3421 output->addInstruction(store);
3422 } else if (ref.dataType == BindingReference::V4) {
3423 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3425 Instruction::StoreV4Binding store;
3426 store.value = js.compiledIndex;
3427 store.context = js.bindingContext.stack;
3428 store.owner = js.bindingContext.owner;
3429 store.isAlias = prop->isAlias;
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;
3545 expr.context = binding.bindingContext.object;
3546 expr.property = binding.property;
3547 expr.expression = binding.expression;
3549 int index = bindingCompiler.compile(expr, enginePrivate);
3551 binding.dataType = BindingReference::V4;
3552 binding.compiledIndex = index;
3554 componentStats->componentStat.optimizedBindings.append(b->value->location);
3558 // Pre-rewrite the expression
3559 QString expression = binding.expression.asScript();
3561 QQmlRewrite::RewriteBinding rewriteBinding;
3562 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3563 bool isSharable = false;
3564 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3566 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3567 binding.dataType = BindingReference::V8;
3568 sharedBindings.append(b);
3571 componentStats->componentStat.sharedBindings.append(b->value->location);
3573 binding.dataType = BindingReference::QtScript;
3576 componentStats->componentStat.scriptBindings.append(b->value->location);
3580 if (!sharedBindings.isEmpty()) {
3582 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3584 return lhs->value->location.start.line < rhs->value->location.start.line;
3588 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3590 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3591 int lineNumber = startLineNumber;
3593 QByteArray functionArray("[", 1);
3594 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3596 JSBindingReference *reference = sharedBindings.at(ii);
3597 QQmlScript::Value *value = reference->value;
3598 const QString &expression = reference->rewrittenExpression;
3600 if (ii != 0) functionArray.append(",", 1);
3602 while (lineNumber < value->location.start.line) {
3604 functionArray.append("\n", 1);
3607 functionArray += expression.toUtf8();
3608 lineNumber += expression.count(QLatin1Char('\n'));
3609 reference->compiledIndex = ii;
3611 functionArray.append("]", 1);
3613 compileState->v8BindingProgram = functionArray;
3614 compileState->v8BindingProgramLine = startLineNumber;
3617 if (bindingCompiler.isValid())
3618 compileState->compiledBindingData = bindingCompiler.program();
3620 // Check pop()'s matched push()'s
3621 Q_ASSERT(compileState->objectDepth.depth() == 0);
3622 Q_ASSERT(compileState->listDepth.depth() == 0);
3624 saveComponentState();
3629 void QQmlCompiler::dumpStats()
3631 Q_ASSERT(componentStats);
3632 qWarning().nospace() << "QML Document: " << output->url.toString();
3633 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3634 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3635 qWarning().nospace() << " Component Line " << stat.lineNumber;
3636 qWarning().nospace() << " Total Objects: " << stat.objects;
3637 qWarning().nospace() << " IDs Used: " << stat.ids;
3638 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3642 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3643 if (0 == (ii % 10)) {
3644 if (ii) output.append("\n");
3649 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3651 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3652 output.append(") ");
3654 if (!output.isEmpty())
3655 qWarning().nospace() << output.constData();
3658 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3661 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3662 if (0 == (ii % 10)) {
3663 if (ii) output.append('\n');
3668 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3670 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3671 output.append(") ");
3673 if (!output.isEmpty())
3674 qWarning().nospace() << output.constData();
3677 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3680 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3681 if (0 == (ii % 10)) {
3682 if (ii) output.append('\n');
3687 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3689 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3690 output.append(") ");
3692 if (!output.isEmpty())
3693 qWarning().nospace() << output.constData();
3699 Returns true if from can be assigned to a (QObject) property of type
3702 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3704 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3705 const QMetaObject *fromMo = from->metaObject();
3708 if (QQmlPropertyPrivate::equal(fromMo, toMo))
3710 fromMo = fromMo->superClass();
3716 Returns the element name, as written in the QML file, for o.
3718 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3721 if (o->type != -1) {
3722 return unit->parser().referencedTypes().at(o->type)->name;
3728 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3730 if (from->type != -1 && output->types.at(from->type).type)
3731 return output->types.at(from->type).type;
3734 const QMetaObject *mo = from->metatype;
3736 while (!type && mo) {
3737 type = QQmlMetaType::qmlType(mo);
3738 mo = mo->superClass();
3743 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3745 const QMetaObject *mo = obj->metatype;
3747 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3749 return QStringList();
3751 QMetaClassInfo classInfo = mo->classInfo(idx);
3752 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3757 QQmlCompiler::property(QQmlScript::Object *object, int index)
3759 QQmlPropertyCache *cache = 0;
3761 if (object->synthCache)
3762 cache = object->synthCache;
3763 else if (object->type != -1)
3764 cache = output->types[object->type].createPropertyCache(engine);
3766 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3768 return cache->property(index);
3772 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3774 if (notInRevision) *notInRevision = false;
3776 QQmlPropertyCache *cache = 0;
3778 if (object->synthCache)
3779 cache = object->synthCache;
3780 else if (object->type != -1)
3781 cache = output->types[object->type].createPropertyCache(engine);
3783 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3785 QQmlPropertyData *d = cache->property(name);
3787 // Find the first property
3788 while (d && d->isFunction())
3789 d = cache->overrideData(d);
3791 if (d && !cache->isAllowedInRevision(d)) {
3792 if (notInRevision) *notInRevision = true;
3799 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3801 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3803 if (notInRevision) *notInRevision = false;
3805 QQmlPropertyCache *cache = 0;
3807 if (object->synthCache)
3808 cache = object->synthCache;
3809 else if (object->type != -1)
3810 cache = output->types[object->type].createPropertyCache(engine);
3812 cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3815 QQmlPropertyData *d = cache->property(name);
3816 if (notInRevision) *notInRevision = false;
3818 while (d && !(d->isFunction()))
3819 d = cache->overrideData(d);
3821 if (d && !cache->isAllowedInRevision(d)) {
3822 if (notInRevision) *notInRevision = true;
3828 if (name.endsWith(Changed_string)) {
3829 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3831 d = property(object, propName, notInRevision);
3833 return cache->method(d->notifyIndex);
3839 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3840 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3841 bool *notInRevision)
3843 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3844 return d?d->coreIndex:-1;
3847 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3848 bool *notInRevision)
3850 return indexOfProperty(object, QStringRef(&name), notInRevision);
3853 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3854 bool *notInRevision)
3856 QQmlPropertyData *d = property(object, name, notInRevision);
3857 return d?d->coreIndex:-1;