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 "qqmlstringconverters_p.h"
48 #include "qqmlengine_p.h"
49 #include "qqmlengine.h"
50 #include "qqmlcontext.h"
51 #include "qqmlmetatype_p.h"
52 #include "qqmlcustomparser_p_p.h"
53 #include "qqmlcontext_p.h"
54 #include "qqmlcomponent_p.h"
55 #include <private/qqmljsast_p.h>
56 #include "qqmlvmemetaobject_p.h"
57 #include "qqmlexpression_p.h"
58 #include "qqmlproperty_p.h"
59 #include "qqmlrewrite_p.h"
60 #include "qqmlscriptstring.h"
61 #include "qqmlglobal_p.h"
62 #include "qqmlbinding_p.h"
63 #include <private/qv4compiler_p.h>
70 #include <QtCore/qdebug.h>
71 #include <QtCore/qdatetime.h>
72 #include <QtCore/qvarlengtharray.h>
74 Q_DECLARE_METATYPE(QList<int>)
75 Q_DECLARE_METATYPE(QList<qreal>)
76 Q_DECLARE_METATYPE(QList<bool>)
77 Q_DECLARE_METATYPE(QList<QString>)
78 Q_DECLARE_METATYPE(QList<QUrl>)
79 Q_DECLARE_METATYPE(QJSValue)
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_string(QLatin1String("Component"));
94 static QString Component_module_string(QLatin1String("QML"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QQmlCompiler.
101 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
102 : compileState(0), pool(pool), output(0), engine(0), enginePrivate(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QQmlCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QQmlError> QQmlCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QQmlCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
191 error.setUrl(output->url); \
192 error.setLine(line); \
193 error.setColumn(column); \
194 error.setDescription(desc.trimmed()); \
195 exceptions << error; \
199 #define COMPILE_EXCEPTION(token, desc) \
200 COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
205 Returns false if \a is false, otherwise does nothing.
207 #define COMPILE_CHECK(a) \
209 if (!a) return false; \
213 Returns true if literal \a v can be assigned to property \a prop, otherwise
216 This test corresponds to action taken by genLiteralAssignment(). Any change
217 made here, must have a corresponding action in genLiteralAssigment().
219 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, 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->metatype->firstCppMetaObject()->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"));
397 } else if (type == qMetaTypeId<QJSValue>()) {
401 // otherwise, check for existence of string converter to custom type
402 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
404 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(type))));
412 Generate a store instruction for assigning literal \a v to property \a prop.
414 Any literal assignment that is approved in testLiteralAssignment() must have
415 a corresponding action in this method.
417 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
418 QQmlScript::Value *v)
420 if (prop->core.isEnum()) {
421 Q_ASSERT(v->value.isNumber());
423 int value = (int)v->value.asNumber();
425 Instruction::StoreInteger instr;
426 instr.propertyIndex = prop->index;
428 output->addInstruction(instr);
432 int type = prop->type;
434 case QMetaType::QVariant:
436 if (v->value.isNumber()) {
437 double n = v->value.asNumber();
438 if (double(int(n)) == n) {
439 if (prop->core.isVarProperty()) {
440 Instruction::StoreVarInteger instr;
441 instr.propertyIndex = prop->index;
442 instr.value = int(n);
443 output->addInstruction(instr);
445 Instruction::StoreVariantInteger instr;
446 instr.propertyIndex = prop->index;
447 instr.value = int(n);
448 output->addInstruction(instr);
451 if (prop->core.isVarProperty()) {
452 Instruction::StoreVarDouble instr;
453 instr.propertyIndex = prop->index;
455 output->addInstruction(instr);
457 Instruction::StoreVariantDouble instr;
458 instr.propertyIndex = prop->index;
460 output->addInstruction(instr);
463 } else if (v->value.isBoolean()) {
464 if (prop->core.isVarProperty()) {
465 Instruction::StoreVarBool instr;
466 instr.propertyIndex = prop->index;
467 instr.value = v->value.asBoolean();
468 output->addInstruction(instr);
470 Instruction::StoreVariantBool instr;
471 instr.propertyIndex = prop->index;
472 instr.value = v->value.asBoolean();
473 output->addInstruction(instr);
476 if (prop->core.isVarProperty()) {
477 Instruction::StoreVar instr;
478 instr.propertyIndex = prop->index;
479 instr.value = output->indexForString(v->value.asString());
480 output->addInstruction(instr);
482 Instruction::StoreVariant instr;
483 instr.propertyIndex = prop->index;
484 instr.value = output->indexForString(v->value.asString());
485 output->addInstruction(instr);
490 case QVariant::String:
492 Instruction::StoreString instr;
493 instr.propertyIndex = prop->index;
494 instr.value = output->indexForString(v->value.asString());
495 output->addInstruction(instr);
498 case QVariant::StringList:
500 Instruction::StoreStringList instr;
501 instr.propertyIndex = prop->index;
502 instr.value = output->indexForString(v->value.asString());
503 output->addInstruction(instr);
506 case QVariant::ByteArray:
508 Instruction::StoreByteArray instr;
509 instr.propertyIndex = prop->index;
510 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
511 output->addInstruction(instr);
516 Instruction::StoreUrl instr;
517 QString string = v->value.asString();
518 // Encoded dir-separators defeat QUrl processing - decode them first
519 string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
520 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
521 instr.propertyIndex = prop->index;
522 instr.value = output->indexForUrl(u);
523 output->addInstruction(instr);
528 Instruction::StoreInteger instr;
529 instr.propertyIndex = prop->index;
530 instr.value = uint(v->value.asNumber());
531 output->addInstruction(instr);
536 Instruction::StoreInteger instr;
537 instr.propertyIndex = prop->index;
538 instr.value = int(v->value.asNumber());
539 output->addInstruction(instr);
542 case QMetaType::Float:
544 Instruction::StoreFloat instr;
545 instr.propertyIndex = prop->index;
546 instr.value = float(v->value.asNumber());
547 output->addInstruction(instr);
550 case QVariant::Double:
552 Instruction::StoreDouble instr;
553 instr.propertyIndex = prop->index;
554 instr.value = v->value.asNumber();
555 output->addInstruction(instr);
558 case QVariant::Color:
560 Instruction::StoreColor instr;
561 instr.propertyIndex = prop->index;
562 instr.value = QQmlStringConverters::rgbaFromString(v->value.asString());
563 output->addInstruction(instr);
566 #ifndef QT_NO_DATESTRING
569 Instruction::StoreDate instr;
570 QDate d = QQmlStringConverters::dateFromString(v->value.asString());
571 instr.propertyIndex = prop->index;
572 instr.value = d.toJulianDay();
573 output->addInstruction(instr);
578 Instruction::StoreTime instr;
579 QTime time = QQmlStringConverters::timeFromString(v->value.asString());
580 instr.propertyIndex = prop->index;
581 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
582 ::memcpy(&instr.time, &time, sizeof(QTime));
583 output->addInstruction(instr);
586 case QVariant::DateTime:
588 Instruction::StoreDateTime instr;
589 QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
590 QTime time = dateTime.time();
591 instr.propertyIndex = prop->index;
592 instr.date = dateTime.date().toJulianDay();
593 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
594 ::memcpy(&instr.time, &time, sizeof(QTime));
595 output->addInstruction(instr);
598 #endif // QT_NO_DATESTRING
599 case QVariant::Point:
601 Instruction::StorePoint instr;
603 QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
604 instr.propertyIndex = prop->index;
605 instr.point.xp = point.x();
606 instr.point.yp = point.y();
607 output->addInstruction(instr);
610 case QVariant::PointF:
612 Instruction::StorePointF instr;
614 QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
615 instr.propertyIndex = prop->index;
616 instr.point.xp = point.x();
617 instr.point.yp = point.y();
618 output->addInstruction(instr);
623 Instruction::StoreSize instr;
625 QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
626 instr.propertyIndex = prop->index;
627 instr.size.wd = size.width();
628 instr.size.ht = size.height();
629 output->addInstruction(instr);
632 case QVariant::SizeF:
634 Instruction::StoreSizeF instr;
636 QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
637 instr.propertyIndex = prop->index;
638 instr.size.wd = size.width();
639 instr.size.ht = size.height();
640 output->addInstruction(instr);
645 Instruction::StoreRect instr;
647 QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
648 instr.propertyIndex = prop->index;
649 instr.rect.x1 = rect.left();
650 instr.rect.y1 = rect.top();
651 instr.rect.x2 = rect.right();
652 instr.rect.y2 = rect.bottom();
653 output->addInstruction(instr);
656 case QVariant::RectF:
658 Instruction::StoreRectF instr;
660 QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
661 instr.propertyIndex = prop->index;
662 instr.rect.xp = rect.left();
663 instr.rect.yp = rect.top();
664 instr.rect.w = rect.width();
665 instr.rect.h = rect.height();
666 output->addInstruction(instr);
671 Instruction::StoreBool instr;
672 bool b = v->value.asBoolean();
673 instr.propertyIndex = prop->index;
675 output->addInstruction(instr);
678 case QVariant::Vector3D:
680 Instruction::StoreVector3D instr;
681 instr.propertyIndex = prop->index;
682 QQmlStringConverters::createFromString(QMetaType::QVector3D, v->value.asString(), &instr.vector, sizeof(instr.vector));
683 output->addInstruction(instr);
686 case QVariant::Vector4D:
688 Instruction::StoreVector4D instr;
689 instr.propertyIndex = prop->index;
690 QQmlStringConverters::createFromString(QMetaType::QVector4D, v->value.asString(), &instr.vector, sizeof(instr.vector));
691 output->addInstruction(instr);
696 // generate single literal value assignment to a list property if required
697 if (type == qMetaTypeId<QList<qreal> >()) {
698 Instruction::StoreDoubleQList instr;
699 instr.propertyIndex = prop->index;
700 instr.value = v->value.asNumber();
701 output->addInstruction(instr);
703 } else if (type == qMetaTypeId<QList<int> >()) {
704 Instruction::StoreIntegerQList instr;
705 instr.propertyIndex = prop->index;
706 instr.value = int(v->value.asNumber());
707 output->addInstruction(instr);
709 } else if (type == qMetaTypeId<QList<bool> >()) {
710 Instruction::StoreBoolQList instr;
711 bool b = v->value.asBoolean();
712 instr.propertyIndex = prop->index;
714 output->addInstruction(instr);
716 } else if (type == qMetaTypeId<QList<QUrl> >()) {
717 Instruction::StoreUrlQList instr;
718 QString string = v->value.asString();
719 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
720 instr.propertyIndex = prop->index;
721 instr.value = output->indexForUrl(u);
722 output->addInstruction(instr);
724 } else if (type == qMetaTypeId<QList<QString> >()) {
725 Instruction::StoreStringQList instr;
726 instr.propertyIndex = prop->index;
727 instr.value = output->indexForString(v->value.asString());
728 output->addInstruction(instr);
730 } else if (type == qMetaTypeId<QJSValue>()) {
731 if (v->value.isBoolean()) {
732 Instruction::StoreJSValueBool instr;
733 instr.propertyIndex = prop->index;
734 instr.value = v->value.asBoolean();
735 output->addInstruction(instr);
736 } else if (v->value.isNumber()) {
737 double n = v->value.asNumber();
738 if (double(int(n)) == n) {
739 Instruction::StoreJSValueInteger instr;
740 instr.propertyIndex = prop->index;
741 instr.value = int(n);
742 output->addInstruction(instr);
744 Instruction::StoreJSValueDouble instr;
745 instr.propertyIndex = prop->index;
747 output->addInstruction(instr);
750 Instruction::StoreJSValueString instr;
751 instr.propertyIndex = prop->index;
752 instr.value = output->indexForString(v->value.asString());
753 output->addInstruction(instr);
758 // otherwise, generate custom type literal assignment
759 Instruction::AssignCustomType instr;
760 instr.propertyIndex = prop->index;
761 instr.primitive = output->indexForString(v->value.asString());
763 output->addInstruction(instr);
770 Resets data by clearing the lists that the QQmlCompiler modifies.
772 void QQmlCompiler::reset(QQmlCompiledData *data)
775 data->primitives.clear();
777 data->bytecode.resize(0);
781 Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
782 with which the QQmlCompiledData will be associated.
784 Returns true on success, false on failure. On failure, the compile errors
785 are available from errors().
787 If the environment variant QML_COMPILER_DUMP is set
788 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
789 on a successful compiler.
791 bool QQmlCompiler::compile(QQmlEngine *engine,
793 QQmlCompiledData *out)
800 QQmlScript::Object *root = unit->parser().tree();
803 this->engine = engine;
804 this->enginePrivate = QQmlEnginePrivate::get(engine);
806 this->unitRoot = root;
810 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
811 QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
813 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
814 QQmlCompiledData::TypeReference ref;
816 const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
817 QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
820 ref.type = tref.type;
821 if (!ref.type->isCreatable()) {
822 QString err = ref.type->noCreationReason();
824 err = tr( "Element is not creatable.");
825 COMPILE_EXCEPTION(parserRef->firstUse, err);
828 if (ref.type->containsRevisionedAttributes()) {
829 QQmlError cacheError;
830 ref.typePropertyCache = enginePrivate->cache(ref.type,
831 resolvedTypes.at(ii).minorVersion,
833 if (!ref.typePropertyCache)
834 COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
835 ref.typePropertyCache->addref();
838 } else if (tref.typeData) {
839 ref.component = tref.typeData->compiledData();
840 ref.component->addref();
849 out->dumpInstructions();
852 Q_ASSERT(out->rootPropertyCache);
860 this->enginePrivate = 0;
862 this->cachedComponentTypeRef = -1;
863 this->cachedTranslationContextIndex = -1;
869 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
871 compileState = pool->New<ComponentCompileState>();
873 compileState->root = tree;
875 componentStats->componentStat.lineNumber = tree->location.start.line;
877 // We generate the importCache before we build the tree so that
878 // it can be used in the binding compiler. Given we "expect" the
879 // QML compilation to succeed, this isn't a waste.
880 output->importCache = new QQmlTypeNameCache();
881 foreach (const QString &ns, unit->namespaces()) {
882 output->importCache->add(ns);
886 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
887 QString qualifier = script.qualifier;
888 QString enclosingNamespace;
890 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
891 if (lastDotIndex != -1) {
892 enclosingNamespace = qualifier.left(lastDotIndex);
893 qualifier = qualifier.mid(lastDotIndex+1);
896 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
899 unit->imports().populateCache(output->importCache, engine);
901 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
904 Instruction::Init init;
905 init.bindingsSize = compileState->totalBindingsCount;
906 init.parserStatusSize = compileState->parserStatusCount;
907 init.contextCache = genContextCache();
908 init.objectStackSize = compileState->objectDepth.maxDepth();
909 init.listStackSize = compileState->listDepth.maxDepth();
910 if (compileState->compiledBindingData.isEmpty())
911 init.compiledBinding = -1;
913 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
914 output->addInstruction(init);
916 foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
917 Instruction::StoreImportedScript import;
918 import.value = output->scripts.count();
920 QQmlScriptData *scriptData = script.script->scriptData();
921 scriptData->addref();
922 output->scripts << scriptData;
923 output->addInstruction(import);
926 if (!compileState->v8BindingProgram.isEmpty()) {
927 Instruction::InitV8Bindings bindings;
928 int index = output->programs.count();
930 typedef QQmlCompiledData::V8Program V8Program;
931 output->programs.append(V8Program(compileState->v8BindingProgram, output));
933 bindings.programIndex = index;
934 bindings.line = compileState->v8BindingProgramLine;
935 output->addInstruction(bindings);
940 Instruction::SetDefault def;
941 output->addInstruction(def);
943 Instruction::Done done;
944 output->addInstruction(done);
946 Q_ASSERT(tree->metatype);
947 if (!tree->synthdata.isEmpty()) {
948 enginePrivate->registerCompositeType(output);
949 } else if (output->types.at(tree->type).component) {
950 output->metaTypeId = output->types.at(tree->type).component->metaTypeId;
951 output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId;
953 Q_ASSERT(output->types.at(tree->type).type);
954 output->metaTypeId = output->types.at(tree->type).type->typeId();
955 output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId();
957 if (!tree->synthdata.isEmpty())
958 enginePrivate->registerCompositeType(output);
961 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
963 for (int ii = 0; ii < list.count(); ++ii)
964 if (string == list.at(ii))
970 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
973 componentStats->componentStat.objects++;
975 Q_ASSERT (obj->type != -1);
976 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
977 obj->metatype = tr.createPropertyCache(engine);
979 // This object is a "Component" element.
980 if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
981 COMPILE_CHECK(buildComponent(obj, ctxt));
986 typedef QQmlInstruction I;
987 const I *init = ((const I *)tr.component->bytecode.constData());
988 Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
990 // Adjust stack depths to include nested components
991 compileState->objectDepth.pushPop(init->init.objectStackSize);
992 compileState->listDepth.pushPop(init->init.listStackSize);
993 compileState->parserStatusCount += init->init.parserStatusSize;
994 compileState->totalBindingsCount += init->init.bindingsSize;
997 compileState->objectDepth.push();
999 // Object instantiations reset the binding context
1000 BindingContext objCtxt(obj);
1002 // Create the synthesized meta object, ignoring aliases
1003 COMPILE_CHECK(checkDynamicMeta(obj));
1004 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
1005 COMPILE_CHECK(buildDynamicMeta(obj, Normal));
1007 // Find the native type and check for the QQmlParserStatus interface
1008 QQmlType *type = toQmlType(obj);
1010 obj->parserStatusCast = type->parserStatusCast();
1011 if (obj->parserStatusCast != -1)
1012 compileState->parserStatusCount++;
1014 // Check if this is a custom parser type. Custom parser types allow
1015 // assignments to non-existent properties. These assignments are then
1016 // compiled by the type.
1017 bool isCustomParser = output->types.at(obj->type).type &&
1018 output->types.at(obj->type).type->customParser() != 0;
1019 QList<QQmlCustomParserProperty> customProps;
1021 // Fetch the list of deferred properties
1022 QStringList deferredList = deferredProperties(obj);
1024 // Must do id property first. This is to ensure that the id given to any
1025 // id reference created matches the order in which the objects are
1027 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1028 if (prop->name() == id_string) {
1029 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1035 Property *defaultProperty = 0;
1036 Property *skipProperty = 0;
1037 if (obj->defaultProperty) {
1038 defaultProperty = obj->defaultProperty;
1040 Property *explicitProperty = 0;
1042 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1043 if (!defaultPropertyName.isEmpty()) {
1044 QString *s = pool->NewString(defaultPropertyName);
1045 QHashedStringRef r(*s);
1047 if (obj->propertiesHashField.test(r.hash())) {
1048 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1049 if (ep->name() == r) {
1050 explicitProperty = ep;
1056 if (!explicitProperty)
1057 defaultProperty->setName(r);
1060 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1062 skipProperty = explicitProperty; // We merge the values into defaultProperty
1064 // Find the correct insertion point
1065 Value *insertPos = 0;
1067 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1068 if (!(v->location.start < explicitProperty->values.first()->location.start))
1073 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1077 QQmlCustomParser *cp = 0;
1079 cp = output->types.at(obj->type).type->customParser();
1081 // Build all explicit properties specified
1082 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1084 if (prop == skipProperty)
1086 if (prop->name() == id_string)
1089 bool canDefer = false;
1090 if (isCustomParser) {
1091 if (doesPropertyExist(prop, obj) &&
1092 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1093 !isAttachedPropertyName(prop->name()))) {
1094 int ids = compileState->ids.count();
1095 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1096 canDefer = ids == compileState->ids.count();
1097 } else if (isSignalPropertyName(prop->name()) &&
1098 (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1099 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1101 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1104 if (isSignalPropertyName(prop->name())) {
1105 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1107 int ids = compileState->ids.count();
1108 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1109 canDefer = ids == compileState->ids.count();
1113 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1114 prop->isDeferred = true;
1118 // Build the default property
1119 if (defaultProperty) {
1120 Property *prop = defaultProperty;
1122 bool canDefer = false;
1123 if (isCustomParser) {
1124 if (doesPropertyExist(prop, obj)) {
1125 int ids = compileState->ids.count();
1126 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1127 canDefer = ids == compileState->ids.count();
1129 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1132 int ids = compileState->ids.count();
1133 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1134 canDefer = ids == compileState->ids.count();
1137 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1138 prop->isDeferred = true;
1141 // Compile custom parser parts
1142 if (isCustomParser && !customProps.isEmpty()) {
1144 cp->compiler = this;
1146 obj->custom = cp->compile(customProps);
1149 foreach (QQmlError err, cp->errors()) {
1150 err.setUrl(output->url);
1155 compileState->objectDepth.pop();
1160 void QQmlCompiler::genObject(QQmlScript::Object *obj, bool parentToSuper)
1162 QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1163 if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
1168 // Create the object
1169 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1170 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1172 Instruction::CreateSimpleObject create;
1173 create.create = output->types.at(obj->type).type->createFunction();
1174 create.typeSize = output->types.at(obj->type).type->createSize();
1175 create.type = obj->type;
1176 create.line = obj->location.start.line;
1177 create.column = obj->location.start.column;
1178 create.parentToSuper = parentToSuper;
1179 output->addInstruction(create);
1183 if (output->types.at(obj->type).type) {
1184 Instruction::CreateCppObject create;
1185 create.line = obj->location.start.line;
1186 create.column = obj->location.start.column;
1188 if (!obj->custom.isEmpty())
1189 create.data = output->indexForByteArray(obj->custom);
1190 create.type = obj->type;
1191 create.isRoot = (compileState->root == obj);
1192 create.parentToSuper = parentToSuper;
1193 output->addInstruction(create);
1195 Instruction::CreateQMLObject create;
1196 create.type = obj->type;
1197 create.isRoot = (compileState->root == obj);
1199 if (!obj->bindingBitmask.isEmpty()) {
1200 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1201 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1203 create.bindingBits = -1;
1205 output->addInstruction(create);
1207 Instruction::CompleteQMLObject complete;
1208 complete.line = obj->location.start.line;
1209 complete.column = obj->location.start.column;
1210 complete.isRoot = (compileState->root == obj);
1211 output->addInstruction(complete);
1215 // Setup the synthesized meta object if necessary
1216 if (!obj->synthdata.isEmpty()) {
1217 Instruction::StoreMetaObject meta;
1218 meta.aliasData = output->indexForByteArray(obj->synthdata);
1219 meta.propertyCache = output->propertyCaches.count();
1221 QQmlPropertyCache *propertyCache = obj->synthCache;
1222 Q_ASSERT(propertyCache);
1223 propertyCache->addref();
1225 if (obj == unitRoot) {
1226 propertyCache->addref();
1227 output->rootPropertyCache = propertyCache;
1230 output->propertyCaches << propertyCache;
1231 output->addInstruction(meta);
1232 } else if (obj == unitRoot) {
1233 output->rootPropertyCache = tr.createPropertyCache(engine);
1234 output->rootPropertyCache->addref();
1237 // Set the object id
1238 if (!obj->id.isEmpty()) {
1239 Instruction::SetId id;
1240 id.value = output->indexForString(obj->id);
1241 id.index = obj->idIndex;
1242 output->addInstruction(id);
1246 if (tr.type && obj->parserStatusCast != -1) {
1247 Instruction::BeginObject begin;
1248 begin.castValue = obj->parserStatusCast;
1249 output->addInstruction(begin);
1255 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1257 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1258 Q_ASSERT(prop->scriptStringScope != -1);
1259 const QString &script = prop->values.first()->value.asScript();
1260 Instruction::StoreScriptString ss;
1261 ss.propertyIndex = prop->index;
1262 ss.value = output->indexForString(script);
1263 ss.scope = prop->scriptStringScope;
1264 // ss.bindingId = rewriteBinding(script, prop->name());
1265 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1266 ss.line = prop->location.start.line;
1267 ss.column = prop->location.start.column;
1268 output->addInstruction(ss);
1271 bool seenDefer = false;
1272 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1273 if (prop->isDeferred) {
1278 genValueProperty(prop, obj);
1281 Instruction::Defer defer;
1282 defer.deferCount = 0;
1283 int deferIdx = output->addInstruction(defer);
1284 int nextInstructionIndex = output->nextInstructionIndex();
1286 Instruction::DeferInit dinit;
1287 // XXX - these are now massive over allocations
1288 dinit.bindingsSize = compileState->totalBindingsCount;
1289 dinit.parserStatusSize = compileState->parserStatusCount;
1290 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1291 dinit.listStackSize = compileState->listDepth.maxDepth();
1292 output->addInstruction(dinit);
1294 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1295 if (!prop->isDeferred)
1297 genValueProperty(prop, obj);
1300 Instruction::Done done;
1301 output->addInstruction(done);
1303 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1306 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1308 QQmlScript::Value *v = prop->values.first();
1310 if (v->type == Value::SignalObject) {
1312 genObject(v->object);
1314 Instruction::AssignSignalObject assign;
1315 assign.line = v->location.start.line;
1316 assign.signal = output->indexForString(prop->name().toString());
1317 output->addInstruction(assign);
1319 } else if (v->type == Value::SignalExpression) {
1321 Instruction::StoreSignal store;
1322 store.signalIndex = prop->index;
1323 const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1324 store.value = output->indexForByteArray(rewrite.toUtf8());
1325 store.context = v->signalExpressionContextStack;
1326 store.line = v->location.start.line;
1327 store.column = v->location.start.column;
1328 output->addInstruction(store);
1334 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1335 Instruction::FetchAttached fetch;
1336 fetch.id = prop->index;
1337 fetch.line = prop->location.start.line;
1338 output->addInstruction(fetch);
1340 genObjectBody(prop->value);
1342 Instruction::PopFetchedObject pop;
1343 output->addInstruction(pop);
1346 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1347 Instruction::FetchObject fetch;
1348 fetch.property = prop->index;
1349 fetch.line = prop->location.start.line;
1350 output->addInstruction(fetch);
1352 if (!prop->value->synthdata.isEmpty()) {
1353 Instruction::StoreMetaObject meta;
1354 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1355 meta.propertyCache = output->propertyCaches.count();
1356 QQmlPropertyCache *propertyCache = prop->value->synthCache;
1357 Q_ASSERT(propertyCache);
1358 propertyCache->addref();
1359 output->propertyCaches << propertyCache;
1360 output->addInstruction(meta);
1363 genObjectBody(prop->value);
1365 Instruction::PopFetchedObject pop;
1366 output->addInstruction(pop);
1369 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1371 genValueTypeProperty(obj, prop);
1374 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1375 if (prop->isDeferred)
1378 genValueProperty(prop, obj);
1381 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1383 genValueTypeProperty(obj, prop);
1387 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1389 Instruction::FetchValueType fetch;
1390 fetch.property = prop->index;
1391 fetch.type = prop->type;
1392 fetch.bindingSkipList = 0;
1394 if (obj->type == -1 || output->types.at(obj->type).component) {
1395 // We only have to do this if this is a composite type. If it is a builtin
1396 // type it can't possibly already have bindings that need to be cleared.
1397 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1398 if (!vprop->values.isEmpty()) {
1399 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1400 fetch.bindingSkipList |= (1 << vprop->index);
1405 output->addInstruction(fetch);
1407 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1408 genPropertyAssignment(vprop, prop->value, prop);
1411 Instruction::PopValueType pop;
1412 pop.property = prop->index;
1413 pop.type = prop->type;
1414 pop.bindingSkipList = 0;
1415 output->addInstruction(pop);
1417 genPropertyAssignment(prop, obj);
1420 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1422 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1425 Instruction::CreateComponent create;
1426 create.line = root->location.start.line;
1427 create.column = root->location.start.column;
1428 create.endLine = root->location.end.line;
1429 create.isRoot = (compileState->root == obj);
1430 int createInstruction = output->addInstruction(create);
1431 int nextInstructionIndex = output->nextInstructionIndex();
1433 ComponentCompileState *oldCompileState = compileState;
1434 compileState = componentState(root);
1436 Instruction::Init init;
1437 init.bindingsSize = compileState->totalBindingsCount;
1438 init.parserStatusSize = compileState->parserStatusCount;
1439 init.contextCache = genContextCache();
1440 init.objectStackSize = compileState->objectDepth.maxDepth();
1441 init.listStackSize = compileState->listDepth.maxDepth();
1442 if (compileState->compiledBindingData.isEmpty())
1443 init.compiledBinding = -1;
1445 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1446 output->addInstruction(init);
1448 if (!compileState->v8BindingProgram.isEmpty()) {
1449 Instruction::InitV8Bindings bindings;
1450 int index = output->programs.count();
1452 typedef QQmlCompiledData::V8Program V8Program;
1453 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1455 bindings.programIndex = index;
1456 bindings.line = compileState->v8BindingProgramLine;
1457 output->addInstruction(bindings);
1462 Instruction::SetDefault def;
1463 output->addInstruction(def);
1465 Instruction::Done done;
1466 output->addInstruction(done);
1468 output->instruction(createInstruction)->createComponent.count =
1469 output->nextInstructionIndex() - nextInstructionIndex;
1471 compileState = oldCompileState;
1473 if (!obj->id.isEmpty()) {
1474 Instruction::SetId id;
1475 id.value = output->indexForString(obj->id);
1476 id.index = obj->idIndex;
1477 output->addInstruction(id);
1480 if (obj == unitRoot) {
1481 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1482 output->rootPropertyCache->addref();
1486 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1487 const BindingContext &ctxt)
1489 // The special "Component" element can only have the id property and a
1490 // default property, that actually defines the component's tree
1492 compileState->objectDepth.push();
1494 // Find, check and set the "id" property (if any)
1495 Property *idProp = 0;
1496 if (obj->properties.isMany() ||
1497 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1498 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1500 if (!obj->properties.isEmpty())
1501 idProp = obj->properties.first();
1504 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1505 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1506 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1508 QString idVal = idProp->values.first()->primitive();
1510 if (compileState->ids.value(idVal))
1511 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1517 // Check the Component tree is well formed
1518 if (obj->defaultProperty &&
1519 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1520 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1521 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1523 if (!obj->dynamicProperties.isEmpty())
1524 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1525 if (!obj->dynamicSignals.isEmpty())
1526 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1527 if (!obj->dynamicSlots.isEmpty())
1528 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1530 QQmlScript::Object *root = 0;
1531 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1532 root = obj->defaultProperty->values.first()->object;
1535 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1537 // Build the component tree
1538 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1540 compileState->objectDepth.pop();
1545 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1546 const BindingContext &ctxt)
1548 ComponentCompileState *oldComponentCompileState = compileState;
1549 compileState = pool->New<ComponentCompileState>();
1550 compileState->root = obj;
1551 compileState->nested = true;
1553 if (componentStats) {
1554 ComponentStat oldComponentStat = componentStats->componentStat;
1556 componentStats->componentStat = ComponentStat();
1557 componentStats->componentStat.lineNumber = obj->location.start.line;
1560 COMPILE_CHECK(buildObject(obj, ctxt));
1562 COMPILE_CHECK(completeComponentBuild());
1564 componentStats->componentStat = oldComponentStat;
1567 COMPILE_CHECK(buildObject(obj, ctxt));
1569 COMPILE_CHECK(completeComponentBuild());
1572 compileState = oldComponentCompileState;
1578 // Build a sub-object. A sub-object is one that was not created directly by
1579 // QML - such as a grouped property object, or an attached object. Sub-object's
1580 // can't have an id, involve a custom parser, have attached properties etc.
1581 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1583 Q_ASSERT(obj->metatype);
1584 Q_ASSERT(!obj->defaultProperty);
1585 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1588 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1589 if (isSignalPropertyName(prop->name())) {
1590 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1592 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1599 int QQmlCompiler::componentTypeRef()
1601 if (cachedComponentTypeRef == -1) {
1602 QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1603 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1604 if (output->types.at(ii).type == t) {
1605 cachedComponentTypeRef = ii;
1609 QQmlCompiledData::TypeReference ref;
1611 output->types << ref;
1612 cachedComponentTypeRef = output->types.count() - 1;
1614 return cachedComponentTypeRef;
1617 int QQmlCompiler::translationContextIndex()
1619 if (cachedTranslationContextIndex == -1) {
1620 // This code must match that in the qsTr() implementation
1621 const QString &path = output->name;
1622 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1623 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1625 QByteArray contextUtf8 = context.toUtf8();
1626 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1628 return cachedTranslationContextIndex;
1631 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1632 const BindingContext &ctxt)
1634 Q_ASSERT(obj->metatype);
1636 const QHashedStringRef &propName = prop->name();
1638 Q_ASSERT(propName.startsWith(on_string));
1639 QString name = propName.mid(2, -1).toString();
1641 // Note that the property name could start with any alpha or '_' or '$' character,
1642 // so we need to do the lower-casing of the first alpha character.
1643 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1644 if (name.at(firstAlphaIndex).isUpper()) {
1645 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1650 bool notInRevision = false;
1652 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1656 if (notInRevision && 0 == property(obj, propName, 0)) {
1657 Q_ASSERT(obj->type != -1);
1658 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1659 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1661 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));
1663 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1667 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1669 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1673 if (prop->value || !prop->values.isOne())
1674 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1676 prop->index = propertyCacheForObject(obj)->methodIndexToSignalIndex(sig->coreIndex);
1679 obj->addSignalProperty(prop);
1681 if (prop->values.first()->object) {
1682 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1683 prop->values.first()->type = Value::SignalObject;
1685 prop->values.first()->type = Value::SignalExpression;
1687 if (!prop->values.first()->value.isScript())
1688 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1690 QString script = prop->values.first()->value.asScript().trimmed();
1691 if (script.isEmpty())
1692 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1694 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1703 Returns true if (value) property \a prop exists on obj, false otherwise.
1705 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1706 QQmlScript::Object *obj)
1708 if (prop->name().isEmpty())
1710 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1713 return property(obj, prop->name()) != 0;
1716 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1717 QQmlScript::Object *obj,
1718 const BindingContext &ctxt)
1720 if (prop->isEmpty())
1721 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1723 if (isAttachedPropertyName(prop->name())) {
1724 // Setup attached property data
1726 if (ctxt.isSubContext()) {
1727 // Attached properties cannot be used on sub-objects. Sub-objects
1728 // always exist in a binding sub-context, which is what we test
1730 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1734 QQmlImportNamespace *typeNamespace = 0;
1735 unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1737 if (typeNamespace) {
1738 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1741 } else if (!type || !type->attachedPropertiesType()) {
1742 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1746 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1748 Q_ASSERT(type->attachedPropertiesFunction());
1749 prop->index = type->attachedPropertiesId();
1750 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1752 // Setup regular property data
1753 bool notInRevision = false;
1754 QQmlPropertyData *d =
1755 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1757 if (d == 0 && notInRevision) {
1758 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1759 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1761 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));
1763 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1766 prop->index = d->coreIndex;
1768 } else if (prop->isDefault) {
1769 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1771 if (!defaultPropertyName.isEmpty()) {
1772 prop->setName(defaultPropertyName);
1773 prop->core = *obj->metatype->defaultProperty();
1774 prop->index = prop->core.coreIndex;
1778 // We can't error here as the "id" property does not require a
1779 // successful index resolution
1780 if (prop->index != -1)
1781 prop->type = prop->core.propType;
1783 // Check if this is an alias
1784 if (prop->index != -1 &&
1786 prop->parent->type != -1 &&
1787 output->types.at(prop->parent->type).component) {
1789 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1790 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1791 prop->isAlias = true;
1794 if (prop->index != -1 && !prop->values.isEmpty())
1795 prop->parent->setBindingBit(prop->index);
1798 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1800 // The magic "id" behavior doesn't apply when "id" is resolved as a
1801 // default property or to sub-objects (which are always in binding
1803 COMPILE_CHECK(buildIdProperty(prop, obj));
1804 if (prop->type == QVariant::String &&
1805 prop->values.first()->value.isString())
1806 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1808 } else if (isAttachedPropertyName(prop->name())) {
1810 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1812 } else if (prop->index == -1) {
1814 if (prop->isDefault) {
1815 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1817 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1820 } else if (prop->value) {
1822 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1824 } else if (prop->core.isQList()) {
1826 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1828 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1830 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1834 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1841 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1842 QQmlScript::Property *nsProp,
1843 QQmlScript::Object *obj,
1844 const BindingContext &ctxt)
1847 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1849 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1851 if (!isAttachedPropertyName(prop->name()))
1852 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1854 // Setup attached property data
1857 unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1859 if (!type || !type->attachedPropertiesType())
1860 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1863 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1865 Q_ASSERT(type->attachedPropertiesFunction());
1866 prop->index = type->index();
1867 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1869 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1875 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1876 QQmlScript::Object *obj)
1878 if (prop->core.isQList()) {
1879 genListProperty(prop, obj);
1881 genPropertyAssignment(prop, obj);
1885 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1886 QQmlScript::Object *obj)
1888 int listType = enginePrivate->listType(prop->type);
1890 Instruction::FetchQList fetch;
1891 fetch.property = prop->index;
1892 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1893 fetch.type = listType;
1894 output->addInstruction(fetch);
1896 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1898 if (v->type == Value::CreatedObject) {
1900 genObject(v->object);
1901 if (listTypeIsInterface) {
1902 Instruction::AssignObjectList assign;
1903 assign.line = prop->location.start.line;
1904 output->addInstruction(assign);
1906 Instruction::StoreObjectQList store;
1907 output->addInstruction(store);
1910 } else if (v->type == Value::PropertyBinding) {
1912 genBindingAssignment(v, prop, obj);
1918 Instruction::PopQList pop;
1919 output->addInstruction(pop);
1922 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1923 QQmlScript::Object *obj,
1924 QQmlScript::Property *valueTypeProperty)
1926 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1928 Q_ASSERT(v->type == Value::CreatedObject ||
1929 v->type == Value::PropertyBinding ||
1930 v->type == Value::Literal);
1932 if (v->type == Value::CreatedObject) {
1934 genObject(v->object);
1936 if (QQmlMetaType::isInterface(prop->type)) {
1938 Instruction::StoreInterface store;
1939 store.line = v->object->location.start.line;
1940 store.propertyIndex = prop->index;
1941 output->addInstruction(store);
1943 } else if (prop->type == QMetaType::QVariant) {
1945 if (prop->core.isVarProperty()) {
1946 Instruction::StoreVarObject store;
1947 store.line = v->object->location.start.line;
1948 store.propertyIndex = prop->index;
1949 output->addInstruction(store);
1951 Instruction::StoreVariantObject store;
1952 store.line = v->object->location.start.line;
1953 store.propertyIndex = prop->index;
1954 output->addInstruction(store);
1960 Instruction::StoreObject store;
1961 store.line = v->object->location.start.line;
1962 store.propertyIndex = prop->index;
1963 output->addInstruction(store);
1966 } else if (v->type == Value::PropertyBinding) {
1968 genBindingAssignment(v, prop, obj, valueTypeProperty);
1970 } else if (v->type == Value::Literal) {
1972 genLiteralAssignment(prop, v);
1978 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1980 Q_ASSERT(v->type == Value::ValueSource ||
1981 v->type == Value::ValueInterceptor);
1983 if (v->type == Value::ValueSource) {
1984 genObject(v->object, valueTypeProperty?true:false);
1986 Instruction::StoreValueSource store;
1987 if (valueTypeProperty)
1988 store.property = genValueTypeData(prop, valueTypeProperty);
1990 store.property = prop->core;
1991 QQmlType *valueType = toQmlType(v->object);
1992 store.castValue = valueType->propertyValueSourceCast();
1993 output->addInstruction(store);
1995 } else if (v->type == Value::ValueInterceptor) {
1996 genObject(v->object, valueTypeProperty?true:false);
1998 Instruction::StoreValueInterceptor store;
1999 if (valueTypeProperty)
2000 store.property = genValueTypeData(prop, valueTypeProperty);
2002 store.property = prop->core;
2003 QQmlType *valueType = toQmlType(v->object);
2004 store.castValue = valueType->propertyValueInterceptorCast();
2005 output->addInstruction(store);
2011 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2012 QQmlScript::Object *obj)
2015 prop->values.isMany() ||
2016 prop->values.first()->object)
2017 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2019 QQmlScript::Value *idValue = prop->values.first();
2020 QString val = idValue->primitive();
2022 COMPILE_CHECK(checkValidId(idValue, val));
2024 if (compileState->ids.value(val))
2025 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2027 prop->values.first()->type = Value::Id;
2035 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2038 Q_ASSERT(!compileState->ids.value(id));
2039 Q_ASSERT(obj->id == id);
2040 obj->idIndex = compileState->ids.count();
2041 compileState->ids.append(obj);
2044 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2046 Q_ASSERT(ref->value && !ref->value->bindingReference);
2047 ref->value->bindingReference = ref;
2048 compileState->totalBindingsCount++;
2049 compileState->bindings.prepend(ref);
2052 void QQmlCompiler::saveComponentState()
2054 Q_ASSERT(compileState->root);
2055 Q_ASSERT(compileState->root->componentCompileState == 0);
2057 compileState->root->componentCompileState = compileState;
2060 componentStats->savedComponentStats.append(componentStats->componentStat);
2063 QQmlCompilerTypes::ComponentCompileState *
2064 QQmlCompiler::componentState(QQmlScript::Object *obj)
2066 Q_ASSERT(obj->componentCompileState);
2067 return obj->componentCompileState;
2070 // Build attached property object. In this example,
2074 // GridView is an attached property object.
2075 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2076 QQmlScript::Object *obj,
2077 const BindingContext &ctxt)
2079 Q_ASSERT(prop->value);
2080 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2082 compileState->objectDepth.push();
2084 obj->addAttachedProperty(prop);
2086 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2088 compileState->objectDepth.pop();
2094 // Build "grouped" properties. In this example:
2096 // font.pointSize: 12
2097 // font.family: "Helvetica"
2099 // font is a nested property. pointSize and family are not.
2100 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2101 QQmlScript::Object *obj,
2102 const BindingContext &ctxt)
2104 Q_ASSERT(prop->type != 0);
2105 Q_ASSERT(prop->index != -1);
2107 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2108 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2110 if (!prop->values.isEmpty()) {
2111 // Only error if we are assigning values, and not e.g. a property interceptor
2112 for (Property *dotProp = prop->value->properties.first(); dotProp; dotProp = prop->value->properties.next(dotProp)) {
2113 if (!dotProp->values.isEmpty()) {
2114 if (prop->values.first()->location < prop->value->location) {
2115 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2117 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2123 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2124 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2127 if (prop->isAlias) {
2128 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2129 vtProp->isAlias = true;
2133 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2134 prop->value, obj, ctxt.incr()));
2136 // When building a value type where sub components are declared, this
2137 // code path is followed from buildProperty, even if there is a previous
2138 // assignment to the value type as a whole. Therefore we need to look
2139 // for (and build) assignments to the entire value type before looking
2140 // for any onValue assignments.
2141 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2143 COMPILE_EXCEPTION(v->object, tr("Objects cannot be assigned to value types"));
2145 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2148 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2149 Q_ASSERT(v->object);
2150 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2153 obj->addValueTypeProperty(prop);
2156 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2160 // Load the nested property's meta type
2161 prop->value->metatype = enginePrivate->propertyCacheForType(prop->type);
2162 if (!prop->value->metatype)
2163 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2165 if (!prop->values.isEmpty())
2166 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2168 obj->addGroupedProperty(prop);
2170 compileState->objectDepth.push();
2172 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2174 compileState->objectDepth.pop();
2180 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2181 QQmlScript::Object *obj,
2182 QQmlScript::Object *baseObj,
2183 const BindingContext &ctxt)
2185 compileState->objectDepth.push();
2187 if (obj->defaultProperty)
2188 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2189 obj->metatype = enginePrivate->cache(type);
2191 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2193 QQmlPropertyData *d = property(obj, prop->name());
2195 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2197 prop->index = d->coreIndex;
2198 prop->type = d->propType;
2200 prop->isValueTypeSubProperty = true;
2203 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2205 if (prop->values.isMany()) {
2206 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2207 } else if (!prop->values.isEmpty()) {
2208 QQmlScript::Value *value = prop->values.first();
2210 if (value->object) {
2211 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2212 } else if (value->value.isScript()) {
2213 // ### Check for writability
2215 //optimization for <Type>.<EnumValue> enum assignments
2216 bool isEnumAssignment = false;
2218 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2219 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2221 if (isEnumAssignment) {
2222 value->type = Value::Literal;
2224 JSBindingReference *reference = pool->New<JSBindingReference>();
2225 reference->expression = value->value;
2226 reference->property = prop;
2227 reference->value = value;
2228 reference->bindingContext = ctxt;
2229 reference->bindingContext.owner++;
2230 addBindingReference(reference);
2231 value->type = Value::PropertyBinding;
2234 COMPILE_CHECK(testLiteralAssignment(prop, value));
2235 value->type = Value::Literal;
2239 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2240 Q_ASSERT(v->object);
2242 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2245 obj->addValueProperty(prop);
2248 compileState->objectDepth.pop();
2253 // Build assignments to QML lists. QML lists are properties of type
2254 // QQmlListProperty<T>. List properties can accept a list of
2255 // objects, or a single binding.
2256 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2257 QQmlScript::Object *obj,
2258 const BindingContext &ctxt)
2260 Q_ASSERT(prop->core.isQList());
2262 compileState->listDepth.push();
2266 obj->addValueProperty(prop);
2268 int listType = enginePrivate->listType(t);
2269 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2271 bool assignedBinding = false;
2272 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2274 v->type = Value::CreatedObject;
2275 COMPILE_CHECK(buildObject(v->object, ctxt));
2277 // We check object coercian here. We check interface assignment
2279 if (!listTypeIsInterface) {
2280 if (!canCoerce(listType, v->object)) {
2281 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2285 } else if (v->value.isScript()) {
2286 if (assignedBinding)
2287 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2289 assignedBinding = true;
2290 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2291 v->type = Value::PropertyBinding;
2293 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2297 compileState->listDepth.pop();
2302 // Compiles an assignment to a QQmlScriptString property
2303 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2304 QQmlScript::Object *obj,
2305 const BindingContext &ctxt)
2307 if (prop->values.isMany())
2308 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2310 if (prop->values.first()->object)
2311 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2313 prop->scriptStringScope = ctxt.stack;
2314 obj->addScriptStringProperty(prop);
2319 // Compile regular property assignments of the form "property: <value>"
2320 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2321 QQmlScript::Object *obj,
2322 const BindingContext &ctxt)
2324 obj->addValueProperty(prop);
2326 if (prop->values.isMany())
2327 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2329 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2332 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2336 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2341 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2342 Q_ASSERT(v->object);
2343 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2349 // Compile assigning a single object instance to a regular property
2350 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2351 QQmlScript::Object *obj,
2352 QQmlScript::Value *v,
2353 const BindingContext &ctxt)
2355 Q_ASSERT(prop->index != -1);
2356 Q_ASSERT(v->object->type != -1);
2358 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2359 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2361 if (QQmlMetaType::isInterface(prop->type)) {
2363 // Assigning an object to an interface ptr property
2364 COMPILE_CHECK(buildObject(v->object, ctxt));
2366 v->type = Value::CreatedObject;
2368 } else if (prop->type == QMetaType::QVariant) {
2370 // Assigning an object to a QVariant
2371 COMPILE_CHECK(buildObject(v->object, ctxt));
2373 v->type = Value::CreatedObject;
2375 // Normally buildObject() will set this up, but we need the static
2376 // meta object earlier to test for assignability. It doesn't matter
2377 // that there may still be outstanding synthesized meta object changes
2378 // on this type, as they are not relevant for assignability testing
2379 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2380 Q_ASSERT(v->object->metatype);
2382 // We want to raw metaObject here as the raw metaobject is the
2383 // actual property type before we applied any extensions that might
2384 // effect the properties on the type, but don't effect assignability
2385 QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type);
2387 // Will be true if the assgned type inherits propertyMetaObject
2388 bool isAssignable = false;
2389 // Determine isAssignable value
2390 if (propertyMetaObject) {
2391 QQmlPropertyCache *c = v->object->metatype;
2392 while (c && !isAssignable) {
2393 isAssignable |= c == propertyMetaObject;
2399 // Simple assignment
2400 COMPILE_CHECK(buildObject(v->object, ctxt));
2402 v->type = Value::CreatedObject;
2403 } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) {
2404 // Automatic "Component" insertion
2405 QQmlScript::Object *root = v->object;
2406 QQmlScript::Object *component = pool->New<Object>();
2407 component->type = componentTypeRef();
2408 component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject);
2409 component->location = root->location;
2410 QQmlScript::Value *componentValue = pool->New<Value>();
2411 componentValue->object = root;
2412 component->getDefaultProperty()->addValue(componentValue);
2413 v->object = component;
2414 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2416 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2423 // Compile assigning a single object instance to a regular property using the "on" syntax.
2427 // NumberAnimation on x { }
2429 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2430 QQmlScript::Object *obj,
2431 QQmlScript::Object *baseObj,
2432 QQmlScript::Value *v,
2433 const BindingContext &ctxt)
2435 Q_ASSERT(prop->index != -1);
2436 Q_ASSERT(v->object->type != -1);
2440 if (!prop->core.isWritable())
2441 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2444 // Normally buildObject() will set this up, but we need the static
2445 // meta object earlier to test for assignability. It doesn't matter
2446 // that there may still be outstanding synthesized meta object changes
2447 // on this type, as they are not relevant for assignability testing
2448 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2449 Q_ASSERT(v->object->metatype);
2451 // Will be true if the assigned type inherits QQmlPropertyValueSource
2452 bool isPropertyValue = false;
2453 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2454 bool isPropertyInterceptor = false;
2455 if (QQmlType *valueType = toQmlType(v->object)) {
2456 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2457 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2460 if (isPropertyValue || isPropertyInterceptor) {
2461 // Assign as a property value source
2462 COMPILE_CHECK(buildObject(v->object, ctxt));
2464 if (isPropertyInterceptor && baseObj->synthdata.isEmpty())
2465 buildDynamicMeta(baseObj, ForceCreation);
2466 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2468 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2474 // Compile assigning a literal or binding to a regular property
2475 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2476 QQmlScript::Object *obj,
2477 QQmlScript::Value *v,
2478 const BindingContext &ctxt)
2480 Q_ASSERT(prop->index != -1);
2482 if (v->value.isScript()) {
2484 //optimization for <Type>.<EnumValue> enum assignments
2485 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2486 bool isEnumAssignment = false;
2487 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2488 if (isEnumAssignment) {
2489 v->type = Value::Literal;
2494 // Test for other binding optimizations
2495 if (!buildLiteralBinding(v, prop, ctxt))
2496 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2498 v->type = Value::PropertyBinding;
2502 COMPILE_CHECK(testLiteralAssignment(prop, v));
2504 v->type = Value::Literal;
2510 struct StaticQtMetaObject : public QObject
2512 static const QMetaObject *get()
2513 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2516 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2517 QQmlScript::Object *obj,
2518 QQmlScript::Value *v,
2521 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2522 *isAssignment = false;
2523 if (!prop->core.isEnum() && !isIntProp)
2526 QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2528 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2529 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2531 QString string = v->value.asString();
2532 if (!string.at(0).isUpper())
2535 int dot = string.indexOf(QLatin1Char('.'));
2536 if (dot == -1 || dot == string.length()-1)
2539 if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2542 QHashedStringRef typeName(string.constData(), dot);
2543 QString enumValue = string.mid(dot+1);
2546 // Allow enum assignment to ints.
2548 int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
2550 v->type = Value::Literal;
2551 v->value = QQmlScript::Variant((double)enumval);
2552 *isAssignment = true;
2558 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2560 if (!type && typeName != QLatin1String("Qt"))
2566 if (type && toQmlType(obj) == type) {
2567 // When these two match, we can short cut the search
2568 if (mprop.isFlagType()) {
2569 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2571 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2574 // Otherwise we have to search the whole type
2576 value = type->enumValue(QHashedStringRef(enumValue), &ok);
2578 QByteArray enumName = enumValue.toUtf8();
2579 const QMetaObject *metaObject = StaticQtMetaObject::get();
2580 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2581 QMetaEnum e = metaObject->enumerator(ii);
2582 value = e.keyToValue(enumName.constData(), &ok);
2590 v->type = Value::Literal;
2591 v->value = QQmlScript::Variant((double)value);
2592 *isAssignment = true;
2597 // Similar logic to above, but not knowing target property.
2598 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
2600 Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
2603 if (scope != QLatin1String("Qt")) {
2605 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2606 return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
2609 const QMetaObject *mo = StaticQtMetaObject::get();
2610 int i = mo->enumeratorCount();
2612 int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
2619 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2621 QQmlType *qmltype = 0;
2622 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2626 return qmltype->metaObject();
2629 // similar to logic of completeComponentBuild, but also sticks data
2630 // into primitives at the end
2631 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2633 QQmlRewrite::RewriteBinding rewriteBinding;
2634 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2636 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2638 return output->indexForString(rewrite);
2641 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2643 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2644 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2647 // Ensures that the dynamic meta specification on obj is valid
2648 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2650 bool seenDefaultProperty = false;
2652 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2653 // Calculating the hash for the names is not a waste as we have to test
2654 // them against the illegalNames set anyway.
2655 QHashField propNames;
2656 QHashField methodNames;
2659 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2660 const QQmlScript::Object::DynamicProperty &prop = *p;
2662 if (prop.isDefaultProperty) {
2663 if (seenDefaultProperty)
2664 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2665 seenDefaultProperty = true;
2668 if (propNames.testAndSet(prop.name.hash())) {
2669 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2670 p2 = obj->dynamicProperties.next(p2)) {
2671 if (p2->name == prop.name) {
2672 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2673 prop.nameLocation.column,
2674 tr("Duplicate property name"));
2679 if (prop.name.at(0).isUpper()) {
2680 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2681 prop.nameLocation.column,
2682 tr("Property names cannot begin with an upper case letter"));
2685 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2686 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2687 prop.nameLocation.column,
2688 tr("Illegal property name"));
2692 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2693 const QQmlScript::Object::DynamicSignal &currSig = *s;
2695 if (methodNames.testAndSet(currSig.name.hash())) {
2696 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2697 s2 = obj->dynamicSignals.next(s2)) {
2698 if (s2->name == currSig.name)
2699 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2703 if (currSig.name.at(0).isUpper())
2704 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2705 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2706 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2709 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2710 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2712 if (methodNames.testAndSet(currSlot.name.hash())) {
2713 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2714 s2 = obj->dynamicSignals.next(s2)) {
2715 if (s2->name == currSlot.name)
2716 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2718 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2719 s2 = obj->dynamicSlots.next(s2)) {
2720 if (s2->name == currSlot.name)
2721 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2725 if (currSlot.name.at(0).isUpper())
2726 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2727 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2728 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2734 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2736 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2737 p = obj->dynamicProperties.next(p)) {
2739 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2742 Property *property = 0;
2743 if (p->isDefaultProperty) {
2744 property = obj->getDefaultProperty();
2746 property = obj->getProperty(p->name);
2747 if (!property->values.isEmpty())
2748 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2752 property->isReadOnlyDeclaration = true;
2754 if (property->value)
2755 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2757 property->values.append(p->defaultValue->values);
2762 #include <private/qqmljsparser_p.h>
2764 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2766 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2768 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2769 return QStringList() << name;
2770 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2771 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2773 QStringList rv = astNodeToStringList(expr->base);
2776 rv.append(expr->name.toString());
2779 return QStringList();
2782 static QAtomicInt classIndexCounter(0);
2784 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2787 Q_ASSERT(obj->metatype);
2789 if (mode != ForceCreation &&
2790 obj->dynamicProperties.isEmpty() &&
2791 obj->dynamicSignals.isEmpty() &&
2792 obj->dynamicSlots.isEmpty())
2795 Q_ASSERT(obj->synthCache == 0);
2798 Object::DynamicProperty::Type dtype;
2800 } builtinTypes[] = {
2801 { Object::DynamicProperty::Var, QMetaType::QVariant },
2802 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2803 { Object::DynamicProperty::Int, QMetaType::Int },
2804 { Object::DynamicProperty::Bool, QMetaType::Bool },
2805 { Object::DynamicProperty::Real, QMetaType::Double },
2806 { Object::DynamicProperty::String, QMetaType::QString },
2807 { Object::DynamicProperty::Url, QMetaType::QUrl },
2808 { Object::DynamicProperty::Color, QMetaType::QColor },
2809 { Object::DynamicProperty::Time, QMetaType::QTime },
2810 { Object::DynamicProperty::Date, QMetaType::QDate },
2811 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2812 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2814 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2816 QByteArray newClassName;
2818 if (compileState->root == obj && !compileState->nested) {
2819 QString path = output->url.path();
2820 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2821 if (lastSlash > -1) {
2822 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2823 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2824 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2825 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2828 if (newClassName.isEmpty()) {
2829 newClassName = QQmlMetaObject(obj->metatype).className();
2830 newClassName.append("_QML_");
2831 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2833 QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2834 obj->dynamicProperties.count() +
2835 obj->dynamicSignals.count() +
2836 obj->dynamicSlots.count(),
2837 obj->dynamicProperties.count() +
2838 obj->dynamicSignals.count());
2840 cache->_dynamicClassName = newClassName;
2842 int cStringNameCount = 0;
2845 int varPropCount = 0;
2847 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2848 p = obj->dynamicProperties.next(p)) {
2850 if (p->type == Object::DynamicProperty::Alias)
2852 else if (p->type == Object::DynamicProperty::Var)
2855 if (p->name.isLatin1()) {
2856 p->nameIndex = cStringNameCount;
2857 cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2860 // No point doing this for both the alias and non alias cases
2861 QQmlPropertyData *d = property(obj, p->name);
2862 if (d && d->isFinal())
2863 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2866 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2867 if (s->name.isLatin1()) {
2868 s->nameIndex = cStringNameCount;
2869 cStringNameCount += s->name.length();
2873 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2874 if (s->name.isLatin1()) {
2875 s->nameIndex = cStringNameCount;
2876 cStringNameCount += s->name.length();
2880 char *cStringData = 0;
2881 if (cStringNameCount) {
2882 cache->_dynamicStringData.resize(cStringNameCount);
2883 cStringData = cache->_dynamicStringData.data();
2885 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2886 p = obj->dynamicProperties.next(p)) {
2888 if (p->nameIndex == -1) continue;
2890 char *myData = cStringData + p->nameIndex;
2891 for (int ii = 0; ii < p->name.length(); ++ii)
2892 *myData++ = p->name.at(ii).unicode();
2893 *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2894 *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2897 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2899 if (s->nameIndex == -1) continue;
2901 char *myData = cStringData + s->nameIndex;
2902 for (int ii = 0; ii < s->name.length(); ++ii)
2903 *myData++ = s->name.at(ii).unicode();
2906 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2907 s = obj->dynamicSignals.next(s)) {
2909 if (s->nameIndex == -1) continue;
2911 char *myData = cStringData + s->nameIndex;
2912 for (int ii = 0; ii < s->name.length(); ++ii)
2913 *myData++ = s->name.at(ii).unicode();
2917 QByteArray dynamicData;
2918 typedef QQmlVMEMetaData VMD;
2920 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2921 obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2922 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2923 aliasCount * sizeof(VMD::AliasData), 0);
2925 int effectivePropertyIndex = cache->propertyIndexCacheStart;
2926 int effectiveMethodIndex = cache->methodIndexCacheStart;
2928 // First set up notify signals for properties - first normal, then var, then alias
2929 enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2930 for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2932 if (ii == NSS_Var && varPropCount == 0) continue;
2933 else if (ii == NSS_Alias && aliasCount == 0) continue;
2935 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2936 p = obj->dynamicProperties.next(p)) {
2938 if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2939 p->type == Object::DynamicProperty::Var)) ||
2940 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2941 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2944 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2945 QQmlPropertyData::IsVMESignal;
2947 if (p->nameIndex != -1) {
2948 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2949 p->name.length() + 7 /* strlen("Changed") */);
2950 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2952 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2954 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2960 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2961 int paramCount = s->parameterNames.count();
2963 QList<QByteArray> names;
2964 QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2967 paramTypes[0] = paramCount;
2969 for (int i = 0; i < paramCount; ++i) {
2970 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2971 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2972 names.append(s->parameterNames.at(i).toString().toUtf8());
2976 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2978 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2979 QQmlPropertyData::IsVMESignal;
2981 flags |= QQmlPropertyData::HasArguments;
2983 if (s->nameIndex != -1) {
2984 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2985 cache->appendSignal(name, flags, effectiveMethodIndex++,
2986 paramCount?paramTypes.constData():0, names);
2988 QString name = s->name.toString();
2989 cache->appendSignal(name, flags, effectiveMethodIndex++,
2990 paramCount?paramTypes.constData():0, names);
2996 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2997 int paramCount = s->parameterNames.count();
2999 quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
3002 flags |= QQmlPropertyData::HasArguments;
3004 if (s->nameIndex != -1) {
3005 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
3006 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
3008 QString name = s->name.toString();
3009 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
3014 // Dynamic properties (except var and aliases)
3015 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
3016 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3017 p = obj->dynamicProperties.next(p)) {
3019 if (p->type == Object::DynamicProperty::Alias ||
3020 p->type == Object::DynamicProperty::Var)
3023 int propertyType = 0;
3024 int vmePropertyType = 0;
3025 quint32 propertyFlags = 0;
3027 if (p->type < builtinTypeCount) {
3028 propertyType = builtinTypes[p->type].metaType;
3029 vmePropertyType = propertyType;
3031 if (p->type == Object::DynamicProperty::Variant)
3032 propertyFlags |= QQmlPropertyData::IsQVariant;
3034 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3035 p->type == Object::DynamicProperty::Custom);
3037 QQmlType *qmltype = 0;
3039 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3040 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3043 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3045 Q_ASSERT(tdata->isComplete());
3047 QQmlCompiledData *data = tdata->compiledData();
3049 if (p->type == Object::DynamicProperty::Custom) {
3050 propertyType = data->metaTypeId;
3051 vmePropertyType = QMetaType::QObjectStar;
3053 propertyType = data->listMetaTypeId;
3054 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3059 if (p->type == Object::DynamicProperty::Custom) {
3060 propertyType = qmltype->typeId();
3061 vmePropertyType = QMetaType::QObjectStar;
3063 propertyType = qmltype->qListTypeId();
3064 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3068 if (p->type == Object::DynamicProperty::Custom)
3069 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3071 propertyFlags |= QQmlPropertyData::IsQList;
3074 if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3075 propertyFlags |= QQmlPropertyData::IsWritable;
3077 if (p->nameIndex != -1) {
3078 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3080 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3081 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3082 propertyType, effectiveSignalIndex);
3084 QString propertyName = p->name.toString();
3085 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3086 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3087 propertyType, effectiveSignalIndex);
3090 effectiveSignalIndex++;
3092 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3093 (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3094 vmd->propertyCount++;
3097 // Now do var properties
3098 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3099 p = obj->dynamicProperties.next(p)) {
3101 if (p->type != Object::DynamicProperty::Var)
3104 quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3106 propertyFlags |= QQmlPropertyData::IsWritable;
3108 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3109 (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3110 vmd->propertyCount++;
3111 ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3113 if (p->nameIndex != -1) {
3114 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3116 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3117 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3118 QMetaType::QVariant, effectiveSignalIndex);
3120 QString propertyName = p->name.toString();
3121 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3122 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3123 QMetaType::QVariant, effectiveSignalIndex);
3126 effectiveSignalIndex++;
3129 // Alias property count. Actual data is setup in buildDynamicMetaAliases
3130 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3132 // Dynamic slot data - comes after the property data
3133 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3134 int paramCount = s->parameterNames.count();
3138 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3139 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3140 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3141 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3142 for (int jj = 0; jj < paramCount; ++jj) {
3143 if (jj) funcScript.append(QLatin1Char(','));
3144 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3146 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3148 QByteArray utf8 = funcScript.toUtf8();
3149 VMD::MethodData methodData = { s->parameterNames.count(),
3152 s->location.start.line };
3154 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3155 VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3159 dynamicData.append((const char *)utf8.constData(), utf8.length());
3163 compileState->aliasingObjects.append(obj);
3165 obj->synthdata = dynamicData;
3166 obj->synthCache = cache;
3167 obj->metatype = cache;
3172 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3174 Q_ASSERT(obj->synthCache);
3176 QByteArray &dynamicData = obj->synthdata;
3178 QQmlPropertyCache *cache = obj->synthCache;
3179 char *cStringData = cache->_dynamicStringData.data();
3181 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
3182 int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3183 int effectiveAliasIndex = 0;
3185 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3186 p = obj->dynamicProperties.next(p)) {
3188 if (p->type != Object::DynamicProperty::Alias)
3191 if (!p->defaultValue)
3192 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3194 if (!p->defaultValue->values.isOne() ||
3195 p->defaultValue->values.first()->object ||
3196 !p->defaultValue->values.first()->value.isScript())
3197 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3199 QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3202 QStringList alias = astNodeToStringList(node);
3203 if (alias.count() < 1 || alias.count() > 3)
3204 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3206 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3208 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3211 int notifySignal = -1;
3214 bool writable = false;
3215 bool resettable = false;
3217 quint32 propertyFlags = QQmlPropertyData::IsAlias;
3219 if (alias.count() == 2 || alias.count() == 3) {
3220 QQmlPropertyData *property = this->property(idObject, alias.at(1));
3222 if (!property || property->coreIndex > 0xFFFF)
3223 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3225 propIdx = property->coreIndex;
3226 type = property->propType;
3228 writable = property->isWritable();
3229 resettable = property->isResettable();
3230 notifySignal = property->notifyIndex;
3232 if (alias.count() == 3) {
3233 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3235 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3237 propIdx |= ((unsigned int)type) << 24;
3238 int valueTypeIndex =
3239 valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3240 if (valueTypeIndex == -1)
3241 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3242 Q_ASSERT(valueTypeIndex <= 0xFF);
3244 propIdx |= (valueTypeIndex << 16);
3245 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3246 type = QVariant::Int;
3248 type = valueType->metaObject()->property(valueTypeIndex).userType();
3251 if (property->isEnum()) {
3252 type = QVariant::Int;
3255 propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3257 if (property->isVarProperty())
3258 propertyFlags |= QQmlPropertyData::IsQVariant;
3260 if (property->isQObject())
3261 flags |= QML_ALIAS_FLAG_PTR;
3265 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3267 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3269 type = ref.type->typeId();
3271 type = ref.component->metaTypeId;
3273 flags |= QML_ALIAS_FLAG_PTR;
3274 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3277 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3279 typedef QQmlVMEMetaData VMD;
3280 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3281 *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3283 if (!p->isReadOnly && writable)
3284 propertyFlags |= QQmlPropertyData::IsWritable;
3286 propertyFlags &= ~QQmlPropertyData::IsWritable;
3289 propertyFlags |= QQmlPropertyData::IsResettable;
3291 propertyFlags &= ~QQmlPropertyData::IsResettable;
3293 if (p->nameIndex != -1) {
3294 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3296 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3297 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3298 type, effectiveSignalIndex++);
3300 QString propertyName = p->name.toString();
3301 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3302 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3303 type, effectiveSignalIndex++);
3310 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3313 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3315 QChar ch = val.at(0);
3316 if (ch.isLetter() && !ch.isLower())
3317 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3319 QChar u(QLatin1Char('_'));
3320 if (!ch.isLetter() && ch != u)
3321 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3323 for (int ii = 1; ii < val.count(); ++ii) {
3325 if (!ch.isLetterOrNumber() && ch != u)
3326 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3329 if (enginePrivate->v8engine()->illegalNames().contains(val))
3330 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3335 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3336 QQmlScript::Property *prop,
3337 const BindingContext &ctxt)
3339 Q_ASSERT(prop->index != -1);
3340 Q_ASSERT(prop->parent);
3341 Q_ASSERT(prop->parent->metatype);
3343 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3344 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3346 JSBindingReference *reference = pool->New<JSBindingReference>();
3347 reference->expression = value->value;
3348 reference->property = prop;
3349 reference->value = value;
3350 reference->bindingContext = ctxt;
3351 addBindingReference(reference);
3356 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3357 QQmlScript::Property *prop,
3358 const QQmlCompilerTypes::BindingContext &)
3360 Q_ASSERT(v->value.isScript());
3362 if (!prop->core.isWritable())
3365 AST::Node *binding = v->value.asAST();
3367 if (prop->type == QVariant::String) {
3368 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3369 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3370 if (i->name == qsTrId_string) {
3371 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3372 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3374 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3375 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3376 (!arg2 || !arg2->next)) {
3381 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3382 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3384 TrBindingReference *reference = pool->New<TrBindingReference>();
3385 reference->dataType = BindingReference::TrId;
3386 reference->text = text;
3388 v->bindingReference = reference;
3392 } else if (i->name == qsTr_string) {
3394 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3395 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3396 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3398 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3399 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3400 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3401 (!arg3 || !arg3->next)) {
3407 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3408 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3409 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3411 TrBindingReference *reference = pool->New<TrBindingReference>();
3412 reference->dataType = BindingReference::Tr;
3413 reference->text = text;
3414 reference->comment = comment;
3416 v->bindingReference = reference;
3429 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3430 QQmlScript::Property *prop,
3431 QQmlScript::Object *obj,
3432 QQmlScript::Property *valueTypeProperty)
3435 Q_ASSERT(binding->bindingReference);
3437 const BindingReference &ref = *binding->bindingReference;
3438 if (ref.dataType == BindingReference::TrId) {
3439 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3441 Instruction::StoreTrIdString store;
3442 store.propertyIndex = prop->core.coreIndex;
3443 store.text = output->indexForByteArray(tr.text.toUtf8());
3445 output->addInstruction(store);
3446 } else if (ref.dataType == BindingReference::Tr) {
3447 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3449 Instruction::StoreTrString store;
3450 store.propertyIndex = prop->core.coreIndex;
3451 store.context = translationContextIndex();
3452 store.text = output->indexForByteArray(tr.text.toUtf8());
3453 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3455 output->addInstruction(store);
3456 } else if (ref.dataType == BindingReference::V4) {
3457 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3459 Instruction::StoreV4Binding store;
3460 store.value = js.compiledIndex;
3461 store.context = js.bindingContext.stack;
3462 store.owner = js.bindingContext.owner;
3463 store.isAlias = prop->isAlias;
3464 if (valueTypeProperty) {
3465 store.property = (valueTypeProperty->index & 0xFFFF) |
3466 ((valueTypeProperty->type & 0xFF)) << 16 |
3467 ((prop->index & 0xFF) << 24);
3468 store.isRoot = (compileState->root == valueTypeProperty->parent);
3470 store.property = prop->index;
3471 store.isRoot = (compileState->root == obj);
3473 store.line = binding->location.start.line;
3474 store.column = binding->location.start.column;
3475 output->addInstruction(store);
3476 } else if (ref.dataType == BindingReference::V8) {
3477 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3479 Instruction::StoreV8Binding store;
3480 store.value = js.compiledIndex;
3481 store.context = js.bindingContext.stack;
3482 store.owner = js.bindingContext.owner;
3483 store.isAlias = prop->isAlias;
3484 if (valueTypeProperty) {
3485 store.isRoot = (compileState->root == valueTypeProperty->parent);
3487 store.isRoot = (compileState->root == obj);
3489 store.line = binding->location.start.line;
3490 store.column = binding->location.start.column;
3492 Q_ASSERT(js.bindingContext.owner == 0 ||
3493 (js.bindingContext.owner != 0 && valueTypeProperty));
3494 if (js.bindingContext.owner) {
3495 store.property = genValueTypeData(prop, valueTypeProperty);
3497 store.property = prop->core;
3500 output->addInstruction(store);
3501 } else if (ref.dataType == BindingReference::QtScript) {
3502 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3504 Instruction::StoreBinding store;
3505 store.value = output->indexForString(js.rewrittenExpression);
3506 store.context = js.bindingContext.stack;
3507 store.owner = js.bindingContext.owner;
3508 store.line = binding->location.start.line;
3509 store.column = binding->location.start.column;
3510 store.isAlias = prop->isAlias;
3512 if (valueTypeProperty) {
3513 store.isRoot = (compileState->root == valueTypeProperty->parent);
3515 store.isRoot = (compileState->root == obj);
3518 Q_ASSERT(js.bindingContext.owner == 0 ||
3519 (js.bindingContext.owner != 0 && valueTypeProperty));
3520 if (js.bindingContext.owner) {
3521 store.property = genValueTypeData(prop, valueTypeProperty);
3523 store.property = prop->core;
3526 output->addInstruction(store);
3528 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3532 int QQmlCompiler::genContextCache()
3534 if (compileState->ids.count() == 0)
3537 QQmlIntegerCache *cache = new QQmlIntegerCache();
3538 cache->reserve(compileState->ids.count());
3539 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3540 cache->add(o->id, o->idIndex);
3542 output->contextCaches.append(cache);
3543 return output->contextCaches.count() - 1;
3547 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3548 QQmlScript::Property *prop)
3550 typedef QQmlPropertyPrivate QDPP;
3551 return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3552 valueTypeProp->index, engine);
3555 bool QQmlCompiler::completeComponentBuild()
3558 componentStats->componentStat.ids = compileState->ids.count();
3560 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3561 aliasObject = compileState->aliasingObjects.next(aliasObject))
3562 COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3564 QV4Compiler::Expression expr(unit->imports());
3565 expr.component = compileState->root;
3566 expr.ids = &compileState->ids;
3567 expr.importCache = output->importCache;
3569 QV4Compiler bindingCompiler;
3571 QList<JSBindingReference*> sharedBindings;
3573 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3575 JSBindingReference &binding = *b;
3578 expr.context = binding.bindingContext.object;
3579 expr.property = binding.property;
3580 expr.expression = binding.expression;
3582 int index = bindingCompiler.compile(expr, enginePrivate);
3584 binding.dataType = BindingReference::V4;
3585 binding.compiledIndex = index;
3587 componentStats->componentStat.optimizedBindings.append(b->value->location);
3591 // Pre-rewrite the expression
3592 QString expression = binding.expression.asScript();
3594 QQmlRewrite::RewriteBinding rewriteBinding;
3595 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3596 bool isSharable = false;
3597 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3599 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3600 binding.dataType = BindingReference::V8;
3601 sharedBindings.append(b);
3604 componentStats->componentStat.sharedBindings.append(b->value->location);
3606 binding.dataType = BindingReference::QtScript;
3609 componentStats->componentStat.scriptBindings.append(b->value->location);
3613 if (!sharedBindings.isEmpty()) {
3615 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3617 return lhs->value->location.start.line < rhs->value->location.start.line;
3621 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3623 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3624 int lineNumber = startLineNumber;
3626 QByteArray functionArray("[", 1);
3627 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3629 JSBindingReference *reference = sharedBindings.at(ii);
3630 QQmlScript::Value *value = reference->value;
3631 const QString &expression = reference->rewrittenExpression;
3633 if (ii != 0) functionArray.append(",", 1);
3635 while (lineNumber < value->location.start.line) {
3637 functionArray.append("\n", 1);
3640 functionArray += expression.toUtf8();
3641 lineNumber += expression.count(QLatin1Char('\n'));
3642 reference->compiledIndex = ii;
3644 functionArray.append("]", 1);
3646 compileState->v8BindingProgram = functionArray;
3647 compileState->v8BindingProgramLine = startLineNumber;
3650 if (bindingCompiler.isValid())
3651 compileState->compiledBindingData = bindingCompiler.program();
3653 // Check pop()'s matched push()'s
3654 Q_ASSERT(compileState->objectDepth.depth() == 0);
3655 Q_ASSERT(compileState->listDepth.depth() == 0);
3657 saveComponentState();
3662 void QQmlCompiler::dumpStats()
3664 Q_ASSERT(componentStats);
3665 qWarning().nospace() << "QML Document: " << output->url.toString();
3666 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3667 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3668 qWarning().nospace() << " Component Line " << stat.lineNumber;
3669 qWarning().nospace() << " Total Objects: " << stat.objects;
3670 qWarning().nospace() << " IDs Used: " << stat.ids;
3671 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3675 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3676 if (0 == (ii % 10)) {
3677 if (ii) output.append("\n");
3682 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3684 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3685 output.append(") ");
3687 if (!output.isEmpty())
3688 qWarning().nospace() << output.constData();
3691 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3694 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3695 if (0 == (ii % 10)) {
3696 if (ii) output.append('\n');
3701 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3703 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3704 output.append(") ");
3706 if (!output.isEmpty())
3707 qWarning().nospace() << output.constData();
3710 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3713 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3714 if (0 == (ii % 10)) {
3715 if (ii) output.append('\n');
3720 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3722 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3723 output.append(") ");
3725 if (!output.isEmpty())
3726 qWarning().nospace() << output.constData();
3732 Returns true if from can be assigned to a (QObject) property of type
3735 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3737 QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3738 QQmlPropertyCache *fromMo = from->metatype;
3743 fromMo = fromMo->parent();
3749 Returns the element name, as written in the QML file, for o.
3751 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3754 if (o->type != -1) {
3755 return unit->parser().referencedTypes().at(o->type)->name;
3761 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3763 if (from->type != -1 && output->types.at(from->type).type)
3764 return output->types.at(from->type).type;
3766 const QMetaObject *mo = from->metatype->firstCppMetaObject();
3768 while (!type && mo) {
3769 type = QQmlMetaType::qmlType(mo);
3770 mo = mo->superClass();
3775 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3777 const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3779 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3781 return QStringList();
3783 QMetaClassInfo classInfo = mo->classInfo(idx);
3784 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3789 QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
3791 if (object->synthCache)
3792 return object->synthCache;
3793 else if (object->type != -1)
3794 return output->types[object->type].createPropertyCache(engine);
3796 return object->metatype;
3800 QQmlCompiler::property(QQmlScript::Object *object, int index)
3802 QQmlPropertyCache *cache = propertyCacheForObject(object);
3804 return cache->property(index);
3808 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3810 if (notInRevision) *notInRevision = false;
3812 QQmlPropertyCache *cache = propertyCacheForObject(object);
3814 QQmlPropertyData *d = cache->property(name);
3816 // Find the first property
3817 while (d && d->isFunction())
3818 d = cache->overrideData(d);
3820 if (d && !cache->isAllowedInRevision(d)) {
3821 if (notInRevision) *notInRevision = true;
3828 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3830 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3832 if (notInRevision) *notInRevision = false;
3834 QQmlPropertyCache *cache = propertyCacheForObject(object);
3837 QQmlPropertyData *d = cache->property(name);
3838 if (notInRevision) *notInRevision = false;
3840 while (d && !(d->isFunction()))
3841 d = cache->overrideData(d);
3843 if (d && !cache->isAllowedInRevision(d)) {
3844 if (notInRevision) *notInRevision = true;
3846 } else if (d && d->isSignal()) {
3850 if (name.endsWith(Changed_string)) {
3851 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3853 d = property(object, propName, notInRevision);
3855 return cache->signal(d->notifyIndex);
3861 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3862 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3863 bool *notInRevision)
3865 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3866 return d?d->coreIndex:-1;
3869 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3870 bool *notInRevision)
3872 return indexOfProperty(object, QStringRef(&name), notInRevision);
3875 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3876 bool *notInRevision)
3878 QQmlPropertyData *d = property(object, name, notInRevision);
3879 return d?d->coreIndex:-1;