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
2550 // This matches the logic in QV8TypeWrapper
2551 QByteArray enumName = enumValue.toUtf8();
2552 const QMetaObject *metaObject = type ? type->baseMetaObject() : StaticQtMetaObject::get();
2554 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2555 QMetaEnum e = metaObject->enumerator(ii);
2556 value = e.keyToValue(enumName.constData(), &ok);
2563 v->type = Value::Literal;
2564 v->value = QQmlScript::Variant((double)value);
2565 *isAssignment = true;
2570 // Similar logic to above, but not knowing target property.
2571 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
2573 Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
2576 if (scope != QLatin1String("Qt")) {
2577 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2582 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2583 int i = mo->enumeratorCount();
2585 int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
2592 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2594 QQmlType *qmltype = 0;
2595 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2599 return qmltype->metaObject();
2602 // similar to logic of completeComponentBuild, but also sticks data
2603 // into primitives at the end
2604 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2606 QQmlRewrite::RewriteBinding rewriteBinding;
2607 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2609 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2611 return output->indexForString(rewrite);
2614 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2616 QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2617 return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2620 // Ensures that the dynamic meta specification on obj is valid
2621 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2623 bool seenDefaultProperty = false;
2625 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2626 // Calculating the hash for the names is not a waste as we have to test
2627 // them against the illegalNames set anyway.
2628 QHashField propNames;
2629 QHashField methodNames;
2632 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2633 const QQmlScript::Object::DynamicProperty &prop = *p;
2635 if (prop.isDefaultProperty) {
2636 if (seenDefaultProperty)
2637 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2638 seenDefaultProperty = true;
2641 if (propNames.testAndSet(prop.name.hash())) {
2642 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2643 p2 = obj->dynamicProperties.next(p2)) {
2644 if (p2->name == prop.name) {
2645 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2646 prop.nameLocation.column,
2647 tr("Duplicate property name"));
2652 if (prop.name.at(0).isUpper()) {
2653 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2654 prop.nameLocation.column,
2655 tr("Property names cannot begin with an upper case letter"));
2658 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2659 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2660 prop.nameLocation.column,
2661 tr("Illegal property name"));
2665 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2666 const QQmlScript::Object::DynamicSignal &currSig = *s;
2668 if (methodNames.testAndSet(currSig.name.hash())) {
2669 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2670 s2 = obj->dynamicSignals.next(s2)) {
2671 if (s2->name == currSig.name)
2672 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2676 if (currSig.name.at(0).isUpper())
2677 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2678 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2679 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2682 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2683 const QQmlScript::Object::DynamicSlot &currSlot = *s;
2685 if (methodNames.testAndSet(currSlot.name.hash())) {
2686 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2687 s2 = obj->dynamicSignals.next(s2)) {
2688 if (s2->name == currSlot.name)
2689 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2691 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2692 s2 = obj->dynamicSlots.next(s2)) {
2693 if (s2->name == currSlot.name)
2694 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2698 if (currSlot.name.at(0).isUpper())
2699 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2700 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2701 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2707 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2709 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2710 p = obj->dynamicProperties.next(p)) {
2712 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2715 Property *property = 0;
2716 if (p->isDefaultProperty) {
2717 property = obj->getDefaultProperty();
2719 property = obj->getProperty(p->name);
2720 if (!property->values.isEmpty())
2721 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2725 property->isReadOnlyDeclaration = true;
2727 if (property->value)
2728 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2730 property->values.append(p->defaultValue->values);
2735 #include <private/qqmljsparser_p.h>
2737 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2739 if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2741 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2742 return QStringList() << name;
2743 } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2744 QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2746 QStringList rv = astNodeToStringList(expr->base);
2749 rv.append(expr->name.toString());
2752 return QStringList();
2755 static QAtomicInt classIndexCounter(0);
2757 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2760 Q_ASSERT(obj->metatype);
2762 if (mode != ForceCreation &&
2763 obj->dynamicProperties.isEmpty() &&
2764 obj->dynamicSignals.isEmpty() &&
2765 obj->dynamicSlots.isEmpty())
2768 Q_ASSERT(obj->synthCache == 0);
2771 Object::DynamicProperty::Type dtype;
2773 } builtinTypes[] = {
2774 { Object::DynamicProperty::Var, QMetaType::QVariant },
2775 { Object::DynamicProperty::Variant, QMetaType::QVariant },
2776 { Object::DynamicProperty::Int, QMetaType::Int },
2777 { Object::DynamicProperty::Bool, QMetaType::Bool },
2778 { Object::DynamicProperty::Real, QMetaType::Double },
2779 { Object::DynamicProperty::String, QMetaType::QString },
2780 { Object::DynamicProperty::Url, QMetaType::QUrl },
2781 { Object::DynamicProperty::Color, QMetaType::QColor },
2782 { Object::DynamicProperty::Time, QMetaType::QTime },
2783 { Object::DynamicProperty::Date, QMetaType::QDate },
2784 { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2785 { Object::DynamicProperty::Rect, QMetaType::QRectF },
2787 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2789 QByteArray newClassName;
2791 if (compileState->root == obj && !compileState->nested) {
2792 QString path = output->url.path();
2793 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2794 if (lastSlash > -1) {
2795 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2796 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2797 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2798 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2801 if (newClassName.isEmpty()) {
2802 newClassName = QQmlMetaObject(obj->metatype).className();
2803 newClassName.append("_QML_");
2804 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2806 QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2807 obj->dynamicProperties.count() +
2808 obj->dynamicSignals.count() +
2809 obj->dynamicSlots.count(),
2810 obj->dynamicProperties.count() +
2811 obj->dynamicSignals.count());
2813 cache->_dynamicClassName = newClassName;
2815 int cStringNameCount = 0;
2818 int varPropCount = 0;
2820 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2821 p = obj->dynamicProperties.next(p)) {
2823 if (p->type == Object::DynamicProperty::Alias)
2825 else if (p->type == Object::DynamicProperty::Var)
2828 if (p->name.isLatin1()) {
2829 p->nameIndex = cStringNameCount;
2830 cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2833 // No point doing this for both the alias and non alias cases
2834 QQmlPropertyData *d = property(obj, p->name);
2835 if (d && d->isFinal())
2836 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2839 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2840 if (s->name.isLatin1()) {
2841 s->nameIndex = cStringNameCount;
2842 cStringNameCount += s->name.length();
2846 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2847 if (s->name.isLatin1()) {
2848 s->nameIndex = cStringNameCount;
2849 cStringNameCount += s->name.length();
2853 char *cStringData = 0;
2854 if (cStringNameCount) {
2855 cache->_dynamicStringData.resize(cStringNameCount);
2856 cStringData = cache->_dynamicStringData.data();
2858 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2859 p = obj->dynamicProperties.next(p)) {
2861 if (p->nameIndex == -1) continue;
2863 char *myData = cStringData + p->nameIndex;
2864 for (int ii = 0; ii < p->name.length(); ++ii)
2865 *myData++ = p->name.at(ii).unicode();
2866 *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2867 *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2870 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2872 if (s->nameIndex == -1) continue;
2874 char *myData = cStringData + s->nameIndex;
2875 for (int ii = 0; ii < s->name.length(); ++ii)
2876 *myData++ = s->name.at(ii).unicode();
2879 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2880 s = obj->dynamicSignals.next(s)) {
2882 if (s->nameIndex == -1) continue;
2884 char *myData = cStringData + s->nameIndex;
2885 for (int ii = 0; ii < s->name.length(); ++ii)
2886 *myData++ = s->name.at(ii).unicode();
2890 QByteArray dynamicData;
2891 typedef QQmlVMEMetaData VMD;
2893 dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2894 obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2895 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2896 aliasCount * sizeof(VMD::AliasData), 0);
2898 int effectivePropertyIndex = cache->propertyIndexCacheStart;
2899 int effectiveMethodIndex = cache->methodIndexCacheStart;
2901 // First set up notify signals for properties - first normal, then var, then alias
2902 enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2903 for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2905 if (ii == NSS_Var && varPropCount == 0) continue;
2906 else if (ii == NSS_Alias && aliasCount == 0) continue;
2908 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2909 p = obj->dynamicProperties.next(p)) {
2911 if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2912 p->type == Object::DynamicProperty::Var)) ||
2913 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2914 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2917 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2918 QQmlPropertyData::IsVMESignal;
2920 if (p->nameIndex != -1) {
2921 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2922 p->name.length() + 7 /* strlen("Changed") */);
2923 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2925 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2927 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2933 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2934 int paramCount = s->parameterNames.count();
2936 QList<QByteArray> names;
2937 QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2940 paramTypes[0] = paramCount;
2942 for (int i = 0; i < paramCount; ++i) {
2943 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2944 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2945 names.append(s->parameterNames.at(i).toString().toUtf8());
2949 ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2951 quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2952 QQmlPropertyData::IsVMESignal;
2954 flags |= QQmlPropertyData::HasArguments;
2956 if (s->nameIndex != -1) {
2957 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2958 cache->appendSignal(name, flags, effectiveMethodIndex++,
2959 paramCount?paramTypes.constData():0, names);
2961 QString name = s->name.toString();
2962 cache->appendSignal(name, flags, effectiveMethodIndex++,
2963 paramCount?paramTypes.constData():0, names);
2969 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2970 int paramCount = s->parameterNames.count();
2972 quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
2975 flags |= QQmlPropertyData::HasArguments;
2977 if (s->nameIndex != -1) {
2978 QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2979 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2981 QString name = s->name.toString();
2982 cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2987 // Dynamic properties (except var and aliases)
2988 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
2989 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2990 p = obj->dynamicProperties.next(p)) {
2992 if (p->type == Object::DynamicProperty::Alias ||
2993 p->type == Object::DynamicProperty::Var)
2996 int propertyType = 0;
2997 int vmePropertyType = 0;
2998 quint32 propertyFlags = 0;
3000 if (p->type < builtinTypeCount) {
3001 propertyType = builtinTypes[p->type].metaType;
3002 vmePropertyType = propertyType;
3004 if (p->type == Object::DynamicProperty::Variant)
3005 propertyFlags |= QQmlPropertyData::IsQVariant;
3007 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3008 p->type == Object::DynamicProperty::Custom);
3010 QQmlType *qmltype = 0;
3012 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3013 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3016 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3018 Q_ASSERT(tdata->isComplete());
3020 QQmlCompiledData *data = tdata->compiledData();
3022 if (p->type == Object::DynamicProperty::Custom) {
3023 propertyType = data->metaTypeId;
3024 vmePropertyType = QMetaType::QObjectStar;
3026 propertyType = data->listMetaTypeId;
3027 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3032 if (p->type == Object::DynamicProperty::Custom) {
3033 propertyType = qmltype->typeId();
3034 vmePropertyType = QMetaType::QObjectStar;
3036 propertyType = qmltype->qListTypeId();
3037 vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3041 if (p->type == Object::DynamicProperty::Custom)
3042 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3044 propertyFlags |= QQmlPropertyData::IsQList;
3047 if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3048 propertyFlags |= QQmlPropertyData::IsWritable;
3050 if (p->nameIndex != -1) {
3051 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3053 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3054 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3055 propertyType, effectiveSignalIndex);
3057 QString propertyName = p->name.toString();
3058 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3059 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3060 propertyType, effectiveSignalIndex);
3063 effectiveSignalIndex++;
3065 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3066 (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3067 vmd->propertyCount++;
3070 // Now do var properties
3071 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3072 p = obj->dynamicProperties.next(p)) {
3074 if (p->type != Object::DynamicProperty::Var)
3077 quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3079 propertyFlags |= QQmlPropertyData::IsWritable;
3081 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3082 (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3083 vmd->propertyCount++;
3084 ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3086 if (p->nameIndex != -1) {
3087 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3089 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3090 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3091 QMetaType::QVariant, effectiveSignalIndex);
3093 QString propertyName = p->name.toString();
3094 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3095 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3096 QMetaType::QVariant, effectiveSignalIndex);
3099 effectiveSignalIndex++;
3102 // Alias property count. Actual data is setup in buildDynamicMetaAliases
3103 ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3105 // Dynamic slot data - comes after the property data
3106 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3107 int paramCount = s->parameterNames.count();
3111 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3112 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3113 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3114 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3115 for (int jj = 0; jj < paramCount; ++jj) {
3116 if (jj) funcScript.append(QLatin1Char(','));
3117 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3119 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3121 QByteArray utf8 = funcScript.toUtf8();
3122 VMD::MethodData methodData = { s->parameterNames.count(),
3125 s->location.start.line };
3127 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3128 VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3132 dynamicData.append((const char *)utf8.constData(), utf8.length());
3136 compileState->aliasingObjects.append(obj);
3138 obj->synthdata = dynamicData;
3139 obj->synthCache = cache;
3140 obj->metatype = cache;
3145 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3147 Q_ASSERT(obj->synthCache);
3149 QByteArray &dynamicData = obj->synthdata;
3151 QQmlPropertyCache *cache = obj->synthCache;
3152 char *cStringData = cache->_dynamicStringData.data();
3154 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
3155 int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3156 int effectiveAliasIndex = 0;
3158 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3159 p = obj->dynamicProperties.next(p)) {
3161 if (p->type != Object::DynamicProperty::Alias)
3164 if (!p->defaultValue)
3165 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3167 if (!p->defaultValue->values.isOne() ||
3168 p->defaultValue->values.first()->object ||
3169 !p->defaultValue->values.first()->value.isScript())
3170 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3172 QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3175 QStringList alias = astNodeToStringList(node);
3176 if (alias.count() < 1 || alias.count() > 3)
3177 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3179 QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3181 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3184 int notifySignal = -1;
3187 bool writable = false;
3188 bool resettable = false;
3190 quint32 propertyFlags = QQmlPropertyData::IsAlias;
3192 if (alias.count() == 2 || alias.count() == 3) {
3193 QQmlPropertyData *property = this->property(idObject, alias.at(1));
3195 if (!property || property->coreIndex > 0xFFFF)
3196 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3198 propIdx = property->coreIndex;
3199 type = property->propType;
3201 writable = property->isWritable();
3202 resettable = property->isResettable();
3203 notifySignal = property->notifyIndex;
3205 if (alias.count() == 3) {
3206 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3208 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3210 propIdx |= ((unsigned int)type) << 24;
3211 int valueTypeIndex =
3212 valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3213 if (valueTypeIndex == -1)
3214 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3215 Q_ASSERT(valueTypeIndex <= 0xFF);
3217 propIdx |= (valueTypeIndex << 16);
3218 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3219 type = QVariant::Int;
3221 type = valueType->metaObject()->property(valueTypeIndex).userType();
3224 if (property->isEnum()) {
3225 type = QVariant::Int;
3228 propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3230 if (property->isVarProperty())
3231 propertyFlags |= QQmlPropertyData::IsQVariant;
3233 if (property->isQObject())
3234 flags |= QML_ALIAS_FLAG_PTR;
3238 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3240 const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3242 type = ref.type->typeId();
3244 type = ref.component->metaTypeId;
3246 flags |= QML_ALIAS_FLAG_PTR;
3247 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3250 QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3252 typedef QQmlVMEMetaData VMD;
3253 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3254 *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3256 if (!p->isReadOnly && writable)
3257 propertyFlags |= QQmlPropertyData::IsWritable;
3259 propertyFlags &= ~QQmlPropertyData::IsWritable;
3262 propertyFlags |= QQmlPropertyData::IsResettable;
3264 propertyFlags &= ~QQmlPropertyData::IsResettable;
3266 if (p->nameIndex != -1) {
3267 QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3269 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3270 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3271 type, effectiveSignalIndex++);
3273 QString propertyName = p->name.toString();
3274 if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3275 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3276 type, effectiveSignalIndex++);
3283 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3286 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3288 QChar ch = val.at(0);
3289 if (ch.isLetter() && !ch.isLower())
3290 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3292 QChar u(QLatin1Char('_'));
3293 if (!ch.isLetter() && ch != u)
3294 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3296 for (int ii = 1; ii < val.count(); ++ii) {
3298 if (!ch.isLetterOrNumber() && ch != u)
3299 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3302 if (enginePrivate->v8engine()->illegalNames().contains(val))
3303 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3308 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3309 QQmlScript::Property *prop,
3310 const BindingContext &ctxt)
3312 Q_ASSERT(prop->index != -1);
3313 Q_ASSERT(prop->parent);
3314 Q_ASSERT(prop->parent->metatype);
3316 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3317 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3319 JSBindingReference *reference = pool->New<JSBindingReference>();
3320 reference->expression = value->value;
3321 reference->property = prop;
3322 reference->value = value;
3323 reference->bindingContext = ctxt;
3324 addBindingReference(reference);
3329 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3330 QQmlScript::Property *prop,
3331 const QQmlCompilerTypes::BindingContext &)
3333 Q_ASSERT(v->value.isScript());
3335 if (!prop->core.isWritable())
3338 AST::Node *binding = v->value.asAST();
3340 if (prop->type == QVariant::String) {
3341 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3342 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3343 if (i->name == qsTrId_string) {
3344 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3345 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3347 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3348 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3349 (!arg2 || !arg2->next)) {
3354 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3355 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3357 TrBindingReference *reference = pool->New<TrBindingReference>();
3358 reference->dataType = BindingReference::TrId;
3359 reference->text = text;
3361 v->bindingReference = reference;
3365 } else if (i->name == qsTr_string) {
3367 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3368 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3369 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3371 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3372 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3373 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3374 (!arg3 || !arg3->next)) {
3380 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3381 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3382 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3384 TrBindingReference *reference = pool->New<TrBindingReference>();
3385 reference->dataType = BindingReference::Tr;
3386 reference->text = text;
3387 reference->comment = comment;
3389 v->bindingReference = reference;
3402 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3403 QQmlScript::Property *prop,
3404 QQmlScript::Object *obj,
3405 QQmlScript::Property *valueTypeProperty)
3408 Q_ASSERT(binding->bindingReference);
3410 const BindingReference &ref = *binding->bindingReference;
3411 if (ref.dataType == BindingReference::TrId) {
3412 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3414 Instruction::StoreTrIdString store;
3415 store.propertyIndex = prop->core.coreIndex;
3416 store.text = output->indexForByteArray(tr.text.toUtf8());
3418 output->addInstruction(store);
3419 } else if (ref.dataType == BindingReference::Tr) {
3420 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3422 Instruction::StoreTrString store;
3423 store.propertyIndex = prop->core.coreIndex;
3424 store.context = translationContextIndex();
3425 store.text = output->indexForByteArray(tr.text.toUtf8());
3426 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3428 output->addInstruction(store);
3429 } else if (ref.dataType == BindingReference::V4) {
3430 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3432 Instruction::StoreV4Binding store;
3433 store.value = js.compiledIndex;
3434 store.context = js.bindingContext.stack;
3435 store.owner = js.bindingContext.owner;
3436 store.isAlias = prop->isAlias;
3437 if (valueTypeProperty) {
3438 store.property = (valueTypeProperty->index & 0xFFFF) |
3439 ((valueTypeProperty->type & 0xFF)) << 16 |
3440 ((prop->index & 0xFF) << 24);
3441 store.isRoot = (compileState->root == valueTypeProperty->parent);
3443 store.property = prop->index;
3444 store.isRoot = (compileState->root == obj);
3446 store.line = binding->location.start.line;
3447 store.column = binding->location.start.column;
3448 output->addInstruction(store);
3449 } else if (ref.dataType == BindingReference::V8) {
3450 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3452 Instruction::StoreV8Binding store;
3453 store.value = js.compiledIndex;
3454 store.context = js.bindingContext.stack;
3455 store.owner = js.bindingContext.owner;
3456 store.isAlias = prop->isAlias;
3457 if (valueTypeProperty) {
3458 store.isRoot = (compileState->root == valueTypeProperty->parent);
3460 store.isRoot = (compileState->root == obj);
3462 store.line = binding->location.start.line;
3463 store.column = binding->location.start.column;
3465 Q_ASSERT(js.bindingContext.owner == 0 ||
3466 (js.bindingContext.owner != 0 && valueTypeProperty));
3467 if (js.bindingContext.owner) {
3468 store.property = genValueTypeData(prop, valueTypeProperty);
3470 store.property = prop->core;
3473 output->addInstruction(store);
3474 } else if (ref.dataType == BindingReference::QtScript) {
3475 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3477 Instruction::StoreBinding store;
3478 store.value = output->indexForString(js.rewrittenExpression);
3479 store.context = js.bindingContext.stack;
3480 store.owner = js.bindingContext.owner;
3481 store.line = binding->location.start.line;
3482 store.column = binding->location.start.column;
3483 store.isAlias = prop->isAlias;
3485 if (valueTypeProperty) {
3486 store.isRoot = (compileState->root == valueTypeProperty->parent);
3488 store.isRoot = (compileState->root == obj);
3491 Q_ASSERT(js.bindingContext.owner == 0 ||
3492 (js.bindingContext.owner != 0 && valueTypeProperty));
3493 if (js.bindingContext.owner) {
3494 store.property = genValueTypeData(prop, valueTypeProperty);
3496 store.property = prop->core;
3499 output->addInstruction(store);
3501 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3505 int QQmlCompiler::genContextCache()
3507 if (compileState->ids.count() == 0)
3510 QQmlIntegerCache *cache = new QQmlIntegerCache();
3511 cache->reserve(compileState->ids.count());
3512 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3513 cache->add(o->id, o->idIndex);
3515 output->contextCaches.append(cache);
3516 return output->contextCaches.count() - 1;
3520 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
3521 QQmlScript::Property *prop)
3523 typedef QQmlPropertyPrivate QDPP;
3524 return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3525 valueTypeProp->index, engine);
3528 bool QQmlCompiler::completeComponentBuild()
3531 componentStats->componentStat.ids = compileState->ids.count();
3533 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3534 aliasObject = compileState->aliasingObjects.next(aliasObject))
3535 COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3537 QV4Compiler::Expression expr(unit->imports());
3538 expr.component = compileState->root;
3539 expr.ids = &compileState->ids;
3540 expr.importCache = output->importCache;
3542 QV4Compiler bindingCompiler;
3544 QList<JSBindingReference*> sharedBindings;
3546 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3548 JSBindingReference &binding = *b;
3551 expr.context = binding.bindingContext.object;
3552 expr.property = binding.property;
3553 expr.expression = binding.expression;
3555 int index = bindingCompiler.compile(expr, enginePrivate);
3557 binding.dataType = BindingReference::V4;
3558 binding.compiledIndex = index;
3560 componentStats->componentStat.optimizedBindings.append(b->value->location);
3564 // Pre-rewrite the expression
3565 QString expression = binding.expression.asScript();
3567 QQmlRewrite::RewriteBinding rewriteBinding;
3568 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3569 bool isSharable = false;
3570 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3572 if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3573 binding.dataType = BindingReference::V8;
3574 sharedBindings.append(b);
3577 componentStats->componentStat.sharedBindings.append(b->value->location);
3579 binding.dataType = BindingReference::QtScript;
3582 componentStats->componentStat.scriptBindings.append(b->value->location);
3586 if (!sharedBindings.isEmpty()) {
3588 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3590 return lhs->value->location.start.line < rhs->value->location.start.line;
3594 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3596 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3597 int lineNumber = startLineNumber;
3599 QByteArray functionArray("[", 1);
3600 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3602 JSBindingReference *reference = sharedBindings.at(ii);
3603 QQmlScript::Value *value = reference->value;
3604 const QString &expression = reference->rewrittenExpression;
3606 if (ii != 0) functionArray.append(",", 1);
3608 while (lineNumber < value->location.start.line) {
3610 functionArray.append("\n", 1);
3613 functionArray += expression.toUtf8();
3614 lineNumber += expression.count(QLatin1Char('\n'));
3615 reference->compiledIndex = ii;
3617 functionArray.append("]", 1);
3619 compileState->v8BindingProgram = functionArray;
3620 compileState->v8BindingProgramLine = startLineNumber;
3623 if (bindingCompiler.isValid())
3624 compileState->compiledBindingData = bindingCompiler.program();
3626 // Check pop()'s matched push()'s
3627 Q_ASSERT(compileState->objectDepth.depth() == 0);
3628 Q_ASSERT(compileState->listDepth.depth() == 0);
3630 saveComponentState();
3635 void QQmlCompiler::dumpStats()
3637 Q_ASSERT(componentStats);
3638 qWarning().nospace() << "QML Document: " << output->url.toString();
3639 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3640 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3641 qWarning().nospace() << " Component Line " << stat.lineNumber;
3642 qWarning().nospace() << " Total Objects: " << stat.objects;
3643 qWarning().nospace() << " IDs Used: " << stat.ids;
3644 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3648 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3649 if (0 == (ii % 10)) {
3650 if (ii) output.append("\n");
3655 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3657 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3658 output.append(") ");
3660 if (!output.isEmpty())
3661 qWarning().nospace() << output.constData();
3664 qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
3667 for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3668 if (0 == (ii % 10)) {
3669 if (ii) output.append('\n');
3674 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3676 output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3677 output.append(") ");
3679 if (!output.isEmpty())
3680 qWarning().nospace() << output.constData();
3683 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3686 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3687 if (0 == (ii % 10)) {
3688 if (ii) output.append('\n');
3693 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3695 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3696 output.append(") ");
3698 if (!output.isEmpty())
3699 qWarning().nospace() << output.constData();
3705 Returns true if from can be assigned to a (QObject) property of type
3708 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3710 QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3711 QQmlPropertyCache *fromMo = from->metatype;
3716 fromMo = fromMo->parent();
3722 Returns the element name, as written in the QML file, for o.
3724 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3727 if (o->type != -1) {
3728 return unit->parser().referencedTypes().at(o->type)->name;
3734 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3736 if (from->type != -1 && output->types.at(from->type).type)
3737 return output->types.at(from->type).type;
3739 const QMetaObject *mo = from->metatype->firstCppMetaObject();
3741 while (!type && mo) {
3742 type = QQmlMetaType::qmlType(mo);
3743 mo = mo->superClass();
3748 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3750 const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3752 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3754 return QStringList();
3756 QMetaClassInfo classInfo = mo->classInfo(idx);
3757 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3762 QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
3764 if (object->synthCache)
3765 return object->synthCache;
3766 else if (object->type != -1)
3767 return output->types[object->type].createPropertyCache(engine);
3769 return object->metatype;
3773 QQmlCompiler::property(QQmlScript::Object *object, int index)
3775 QQmlPropertyCache *cache = propertyCacheForObject(object);
3777 return cache->property(index);
3781 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3783 if (notInRevision) *notInRevision = false;
3785 QQmlPropertyCache *cache = propertyCacheForObject(object);
3787 QQmlPropertyData *d = cache->property(name);
3789 // Find the first property
3790 while (d && d->isFunction())
3791 d = cache->overrideData(d);
3793 if (d && !cache->isAllowedInRevision(d)) {
3794 if (notInRevision) *notInRevision = true;
3801 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3803 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3805 if (notInRevision) *notInRevision = false;
3807 QQmlPropertyCache *cache = propertyCacheForObject(object);
3810 QQmlPropertyData *d = cache->property(name);
3811 if (notInRevision) *notInRevision = false;
3813 while (d && !(d->isFunction()))
3814 d = cache->overrideData(d);
3816 if (d && !cache->isAllowedInRevision(d)) {
3817 if (notInRevision) *notInRevision = true;
3819 } else if (d && d->isSignal()) {
3823 if (name.endsWith(Changed_string)) {
3824 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3826 d = property(object, propName, notInRevision);
3828 return cache->signal(d->notifyIndex);
3834 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3835 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
3836 bool *notInRevision)
3838 QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3839 return d?d->coreIndex:-1;
3842 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
3843 bool *notInRevision)
3845 return indexOfProperty(object, QStringRef(&name), notInRevision);
3848 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
3849 bool *notInRevision)
3851 QQmlPropertyData *d = property(object, name, notInRevision);
3852 return d?d->coreIndex:-1;