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 QtDeclarative 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 "qdeclarativecompiler_p.h"
44 #include "qdeclarativepropertyvaluesource.h"
45 #include "qdeclarativecomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qdeclarativestringconverters_p.h"
49 #include "qdeclarativeengine_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativecontext.h"
52 #include "qdeclarativemetatype_p.h"
53 #include "qdeclarativecustomparser_p_p.h"
54 #include "qdeclarativecontext_p.h"
55 #include "qdeclarativecomponent_p.h"
56 #include <private/qdeclarativejsast_p.h>
57 #include "qdeclarativevmemetaobject_p.h"
58 #include "qdeclarativeexpression_p.h"
59 #include "qdeclarativeproperty_p.h"
60 #include "qdeclarativerewrite_p.h"
61 #include "qdeclarativescriptstring.h"
62 #include "qdeclarativeglobal_p.h"
63 #include "qdeclarativebinding_p.h"
64 #include <private/qv4compiler_p.h>
72 #include <QtCore/qdebug.h>
73 #include <QtCore/qdatetime.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QDeclarativeJS;
87 using namespace QDeclarativeScript;
88 using namespace QDeclarativeCompilerTypes;
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_import_string(QLatin1String("QML/Component"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QDeclarativeCompiler.
101 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
102 : pool(pool), output(0), engine(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 QDeclarativeCompiler::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<QDeclarativeError> QDeclarativeCompiler::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 QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QDeclarativeCompiler::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 QDeclarativeCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QDeclarativeCompiler::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 QDeclarativeCompiler 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) \
190 QDeclarativeError error; \
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 QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *prop,
220 QDeclarativeScript::Value *v)
222 const QDeclarativeScript::Variant &value = v->value;
224 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
225 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
227 if (prop->core.isEnum()) {
228 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
231 if (p.isFlagType()) {
232 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
234 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
237 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
239 v->value = QDeclarativeScript::Variant((double)enumValue);
243 int type = prop->type;
246 case QMetaType::QVariant:
248 case QVariant::String:
249 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
251 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
252 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
254 case QVariant::ByteArray:
255 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
258 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
260 case QVariant::RegExp:
261 COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
265 bool ok = v->value.isNumber();
267 double n = v->value.asNumber();
268 if (double(uint(n)) != n)
271 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
276 bool ok = v->value.isNumber();
278 double n = v->value.asNumber();
279 if (double(int(n)) != n)
282 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
285 case QMetaType::Float:
286 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
288 case QVariant::Double:
289 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
291 case QVariant::Color:
294 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
295 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
298 #ifndef QT_NO_DATESTRING
302 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
303 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
309 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
310 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
313 case QVariant::DateTime:
316 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
317 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
320 #endif // QT_NO_DATESTRING
321 case QVariant::Point:
322 case QVariant::PointF:
325 QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
326 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
330 case QVariant::SizeF:
333 QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
334 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
338 case QVariant::RectF:
341 QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
342 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
347 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
350 case QVariant::Vector3D:
353 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
354 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
357 case QVariant::Vector4D:
360 QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok);
361 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
366 // check if assigning a literal value to a list property.
367 // in each case, check the singular, since an Array of the specified type
368 // will not go via this literal assignment codepath.
369 if (type == qMetaTypeId<QList<qreal> >()) {
370 if (!v->value.isNumber()) {
371 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
374 } else if (type == qMetaTypeId<QList<int> >()) {
375 bool ok = v->value.isNumber();
377 double n = v->value.asNumber();
378 if (double(int(n)) != n)
381 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
383 } else if (type == qMetaTypeId<QList<bool> >()) {
384 if (!v->value.isBoolean()) {
385 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
388 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
389 if (!v->value.isString()) {
390 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
393 } else if (type == qMetaTypeId<QList<QUrl> >()) {
394 if (!v->value.isString()) {
395 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
400 // otherwise, check for existence of string converter to custom type
401 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
403 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
410 static QUrl urlFromUserString(const QString &data)
413 // Preserve any valid percent-encoded octets supplied by the source
414 u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
419 Generate a store instruction for assigning literal \a v to property \a prop.
421 Any literal assignment that is approved in testLiteralAssignment() must have
422 a corresponding action in this method.
424 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop,
425 QDeclarativeScript::Value *v)
427 if (prop->core.isEnum()) {
428 Q_ASSERT(v->value.isNumber());
430 int value = (int)v->value.asNumber();
432 Instruction::StoreInteger instr;
433 instr.propertyIndex = prop->index;
435 output->addInstruction(instr);
439 int type = prop->type;
441 case QMetaType::QVariant:
443 if (v->value.isNumber()) {
444 double n = v->value.asNumber();
445 if (double(int(n)) == n) {
446 if (prop->core.isVMEProperty()) {
447 Instruction::StoreVarInteger instr;
448 instr.propertyIndex = prop->index;
449 instr.value = int(n);
450 output->addInstruction(instr);
452 Instruction::StoreVariantInteger instr;
453 instr.propertyIndex = prop->index;
454 instr.value = int(n);
455 output->addInstruction(instr);
458 if (prop->core.isVMEProperty()) {
459 Instruction::StoreVarDouble instr;
460 instr.propertyIndex = prop->index;
462 output->addInstruction(instr);
464 Instruction::StoreVariantDouble instr;
465 instr.propertyIndex = prop->index;
467 output->addInstruction(instr);
470 } else if (v->value.isBoolean()) {
471 if (prop->core.isVMEProperty()) {
472 Instruction::StoreVarBool instr;
473 instr.propertyIndex = prop->index;
474 instr.value = v->value.asBoolean();
475 output->addInstruction(instr);
477 Instruction::StoreVariantBool instr;
478 instr.propertyIndex = prop->index;
479 instr.value = v->value.asBoolean();
480 output->addInstruction(instr);
483 if (prop->core.isVMEProperty()) {
484 Instruction::StoreVar instr;
485 instr.propertyIndex = prop->index;
486 instr.value = output->indexForString(v->value.asString());
487 output->addInstruction(instr);
489 Instruction::StoreVariant instr;
490 instr.propertyIndex = prop->index;
491 instr.value = output->indexForString(v->value.asString());
492 output->addInstruction(instr);
497 case QVariant::String:
499 Instruction::StoreString instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForString(v->value.asString());
502 output->addInstruction(instr);
505 case QVariant::StringList:
507 Instruction::StoreStringList instr;
508 instr.propertyIndex = prop->index;
509 instr.value = output->indexForString(v->value.asString());
510 output->addInstruction(instr);
513 case QVariant::ByteArray:
515 Instruction::StoreByteArray instr;
516 instr.propertyIndex = prop->index;
517 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
518 output->addInstruction(instr);
523 Instruction::StoreUrl instr;
524 QString string = v->value.asString();
525 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
526 instr.propertyIndex = prop->index;
527 instr.value = output->indexForUrl(u);
528 output->addInstruction(instr);
533 Instruction::StoreInteger instr;
534 instr.propertyIndex = prop->index;
535 instr.value = uint(v->value.asNumber());
536 output->addInstruction(instr);
541 Instruction::StoreInteger instr;
542 instr.propertyIndex = prop->index;
543 instr.value = int(v->value.asNumber());
544 output->addInstruction(instr);
547 case QMetaType::Float:
549 Instruction::StoreFloat instr;
550 instr.propertyIndex = prop->index;
551 instr.value = float(v->value.asNumber());
552 output->addInstruction(instr);
555 case QVariant::Double:
557 Instruction::StoreDouble instr;
558 instr.propertyIndex = prop->index;
559 instr.value = v->value.asNumber();
560 output->addInstruction(instr);
563 case QVariant::Color:
565 Instruction::StoreColor instr;
566 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
567 instr.propertyIndex = prop->index;
568 instr.value = c.rgba();
569 output->addInstruction(instr);
572 #ifndef QT_NO_DATESTRING
575 Instruction::StoreDate instr;
576 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
577 instr.propertyIndex = prop->index;
578 instr.value = d.toJulianDay();
579 output->addInstruction(instr);
584 Instruction::StoreTime instr;
585 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
586 instr.propertyIndex = prop->index;
587 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
588 ::memcpy(&instr.time, &time, sizeof(QTime));
589 output->addInstruction(instr);
592 case QVariant::DateTime:
594 Instruction::StoreDateTime instr;
595 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
596 QTime time = dateTime.time();
597 instr.propertyIndex = prop->index;
598 instr.date = dateTime.date().toJulianDay();
599 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
600 ::memcpy(&instr.time, &time, sizeof(QTime));
601 output->addInstruction(instr);
604 #endif // QT_NO_DATESTRING
605 case QVariant::Point:
607 Instruction::StorePoint instr;
609 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
610 instr.propertyIndex = prop->index;
611 instr.point.xp = point.x();
612 instr.point.yp = point.y();
613 output->addInstruction(instr);
616 case QVariant::PointF:
618 Instruction::StorePointF instr;
620 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
621 instr.propertyIndex = prop->index;
622 instr.point.xp = point.x();
623 instr.point.yp = point.y();
624 output->addInstruction(instr);
629 Instruction::StoreSize instr;
631 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
632 instr.propertyIndex = prop->index;
633 instr.size.wd = size.width();
634 instr.size.ht = size.height();
635 output->addInstruction(instr);
638 case QVariant::SizeF:
640 Instruction::StoreSizeF instr;
642 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
643 instr.propertyIndex = prop->index;
644 instr.size.wd = size.width();
645 instr.size.ht = size.height();
646 output->addInstruction(instr);
651 Instruction::StoreRect instr;
653 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
654 instr.propertyIndex = prop->index;
655 instr.rect.x1 = rect.left();
656 instr.rect.y1 = rect.top();
657 instr.rect.x2 = rect.right();
658 instr.rect.y2 = rect.bottom();
659 output->addInstruction(instr);
662 case QVariant::RectF:
664 Instruction::StoreRectF instr;
666 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
667 instr.propertyIndex = prop->index;
668 instr.rect.xp = rect.left();
669 instr.rect.yp = rect.top();
670 instr.rect.w = rect.width();
671 instr.rect.h = rect.height();
672 output->addInstruction(instr);
677 Instruction::StoreBool instr;
678 bool b = v->value.asBoolean();
679 instr.propertyIndex = prop->index;
681 output->addInstruction(instr);
684 case QVariant::Vector3D:
686 Instruction::StoreVector3D instr;
688 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
689 instr.propertyIndex = prop->index;
690 instr.vector.xp = vector.x();
691 instr.vector.yp = vector.y();
692 instr.vector.zp = vector.z();
693 output->addInstruction(instr);
696 case QVariant::Vector4D:
698 Instruction::StoreVector4D instr;
700 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
701 instr.propertyIndex = prop->index;
702 instr.vector.xp = vector.x();
703 instr.vector.yp = vector.y();
704 instr.vector.zp = vector.z();
705 instr.vector.wp = vector.w();
706 output->addInstruction(instr);
711 // generate single literal value assignment to a list property if required
712 if (type == qMetaTypeId<QList<qreal> >()) {
713 Instruction::StoreDoubleQList instr;
714 instr.propertyIndex = prop->index;
715 instr.value = v->value.asNumber();
716 output->addInstruction(instr);
718 } else if (type == qMetaTypeId<QList<int> >()) {
719 Instruction::StoreIntegerQList instr;
720 instr.propertyIndex = prop->index;
721 instr.value = int(v->value.asNumber());
722 output->addInstruction(instr);
724 } else if (type == qMetaTypeId<QList<bool> >()) {
725 Instruction::StoreBoolQList instr;
726 bool b = v->value.asBoolean();
727 instr.propertyIndex = prop->index;
729 output->addInstruction(instr);
731 } else if (type == qMetaTypeId<QList<QUrl> >()) {
732 Instruction::StoreUrlQList instr;
733 QString string = v->value.asString();
734 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
735 instr.propertyIndex = prop->index;
736 instr.value = output->indexForUrl(u);
737 output->addInstruction(instr);
739 } else if (type == qMetaTypeId<QList<QString> >()) {
740 Instruction::StoreStringQList instr;
741 instr.propertyIndex = prop->index;
742 instr.value = output->indexForString(v->value.asString());
743 output->addInstruction(instr);
747 // otherwise, generate custom type literal assignment
748 Instruction::AssignCustomType instr;
749 instr.propertyIndex = prop->index;
750 instr.primitive = output->indexForString(v->value.asString());
752 output->addInstruction(instr);
759 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
761 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
764 data->primitives.clear();
766 data->bytecode.resize(0);
770 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
771 with which the QDeclarativeCompiledData will be associated.
773 Returns true on success, false on failure. On failure, the compile errors
774 are available from errors().
776 If the environment variant QML_COMPILER_DUMP is set
777 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
778 on a successful compiler.
780 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
781 QDeclarativeTypeData *unit,
782 QDeclarativeCompiledData *out)
789 QDeclarativeScript::Object *root = unit->parser().tree();
792 this->engine = engine;
793 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
795 this->unitRoot = root;
799 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
800 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
802 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
803 QDeclarativeCompiledData::TypeReference ref;
805 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
806 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
809 ref.type = tref.type;
810 if (!ref.type->isCreatable()) {
811 QString err = ref.type->noCreationReason();
813 err = tr( "Element is not creatable.");
814 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
817 if (ref.type->containsRevisionedAttributes()) {
818 QDeclarativeError cacheError;
819 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
821 if (!ref.typePropertyCache)
822 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
823 ref.typePropertyCache->addref();
826 } else if (tref.typeData) {
827 ref.component = tref.typeData->compiledData();
829 ref.className = parserRef->name;
837 out->dumpInstructions();
840 Q_ASSERT(out->rootPropertyCache);
848 this->enginePrivate = 0;
850 this->cachedComponentTypeRef = -1;
851 this->cachedTranslationContextIndex = -1;
857 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
859 compileState = pool->New<ComponentCompileState>();
861 compileState->root = tree;
863 componentStats->componentStat.lineNumber = tree->location.start.line;
865 // We generate the importCache before we build the tree so that
866 // it can be used in the binding compiler. Given we "expect" the
867 // QML compilation to succeed, this isn't a waste.
868 output->importCache = new QDeclarativeTypeNameCache();
869 foreach (const QString &ns, unit->namespaces()) {
870 output->importCache->add(ns);
874 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
875 QString qualifier = script.qualifier;
876 QString enclosingNamespace;
878 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
879 if (lastDotIndex != -1) {
880 enclosingNamespace = qualifier.left(lastDotIndex);
881 qualifier = qualifier.mid(lastDotIndex+1);
884 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
887 unit->imports().populateCache(output->importCache, engine);
889 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
892 Instruction::Init init;
893 init.bindingsSize = compileState->totalBindingsCount;
894 init.parserStatusSize = compileState->parserStatusCount;
895 init.contextCache = genContextCache();
896 init.objectStackSize = compileState->objectDepth.maxDepth();
897 init.listStackSize = compileState->listDepth.maxDepth();
898 if (compileState->compiledBindingData.isEmpty())
899 init.compiledBinding = -1;
901 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
902 output->addInstruction(init);
904 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
905 Instruction::StoreImportedScript import;
906 import.value = output->scripts.count();
908 QDeclarativeScriptData *scriptData = script.script->scriptData();
909 scriptData->addref();
910 output->scripts << scriptData;
911 output->addInstruction(import);
914 if (!compileState->v8BindingProgram.isEmpty()) {
915 Instruction::InitV8Bindings bindings;
916 bindings.program = output->indexForString(compileState->v8BindingProgram);
917 bindings.programIndex = compileState->v8BindingProgramIndex;
918 bindings.line = compileState->v8BindingProgramLine;
919 output->addInstruction(bindings);
924 Instruction::SetDefault def;
925 output->addInstruction(def);
927 Instruction::Done done;
928 output->addInstruction(done);
930 Q_ASSERT(tree->metatype);
932 if (tree->metadata.isEmpty()) {
933 output->root = tree->metatype;
935 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
936 output->root = &output->rootData;
938 if (!tree->metadata.isEmpty())
939 enginePrivate->registerCompositeType(output);
942 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
944 for (int ii = 0; ii < list.count(); ++ii)
945 if (string == list.at(ii))
951 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
954 componentStats->componentStat.objects++;
956 Q_ASSERT (obj->type != -1);
957 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
958 obj->metatype = tr.metaObject();
961 obj->typeName = tr.type->qmlTypeName();
963 // This object is a "Component" element
964 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
965 COMPILE_CHECK(buildComponent(obj, ctxt));
970 typedef QDeclarativeInstruction I;
971 const I *init = ((const I *)tr.component->bytecode.constData());
972 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
974 // Adjust stack depths to include nested components
975 compileState->objectDepth.pushPop(init->init.objectStackSize);
976 compileState->listDepth.pushPop(init->init.listStackSize);
977 compileState->parserStatusCount += init->init.parserStatusSize;
978 compileState->totalBindingsCount += init->init.bindingsSize;
981 compileState->objectDepth.push();
983 // Object instantiations reset the binding context
984 BindingContext objCtxt(obj);
986 // Create the synthesized meta object, ignoring aliases
987 COMPILE_CHECK(checkDynamicMeta(obj));
988 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
989 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
991 // Find the native type and check for the QDeclarativeParserStatus interface
992 QDeclarativeType *type = toQmlType(obj);
994 obj->parserStatusCast = type->parserStatusCast();
995 if (obj->parserStatusCast != -1)
996 compileState->parserStatusCount++;
998 // Check if this is a custom parser type. Custom parser types allow
999 // assignments to non-existent properties. These assignments are then
1000 // compiled by the type.
1001 bool isCustomParser = output->types.at(obj->type).type &&
1002 output->types.at(obj->type).type->customParser() != 0;
1003 QList<QDeclarativeCustomParserProperty> customProps;
1005 // Fetch the list of deferred properties
1006 QStringList deferredList = deferredProperties(obj);
1008 // Must do id property first. This is to ensure that the id given to any
1009 // id reference created matches the order in which the objects are
1011 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1012 if (prop->name() == id_string) {
1013 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1019 Property *defaultProperty = 0;
1020 Property *skipProperty = 0;
1021 if (obj->defaultProperty) {
1022 defaultProperty = obj->defaultProperty;
1024 Property *explicitProperty = 0;
1026 const QMetaObject *mo = obj->metatype;
1027 int idx = mo->indexOfClassInfo("DefaultProperty");
1029 QMetaClassInfo info = mo->classInfo(idx);
1030 const char *p = info.value();
1034 while (char c = p[plen++]) { ord |= c; };
1038 // Utf8 - unoptimal, but seldom hit
1039 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1040 QHashedStringRef r(*s);
1042 if (obj->propertiesHashField.test(r.hash())) {
1043 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1044 if (ep->name() == r) {
1045 explicitProperty = ep;
1051 if (!explicitProperty)
1052 defaultProperty->setName(r);
1055 QHashedCStringRef r(p, plen);
1057 if (obj->propertiesHashField.test(r.hash())) {
1058 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1059 if (ep->name() == r) {
1060 explicitProperty = ep;
1066 if (!explicitProperty) {
1067 // Set the default property name
1068 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1069 r.writeUtf16(buffer);
1070 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1076 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1078 skipProperty = explicitProperty; // We merge the values into defaultProperty
1080 // Find the correct insertion point
1081 Value *insertPos = 0;
1083 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1084 if (!(v->location.start < explicitProperty->values.first()->location.start))
1089 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1093 QDeclarativeCustomParser *cp = 0;
1095 cp = output->types.at(obj->type).type->customParser();
1097 // Build all explicit properties specified
1098 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1100 if (prop == skipProperty)
1102 if (prop->name() == id_string)
1105 bool canDefer = false;
1106 if (isCustomParser) {
1107 if (doesPropertyExist(prop, obj) &&
1108 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
1109 !isAttachedPropertyName(prop->name()))) {
1110 int ids = compileState->ids.count();
1111 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1112 canDefer = ids == compileState->ids.count();
1113 } else if (isSignalPropertyName(prop->name()) &&
1114 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
1115 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1117 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1120 if (isSignalPropertyName(prop->name())) {
1121 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1123 int ids = compileState->ids.count();
1124 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1125 canDefer = ids == compileState->ids.count();
1129 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1130 prop->isDeferred = true;
1134 // Build the default property
1135 if (defaultProperty) {
1136 Property *prop = defaultProperty;
1138 bool canDefer = false;
1139 if (isCustomParser) {
1140 if (doesPropertyExist(prop, obj)) {
1141 int ids = compileState->ids.count();
1142 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1143 canDefer = ids == compileState->ids.count();
1145 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1148 int ids = compileState->ids.count();
1149 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1150 canDefer = ids == compileState->ids.count();
1153 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1154 prop->isDeferred = true;
1157 // Compile custom parser parts
1158 if (isCustomParser && !customProps.isEmpty()) {
1160 cp->compiler = this;
1162 obj->custom = cp->compile(customProps);
1165 foreach (QDeclarativeError err, cp->errors()) {
1166 err.setUrl(output->url);
1171 compileState->objectDepth.pop();
1176 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1178 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1179 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1184 // Create the object
1185 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1186 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1188 Instruction::CreateSimpleObject create;
1189 create.create = output->types.at(obj->type).type->createFunction();
1190 create.typeSize = output->types.at(obj->type).type->createSize();
1191 create.type = obj->type;
1192 create.line = obj->location.start.line;
1193 create.column = obj->location.start.column;
1194 output->addInstruction(create);
1198 if (output->types.at(obj->type).type) {
1199 Instruction::CreateCppObject create;
1200 create.line = obj->location.start.line;
1201 create.column = obj->location.start.column;
1203 if (!obj->custom.isEmpty())
1204 create.data = output->indexForByteArray(obj->custom);
1205 create.type = obj->type;
1206 create.isRoot = (compileState->root == obj);
1207 output->addInstruction(create);
1209 Instruction::CreateQMLObject create;
1210 create.type = obj->type;
1211 create.isRoot = (compileState->root == obj);
1213 if (!obj->bindingBitmask.isEmpty()) {
1214 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1215 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1217 create.bindingBits = -1;
1219 output->addInstruction(create);
1221 Instruction::CompleteQMLObject complete;
1222 complete.line = obj->location.start.line;
1223 complete.column = obj->location.start.column;
1224 complete.isRoot = (compileState->root == obj);
1225 output->addInstruction(complete);
1229 // Setup the synthesized meta object if necessary
1230 if (!obj->metadata.isEmpty()) {
1231 Instruction::StoreMetaObject meta;
1232 meta.data = output->indexForByteArray(obj->metadata);
1233 meta.aliasData = output->indexForByteArray(obj->synthdata);
1234 meta.propertyCache = output->propertyCaches.count();
1236 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1237 Q_ASSERT(propertyCache);
1238 propertyCache->addref();
1240 // Add flag for alias properties
1241 if (!obj->synthdata.isEmpty()) {
1242 const QDeclarativeVMEMetaData *vmeMetaData =
1243 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1244 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1245 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1246 QDeclarativePropertyData *data = propertyCache->property(index);
1247 data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias);
1251 if (obj == unitRoot) {
1252 propertyCache->addref();
1253 output->rootPropertyCache = propertyCache;
1256 output->propertyCaches << propertyCache;
1257 output->addInstruction(meta);
1258 } else if (obj == unitRoot) {
1259 output->rootPropertyCache = tr.createPropertyCache(engine);
1260 output->rootPropertyCache->addref();
1263 // Set the object id
1264 if (!obj->id.isEmpty()) {
1265 Instruction::SetId id;
1266 id.value = output->indexForString(obj->id);
1267 id.index = obj->idIndex;
1268 output->addInstruction(id);
1272 if (tr.type && obj->parserStatusCast != -1) {
1273 Instruction::BeginObject begin;
1274 begin.castValue = obj->parserStatusCast;
1275 output->addInstruction(begin);
1281 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1283 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1284 Q_ASSERT(prop->scriptStringScope != -1);
1285 const QString &script = prop->values.first()->value.asScript();
1286 Instruction::StoreScriptString ss;
1287 ss.propertyIndex = prop->index;
1288 ss.value = output->indexForString(script);
1289 ss.scope = prop->scriptStringScope;
1290 // ss.bindingId = rewriteBinding(script, prop->name());
1291 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1292 ss.line = prop->location.start.line;
1293 ss.column = prop->location.start.column;
1294 output->addInstruction(ss);
1297 bool seenDefer = false;
1298 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1299 if (prop->isDeferred) {
1304 genValueProperty(prop, obj);
1307 Instruction::Defer defer;
1308 defer.deferCount = 0;
1309 int deferIdx = output->addInstruction(defer);
1310 int nextInstructionIndex = output->nextInstructionIndex();
1312 Instruction::DeferInit dinit;
1313 // XXX - these are now massive over allocations
1314 dinit.bindingsSize = compileState->totalBindingsCount;
1315 dinit.parserStatusSize = compileState->parserStatusCount;
1316 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1317 dinit.listStackSize = compileState->listDepth.maxDepth();
1318 output->addInstruction(dinit);
1320 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1321 if (!prop->isDeferred)
1323 genValueProperty(prop, obj);
1326 Instruction::Done done;
1327 output->addInstruction(done);
1329 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1332 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1334 QDeclarativeScript::Value *v = prop->values.first();
1336 if (v->type == Value::SignalObject) {
1338 genObject(v->object);
1340 Instruction::AssignSignalObject assign;
1341 assign.line = v->location.start.line;
1342 assign.signal = output->indexForString(prop->name().toString());
1343 output->addInstruction(assign);
1345 } else if (v->type == Value::SignalExpression) {
1347 Instruction::StoreSignal store;
1348 store.signalIndex = prop->index;
1349 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
1350 const QString &rewrite =
1351 rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString());
1352 store.value = output->indexForString(rewrite);
1353 store.context = v->signalExpressionContextStack;
1354 store.line = v->location.start.line;
1355 store.column = v->location.start.column;
1356 output->addInstruction(store);
1362 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1363 Instruction::FetchAttached fetch;
1364 fetch.id = prop->index;
1365 fetch.line = prop->location.start.line;
1366 output->addInstruction(fetch);
1368 genObjectBody(prop->value);
1370 Instruction::PopFetchedObject pop;
1371 output->addInstruction(pop);
1374 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1375 Instruction::FetchObject fetch;
1376 fetch.property = prop->index;
1377 fetch.line = prop->location.start.line;
1378 output->addInstruction(fetch);
1380 if (!prop->value->metadata.isEmpty()) {
1381 Instruction::StoreMetaObject meta;
1382 meta.data = output->indexForByteArray(prop->value->metadata);
1383 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1384 meta.propertyCache = -1;
1385 output->addInstruction(meta);
1388 genObjectBody(prop->value);
1390 Instruction::PopFetchedObject pop;
1391 output->addInstruction(pop);
1394 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1396 genValueTypeProperty(obj, prop);
1399 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1400 if (prop->isDeferred)
1403 genValueProperty(prop, obj);
1406 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1408 genValueTypeProperty(obj, prop);
1412 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1414 Instruction::FetchValueType fetch;
1415 fetch.property = prop->index;
1416 fetch.type = prop->type;
1417 fetch.bindingSkipList = 0;
1419 if (obj->type == -1 || output->types.at(obj->type).component) {
1420 // We only have to do this if this is a composite type. If it is a builtin
1421 // type it can't possibly already have bindings that need to be cleared.
1422 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1423 if (!vprop->values.isEmpty()) {
1424 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1425 fetch.bindingSkipList |= (1 << vprop->index);
1430 output->addInstruction(fetch);
1432 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1433 genPropertyAssignment(vprop, prop->value, prop);
1436 Instruction::PopValueType pop;
1437 pop.property = prop->index;
1438 pop.type = prop->type;
1439 pop.bindingSkipList = 0;
1440 output->addInstruction(pop);
1443 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1445 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1448 Instruction::CreateComponent create;
1449 create.line = root->location.start.line;
1450 create.column = root->location.start.column;
1451 create.endLine = root->location.end.line;
1452 create.isRoot = (compileState->root == obj);
1453 int createInstruction = output->addInstruction(create);
1454 int nextInstructionIndex = output->nextInstructionIndex();
1456 ComponentCompileState *oldCompileState = compileState;
1457 compileState = componentState(root);
1459 Instruction::Init init;
1460 init.bindingsSize = compileState->totalBindingsCount;
1461 init.parserStatusSize = compileState->parserStatusCount;
1462 init.contextCache = genContextCache();
1463 init.objectStackSize = compileState->objectDepth.maxDepth();
1464 init.listStackSize = compileState->listDepth.maxDepth();
1465 if (compileState->compiledBindingData.isEmpty())
1466 init.compiledBinding = -1;
1468 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1469 output->addInstruction(init);
1471 if (!compileState->v8BindingProgram.isEmpty()) {
1472 Instruction::InitV8Bindings bindings;
1473 bindings.program = output->indexForString(compileState->v8BindingProgram);
1474 bindings.programIndex = compileState->v8BindingProgramIndex;
1475 bindings.line = compileState->v8BindingProgramLine;
1476 output->addInstruction(bindings);
1481 Instruction::SetDefault def;
1482 output->addInstruction(def);
1484 Instruction::Done done;
1485 output->addInstruction(done);
1487 output->instruction(createInstruction)->createComponent.count =
1488 output->nextInstructionIndex() - nextInstructionIndex;
1490 compileState = oldCompileState;
1492 if (!obj->id.isEmpty()) {
1493 Instruction::SetId id;
1494 id.value = output->indexForString(obj->id);
1495 id.index = obj->idIndex;
1496 output->addInstruction(id);
1499 if (obj == unitRoot) {
1500 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1501 output->rootPropertyCache->addref();
1505 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1506 const BindingContext &ctxt)
1508 // The special "Component" element can only have the id property and a
1509 // default property, that actually defines the component's tree
1511 compileState->objectDepth.push();
1513 // Find, check and set the "id" property (if any)
1514 Property *idProp = 0;
1515 if (obj->properties.isMany() ||
1516 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1517 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1519 if (!obj->properties.isEmpty())
1520 idProp = obj->properties.first();
1523 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1524 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1525 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1527 QString idVal = idProp->values.first()->primitive();
1529 if (compileState->ids.value(idVal))
1530 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1536 // Check the Component tree is well formed
1537 if (obj->defaultProperty &&
1538 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1539 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1540 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1542 if (!obj->dynamicProperties.isEmpty())
1543 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1544 if (!obj->dynamicSignals.isEmpty())
1545 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1546 if (!obj->dynamicSlots.isEmpty())
1547 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1549 QDeclarativeScript::Object *root = 0;
1550 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1551 root = obj->defaultProperty->values.first()->object;
1554 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1556 // Build the component tree
1557 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1559 compileState->objectDepth.pop();
1564 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1565 const BindingContext &ctxt)
1567 ComponentCompileState *oldComponentCompileState = compileState;
1568 compileState = pool->New<ComponentCompileState>();
1569 compileState->root = obj;
1570 compileState->nested = true;
1572 if (componentStats) {
1573 ComponentStat oldComponentStat = componentStats->componentStat;
1575 componentStats->componentStat = ComponentStat();
1576 componentStats->componentStat.lineNumber = obj->location.start.line;
1579 COMPILE_CHECK(buildObject(obj, ctxt));
1581 COMPILE_CHECK(completeComponentBuild());
1583 componentStats->componentStat = oldComponentStat;
1586 COMPILE_CHECK(buildObject(obj, ctxt));
1588 COMPILE_CHECK(completeComponentBuild());
1591 compileState = oldComponentCompileState;
1597 // Build a sub-object. A sub-object is one that was not created directly by
1598 // QML - such as a grouped property object, or an attached object. Sub-object's
1599 // can't have an id, involve a custom parser, have attached properties etc.
1600 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1602 Q_ASSERT(obj->metatype);
1603 Q_ASSERT(!obj->defaultProperty);
1604 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1607 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1608 if (isSignalPropertyName(prop->name())) {
1609 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1611 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1618 int QDeclarativeCompiler::componentTypeRef()
1620 if (cachedComponentTypeRef == -1) {
1621 QDeclarativeType *t = QDeclarativeMetaType::qmlType(Component_import_string,1,0);
1622 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1623 if (output->types.at(ii).type == t) {
1624 cachedComponentTypeRef = ii;
1628 QDeclarativeCompiledData::TypeReference ref;
1629 ref.className = Component_string;
1631 output->types << ref;
1632 cachedComponentTypeRef = output->types.count() - 1;
1634 return cachedComponentTypeRef;
1637 int QDeclarativeCompiler::translationContextIndex()
1639 if (cachedTranslationContextIndex == -1) {
1640 // This code must match that in the qsTr() implementation
1641 QString path = output->url.toString();
1642 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1643 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1645 QByteArray contextUtf8 = context.toUtf8();
1646 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1648 return cachedTranslationContextIndex;
1651 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1652 const BindingContext &ctxt)
1654 Q_ASSERT(obj->metaObject());
1656 const QHashedStringRef &propName = prop->name();
1658 Q_ASSERT(propName.startsWith(on_string));
1659 QString name = propName.mid(2, -1).toString();
1661 // Note that the property name could start with any alpha or '_' or '$' character,
1662 // so we need to do the lower-casing of the first alpha character.
1663 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1664 if (name.at(firstAlphaIndex).isUpper()) {
1665 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1670 bool notInRevision = false;
1672 QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1676 if (notInRevision && 0 == property(obj, propName, 0)) {
1677 Q_ASSERT(obj->type != -1);
1678 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1679 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1681 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));
1683 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1687 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1689 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1693 if (prop->value || !prop->values.isOne())
1694 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1696 prop->index = sig->coreIndex;
1699 obj->addSignalProperty(prop);
1701 if (prop->values.first()->object) {
1702 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1703 prop->values.first()->type = Value::SignalObject;
1705 prop->values.first()->type = Value::SignalExpression;
1707 if (!prop->values.first()->value.isScript())
1708 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1710 QString script = prop->values.first()->value.asScript().trimmed();
1711 if (script.isEmpty())
1712 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1714 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1723 Returns true if (value) property \a prop exists on obj, false otherwise.
1725 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1726 QDeclarativeScript::Object *obj)
1728 if (prop->name().isEmpty())
1730 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1733 return property(obj, prop->name()) != 0;
1736 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1737 QDeclarativeScript::Object *obj,
1738 const BindingContext &ctxt)
1740 if (prop->isEmpty())
1741 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1743 const QMetaObject *metaObject = obj->metaObject();
1744 Q_ASSERT(metaObject);
1746 if (isAttachedPropertyName(prop->name())) {
1747 // Setup attached property data
1749 if (ctxt.isSubContext()) {
1750 // Attached properties cannot be used on sub-objects. Sub-objects
1751 // always exist in a binding sub-context, which is what we test
1753 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1756 QDeclarativeType *type = 0;
1757 QDeclarativeImportedNamespace *typeNamespace = 0;
1758 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1760 if (typeNamespace) {
1761 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1764 } else if (!type || !type->attachedPropertiesType()) {
1765 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1769 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1771 Q_ASSERT(type->attachedPropertiesFunction());
1772 prop->index = type->attachedPropertiesId();
1773 prop->value->metatype = type->attachedPropertiesType();
1775 // Setup regular property data
1776 bool notInRevision = false;
1777 QDeclarativePropertyData *d =
1778 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1780 if (d == 0 && notInRevision) {
1781 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1782 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1784 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));
1786 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1789 prop->index = d->coreIndex;
1791 } else if (prop->isDefault) {
1792 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1793 QDeclarativePropertyData defaultPropertyData;
1794 defaultPropertyData.load(p, engine);
1796 prop->setName(QLatin1String(p.name()));
1797 prop->core = defaultPropertyData;
1798 prop->index = prop->core.coreIndex;
1801 // We can't error here as the "id" property does not require a
1802 // successful index resolution
1803 if (prop->index != -1)
1804 prop->type = prop->core.propType;
1806 // Check if this is an alias
1807 if (prop->index != -1 &&
1809 prop->parent->type != -1 &&
1810 output->types.at(prop->parent->type).component) {
1812 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1813 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1814 prop->isAlias = true;
1817 if (prop->index != -1 && !prop->values.isEmpty())
1818 prop->parent->setBindingBit(prop->index);
1821 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1823 // The magic "id" behavior doesn't apply when "id" is resolved as a
1824 // default property or to sub-objects (which are always in binding
1826 COMPILE_CHECK(buildIdProperty(prop, obj));
1827 if (prop->type == QVariant::String &&
1828 prop->values.first()->value.isString())
1829 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1831 } else if (isAttachedPropertyName(prop->name())) {
1833 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1835 } else if (prop->index == -1) {
1837 if (prop->isDefault) {
1838 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1840 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1843 } else if (prop->value) {
1845 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1847 } else if (prop->core.isQList()) {
1849 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1851 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1853 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1857 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1864 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1865 QDeclarativeScript::Property *nsProp,
1866 QDeclarativeScript::Object *obj,
1867 const BindingContext &ctxt)
1870 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1872 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1874 if (!isAttachedPropertyName(prop->name()))
1875 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1877 // Setup attached property data
1879 QDeclarativeType *type = 0;
1880 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1882 if (!type || !type->attachedPropertiesType())
1883 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1886 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1888 Q_ASSERT(type->attachedPropertiesFunction());
1889 prop->index = type->index();
1890 prop->value->metatype = type->attachedPropertiesType();
1892 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1898 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1899 QDeclarativeScript::Object *obj)
1901 if (prop->core.isQList()) {
1902 genListProperty(prop, obj);
1904 genPropertyAssignment(prop, obj);
1908 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1909 QDeclarativeScript::Object *obj)
1911 int listType = enginePrivate->listType(prop->type);
1913 Instruction::FetchQList fetch;
1914 fetch.property = prop->index;
1915 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1916 fetch.type = listType;
1917 output->addInstruction(fetch);
1919 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1921 if (v->type == Value::CreatedObject) {
1923 genObject(v->object);
1924 if (listTypeIsInterface) {
1925 Instruction::AssignObjectList assign;
1926 assign.line = prop->location.start.line;
1927 output->addInstruction(assign);
1929 Instruction::StoreObjectQList store;
1930 output->addInstruction(store);
1933 } else if (v->type == Value::PropertyBinding) {
1935 genBindingAssignment(v, prop, obj);
1941 Instruction::PopQList pop;
1942 output->addInstruction(pop);
1945 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1946 QDeclarativeScript::Object *obj,
1947 QDeclarativeScript::Property *valueTypeProperty)
1949 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1951 Q_ASSERT(v->type == Value::CreatedObject ||
1952 v->type == Value::PropertyBinding ||
1953 v->type == Value::Literal);
1955 if (v->type == Value::CreatedObject) {
1957 genObject(v->object);
1959 if (QDeclarativeMetaType::isInterface(prop->type)) {
1961 Instruction::StoreInterface store;
1962 store.line = v->object->location.start.line;
1963 store.propertyIndex = prop->index;
1964 output->addInstruction(store);
1966 } else if (prop->type == QMetaType::QVariant) {
1968 if (prop->core.isVMEProperty()) {
1969 Instruction::StoreVarObject store;
1970 store.line = v->object->location.start.line;
1971 store.propertyIndex = prop->index;
1972 output->addInstruction(store);
1974 Instruction::StoreVariantObject store;
1975 store.line = v->object->location.start.line;
1976 store.propertyIndex = prop->index;
1977 output->addInstruction(store);
1983 Instruction::StoreObject store;
1984 store.line = v->object->location.start.line;
1985 store.propertyIndex = prop->index;
1986 output->addInstruction(store);
1989 } else if (v->type == Value::PropertyBinding) {
1991 genBindingAssignment(v, prop, obj, valueTypeProperty);
1993 } else if (v->type == Value::Literal) {
1995 genLiteralAssignment(prop, v);
2001 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2003 Q_ASSERT(v->type == Value::ValueSource ||
2004 v->type == Value::ValueInterceptor);
2006 if (v->type == Value::ValueSource) {
2007 genObject(v->object);
2009 Instruction::StoreValueSource store;
2010 if (valueTypeProperty) {
2011 store.property = genValueTypeData(prop, valueTypeProperty);
2014 store.property = prop->core;
2017 QDeclarativeType *valueType = toQmlType(v->object);
2018 store.castValue = valueType->propertyValueSourceCast();
2019 output->addInstruction(store);
2021 } else if (v->type == Value::ValueInterceptor) {
2022 genObject(v->object);
2024 Instruction::StoreValueInterceptor store;
2025 if (valueTypeProperty) {
2026 store.property = genValueTypeData(prop, valueTypeProperty);
2029 store.property = prop->core;
2032 QDeclarativeType *valueType = toQmlType(v->object);
2033 store.castValue = valueType->propertyValueInterceptorCast();
2034 output->addInstruction(store);
2040 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
2041 QDeclarativeScript::Object *obj)
2044 prop->values.isMany() ||
2045 prop->values.first()->object)
2046 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2048 QDeclarativeScript::Value *idValue = prop->values.first();
2049 QString val = idValue->primitive();
2051 COMPILE_CHECK(checkValidId(idValue, val));
2053 if (compileState->ids.value(val))
2054 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2056 prop->values.first()->type = Value::Id;
2064 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
2067 Q_ASSERT(!compileState->ids.value(id));
2068 Q_ASSERT(obj->id == id);
2069 obj->idIndex = compileState->ids.count();
2070 compileState->ids.append(obj);
2073 void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref)
2075 Q_ASSERT(ref->value && !ref->value->bindingReference);
2076 ref->value->bindingReference = ref;
2077 compileState->totalBindingsCount++;
2078 compileState->bindings.prepend(ref);
2081 void QDeclarativeCompiler::saveComponentState()
2083 Q_ASSERT(compileState->root);
2084 Q_ASSERT(compileState->root->componentCompileState == 0);
2086 compileState->root->componentCompileState = compileState;
2089 componentStats->savedComponentStats.append(componentStats->componentStat);
2092 QDeclarativeCompilerTypes::ComponentCompileState *
2093 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
2095 Q_ASSERT(obj->componentCompileState);
2096 return obj->componentCompileState;
2099 // Build attached property object. In this example,
2103 // GridView is an attached property object.
2104 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
2105 QDeclarativeScript::Object *obj,
2106 const BindingContext &ctxt)
2108 Q_ASSERT(prop->value);
2109 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2111 compileState->objectDepth.push();
2113 obj->addAttachedProperty(prop);
2115 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2117 compileState->objectDepth.pop();
2123 // Build "grouped" properties. In this example:
2125 // font.pointSize: 12
2126 // font.family: "Helvetica"
2128 // font is a nested property. pointSize and family are not.
2129 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
2130 QDeclarativeScript::Object *obj,
2131 const BindingContext &ctxt)
2133 Q_ASSERT(prop->type != 0);
2134 Q_ASSERT(prop->index != -1);
2136 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
2137 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2139 if (!prop->values.isEmpty()) {
2140 if (prop->values.first()->location < prop->value->location) {
2141 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2143 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2147 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2148 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2152 if (prop->isAlias) {
2153 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2154 vtProp->isAlias = true;
2158 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2159 prop->value, obj, ctxt.incr()));
2160 obj->addValueTypeProperty(prop);
2162 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2166 // Load the nested property's meta type
2167 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2168 if (!prop->value->metatype)
2169 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2171 if (!prop->values.isEmpty())
2172 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2174 obj->addGroupedProperty(prop);
2176 compileState->objectDepth.push();
2178 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2180 compileState->objectDepth.pop();
2186 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2187 QDeclarativeScript::Object *obj,
2188 QDeclarativeScript::Object *baseObj,
2189 const BindingContext &ctxt)
2191 compileState->objectDepth.push();
2193 if (obj->defaultProperty)
2194 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2195 obj->metatype = type->metaObject();
2197 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2199 QDeclarativePropertyData *d = property(obj, prop->name());
2201 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2203 prop->index = d->coreIndex;
2204 prop->type = d->propType;
2206 prop->isValueTypeSubProperty = true;
2209 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2211 if (prop->values.isMany()) {
2212 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2213 } else if (!prop->values.isEmpty()) {
2214 QDeclarativeScript::Value *value = prop->values.first();
2216 if (value->object) {
2217 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2218 } else if (value->value.isScript()) {
2219 // ### Check for writability
2221 //optimization for <Type>.<EnumValue> enum assignments
2222 bool isEnumAssignment = false;
2224 if (prop->core.isEnum())
2225 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2227 if (isEnumAssignment) {
2228 value->type = Value::Literal;
2230 JSBindingReference *reference = pool->New<JSBindingReference>();
2231 reference->expression = value->value;
2232 reference->property = prop;
2233 reference->value = value;
2234 reference->bindingContext = ctxt;
2235 reference->bindingContext.owner++;
2236 addBindingReference(reference);
2237 value->type = Value::PropertyBinding;
2240 COMPILE_CHECK(testLiteralAssignment(prop, value));
2241 value->type = Value::Literal;
2245 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2246 Q_ASSERT(v->object);
2248 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2251 obj->addValueProperty(prop);
2254 compileState->objectDepth.pop();
2259 // Build assignments to QML lists. QML lists are properties of type
2260 // QDeclarativeListProperty<T>. List properties can accept a list of
2261 // objects, or a single binding.
2262 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2263 QDeclarativeScript::Object *obj,
2264 const BindingContext &ctxt)
2266 Q_ASSERT(prop->core.isQList());
2268 compileState->listDepth.push();
2272 obj->addValueProperty(prop);
2274 int listType = enginePrivate->listType(t);
2275 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2277 bool assignedBinding = false;
2278 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2280 v->type = Value::CreatedObject;
2281 COMPILE_CHECK(buildObject(v->object, ctxt));
2283 // We check object coercian here. We check interface assignment
2285 if (!listTypeIsInterface) {
2286 if (!canCoerce(listType, v->object)) {
2287 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2291 } else if (v->value.isScript()) {
2292 if (assignedBinding)
2293 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2295 assignedBinding = true;
2296 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2297 v->type = Value::PropertyBinding;
2299 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2303 compileState->listDepth.pop();
2308 // Compiles an assignment to a QDeclarativeScriptString property
2309 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2310 QDeclarativeScript::Object *obj,
2311 const BindingContext &ctxt)
2313 if (prop->values.isMany())
2314 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2316 if (prop->values.first()->object)
2317 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2319 prop->scriptStringScope = ctxt.stack;
2320 obj->addScriptStringProperty(prop);
2325 // Compile regular property assignments of the form "property: <value>"
2326 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2327 QDeclarativeScript::Object *obj,
2328 const BindingContext &ctxt)
2330 obj->addValueProperty(prop);
2332 if (prop->values.isMany())
2333 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2335 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2338 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2342 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2347 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2348 Q_ASSERT(v->object);
2349 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2355 // Compile assigning a single object instance to a regular property
2356 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2357 QDeclarativeScript::Object *obj,
2358 QDeclarativeScript::Value *v,
2359 const BindingContext &ctxt)
2361 Q_ASSERT(prop->index != -1);
2362 Q_ASSERT(v->object->type != -1);
2364 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2365 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2367 if (QDeclarativeMetaType::isInterface(prop->type)) {
2369 // Assigning an object to an interface ptr property
2370 COMPILE_CHECK(buildObject(v->object, ctxt));
2372 v->type = Value::CreatedObject;
2374 } else if (prop->type == QMetaType::QVariant) {
2376 // Assigning an object to a QVariant
2377 COMPILE_CHECK(buildObject(v->object, ctxt));
2379 v->type = Value::CreatedObject;
2381 // Normally buildObject() will set this up, but we need the static
2382 // meta object earlier to test for assignability. It doesn't matter
2383 // that there may still be outstanding synthesized meta object changes
2384 // on this type, as they are not relevant for assignability testing
2385 v->object->metatype = output->types.at(v->object->type).metaObject();
2386 Q_ASSERT(v->object->metaObject());
2388 // We want to raw metaObject here as the raw metaobject is the
2389 // actual property type before we applied any extensions that might
2390 // effect the properties on the type, but don't effect assignability
2391 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2393 // Will be true if the assgned type inherits propertyMetaObject
2394 bool isAssignable = false;
2395 // Determine isAssignable value
2396 if (propertyMetaObject) {
2397 const QMetaObject *c = v->object->metatype;
2399 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2400 c = c->superClass();
2405 // Simple assignment
2406 COMPILE_CHECK(buildObject(v->object, ctxt));
2408 v->type = Value::CreatedObject;
2409 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2410 // Automatic "Component" insertion
2411 QDeclarativeScript::Object *root = v->object;
2412 QDeclarativeScript::Object *component = pool->New<Object>();
2413 component->type = componentTypeRef();
2414 component->typeName = QStringLiteral("Qt/Component");
2415 component->metatype = &QDeclarativeComponent::staticMetaObject;
2416 component->location = root->location;
2417 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2418 componentValue->object = root;
2419 component->getDefaultProperty()->addValue(componentValue);
2420 v->object = component;
2421 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2423 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2430 // Compile assigning a single object instance to a regular property using the "on" syntax.
2434 // NumberAnimation on x { }
2436 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2437 QDeclarativeScript::Object *obj,
2438 QDeclarativeScript::Object *baseObj,
2439 QDeclarativeScript::Value *v,
2440 const BindingContext &ctxt)
2442 Q_ASSERT(prop->index != -1);
2443 Q_ASSERT(v->object->type != -1);
2447 if (!prop->core.isWritable())
2448 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2451 // Normally buildObject() will set this up, but we need the static
2452 // meta object earlier to test for assignability. It doesn't matter
2453 // that there may still be outstanding synthesized meta object changes
2454 // on this type, as they are not relevant for assignability testing
2455 v->object->metatype = output->types.at(v->object->type).metaObject();
2456 Q_ASSERT(v->object->metaObject());
2458 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2459 bool isPropertyValue = false;
2460 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2461 bool isPropertyInterceptor = false;
2462 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2463 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2464 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2467 if (isPropertyValue || isPropertyInterceptor) {
2468 // Assign as a property value source
2469 COMPILE_CHECK(buildObject(v->object, ctxt));
2471 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2472 buildDynamicMeta(baseObj, ForceCreation);
2473 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2475 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2481 // Compile assigning a literal or binding to a regular property
2482 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2483 QDeclarativeScript::Object *obj,
2484 QDeclarativeScript::Value *v,
2485 const BindingContext &ctxt)
2487 Q_ASSERT(prop->index != -1);
2489 if (v->value.isScript()) {
2491 //optimization for <Type>.<EnumValue> enum assignments
2492 if (prop->core.isEnum()) {
2493 bool isEnumAssignment = false;
2494 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2495 if (isEnumAssignment) {
2496 v->type = Value::Literal;
2501 // Test for other binding optimizations
2502 if (!buildLiteralBinding(v, prop, ctxt))
2503 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2505 v->type = Value::PropertyBinding;
2509 COMPILE_CHECK(testLiteralAssignment(prop, v));
2511 v->type = Value::Literal;
2517 bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
2518 QDeclarativeScript::Object *obj,
2519 QDeclarativeScript::Value *v,
2522 *isAssignment = false;
2523 if (!prop->core.isEnum())
2526 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2528 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2529 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2531 QString string = v->value.asString();
2532 if (!string.at(0).isUpper())
2535 QStringList parts = string.split(QLatin1Char('.'));
2536 if (parts.count() != 2)
2539 QString typeName = parts.at(0);
2540 QDeclarativeType *type = 0;
2541 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2543 //handle enums on value types (where obj->typeName is empty)
2544 QString objTypeName = obj->typeName;
2545 if (objTypeName.isEmpty()) {
2546 QDeclarativeType *objType = toQmlType(obj);
2548 objTypeName = objType->qmlTypeName();
2554 QString enumValue = parts.at(1);
2558 if (objTypeName == type->qmlTypeName()) {
2559 // When these two match, we can short cut the search
2560 if (mprop.isFlagType()) {
2561 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2563 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2566 // Otherwise we have to search the whole type
2567 // This matches the logic in QV8TypeWrapper
2568 QByteArray enumName = enumValue.toUtf8();
2569 const QMetaObject *metaObject = type->baseMetaObject();
2571 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2572 QMetaEnum e = metaObject->enumerator(ii);
2573 value = e.keyToValue(enumName.constData(), &ok);
2580 v->type = Value::Literal;
2581 v->value = QDeclarativeScript::Variant((double)value);
2582 *isAssignment = true;
2587 struct StaticQtMetaObject : public QObject
2589 static const QMetaObject *get()
2590 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2593 // Similar logic to above, but not knowing target property.
2594 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2596 int dot = script.indexOf('.');
2598 const QByteArray &scope = script.left(dot);
2599 QDeclarativeType *type = 0;
2600 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2601 if (!type && scope != "Qt")
2603 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2604 const char *key = script.constData() + dot+1;
2605 int i = mo->enumeratorCount();
2608 int v = mo->enumerator(i).keyToValue(key, &ok);
2616 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2618 QDeclarativeType *qmltype = 0;
2619 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2623 return qmltype->metaObject();
2626 // similar to logic of completeComponentBuild, but also sticks data
2627 // into primitives at the end
2628 int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name)
2630 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2631 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2633 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2635 return output->indexForString(rewrite);
2638 QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name)
2640 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
2641 return rewriteSignalHandler(handler, name);
2644 // Ensures that the dynamic meta specification on obj is valid
2645 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2647 bool seenDefaultProperty = false;
2649 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2650 // Calculating the hash for the names is not a waste as we have to test
2651 // them against the illegalNames set anyway.
2652 QHashField propNames;
2653 QHashField methodNames;
2656 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2657 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2659 if (prop.isDefaultProperty) {
2660 if (seenDefaultProperty)
2661 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2662 seenDefaultProperty = true;
2665 if (propNames.testAndSet(prop.name.hash())) {
2666 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2667 p2 = obj->dynamicProperties.next(p2)) {
2668 if (p2->name == prop.name) {
2669 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2670 prop.nameLocation.column,
2671 tr("Duplicate property name"));
2676 if (prop.name.at(0).isUpper()) {
2677 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2678 prop.nameLocation.column,
2679 tr("Property names cannot begin with an upper case letter"));
2682 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2683 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2684 prop.nameLocation.column,
2685 tr("Illegal property name"));
2689 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2690 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2692 if (methodNames.testAndSet(currSig.name.hash())) {
2693 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2694 s2 = obj->dynamicSignals.next(s2)) {
2695 if (s2->name == currSig.name)
2696 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2700 if (currSig.name.at(0).isUpper())
2701 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2702 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2703 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2706 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2707 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2709 if (methodNames.testAndSet(currSlot.name.hash())) {
2710 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2711 s2 = obj->dynamicSignals.next(s2)) {
2712 if (s2->name == currSlot.name)
2713 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2715 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2716 s2 = obj->dynamicSlots.next(s2)) {
2717 if (s2->name == currSlot.name)
2718 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2722 if (currSlot.name.at(0).isUpper())
2723 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2724 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2725 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2731 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2733 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2734 p = obj->dynamicProperties.next(p)) {
2736 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2739 Property *property = 0;
2740 if (p->isDefaultProperty) {
2741 property = obj->getDefaultProperty();
2743 property = obj->getProperty(p->name);
2744 if (!property->values.isEmpty())
2745 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2749 property->isReadOnlyDeclaration = true;
2751 if (property->value)
2752 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2754 property->values.append(p->defaultValue->values);
2759 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2761 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2764 Q_ASSERT(obj->metatype);
2766 if (mode != ForceCreation &&
2767 obj->dynamicProperties.isEmpty() &&
2768 obj->dynamicSignals.isEmpty() &&
2769 obj->dynamicSlots.isEmpty())
2772 bool resolveAlias = (mode == ResolveAliases);
2774 const Object::DynamicProperty *defaultProperty = 0;
2776 int varPropCount = 0;
2777 int totalPropCount = 0;
2778 int firstPropertyVarIndex = 0;
2780 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2782 if (p->type == Object::DynamicProperty::Alias)
2784 if (p->type == Object::DynamicProperty::Var)
2787 if (p->isDefaultProperty &&
2788 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2789 defaultProperty = p;
2791 if (!resolveAlias) {
2792 // No point doing this for both the alias and non alias cases
2793 QDeclarativePropertyData *d = property(obj, p->name);
2794 if (d && d->isFinal())
2795 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2799 bool buildData = resolveAlias || aliasCount == 0;
2801 QByteArray dynamicData;
2803 typedef QDeclarativeVMEMetaData VMD;
2805 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2806 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2807 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2808 aliasCount * sizeof(VMD::AliasData), 0);
2811 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2813 QByteArray newClassName = obj->metatype->className();
2814 newClassName.append("_QML_");
2815 newClassName.append(QByteArray::number(uniqueClassId));
2817 if (compileState->root == obj && !compileState->nested) {
2818 QString path = output->url.path();
2819 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2820 if (lastSlash > -1) {
2821 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2822 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2823 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2827 QFastMetaBuilder builder;
2828 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2829 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2830 obj->dynamicSlots.count(),
2831 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2832 defaultProperty?1:0);
2835 Object::DynamicProperty::Type dtype;
2837 const char *cppType;
2838 } builtinTypes[] = {
2839 { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" },
2840 { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" },
2841 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2842 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2843 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2844 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2845 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2846 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2847 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2848 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2849 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2851 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2852 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2854 // Reserve dynamic properties
2855 if (obj->dynamicProperties.count()) {
2856 typedef QDeclarativeVMEMetaData VMD;
2858 int effectivePropertyIndex = 0;
2859 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2861 // Reserve space for name
2862 p->nameRef = builder.newString(p->name.utf8length());
2864 int propertyType = 0;
2865 bool readonly = false;
2866 QFastMetaBuilder::StringRef typeRef;
2868 if (p->type == Object::DynamicProperty::Alias) {
2870 } else if (p->type < builtinTypeCount) {
2871 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2872 propertyType = builtinTypes[p->type].metaType;
2873 if (typeRefs[p->type].isEmpty())
2874 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2875 typeRef = typeRefs[p->type];
2878 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2879 p->type == Object::DynamicProperty::Custom);
2881 // XXX don't double resolve this in the case of an alias run
2883 QByteArray customTypeName;
2884 QDeclarativeType *qmltype = 0;
2886 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2887 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2890 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2892 Q_ASSERT(tdata->isComplete());
2894 QDeclarativeCompiledData *data = tdata->compiledData();
2895 customTypeName = data->root->className();
2899 customTypeName = qmltype->typeName();
2902 if (p->type == Object::DynamicProperty::Custom) {
2903 customTypeName += '*';
2904 propertyType = QMetaType::QObjectStar;
2907 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2908 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2911 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2912 p->typeRef = builder.newString(customTypeName.length());
2913 typeRef = p->typeRef;
2916 if (p->type == Object::DynamicProperty::Var)
2923 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2924 vmd->propertyCount++;
2925 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2928 if (p->type < builtinTypeCount)
2929 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2930 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2931 effectivePropertyIndex);
2933 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2934 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2935 effectivePropertyIndex);
2937 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2938 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2940 effectivePropertyIndex++;
2944 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2946 vmd->varPropertyCount = varPropCount;
2947 firstPropertyVarIndex = effectivePropertyIndex;
2948 totalPropCount = varPropCount + effectivePropertyIndex;
2949 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2950 if (p->type == Object::DynamicProperty::Var) {
2951 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2953 vmd->propertyCount++;
2954 (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2957 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2958 QMetaType::QVariant,
2959 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2960 effectivePropertyIndex);
2962 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2963 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2965 effectivePropertyIndex++;
2972 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2973 if (p->type == Object::DynamicProperty::Alias) {
2975 Q_ASSERT(buildData);
2976 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2977 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2980 // Even if we aren't resolving the alias, we need a fake signal so that the
2981 // metaobject remains consistent across the resolve and non-resolve alias runs
2982 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2983 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2984 effectivePropertyIndex++;
2991 // Reserve default property
2992 QFastMetaBuilder::StringRef defPropRef;
2993 if (defaultProperty) {
2994 defPropRef = builder.newString(strlen("DefaultProperty"));
2995 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2998 // Reserve dynamic signals
2999 int signalIndex = 0;
3000 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3002 int paramCount = s->parameterNames.count();
3004 int signatureSize = s->name.utf8length() + 2 /* paren */;
3006 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
3007 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
3009 s->signatureRef = builder.newString(signatureSize);
3010 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3013 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
3015 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
3019 // Reserve dynamic slots
3020 if (obj->dynamicSlots.count()) {
3022 // Allocate QVariant string
3023 if (typeRefs[0].isEmpty())
3024 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
3026 typedef QDeclarativeVMEMetaData VMD;
3028 int methodIndex = 0;
3029 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3030 int paramCount = s->parameterNames.count();
3032 int signatureSize = s->name.utf8length() + 2 /* paren */;
3034 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
3035 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3037 s->signatureRef = builder.newString(signatureSize);
3038 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3040 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
3044 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3045 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3046 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3047 for (int jj = 0; jj < paramCount; ++jj) {
3048 if (jj) funcScript.append(QLatin1Char(','));
3049 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3051 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3053 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3054 funcScript.length(),
3055 s->location.start.line };
3057 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
3060 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3062 md.bodyOffset = dynamicData.size();
3064 dynamicData.append((const char *)funcScript.constData(),
3065 (funcScript.length() * sizeof(QChar)));
3072 // Now allocate used builtin types
3073 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3074 if (!typeRefs[ii].isEmpty())
3075 typeRefs[ii].load(builtinTypes[ii].cppType);
3078 // Now allocate properties
3079 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3081 char *d = p->changedSignatureRef.data();
3082 p->name.writeUtf8(d);
3083 strcpy(d + p->name.utf8length(), "Changed()");
3085 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3088 p->nameRef.load(p->name);
3090 if (p->type >= builtinTypeCount) {
3091 Q_ASSERT(p->resolvedCustomTypeName);
3092 p->typeRef.load(*p->resolvedCustomTypeName);
3096 // Allocate default property if necessary
3097 if (defaultProperty)
3098 strcpy(defPropRef.data(), "DefaultProperty");
3100 // Now allocate signals
3101 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3103 char *d = s->signatureRef.data();
3104 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3105 s->name.writeUtf8(d); d += s->name.utf8length();
3108 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3109 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3110 strcpy(d, s->parameterTypes.at(jj).constData());
3111 d += s->parameterTypes.at(jj).length();
3112 s->parameterNames.at(jj).writeUtf8(d2);
3113 d2 += s->parameterNames.at(jj).utf8length();
3120 // Now allocate methods
3121 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3122 char *d = s->signatureRef.data();
3123 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3124 s->name.writeUtf8(d); d += s->name.utf8length();
3126 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3127 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3128 strcpy(d, "QVariant");
3129 d += strlen("QVariant");
3130 strcpy(d2, s->parameterNames.at(jj).constData());
3131 d2 += s->parameterNames.at(jj).length();
3138 // Now allocate class name
3139 classNameRef.load(newClassName);
3141 obj->metadata = builder.toData();
3142 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3144 if (mode == IgnoreAliases && aliasCount)
3145 compileState->aliasingObjects.append(obj);
3147 obj->synthdata = dynamicData;
3149 if (obj->synthCache) {
3150 obj->synthCache->release();
3151 obj->synthCache = 0;
3154 if (obj->type != -1) {
3155 QDeclarativePropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3156 QDeclarativePropertyCache *cache =
3157 superCache->copyAndAppend(engine, &obj->extObject,
3158 QDeclarativePropertyData::NoFlags,
3159 QDeclarativePropertyData::IsVMEFunction,
3160 QDeclarativePropertyData::IsVMESignal);
3162 // now we modify the flags appropriately for var properties.
3163 int propertyOffset = obj->extObject.propertyOffset();
3164 QDeclarativePropertyData *currPropData = 0;
3165 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3166 currPropData = cache->property(pvi + propertyOffset);
3167 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty);
3170 obj->synthCache = cache;
3176 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3179 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3181 QChar ch = val.at(0);
3182 if (ch.isLetter() && !ch.isLower())
3183 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3185 QChar u(QLatin1Char('_'));
3186 if (!ch.isLetter() && ch != u)
3187 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3189 for (int ii = 1; ii < val.count(); ++ii) {
3191 if (!ch.isLetterOrNumber() && ch != u)
3192 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3195 if (enginePrivate->v8engine()->illegalNames().contains(val))
3196 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3201 #include <private/qdeclarativejsparser_p.h>
3203 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3205 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3207 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3208 return QStringList() << name;
3209 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3210 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3212 QStringList rv = astNodeToStringList(expr->base);
3215 rv.append(expr->name.toString());
3218 return QStringList();
3221 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3223 QDeclarativeScript::Object *obj,
3224 int propIndex, int aliasIndex,
3225 Object::DynamicProperty &prop)
3227 if (!prop.defaultValue)
3228 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3230 if (!prop.defaultValue->values.isOne() ||
3231 prop.defaultValue->values.first()->object ||
3232 !prop.defaultValue->values.first()->value.isScript())
3233 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3235 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3237 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3239 QStringList alias = astNodeToStringList(node);
3241 if (alias.count() < 1 || alias.count() > 3)
3242 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3244 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3246 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3248 QByteArray typeName;
3253 bool writable = false;
3254 bool resettable = false;
3255 if (alias.count() == 2 || alias.count() == 3) {
3256 propIdx = indexOfProperty(idObject, alias.at(1));
3258 if (-1 == propIdx) {
3259 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3260 } else if (propIdx > 0xFFFF) {
3261 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3264 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3265 if (!aliasProperty.isScriptable())
3266 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3268 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3269 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3271 if (aliasProperty.type() < QVariant::UserType
3272 || uint(aliasProperty.type()) == QMetaType::QVariant)
3273 type = aliasProperty.type();
3275 if (alias.count() == 3) {
3276 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3278 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3280 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3282 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3283 if (valueTypeIndex == -1)
3284 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3285 Q_ASSERT(valueTypeIndex <= 0xFF);
3287 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3288 propIdx |= (valueTypeIndex << 16);
3290 // update the property type
3291 type = aliasProperty.type();
3292 if (type >= (int)QVariant::UserType)
3296 if (aliasProperty.isEnumType())
3297 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3299 typeName = aliasProperty.typeName();
3301 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3303 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3305 typeName = ref.type->typeName();
3307 typeName = ref.component->root->className();
3312 if (typeName.endsWith('*'))
3313 flags |= QML_ALIAS_FLAG_PTR;
3315 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3317 typedef QDeclarativeVMEMetaData VMD;
3318 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3319 *(vmd->aliasData() + aliasIndex) = aliasData;
3321 prop.nameRef = builder.newString(prop.name.utf8length());
3322 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3323 prop.typeRef = builder.newString(typeName.length());
3325 int propertyFlags = 0;
3327 propertyFlags |= QFastMetaBuilder::Writable;
3329 propertyFlags |= QFastMetaBuilder::Resettable;
3331 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3332 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3338 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3339 QDeclarativeScript::Property *prop,
3340 const BindingContext &ctxt)
3342 Q_ASSERT(prop->index != -1);
3343 Q_ASSERT(prop->parent);
3344 Q_ASSERT(prop->parent->metaObject());
3346 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3347 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3349 JSBindingReference *reference = pool->New<JSBindingReference>();
3350 reference->expression = value->value;
3351 reference->property = prop;
3352 reference->value = value;
3353 reference->bindingContext = ctxt;
3354 addBindingReference(reference);
3359 bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v,
3360 QDeclarativeScript::Property *prop,
3361 const QDeclarativeCompilerTypes::BindingContext &)
3363 Q_ASSERT(v->value.isScript());
3365 if (!prop->core.isWritable())
3368 AST::Node *binding = v->value.asAST();
3370 if (prop->type == QVariant::String) {
3371 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3372 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3373 if (i->name == qsTrId_string) {
3374 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3375 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3377 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3378 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3379 (!arg2 || !arg2->next)) {
3384 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3385 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3387 TrBindingReference *reference = pool->New<TrBindingReference>();
3388 reference->dataType = BindingReference::TrId;
3389 reference->text = text;
3391 v->bindingReference = reference;
3395 } else if (i->name == qsTr_string) {
3397 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3398 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3399 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3401 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3402 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3403 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3404 (!arg3 || !arg3->next)) {
3410 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3411 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3412 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3414 TrBindingReference *reference = pool->New<TrBindingReference>();
3415 reference->dataType = BindingReference::Tr;
3416 reference->text = text;
3417 reference->comment = comment;
3419 v->bindingReference = reference;
3432 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3433 QDeclarativeScript::Property *prop,
3434 QDeclarativeScript::Object *obj,
3435 QDeclarativeScript::Property *valueTypeProperty)
3438 Q_ASSERT(binding->bindingReference);
3440 const BindingReference &ref = *binding->bindingReference;
3441 if (ref.dataType == BindingReference::TrId) {
3442 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3444 Instruction::StoreTrIdString store;
3445 store.propertyIndex = prop->core.coreIndex;
3446 store.text = output->indexForByteArray(tr.text.toUtf8());
3448 output->addInstruction(store);
3449 } else if (ref.dataType == BindingReference::Tr) {
3450 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3452 Instruction::StoreTrString store;
3453 store.propertyIndex = prop->core.coreIndex;
3454 store.context = translationContextIndex();
3455 store.text = output->indexForByteArray(tr.text.toUtf8());
3456 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3458 output->addInstruction(store);
3459 } else if (ref.dataType == BindingReference::V4) {
3460 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3462 Instruction::StoreV4Binding store;
3463 store.value = js.compiledIndex;
3464 store.context = js.bindingContext.stack;
3465 store.owner = js.bindingContext.owner;
3466 if (valueTypeProperty) {
3467 store.property = (valueTypeProperty->index & 0xFFFF) |
3468 ((valueTypeProperty->type & 0xFF)) << 16 |
3469 ((prop->index & 0xFF) << 24);
3470 store.isRoot = (compileState->root == valueTypeProperty->parent);
3472 store.property = prop->index;
3473 store.isRoot = (compileState->root == obj);
3475 store.line = binding->location.start.line;
3476 store.column = binding->location.start.column;
3477 output->addInstruction(store);
3478 } else if (ref.dataType == BindingReference::V8) {
3479 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3481 Instruction::StoreV8Binding store;
3482 store.value = js.compiledIndex;
3483 store.context = js.bindingContext.stack;
3484 store.owner = js.bindingContext.owner;
3485 if (valueTypeProperty) {
3486 store.isRoot = (compileState->root == valueTypeProperty->parent);
3488 store.isRoot = (compileState->root == obj);
3490 store.line = binding->location.start.line;
3491 store.column = binding->location.start.column;
3493 Q_ASSERT(js.bindingContext.owner == 0 ||
3494 (js.bindingContext.owner != 0 && valueTypeProperty));
3495 if (js.bindingContext.owner) {
3496 store.property = genValueTypeData(prop, valueTypeProperty);
3498 store.property = prop->core;
3501 output->addInstruction(store);
3502 } else if (ref.dataType == BindingReference::QtScript) {
3503 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3505 QDeclarativeInstruction store;
3506 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3507 store.assignBinding.context = js.bindingContext.stack;
3508 store.assignBinding.owner = js.bindingContext.owner;
3509 store.assignBinding.line = binding->location.start.line;
3510 store.assignBinding.column = binding->location.start.column;
3512 if (valueTypeProperty) {
3513 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3515 store.assignBinding.isRoot = (compileState->root == obj);
3518 Q_ASSERT(js.bindingContext.owner == 0 ||
3519 (js.bindingContext.owner != 0 && valueTypeProperty));
3520 if (js.bindingContext.owner) {
3521 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3523 store.assignBinding.property = prop->core;
3525 output->addInstructionHelper(
3526 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3527 : QDeclarativeInstruction::StoreBindingOnAlias
3530 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3534 int QDeclarativeCompiler::genContextCache()
3536 if (compileState->ids.count() == 0)
3539 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3540 cache->reserve(compileState->ids.count());
3541 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3542 cache->add(o->id, o->idIndex);
3544 output->contextCaches.append(cache);
3545 return output->contextCaches.count() - 1;
3548 QDeclarativePropertyData
3549 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3550 QDeclarativeScript::Property *prop)
3552 typedef QDeclarativePropertyPrivate QDPP;
3553 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3554 enginePrivate->valueTypes[prop->type]->metaObject(),
3555 valueTypeProp->index, engine);
3558 bool QDeclarativeCompiler::completeComponentBuild()
3561 componentStats->componentStat.ids = compileState->ids.count();
3563 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3564 aliasObject = compileState->aliasingObjects.next(aliasObject))
3565 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3567 QV4Compiler::Expression expr(unit->imports());
3568 expr.component = compileState->root;
3569 expr.ids = &compileState->ids;
3570 expr.importCache = output->importCache;
3572 QV4Compiler bindingCompiler;
3574 QList<JSBindingReference*> sharedBindings;
3576 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3578 JSBindingReference &binding = *b;
3580 // ### We don't currently optimize for bindings on alias's - because
3581 // of the solution to QTBUG-13719
3582 if (!binding.property->isAlias) {
3583 expr.context = binding.bindingContext.object;
3584 expr.property = binding.property;
3585 expr.expression = binding.expression;
3587 int index = bindingCompiler.compile(expr, enginePrivate);
3589 binding.dataType = BindingReference::V4;
3590 binding.compiledIndex = index;
3592 componentStats->componentStat.optimizedBindings.append(b->value->location);
3597 // Pre-rewrite the expression
3598 QString expression = binding.expression.asScript();
3600 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3601 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3602 bool isSharable = false;
3603 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3605 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3606 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3607 binding.dataType = BindingReference::V8;
3608 sharedBindings.append(b);
3610 binding.dataType = BindingReference::QtScript;
3614 componentStats->componentStat.scriptBindings.append(b->value->location);
3617 if (!sharedBindings.isEmpty()) {
3619 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3621 return lhs->value->location.start.line < rhs->value->location.start.line;
3625 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3627 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3628 int lineNumber = startLineNumber;
3630 QString functionArray(QLatin1String("["));
3631 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3632 JSBindingReference *reference = sharedBindings.at(ii);
3633 QDeclarativeScript::Value *value = reference->value;
3634 const QString &expression = reference->rewrittenExpression;
3636 if (ii != 0) functionArray += QLatin1String(",");
3638 while (lineNumber < value->location.start.line) {
3640 functionArray += QLatin1String("\n");
3643 functionArray += expression;
3644 lineNumber += expression.count(QLatin1Char('\n'));
3645 reference->compiledIndex = ii;
3647 functionArray += QLatin1String("]");
3649 compileState->v8BindingProgram = functionArray;
3650 compileState->v8BindingProgramLine = startLineNumber;
3651 compileState->v8BindingProgramIndex = output->v8bindings.count();
3652 output->v8bindings.append(v8::Persistent<v8::Array>());
3655 if (bindingCompiler.isValid())
3656 compileState->compiledBindingData = bindingCompiler.program();
3658 // Check pop()'s matched push()'s
3659 Q_ASSERT(compileState->objectDepth.depth() == 0);
3660 Q_ASSERT(compileState->listDepth.depth() == 0);
3662 saveComponentState();
3667 void QDeclarativeCompiler::dumpStats()
3669 Q_ASSERT(componentStats);
3670 qWarning().nospace() << "QML Document: " << output->url.toString();
3671 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3672 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3673 qWarning().nospace() << " Component Line " << stat.lineNumber;
3674 qWarning().nospace() << " Total Objects: " << stat.objects;
3675 qWarning().nospace() << " IDs Used: " << stat.ids;
3676 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3680 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3681 if (0 == (ii % 10)) {
3682 if (ii) output.append("\n");
3687 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3689 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3690 output.append(") ");
3692 if (!output.isEmpty())
3693 qWarning().nospace() << output.constData();
3696 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3699 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3700 if (0 == (ii % 10)) {
3701 if (ii) output.append("\n");
3706 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3708 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3709 output.append(") ");
3711 if (!output.isEmpty())
3712 qWarning().nospace() << output.constData();
3718 Returns true if from can be assigned to a (QObject) property of type
3721 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3723 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3724 const QMetaObject *fromMo = from->metaObject();
3727 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3729 fromMo = fromMo->superClass();
3735 Returns the element name, as written in the QML file, for o.
3737 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3740 if (o->type != -1) {
3741 return output->types.at(o->type).className;
3747 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3750 const QMetaObject *mo = from->metatype;
3751 QDeclarativeType *type = 0;
3752 while (!type && mo) {
3753 type = QDeclarativeMetaType::qmlType(mo);
3754 mo = mo->superClass();
3759 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3761 const QMetaObject *mo = obj->metatype;
3763 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3765 return QStringList();
3767 QMetaClassInfo classInfo = mo->classInfo(idx);
3768 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3772 QDeclarativePropertyData *
3773 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3775 QDeclarativePropertyCache *cache = 0;
3777 if (object->synthCache)
3778 cache = object->synthCache;
3779 else if (object->type != -1)
3780 cache = output->types[object->type].createPropertyCache(engine);
3782 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3784 return cache->property(index);
3787 QDeclarativePropertyData *
3788 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3790 if (notInRevision) *notInRevision = false;
3792 QDeclarativePropertyCache *cache = 0;
3794 if (object->synthCache)
3795 cache = object->synthCache;
3796 else if (object->type != -1)
3797 cache = output->types[object->type].createPropertyCache(engine);
3799 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3801 QDeclarativePropertyData *d = cache->property(name);
3803 // Find the first property
3804 while (d && d->isFunction())
3805 d = cache->overrideData(d);
3807 if (d && !cache->isAllowedInRevision(d)) {
3808 if (notInRevision) *notInRevision = true;
3815 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3816 QDeclarativePropertyData *
3817 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3819 if (notInRevision) *notInRevision = false;
3821 QDeclarativePropertyCache *cache = 0;
3823 if (object->synthCache)
3824 cache = object->synthCache;
3825 else if (object->type != -1)
3826 cache = output->types[object->type].createPropertyCache(engine);
3828 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3831 QDeclarativePropertyData *d = cache->property(name);
3832 if (notInRevision) *notInRevision = false;
3834 while (d && !(d->isFunction()))
3835 d = cache->overrideData(d);
3837 if (d && !cache->isAllowedInRevision(d)) {
3838 if (notInRevision) *notInRevision = true;
3844 if (name.endsWith(Changed_string)) {
3845 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3847 d = property(object, propName, notInRevision);
3849 return cache->method(d->notifyIndex);
3855 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3856 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3857 bool *notInRevision)
3859 QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision);
3860 return d?d->coreIndex:-1;
3863 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3864 bool *notInRevision)
3866 return indexOfProperty(object, QStringRef(&name), notInRevision);
3869 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3870 bool *notInRevision)
3872 QDeclarativePropertyData *d = property(object, name, notInRevision);
3873 return d?d->coreIndex:-1;