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);
1418 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1420 QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1423 Instruction::CreateComponent create;
1424 create.line = root->location.start.line;
1425 create.column = root->location.start.column;
1426 create.endLine = root->location.end.line;
1427 create.isRoot = (compileState->root == obj);
1428 int createInstruction = output->addInstruction(create);
1429 int nextInstructionIndex = output->nextInstructionIndex();
1431 ComponentCompileState *oldCompileState = compileState;
1432 compileState = componentState(root);
1434 Instruction::Init init;
1435 init.bindingsSize = compileState->totalBindingsCount;
1436 init.parserStatusSize = compileState->parserStatusCount;
1437 init.contextCache = genContextCache();
1438 init.objectStackSize = compileState->objectDepth.maxDepth();
1439 init.listStackSize = compileState->listDepth.maxDepth();
1440 if (compileState->compiledBindingData.isEmpty())
1441 init.compiledBinding = -1;
1443 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1444 output->addInstruction(init);
1446 if (!compileState->v8BindingProgram.isEmpty()) {
1447 Instruction::InitV8Bindings bindings;
1448 int index = output->programs.count();
1450 typedef QQmlCompiledData::V8Program V8Program;
1451 output->programs.append(V8Program(compileState->v8BindingProgram, output));
1453 bindings.programIndex = index;
1454 bindings.line = compileState->v8BindingProgramLine;
1455 output->addInstruction(bindings);
1460 Instruction::SetDefault def;
1461 output->addInstruction(def);
1463 Instruction::Done done;
1464 output->addInstruction(done);
1466 output->instruction(createInstruction)->createComponent.count =
1467 output->nextInstructionIndex() - nextInstructionIndex;
1469 compileState = oldCompileState;
1471 if (!obj->id.isEmpty()) {
1472 Instruction::SetId id;
1473 id.value = output->indexForString(obj->id);
1474 id.index = obj->idIndex;
1475 output->addInstruction(id);
1478 if (obj == unitRoot) {
1479 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1480 output->rootPropertyCache->addref();
1484 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1485 const BindingContext &ctxt)
1487 // The special "Component" element can only have the id property and a
1488 // default property, that actually defines the component's tree
1490 compileState->objectDepth.push();
1492 // Find, check and set the "id" property (if any)
1493 Property *idProp = 0;
1494 if (obj->properties.isMany() ||
1495 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1496 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1498 if (!obj->properties.isEmpty())
1499 idProp = obj->properties.first();
1502 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1503 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1504 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1506 QString idVal = idProp->values.first()->primitive();
1508 if (compileState->ids.value(idVal))
1509 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1515 // Check the Component tree is well formed
1516 if (obj->defaultProperty &&
1517 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1518 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1519 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1521 if (!obj->dynamicProperties.isEmpty())
1522 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1523 if (!obj->dynamicSignals.isEmpty())
1524 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1525 if (!obj->dynamicSlots.isEmpty())
1526 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1528 QQmlScript::Object *root = 0;
1529 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1530 root = obj->defaultProperty->values.first()->object;
1533 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1535 // Build the component tree
1536 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1538 compileState->objectDepth.pop();
1543 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1544 const BindingContext &ctxt)
1546 ComponentCompileState *oldComponentCompileState = compileState;
1547 compileState = pool->New<ComponentCompileState>();
1548 compileState->root = obj;
1549 compileState->nested = true;
1551 if (componentStats) {
1552 ComponentStat oldComponentStat = componentStats->componentStat;
1554 componentStats->componentStat = ComponentStat();
1555 componentStats->componentStat.lineNumber = obj->location.start.line;
1558 COMPILE_CHECK(buildObject(obj, ctxt));
1560 COMPILE_CHECK(completeComponentBuild());
1562 componentStats->componentStat = oldComponentStat;
1565 COMPILE_CHECK(buildObject(obj, ctxt));
1567 COMPILE_CHECK(completeComponentBuild());
1570 compileState = oldComponentCompileState;
1576 // Build a sub-object. A sub-object is one that was not created directly by
1577 // QML - such as a grouped property object, or an attached object. Sub-object's
1578 // can't have an id, involve a custom parser, have attached properties etc.
1579 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1581 Q_ASSERT(obj->metatype);
1582 Q_ASSERT(!obj->defaultProperty);
1583 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1586 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1587 if (isSignalPropertyName(prop->name())) {
1588 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1590 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1597 int QQmlCompiler::componentTypeRef()
1599 if (cachedComponentTypeRef == -1) {
1600 QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1601 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1602 if (output->types.at(ii).type == t) {
1603 cachedComponentTypeRef = ii;
1607 QQmlCompiledData::TypeReference ref;
1609 output->types << ref;
1610 cachedComponentTypeRef = output->types.count() - 1;
1612 return cachedComponentTypeRef;
1615 int QQmlCompiler::translationContextIndex()
1617 if (cachedTranslationContextIndex == -1) {
1618 // This code must match that in the qsTr() implementation
1619 const QString &path = output->name;
1620 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1621 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1623 QByteArray contextUtf8 = context.toUtf8();
1624 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1626 return cachedTranslationContextIndex;
1629 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1630 const BindingContext &ctxt)
1632 Q_ASSERT(obj->metatype);
1634 const QHashedStringRef &propName = prop->name();
1636 Q_ASSERT(propName.startsWith(on_string));
1637 QString name = propName.mid(2, -1).toString();
1639 // Note that the property name could start with any alpha or '_' or '$' character,
1640 // so we need to do the lower-casing of the first alpha character.
1641 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1642 if (name.at(firstAlphaIndex).isUpper()) {
1643 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1648 bool notInRevision = false;
1650 QQmlPropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1654 if (notInRevision && 0 == property(obj, propName, 0)) {
1655 Q_ASSERT(obj->type != -1);
1656 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1657 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1659 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));
1661 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1665 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1667 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1671 if (prop->value || !prop->values.isOne())
1672 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1674 prop->index = propertyCacheForObject(obj)->methodIndexToSignalIndex(sig->coreIndex);
1677 obj->addSignalProperty(prop);
1679 if (prop->values.first()->object) {
1680 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1681 prop->values.first()->type = Value::SignalObject;
1683 prop->values.first()->type = Value::SignalExpression;
1685 if (!prop->values.first()->value.isScript())
1686 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1688 QString script = prop->values.first()->value.asScript().trimmed();
1689 if (script.isEmpty())
1690 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1692 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1701 Returns true if (value) property \a prop exists on obj, false otherwise.
1703 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1704 QQmlScript::Object *obj)
1706 if (prop->name().isEmpty())
1708 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1711 return property(obj, prop->name()) != 0;
1714 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1715 QQmlScript::Object *obj,
1716 const BindingContext &ctxt)
1718 if (prop->isEmpty())
1719 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1721 if (isAttachedPropertyName(prop->name())) {
1722 // Setup attached property data
1724 if (ctxt.isSubContext()) {
1725 // Attached properties cannot be used on sub-objects. Sub-objects
1726 // always exist in a binding sub-context, which is what we test
1728 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1732 QQmlImportNamespace *typeNamespace = 0;
1733 unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1735 if (typeNamespace) {
1736 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1739 } else if (!type || !type->attachedPropertiesType()) {
1740 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1744 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1746 Q_ASSERT(type->attachedPropertiesFunction());
1747 prop->index = type->attachedPropertiesId();
1748 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1750 // Setup regular property data
1751 bool notInRevision = false;
1752 QQmlPropertyData *d =
1753 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1755 if (d == 0 && notInRevision) {
1756 const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1757 const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1759 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));
1761 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1764 prop->index = d->coreIndex;
1766 } else if (prop->isDefault) {
1767 QString defaultPropertyName = obj->metatype->defaultPropertyName();
1769 if (!defaultPropertyName.isEmpty()) {
1770 prop->setName(defaultPropertyName);
1771 prop->core = *obj->metatype->defaultProperty();
1772 prop->index = prop->core.coreIndex;
1776 // We can't error here as the "id" property does not require a
1777 // successful index resolution
1778 if (prop->index != -1)
1779 prop->type = prop->core.propType;
1781 // Check if this is an alias
1782 if (prop->index != -1 &&
1784 prop->parent->type != -1 &&
1785 output->types.at(prop->parent->type).component) {
1787 QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1788 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1789 prop->isAlias = true;
1792 if (prop->index != -1 && !prop->values.isEmpty())
1793 prop->parent->setBindingBit(prop->index);
1796 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1798 // The magic "id" behavior doesn't apply when "id" is resolved as a
1799 // default property or to sub-objects (which are always in binding
1801 COMPILE_CHECK(buildIdProperty(prop, obj));
1802 if (prop->type == QVariant::String &&
1803 prop->values.first()->value.isString())
1804 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1806 } else if (isAttachedPropertyName(prop->name())) {
1808 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1810 } else if (prop->index == -1) {
1812 if (prop->isDefault) {
1813 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1815 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1818 } else if (prop->value) {
1820 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1822 } else if (prop->core.isQList()) {
1824 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1826 } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1828 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1832 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1839 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1840 QQmlScript::Property *nsProp,
1841 QQmlScript::Object *obj,
1842 const BindingContext &ctxt)
1845 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1847 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1849 if (!isAttachedPropertyName(prop->name()))
1850 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1852 // Setup attached property data
1855 unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1857 if (!type || !type->attachedPropertiesType())
1858 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1861 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1863 Q_ASSERT(type->attachedPropertiesFunction());
1864 prop->index = type->index();
1865 prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1867 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1873 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1874 QQmlScript::Object *obj)
1876 if (prop->core.isQList()) {
1877 genListProperty(prop, obj);
1879 genPropertyAssignment(prop, obj);
1883 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1884 QQmlScript::Object *obj)
1886 int listType = enginePrivate->listType(prop->type);
1888 Instruction::FetchQList fetch;
1889 fetch.property = prop->index;
1890 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1891 fetch.type = listType;
1892 output->addInstruction(fetch);
1894 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1896 if (v->type == Value::CreatedObject) {
1898 genObject(v->object);
1899 if (listTypeIsInterface) {
1900 Instruction::AssignObjectList assign;
1901 assign.line = prop->location.start.line;
1902 output->addInstruction(assign);
1904 Instruction::StoreObjectQList store;
1905 output->addInstruction(store);
1908 } else if (v->type == Value::PropertyBinding) {
1910 genBindingAssignment(v, prop, obj);
1916 Instruction::PopQList pop;
1917 output->addInstruction(pop);
1920 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1921 QQmlScript::Object *obj,
1922 QQmlScript::Property *valueTypeProperty)
1924 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1926 Q_ASSERT(v->type == Value::CreatedObject ||
1927 v->type == Value::PropertyBinding ||
1928 v->type == Value::Literal);
1930 if (v->type == Value::CreatedObject) {
1932 genObject(v->object);
1934 if (QQmlMetaType::isInterface(prop->type)) {
1936 Instruction::StoreInterface store;
1937 store.line = v->object->location.start.line;
1938 store.propertyIndex = prop->index;
1939 output->addInstruction(store);
1941 } else if (prop->type == QMetaType::QVariant) {
1943 if (prop->core.isVarProperty()) {
1944 Instruction::StoreVarObject store;
1945 store.line = v->object->location.start.line;
1946 store.propertyIndex = prop->index;
1947 output->addInstruction(store);
1949 Instruction::StoreVariantObject store;
1950 store.line = v->object->location.start.line;
1951 store.propertyIndex = prop->index;
1952 output->addInstruction(store);
1958 Instruction::StoreObject store;
1959 store.line = v->object->location.start.line;
1960 store.propertyIndex = prop->index;
1961 output->addInstruction(store);
1964 } else if (v->type == Value::PropertyBinding) {
1966 genBindingAssignment(v, prop, obj, valueTypeProperty);
1968 } else if (v->type == Value::Literal) {
1970 genLiteralAssignment(prop, v);
1976 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1978 Q_ASSERT(v->type == Value::ValueSource ||
1979 v->type == Value::ValueInterceptor);
1981 if (v->type == Value::ValueSource) {
1982 genObject(v->object, valueTypeProperty?true:false);
1984 Instruction::StoreValueSource store;
1985 if (valueTypeProperty)
1986 store.property = genValueTypeData(prop, valueTypeProperty);
1988 store.property = prop->core;
1989 QQmlType *valueType = toQmlType(v->object);
1990 store.castValue = valueType->propertyValueSourceCast();
1991 output->addInstruction(store);
1993 } else if (v->type == Value::ValueInterceptor) {
1994 genObject(v->object, valueTypeProperty?true:false);
1996 Instruction::StoreValueInterceptor store;
1997 if (valueTypeProperty)
1998 store.property = genValueTypeData(prop, valueTypeProperty);
2000 store.property = prop->core;
2001 QQmlType *valueType = toQmlType(v->object);
2002 store.castValue = valueType->propertyValueInterceptorCast();
2003 output->addInstruction(store);
2009 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2010 QQmlScript::Object *obj)
2013 prop->values.isMany() ||
2014 prop->values.first()->object)
2015 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2017 QQmlScript::Value *idValue = prop->values.first();
2018 QString val = idValue->primitive();
2020 COMPILE_CHECK(checkValidId(idValue, val));
2022 if (compileState->ids.value(val))
2023 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2025 prop->values.first()->type = Value::Id;
2033 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2036 Q_ASSERT(!compileState->ids.value(id));
2037 Q_ASSERT(obj->id == id);
2038 obj->idIndex = compileState->ids.count();
2039 compileState->ids.append(obj);
2042 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2044 Q_ASSERT(ref->value && !ref->value->bindingReference);
2045 ref->value->bindingReference = ref;
2046 compileState->totalBindingsCount++;
2047 compileState->bindings.prepend(ref);
2050 void QQmlCompiler::saveComponentState()
2052 Q_ASSERT(compileState->root);
2053 Q_ASSERT(compileState->root->componentCompileState == 0);
2055 compileState->root->componentCompileState = compileState;
2058 componentStats->savedComponentStats.append(componentStats->componentStat);
2061 QQmlCompilerTypes::ComponentCompileState *
2062 QQmlCompiler::componentState(QQmlScript::Object *obj)
2064 Q_ASSERT(obj->componentCompileState);
2065 return obj->componentCompileState;
2068 // Build attached property object. In this example,
2072 // GridView is an attached property object.
2073 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2074 QQmlScript::Object *obj,
2075 const BindingContext &ctxt)
2077 Q_ASSERT(prop->value);
2078 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2080 compileState->objectDepth.push();
2082 obj->addAttachedProperty(prop);
2084 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2086 compileState->objectDepth.pop();
2092 // Build "grouped" properties. In this example:
2094 // font.pointSize: 12
2095 // font.family: "Helvetica"
2097 // font is a nested property. pointSize and family are not.
2098 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2099 QQmlScript::Object *obj,
2100 const BindingContext &ctxt)
2102 Q_ASSERT(prop->type != 0);
2103 Q_ASSERT(prop->index != -1);
2105 if (QQmlValueTypeFactory::isValueType(prop->type)) {
2106 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2108 if (!prop->values.isEmpty()) {
2109 if (prop->values.first()->location < prop->value->location) {
2110 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2112 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2116 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2117 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2121 if (prop->isAlias) {
2122 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2123 vtProp->isAlias = true;
2127 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2128 prop->value, obj, ctxt.incr()));
2129 obj->addValueTypeProperty(prop);
2131 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2135 // Load the nested property's meta type
2136 prop->value->metatype = enginePrivate->propertyCacheForType(prop->type);
2137 if (!prop->value->metatype)
2138 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2140 if (!prop->values.isEmpty())
2141 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2143 obj->addGroupedProperty(prop);
2145 compileState->objectDepth.push();
2147 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2149 compileState->objectDepth.pop();
2155 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2156 QQmlScript::Object *obj,
2157 QQmlScript::Object *baseObj,
2158 const BindingContext &ctxt)
2160 compileState->objectDepth.push();
2162 if (obj->defaultProperty)
2163 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2164 obj->metatype = enginePrivate->cache(type);
2166 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2168 QQmlPropertyData *d = property(obj, prop->name());
2170 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2172 prop->index = d->coreIndex;
2173 prop->type = d->propType;
2175 prop->isValueTypeSubProperty = true;
2178 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2180 if (prop->values.isMany()) {
2181 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2182 } else if (!prop->values.isEmpty()) {
2183 QQmlScript::Value *value = prop->values.first();
2185 if (value->object) {
2186 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2187 } else if (value->value.isScript()) {
2188 // ### Check for writability
2190 //optimization for <Type>.<EnumValue> enum assignments
2191 bool isEnumAssignment = false;
2193 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2194 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2196 if (isEnumAssignment) {
2197 value->type = Value::Literal;
2199 JSBindingReference *reference = pool->New<JSBindingReference>();
2200 reference->expression = value->value;
2201 reference->property = prop;
2202 reference->value = value;
2203 reference->bindingContext = ctxt;
2204 reference->bindingContext.owner++;
2205 addBindingReference(reference);
2206 value->type = Value::PropertyBinding;
2209 COMPILE_CHECK(testLiteralAssignment(prop, value));
2210 value->type = Value::Literal;
2214 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2215 Q_ASSERT(v->object);
2217 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2220 obj->addValueProperty(prop);
2223 compileState->objectDepth.pop();
2228 // Build assignments to QML lists. QML lists are properties of type
2229 // QQmlListProperty<T>. List properties can accept a list of
2230 // objects, or a single binding.
2231 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2232 QQmlScript::Object *obj,
2233 const BindingContext &ctxt)
2235 Q_ASSERT(prop->core.isQList());
2237 compileState->listDepth.push();
2241 obj->addValueProperty(prop);
2243 int listType = enginePrivate->listType(t);
2244 bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2246 bool assignedBinding = false;
2247 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2249 v->type = Value::CreatedObject;
2250 COMPILE_CHECK(buildObject(v->object, ctxt));
2252 // We check object coercian here. We check interface assignment
2254 if (!listTypeIsInterface) {
2255 if (!canCoerce(listType, v->object)) {
2256 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2260 } else if (v->value.isScript()) {
2261 if (assignedBinding)
2262 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2264 assignedBinding = true;
2265 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2266 v->type = Value::PropertyBinding;
2268 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2272 compileState->listDepth.pop();
2277 // Compiles an assignment to a QQmlScriptString property
2278 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2279 QQmlScript::Object *obj,
2280 const BindingContext &ctxt)
2282 if (prop->values.isMany())
2283 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2285 if (prop->values.first()->object)
2286 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2288 prop->scriptStringScope = ctxt.stack;
2289 obj->addScriptStringProperty(prop);
2294 // Compile regular property assignments of the form "property: <value>"
2295 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2296 QQmlScript::Object *obj,
2297 const BindingContext &ctxt)
2299 obj->addValueProperty(prop);
2301 if (prop->values.isMany())
2302 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2304 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2307 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2311 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2316 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2317 Q_ASSERT(v->object);
2318 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2324 // Compile assigning a single object instance to a regular property
2325 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2326 QQmlScript::Object *obj,
2327 QQmlScript::Value *v,
2328 const BindingContext &ctxt)
2330 Q_ASSERT(prop->index != -1);
2331 Q_ASSERT(v->object->type != -1);
2333 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2334 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2336 if (QQmlMetaType::isInterface(prop->type)) {
2338 // Assigning an object to an interface ptr property
2339 COMPILE_CHECK(buildObject(v->object, ctxt));
2341 v->type = Value::CreatedObject;
2343 } else if (prop->type == QMetaType::QVariant) {
2345 // Assigning an object to a QVariant
2346 COMPILE_CHECK(buildObject(v->object, ctxt));
2348 v->type = Value::CreatedObject;
2350 // Normally buildObject() will set this up, but we need the static
2351 // meta object earlier to test for assignability. It doesn't matter
2352 // that there may still be outstanding synthesized meta object changes
2353 // on this type, as they are not relevant for assignability testing
2354 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2355 Q_ASSERT(v->object->metatype);
2357 // We want to raw metaObject here as the raw metaobject is the
2358 // actual property type before we applied any extensions that might
2359 // effect the properties on the type, but don't effect assignability
2360 QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type);
2362 // Will be true if the assgned type inherits propertyMetaObject
2363 bool isAssignable = false;
2364 // Determine isAssignable value
2365 if (propertyMetaObject) {
2366 QQmlPropertyCache *c = v->object->metatype;
2367 while (c && !isAssignable) {
2368 isAssignable |= c == propertyMetaObject;
2374 // Simple assignment
2375 COMPILE_CHECK(buildObject(v->object, ctxt));
2377 v->type = Value::CreatedObject;
2378 } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) {
2379 // Automatic "Component" insertion
2380 QQmlScript::Object *root = v->object;
2381 QQmlScript::Object *component = pool->New<Object>();
2382 component->type = componentTypeRef();
2383 component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject);
2384 component->location = root->location;
2385 QQmlScript::Value *componentValue = pool->New<Value>();
2386 componentValue->object = root;
2387 component->getDefaultProperty()->addValue(componentValue);
2388 v->object = component;
2389 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2391 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2398 // Compile assigning a single object instance to a regular property using the "on" syntax.
2402 // NumberAnimation on x { }
2404 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2405 QQmlScript::Object *obj,
2406 QQmlScript::Object *baseObj,
2407 QQmlScript::Value *v,
2408 const BindingContext &ctxt)
2410 Q_ASSERT(prop->index != -1);
2411 Q_ASSERT(v->object->type != -1);
2415 if (!prop->core.isWritable())
2416 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2419 // Normally buildObject() will set this up, but we need the static
2420 // meta object earlier to test for assignability. It doesn't matter
2421 // that there may still be outstanding synthesized meta object changes
2422 // on this type, as they are not relevant for assignability testing
2423 v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2424 Q_ASSERT(v->object->metatype);
2426 // Will be true if the assigned type inherits QQmlPropertyValueSource
2427 bool isPropertyValue = false;
2428 // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2429 bool isPropertyInterceptor = false;
2430 if (QQmlType *valueType = toQmlType(v->object)) {
2431 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2432 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2435 if (isPropertyValue || isPropertyInterceptor) {
2436 // Assign as a property value source
2437 COMPILE_CHECK(buildObject(v->object, ctxt));
2439 if (isPropertyInterceptor && baseObj->synthdata.isEmpty())
2440 buildDynamicMeta(baseObj, ForceCreation);
2441 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2443 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2449 // Compile assigning a literal or binding to a regular property
2450 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2451 QQmlScript::Object *obj,
2452 QQmlScript::Value *v,
2453 const BindingContext &ctxt)
2455 Q_ASSERT(prop->index != -1);
2457 if (v->value.isScript()) {
2459 //optimization for <Type>.<EnumValue> enum assignments
2460 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2461 bool isEnumAssignment = false;
2462 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2463 if (isEnumAssignment) {
2464 v->type = Value::Literal;
2469 // Test for other binding optimizations
2470 if (!buildLiteralBinding(v, prop, ctxt))
2471 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2473 v->type = Value::PropertyBinding;
2477 COMPILE_CHECK(testLiteralAssignment(prop, v));
2479 v->type = Value::Literal;
2485 struct StaticQtMetaObject : public QObject
2487 static const QMetaObject *get()
2488 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2491 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2492 QQmlScript::Object *obj,
2493 QQmlScript::Value *v,
2496 bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2497 *isAssignment = false;
2498 if (!prop->core.isEnum() && !isIntProp)
2501 QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2503 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2504 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2506 QString string = v->value.asString();
2507 if (!string.at(0).isUpper())
2510 int dot = string.indexOf(QLatin1Char('.'));
2511 if (dot == -1 || dot == string.length()-1)
2514 if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2517 QHashedStringRef typeName(string.constData(), dot);
2518 QString enumValue = string.mid(dot+1);
2521 // Allow enum assignment to ints.
2523 int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
2525 v->type = Value::Literal;
2526 v->value = QQmlScript::Variant((double)enumval);
2527 *isAssignment = true;
2533 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2535 if (!type && typeName != QLatin1String("Qt"))
2541 if (type && toQmlType(obj) == type) {
2542 // When these two match, we can short cut the search
2543 if (mprop.isFlagType()) {
2544 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2546 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2549 // Otherwise we have to search the whole type
2551 value = type->enumValue(QHashedStringRef(enumValue), &ok);
2553 QByteArray enumName = enumValue.toUtf8();
2554 const QMetaObject *metaObject = StaticQtMetaObject::get();
2555 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2556 QMetaEnum e = metaObject->enumerator(ii);
2557 value = e.keyToValue(enumName.constData(), &ok);
2565 v->type = Value::Literal;
2566 v->value = QQmlScript::Variant((double)value);
2567 *isAssignment = true;
2572 // Similar logic to above, but not knowing target property.
2573 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
2575 Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
2578 if (scope != QLatin1String("Qt")) {
2580 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2581 return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
2584 const QMetaObject *mo = StaticQtMetaObject::get();
2585 int i = mo->enumeratorCount();
2587 int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
2594 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2596 QQmlType *qmltype = 0;
2597 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2601 return qmltype->metaObject();
2604 // similar to logic of completeComponentBuild, but also sticks data
2605 // into primitives at the end
2606 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2608 QQmlRewrite::RewriteBinding rewriteBinding;
2609 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2611 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2613 return output->indexForString(rewrite);
2616 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2618 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2619 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2622 // Ensures that the dynamic meta specification on obj is valid
2623 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2625 bool seenDefaultProperty = false;
2627 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2628 // Calculating the hash for the names is not a waste as we have to test
2629 // them against the illegalNames set anyway.
2630 QHashField propNames;
2631 QHashField methodNames;
2634 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2635 const QQmlScript::Object::DynamicProperty &prop = *p;
2637 if (prop.isDefaultProperty) {
2638 if (seenDefaultProperty)
2639 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2640 seenDefaultProperty = true;
2643 if (propNames.testAndSet(prop.name.hash())) {
2644 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2645 p2 = obj->dynamicProperties.next(p2)) {
2646 if (p2->name == prop.name) {
2647 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2648 prop.nameLocation.column,
2649 tr("Duplicate property name"));
2654 if (prop.name.at(0).isUpper()) {
2655 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2656 prop.nameLocation.column,
2657 tr("Property names cannot begin with an upper case letter"));
2660 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2661 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2662 prop.nameLocation.column,
2663 tr("Illegal property name"));
2667 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2668 const QQmlScript::Object::DynamicSignal &currSig = *s;
2670 if (methodNames.testAndSet(currSig.name.hash())) {
2671 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2672 s2 = obj->dynamicSignals.next(s2)) {
2673 if (s2->name == currSig.name)
2674 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2678 if (currSig.name.at(0).isUpper())
2679 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2680 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2681 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2684 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2685 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2687 if (methodNames.testAndSet(currSlot.name.hash())) {
2688 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2689 s2 = obj->dynamicSignals.next(s2)) {
2690 if (s2->name == currSlot.name)
2691 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2693 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2694 s2 = obj->dynamicSlots.next(s2)) {
2695 if (s2->name == currSlot.name)
2696 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2700 if (currSlot.name.at(0).isUpper())
2701 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2702 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2703 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2709 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2711 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2712 p = obj->dynamicProperties.next(p)) {
2714 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2717 Property *property = 0;
2718 if (p->isDefaultProperty) {
2719 property = obj->getDefaultProperty();
2721 property = obj->getProperty(p->name);
2722 if (!property->values.isEmpty())
2723 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2727 property->isReadOnlyDeclaration = true;
2729 if (property->value)
2730 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2732 property->values.append(p->defaultValue->values);
2737 #include <private/qqmljsparser_p.h>
2739 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2741 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2743 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2744 return QStringList() << name;
2745 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2746 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2748 QStringList rv = astNodeToStringList(expr->base);
2751 rv.append(expr->name.toString());
2754 return QStringList();
2757 static QAtomicInt classIndexCounter(0);
2759 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2762 Q_ASSERT(obj->metatype);
2764 if (mode != ForceCreation &&
2765 obj->dynamicProperties.isEmpty() &&
2766 obj->dynamicSignals.isEmpty() &&
2767 obj->dynamicSlots.isEmpty())
2770 Q_ASSERT(obj->synthCache == 0);
2773 Object::DynamicProperty::Type dtype;
2775 } builtinTypes[] = {
2776 { Object::DynamicProperty::Var, QMetaType::QVariant },
2777 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2778 { Object::DynamicProperty::Int, QMetaType::Int },
2779 { Object::DynamicProperty::Bool, QMetaType::Bool },
2780 { Object::DynamicProperty::Real, QMetaType::Double },
2781 { Object::DynamicProperty::String, QMetaType::QString },
2782 { Object::DynamicProperty::Url, QMetaType::QUrl },
2783 { Object::DynamicProperty::Color, QMetaType::QColor },
2784 { Object::DynamicProperty::Time, QMetaType::QTime },
2785 { Object::DynamicProperty::Date, QMetaType::QDate },
2786 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2787 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2789 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2791 QByteArray newClassName;
2793 if (compileState->root == obj && !compileState->nested) {
2794 QString path = output->url.path();
2795 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2796 if (lastSlash > -1) {
2797 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2798 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2799 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2800 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2803 if (newClassName.isEmpty()) {
2804 newClassName = QQmlMetaObject(obj->metatype).className();
2805 newClassName.append("_QML_");
2806 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2808 QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2809 obj->dynamicProperties.count() +
2810 obj->dynamicSignals.count() +
2811 obj->dynamicSlots.count(),
2812 obj->dynamicProperties.count() +
2813 obj->dynamicSignals.count());
2815 cache->_dynamicClassName = newClassName;
2817 int cStringNameCount = 0;
2820 int varPropCount = 0;
2822 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2823 p = obj->dynamicProperties.next(p)) {
2825 if (p->type == Object::DynamicProperty::Alias)
2827 else if (p->type == Object::DynamicProperty::Var)
2830 if (p->name.isLatin1()) {
2831 p->nameIndex = cStringNameCount;
2832 cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2835 // No point doing this for both the alias and non alias cases
2836 QQmlPropertyData *d = property(obj, p->name);
2837 if (d && d->isFinal())
2838 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2841 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2842 if (s->name.isLatin1()) {
2843 s->nameIndex = cStringNameCount;
2844 cStringNameCount += s->name.length();
2848 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2849 if (s->name.isLatin1()) {
2850 s->nameIndex = cStringNameCount;
2851 cStringNameCount += s->name.length();
2855 char *cStringData = 0;
2856 if (cStringNameCount) {
2857 cache->_dynamicStringData.resize(cStringNameCount);
2858 cStringData = cache->_dynamicStringData.data();
2860 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2861 p = obj->dynamicProperties.next(p)) {
2863 if (p->nameIndex == -1) continue;
2865 char *myData = cStringData + p->nameIndex;
2866 for (int ii = 0; ii < p->name.length(); ++ii)
2867 *myData++ = p->name.at(ii).unicode();
2868 *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2869 *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2872 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2874 if (s->nameIndex == -1) continue;
2876 char *myData = cStringData + s->nameIndex;
2877 for (int ii = 0; ii < s->name.length(); ++ii)
2878 *myData++ = s->name.at(ii).unicode();
2881 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2882 s = obj->dynamicSignals.next(s)) {
2884 if (s->nameIndex == -1) continue;
2886 char *myData = cStringData + s->nameIndex;
2887 for (int ii = 0; ii < s->name.length(); ++ii)
2888 *myData++ = s->name.at(ii).unicode();
2892 QByteArray dynamicData;
2893 typedef QQmlVMEMetaData VMD;
2895 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2896 obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2897 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2898 aliasCount * sizeof(VMD::AliasData), 0);
2900 int effectivePropertyIndex = cache->propertyIndexCacheStart;
2901 int effectiveMethodIndex = cache->methodIndexCacheStart;
2903 // First set up notify signals for properties - first normal, then var, then alias
2904 enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2905 for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2907 if (ii == NSS_Var && varPropCount == 0) continue;
2908 else if (ii == NSS_Alias && aliasCount == 0) continue;
2910 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2911 p = obj->dynamicProperties.next(p)) {
2913 if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2914 p->type == Object::DynamicProperty::Var)) ||
2915 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2916 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2919 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2920 QQmlPropertyData::IsVMESignal;
2922 if (p->nameIndex != -1) {
2923 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2924 p->name.length() + 7 /* strlen("Changed") */);
2925 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2927 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2929 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2935 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2936 int paramCount = s->parameterNames.count();
2938 QList<QByteArray> names;
2939 QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2942 paramTypes[0] = paramCount;
2944 for (int i = 0; i < paramCount; ++i) {
2945 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2946 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2947 names.append(s->parameterNames.at(i).toString().toUtf8());
2951 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2953 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2954 QQmlPropertyData::IsVMESignal;
2956 flags |= QQmlPropertyData::HasArguments;
2958 if (s->nameIndex != -1) {
2959 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2960 cache->appendSignal(name, flags, effectiveMethodIndex++,
2961 paramCount?paramTypes.constData():0, names);
2963 QString name = s->name.toString();
2964 cache->appendSignal(name, flags, effectiveMethodIndex++,
2965 paramCount?paramTypes.constData():0, names);
2971 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2972 int paramCount = s->parameterNames.count();
2974 quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
2977 flags |= QQmlPropertyData::HasArguments;
2979 if (s->nameIndex != -1) {
2980 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2981 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2983 QString name = s->name.toString();
2984 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2989 // Dynamic properties (except var and aliases)
2990 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
2991 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2992 p = obj->dynamicProperties.next(p)) {
2994 if (p->type == Object::DynamicProperty::Alias ||
2995 p->type == Object::DynamicProperty::Var)
2998 int propertyType = 0;
2999 int vmePropertyType = 0;
3000 quint32 propertyFlags = 0;
3002 if (p->type < builtinTypeCount) {
3003 propertyType = builtinTypes[p->type].metaType;
3004 vmePropertyType = propertyType;
3006 if (p->type == Object::DynamicProperty::Variant)
3007 propertyFlags |= QQmlPropertyData::IsQVariant;
3009 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3010 p->type == Object::DynamicProperty::Custom);
3012 QQmlType *qmltype = 0;
3014 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3015 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3018 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3020 Q_ASSERT(tdata->isComplete());
3022 QQmlCompiledData *data = tdata->compiledData();
3024 if (p->type == Object::DynamicProperty::Custom) {
3025 propertyType = data->metaTypeId;
3026 vmePropertyType = QMetaType::QObjectStar;
3028 propertyType = data->listMetaTypeId;
3029 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3034 if (p->type == Object::DynamicProperty::Custom) {
3035 propertyType = qmltype->typeId();
3036 vmePropertyType = QMetaType::QObjectStar;
3038 propertyType = qmltype->qListTypeId();
3039 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3043 if (p->type == Object::DynamicProperty::Custom)
3044 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3046 propertyFlags |= QQmlPropertyData::IsQList;
3049 if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3050 propertyFlags |= QQmlPropertyData::IsWritable;
3052 if (p->nameIndex != -1) {
3053 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3055 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3056 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3057 propertyType, effectiveSignalIndex);
3059 QString propertyName = p->name.toString();
3060 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3061 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3062 propertyType, effectiveSignalIndex);
3065 effectiveSignalIndex++;
3067 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3068 (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3069 vmd->propertyCount++;
3072 // Now do var properties
3073 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3074 p = obj->dynamicProperties.next(p)) {
3076 if (p->type != Object::DynamicProperty::Var)
3079 quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3081 propertyFlags |= QQmlPropertyData::IsWritable;
3083 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3084 (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3085 vmd->propertyCount++;
3086 ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3088 if (p->nameIndex != -1) {
3089 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3091 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3092 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3093 QMetaType::QVariant, effectiveSignalIndex);
3095 QString propertyName = p->name.toString();
3096 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3097 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3098 QMetaType::QVariant, effectiveSignalIndex);
3101 effectiveSignalIndex++;
3104 // Alias property count. Actual data is setup in buildDynamicMetaAliases
3105 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3107 // Dynamic slot data - comes after the property data
3108 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3109 int paramCount = s->parameterNames.count();
3113 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3114 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3115 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3116 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3117 for (int jj = 0; jj < paramCount; ++jj) {
3118 if (jj) funcScript.append(QLatin1Char(','));
3119 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3121 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3123 QByteArray utf8 = funcScript.toUtf8();
3124 VMD::MethodData methodData = { s->parameterNames.count(),
3127 s->location.start.line };
3129 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3130 VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3134 dynamicData.append((const char *)utf8.constData(), utf8.length());
3138 compileState->aliasingObjects.append(obj);
3140 obj->synthdata = dynamicData;
3141 obj->synthCache = cache;
3142 obj->metatype = cache;
3147 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3149 Q_ASSERT(obj->synthCache);
3151 QByteArray &dynamicData = obj->synthdata;
3153 QQmlPropertyCache *cache = obj->synthCache;
3154 char *cStringData = cache->_dynamicStringData.data();
3156 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
3157 int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3158 int effectiveAliasIndex = 0;
3160 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3161 p = obj->dynamicProperties.next(p)) {
3163 if (p->type != Object::DynamicProperty::Alias)
3166 if (!p->defaultValue)
3167 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3169 if (!p->defaultValue->values.isOne() ||
3170 p->defaultValue->values.first()->object ||
3171 !p->defaultValue->values.first()->value.isScript())
3172 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3174 QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3177 QStringList alias = astNodeToStringList(node);
3178 if (alias.count() < 1 || alias.count() > 3)
3179 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3181 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3183 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3186 int notifySignal = -1;
3189 bool writable = false;
3190 bool resettable = false;
3192 quint32 propertyFlags = QQmlPropertyData::IsAlias;
3194 if (alias.count() == 2 || alias.count() == 3) {
3195 QQmlPropertyData *property = this->property(idObject, alias.at(1));
3197 if (!property || property->coreIndex > 0xFFFF)
3198 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3200 propIdx = property->coreIndex;
3201 type = property->propType;
3203 writable = property->isWritable();
3204 resettable = property->isResettable();
3205 notifySignal = property->notifyIndex;
3207 if (alias.count() == 3) {
3208 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3210 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3212 propIdx |= ((unsigned int)type) << 24;
3213 int valueTypeIndex =
3214 valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3215 if (valueTypeIndex == -1)
3216 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3217 Q_ASSERT(valueTypeIndex <= 0xFF);
3219 propIdx |= (valueTypeIndex << 16);
3220 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3221 type = QVariant::Int;
3223 type = valueType->metaObject()->property(valueTypeIndex).userType();
3226 if (property->isEnum()) {
3227 type = QVariant::Int;
3230 propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3232 if (property->isVarProperty())
3233 propertyFlags |= QQmlPropertyData::IsQVariant;
3235 if (property->isQObject())
3236 flags |= QML_ALIAS_FLAG_PTR;
3240 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3242 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3244 type = ref.type->typeId();
3246 type = ref.component->metaTypeId;
3248 flags |= QML_ALIAS_FLAG_PTR;
3249 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3252 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3254 typedef QQmlVMEMetaData VMD;
3255 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3256 *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3258 if (!p->isReadOnly && writable)
3259 propertyFlags |= QQmlPropertyData::IsWritable;
3261 propertyFlags &= ~QQmlPropertyData::IsWritable;
3264 propertyFlags |= QQmlPropertyData::IsResettable;
3266 propertyFlags &= ~QQmlPropertyData::IsResettable;
3268 if (p->nameIndex != -1) {
3269 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3271 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3272 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3273 type, effectiveSignalIndex++);
3275 QString propertyName = p->name.toString();
3276 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3277 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3278 type, effectiveSignalIndex++);
3285 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3288 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3290 QChar ch = val.at(0);
3291 if (ch.isLetter() && !ch.isLower())
3292 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3294 QChar u(QLatin1Char('_'));
3295 if (!ch.isLetter() && ch != u)
3296 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3298 for (int ii = 1; ii < val.count(); ++ii) {
3300 if (!ch.isLetterOrNumber() && ch != u)
3301 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3304 if (enginePrivate->v8engine()->illegalNames().contains(val))
3305 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3310 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3311 QQmlScript::Property *prop,
3312 const BindingContext &ctxt)
3314 Q_ASSERT(prop->index != -1);
3315 Q_ASSERT(prop->parent);
3316 Q_ASSERT(prop->parent->metatype);
3318 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3319 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3321 JSBindingReference *reference = pool->New<JSBindingReference>();
3322 reference->expression = value->value;
3323 reference->property = prop;
3324 reference->value = value;
3325 reference->bindingContext = ctxt;
3326 addBindingReference(reference);
3331 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3332 QQmlScript::Property *prop,
3333 const QQmlCompilerTypes::BindingContext &)
3335 Q_ASSERT(v->value.isScript());
3337 if (!prop->core.isWritable())
3340 AST::Node *binding = v->value.asAST();
3342 if (prop->type == QVariant::String) {
3343 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3344 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3345 if (i->name == qsTrId_string) {
3346 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3347 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3349 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3350 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3351 (!arg2 || !arg2->next)) {
3356 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3357 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3359 TrBindingReference *reference = pool->New<TrBindingReference>();
3360 reference->dataType = BindingReference::TrId;
3361 reference->text = text;
3363 v->bindingReference = reference;
3367 } else if (i->name == qsTr_string) {
3369 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3370 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3371 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3373 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3374 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3375 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3376 (!arg3 || !arg3->next)) {
3382 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3383 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3384 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3386 TrBindingReference *reference = pool->New<TrBindingReference>();
3387 reference->dataType = BindingReference::Tr;
3388 reference->text = text;
3389 reference->comment = comment;
3391 v->bindingReference = reference;
3404 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3405 QQmlScript::Property *prop,
3406 QQmlScript::Object *obj,
3407 QQmlScript::Property *valueTypeProperty)
3410 Q_ASSERT(binding->bindingReference);
3412 const BindingReference &ref = *binding->bindingReference;
3413 if (ref.dataType == BindingReference::TrId) {
3414 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3416 Instruction::StoreTrIdString store;
3417 store.propertyIndex = prop->core.coreIndex;
3418 store.text = output->indexForByteArray(tr.text.toUtf8());
3420 output->addInstruction(store);
3421 } else if (ref.dataType == BindingReference::Tr) {
3422 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3424 Instruction::StoreTrString store;
3425 store.propertyIndex = prop->core.coreIndex;
3426 store.context = translationContextIndex();
3427 store.text = output->indexForByteArray(tr.text.toUtf8());
3428 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3430 output->addInstruction(store);
3431 } else if (ref.dataType == BindingReference::V4) {
3432 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3434 Instruction::StoreV4Binding store;
3435 store.value = js.compiledIndex;
3436 store.context = js.bindingContext.stack;
3437 store.owner = js.bindingContext.owner;
3438 store.isAlias = prop->isAlias;
3439 if (valueTypeProperty) {
3440 store.property = (valueTypeProperty->index & 0xFFFF) |
3441 ((valueTypeProperty->type & 0xFF)) << 16 |
3442 ((prop->index & 0xFF) << 24);
3443 store.isRoot = (compileState->root == valueTypeProperty->parent);
3445 store.property = prop->index;
3446 store.isRoot = (compileState->root == obj);
3448 store.line = binding->location.start.line;
3449 store.column = binding->location.start.column;
3450 output->addInstruction(store);
3451 } else if (ref.dataType == BindingReference::V8) {
3452 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3454 Instruction::StoreV8Binding store;
3455 store.value = js.compiledIndex;
3456 store.context = js.bindingContext.stack;
3457 store.owner = js.bindingContext.owner;
3458 store.isAlias = prop->isAlias;
3459 if (valueTypeProperty) {
3460 store.isRoot = (compileState->root == valueTypeProperty->parent);
3462 store.isRoot = (compileState->root == obj);
3464 store.line = binding->location.start.line;
3465 store.column = binding->location.start.column;
3467 Q_ASSERT(js.bindingContext.owner == 0 ||
3468 (js.bindingContext.owner != 0 && valueTypeProperty));
3469 if (js.bindingContext.owner) {
3470 store.property = genValueTypeData(prop, valueTypeProperty);
3472 store.property = prop->core;
3475 output->addInstruction(store);
3476 } else if (ref.dataType == BindingReference::QtScript) {
3477 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3479 Instruction::StoreBinding store;
3480 store.value = output->indexForString(js.rewrittenExpression);
3481 store.context = js.bindingContext.stack;
3482 store.owner = js.bindingContext.owner;
3483 store.line = binding->location.start.line;
3484 store.column = binding->location.start.column;
3485 store.isAlias = prop->isAlias;
3487 if (valueTypeProperty) {
3488 store.isRoot = (compileState->root == valueTypeProperty->parent);
3490 store.isRoot = (compileState->root == obj);
3493 Q_ASSERT(js.bindingContext.owner == 0 ||
3494 (js.bindingContext.owner != 0 && valueTypeProperty));
3495 if (js.bindingContext.owner) {
3496 store.property = genValueTypeData(prop, valueTypeProperty);
3498 store.property = prop->core;
3501 output->addInstruction(store);
3503 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3507 int QQmlCompiler::genContextCache()
3509 if (compileState->ids.count() == 0)
3512 QQmlIntegerCache *cache = new QQmlIntegerCache();
3513 cache->reserve(compileState->ids.count());
3514 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3515 cache->add(o->id, o->idIndex);
3517 output->contextCaches.append(cache);
3518 return output->contextCaches.count() - 1;
3522 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3523 QQmlScript::Property *prop)
3525 typedef QQmlPropertyPrivate QDPP;
3526 return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3527 valueTypeProp->index, engine);
3530 bool QQmlCompiler::completeComponentBuild()
3533 componentStats->componentStat.ids = compileState->ids.count();
3535 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3536 aliasObject = compileState->aliasingObjects.next(aliasObject))
3537 COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3539 QV4Compiler::Expression expr(unit->imports());
3540 expr.component = compileState->root;
3541 expr.ids = &compileState->ids;
3542 expr.importCache = output->importCache;
3544 QV4Compiler bindingCompiler;
3546 QList<JSBindingReference*> sharedBindings;
3548 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3550 JSBindingReference &binding = *b;
3553 expr.context = binding.bindingContext.object;
3554 expr.property = binding.property;
3555 expr.expression = binding.expression;
3557 int index = bindingCompiler.compile(expr, enginePrivate);
3559 binding.dataType = BindingReference::V4;
3560 binding.compiledIndex = index;
3562 componentStats->componentStat.optimizedBindings.append(b->value->location);
3566 // Pre-rewrite the expression
3567 QString expression = binding.expression.asScript();
3569 QQmlRewrite::RewriteBinding rewriteBinding;
3570 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3571 bool isSharable = false;
3572 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3574 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3575 binding.dataType = BindingReference::V8;
3576 sharedBindings.append(b);
3579 componentStats->componentStat.sharedBindings.append(b->value->location);
3581 binding.dataType = BindingReference::QtScript;
3584 componentStats->componentStat.scriptBindings.append(b->value->location);
3588 if (!sharedBindings.isEmpty()) {
3590 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3592 return lhs->value->location.start.line < rhs->value->location.start.line;
3596 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3598 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3599 int lineNumber = startLineNumber;
3601 QByteArray functionArray("[", 1);
3602 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3604 JSBindingReference *reference = sharedBindings.at(ii);
3605 QQmlScript::Value *value = reference->value;
3606 const QString &expression = reference->rewrittenExpression;
3608 if (ii != 0) functionArray.append(",", 1);
3610 while (lineNumber < value->location.start.line) {
3612 functionArray.append("\n", 1);
3615 functionArray += expression.toUtf8();
3616 lineNumber += expression.count(QLatin1Char('\n'));
3617 reference->compiledIndex = ii;
3619 functionArray.append("]", 1);
3621 compileState->v8BindingProgram = functionArray;
3622 compileState->v8BindingProgramLine = startLineNumber;
3625 if (bindingCompiler.isValid())
3626 compileState->compiledBindingData = bindingCompiler.program();
3628 // Check pop()'s matched push()'s
3629 Q_ASSERT(compileState->objectDepth.depth() == 0);
3630 Q_ASSERT(compileState->listDepth.depth() == 0);
3632 saveComponentState();
3637 void QQmlCompiler::dumpStats()
3639 Q_ASSERT(componentStats);
3640 qWarning().nospace() << "QML Document: " << output->url.toString();
3641 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3642 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3643 qWarning().nospace() << " Component Line " << stat.lineNumber;
3644 qWarning().nospace() << " Total Objects: " << stat.objects;
3645 qWarning().nospace() << " IDs Used: " << stat.ids;
3646 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3650 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3651 if (0 == (ii % 10)) {
3652 if (ii) output.append("\n");
3657 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3659 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3660 output.append(") ");
3662 if (!output.isEmpty())
3663 qWarning().nospace() << output.constData();
3666 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3669 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3670 if (0 == (ii % 10)) {
3671 if (ii) output.append('\n');
3676 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3678 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3679 output.append(") ");
3681 if (!output.isEmpty())
3682 qWarning().nospace() << output.constData();
3685 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3688 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3689 if (0 == (ii % 10)) {
3690 if (ii) output.append('\n');
3695 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3697 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3698 output.append(") ");
3700 if (!output.isEmpty())
3701 qWarning().nospace() << output.constData();
3707 Returns true if from can be assigned to a (QObject) property of type
3710 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3712 QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3713 QQmlPropertyCache *fromMo = from->metatype;
3718 fromMo = fromMo->parent();
3724 Returns the element name, as written in the QML file, for o.
3726 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3729 if (o->type != -1) {
3730 return unit->parser().referencedTypes().at(o->type)->name;
3736 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3738 if (from->type != -1 && output->types.at(from->type).type)
3739 return output->types.at(from->type).type;
3741 const QMetaObject *mo = from->metatype->firstCppMetaObject();
3743 while (!type && mo) {
3744 type = QQmlMetaType::qmlType(mo);
3745 mo = mo->superClass();
3750 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3752 const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3754 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3756 return QStringList();
3758 QMetaClassInfo classInfo = mo->classInfo(idx);
3759 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3764 QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
3766 if (object->synthCache)
3767 return object->synthCache;
3768 else if (object->type != -1)
3769 return output->types[object->type].createPropertyCache(engine);
3771 return object->metatype;
3775 QQmlCompiler::property(QQmlScript::Object *object, int index)
3777 QQmlPropertyCache *cache = propertyCacheForObject(object);
3779 return cache->property(index);
3783 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3785 if (notInRevision) *notInRevision = false;
3787 QQmlPropertyCache *cache = propertyCacheForObject(object);
3789 QQmlPropertyData *d = cache->property(name);
3791 // Find the first property
3792 while (d && d->isFunction())
3793 d = cache->overrideData(d);
3795 if (d && !cache->isAllowedInRevision(d)) {
3796 if (notInRevision) *notInRevision = true;
3803 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3805 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3807 if (notInRevision) *notInRevision = false;
3809 QQmlPropertyCache *cache = propertyCacheForObject(object);
3812 QQmlPropertyData *d = cache->property(name);
3813 if (notInRevision) *notInRevision = false;
3815 while (d && !(d->isFunction()))
3816 d = cache->overrideData(d);
3818 if (d && !cache->isAllowedInRevision(d)) {
3819 if (notInRevision) *notInRevision = true;
3821 } else if (d && d->isSignal()) {
3825 if (name.endsWith(Changed_string)) {
3826 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3828 d = property(object, propName, notInRevision);
3830 return cache->signal(d->notifyIndex);
3836 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3837 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3838 bool *notInRevision)
3840 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3841 return d?d->coreIndex:-1;
3844 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3845 bool *notInRevision)
3847 return indexOfProperty(object, QStringRef(&name), notInRevision);
3850 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3851 bool *notInRevision)
3853 QQmlPropertyData *d = property(object, name, notInRevision);
3854 return d?d->coreIndex:-1;