1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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"));
262 bool ok = v->value.isNumber();
264 double n = v->value.asNumber();
265 if (double(uint(n)) != n)
268 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
273 bool ok = v->value.isNumber();
275 double n = v->value.asNumber();
276 if (double(int(n)) != n)
279 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
282 case QMetaType::Float:
283 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
285 case QVariant::Double:
286 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
288 case QVariant::Color:
291 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
292 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
295 #ifndef QT_NO_DATESTRING
299 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
300 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
306 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
307 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
310 case QVariant::DateTime:
313 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
314 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
317 #endif // QT_NO_DATESTRING
318 case QVariant::Point:
319 case QVariant::PointF:
322 QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
323 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
327 case QVariant::SizeF:
330 QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
331 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
335 case QVariant::RectF:
338 QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
339 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
344 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
347 case QVariant::Vector3D:
350 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
351 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
354 case QVariant::Vector4D:
357 QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok);
358 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
363 // check if assigning a literal value to a list property.
364 // in each case, check the singular, since an Array of the specified type
365 // will not go via this literal assignment codepath.
366 if (type == qMetaTypeId<QList<qreal> >()) {
367 if (!v->value.isNumber()) {
368 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
371 } else if (type == qMetaTypeId<QList<int> >()) {
372 bool ok = v->value.isNumber();
374 double n = v->value.asNumber();
375 if (double(int(n)) != n)
378 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
380 } else if (type == qMetaTypeId<QList<bool> >()) {
381 if (!v->value.isBoolean()) {
382 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
385 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
386 if (!v->value.isString()) {
387 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
390 } else if (type == qMetaTypeId<QList<QUrl> >()) {
391 if (!v->value.isString()) {
392 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
397 // otherwise, check for existence of string converter to custom type
398 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
400 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
407 static QUrl urlFromUserString(const QString &data)
410 // Preserve any valid percent-encoded octets supplied by the source
411 u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
416 Generate a store instruction for assigning literal \a v to property \a prop.
418 Any literal assignment that is approved in testLiteralAssignment() must have
419 a corresponding action in this method.
421 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop,
422 QDeclarativeScript::Value *v)
424 if (prop->core.isEnum()) {
425 Q_ASSERT(v->value.isNumber());
427 int value = (int)v->value.asNumber();
429 Instruction::StoreInteger instr;
430 instr.propertyIndex = prop->index;
432 output->addInstruction(instr);
436 int type = prop->type;
438 case QMetaType::QVariant:
440 if (v->value.isNumber()) {
441 double n = v->value.asNumber();
442 if (double(int(n)) == n) {
443 if (prop->core.isVMEProperty()) {
444 Instruction::StoreVarInteger instr;
445 instr.propertyIndex = prop->index;
446 instr.value = int(n);
447 output->addInstruction(instr);
449 Instruction::StoreVariantInteger instr;
450 instr.propertyIndex = prop->index;
451 instr.value = int(n);
452 output->addInstruction(instr);
455 if (prop->core.isVMEProperty()) {
456 Instruction::StoreVarDouble instr;
457 instr.propertyIndex = prop->index;
459 output->addInstruction(instr);
461 Instruction::StoreVariantDouble instr;
462 instr.propertyIndex = prop->index;
464 output->addInstruction(instr);
467 } else if (v->value.isBoolean()) {
468 if (prop->core.isVMEProperty()) {
469 Instruction::StoreVarBool instr;
470 instr.propertyIndex = prop->index;
471 instr.value = v->value.asBoolean();
472 output->addInstruction(instr);
474 Instruction::StoreVariantBool instr;
475 instr.propertyIndex = prop->index;
476 instr.value = v->value.asBoolean();
477 output->addInstruction(instr);
480 if (prop->core.isVMEProperty()) {
481 Instruction::StoreVar instr;
482 instr.propertyIndex = prop->index;
483 instr.value = output->indexForString(v->value.asString());
484 output->addInstruction(instr);
486 Instruction::StoreVariant instr;
487 instr.propertyIndex = prop->index;
488 instr.value = output->indexForString(v->value.asString());
489 output->addInstruction(instr);
494 case QVariant::String:
496 Instruction::StoreString instr;
497 instr.propertyIndex = prop->index;
498 instr.value = output->indexForString(v->value.asString());
499 output->addInstruction(instr);
502 case QVariant::StringList:
504 Instruction::StoreStringList instr;
505 instr.propertyIndex = prop->index;
506 instr.value = output->indexForString(v->value.asString());
507 output->addInstruction(instr);
510 case QVariant::ByteArray:
512 Instruction::StoreByteArray instr;
513 instr.propertyIndex = prop->index;
514 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
515 output->addInstruction(instr);
520 Instruction::StoreUrl instr;
521 QString string = v->value.asString();
522 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
523 instr.propertyIndex = prop->index;
524 instr.value = output->indexForUrl(u);
525 output->addInstruction(instr);
530 Instruction::StoreInteger instr;
531 instr.propertyIndex = prop->index;
532 instr.value = uint(v->value.asNumber());
533 output->addInstruction(instr);
538 Instruction::StoreInteger instr;
539 instr.propertyIndex = prop->index;
540 instr.value = int(v->value.asNumber());
541 output->addInstruction(instr);
544 case QMetaType::Float:
546 Instruction::StoreFloat instr;
547 instr.propertyIndex = prop->index;
548 instr.value = float(v->value.asNumber());
549 output->addInstruction(instr);
552 case QVariant::Double:
554 Instruction::StoreDouble instr;
555 instr.propertyIndex = prop->index;
556 instr.value = v->value.asNumber();
557 output->addInstruction(instr);
560 case QVariant::Color:
562 Instruction::StoreColor instr;
563 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
564 instr.propertyIndex = prop->index;
565 instr.value = c.rgba();
566 output->addInstruction(instr);
569 #ifndef QT_NO_DATESTRING
572 Instruction::StoreDate instr;
573 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
574 instr.propertyIndex = prop->index;
575 instr.value = d.toJulianDay();
576 output->addInstruction(instr);
581 Instruction::StoreTime instr;
582 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
583 instr.propertyIndex = prop->index;
584 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
585 ::memcpy(&instr.time, &time, sizeof(QTime));
586 output->addInstruction(instr);
589 case QVariant::DateTime:
591 Instruction::StoreDateTime instr;
592 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
593 QTime time = dateTime.time();
594 instr.propertyIndex = prop->index;
595 instr.date = dateTime.date().toJulianDay();
596 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
597 ::memcpy(&instr.time, &time, sizeof(QTime));
598 output->addInstruction(instr);
601 #endif // QT_NO_DATESTRING
602 case QVariant::Point:
604 Instruction::StorePoint instr;
606 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
607 instr.propertyIndex = prop->index;
608 instr.point.xp = point.x();
609 instr.point.yp = point.y();
610 output->addInstruction(instr);
613 case QVariant::PointF:
615 Instruction::StorePointF instr;
617 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
618 instr.propertyIndex = prop->index;
619 instr.point.xp = point.x();
620 instr.point.yp = point.y();
621 output->addInstruction(instr);
626 Instruction::StoreSize instr;
628 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
629 instr.propertyIndex = prop->index;
630 instr.size.wd = size.width();
631 instr.size.ht = size.height();
632 output->addInstruction(instr);
635 case QVariant::SizeF:
637 Instruction::StoreSizeF instr;
639 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
640 instr.propertyIndex = prop->index;
641 instr.size.wd = size.width();
642 instr.size.ht = size.height();
643 output->addInstruction(instr);
648 Instruction::StoreRect instr;
650 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
651 instr.propertyIndex = prop->index;
652 instr.rect.x1 = rect.left();
653 instr.rect.y1 = rect.top();
654 instr.rect.x2 = rect.right();
655 instr.rect.y2 = rect.bottom();
656 output->addInstruction(instr);
659 case QVariant::RectF:
661 Instruction::StoreRectF instr;
663 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
664 instr.propertyIndex = prop->index;
665 instr.rect.xp = rect.left();
666 instr.rect.yp = rect.top();
667 instr.rect.w = rect.width();
668 instr.rect.h = rect.height();
669 output->addInstruction(instr);
674 Instruction::StoreBool instr;
675 bool b = v->value.asBoolean();
676 instr.propertyIndex = prop->index;
678 output->addInstruction(instr);
681 case QVariant::Vector3D:
683 Instruction::StoreVector3D instr;
685 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
686 instr.propertyIndex = prop->index;
687 instr.vector.xp = vector.x();
688 instr.vector.yp = vector.y();
689 instr.vector.zp = vector.z();
690 output->addInstruction(instr);
693 case QVariant::Vector4D:
695 Instruction::StoreVector4D instr;
697 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
698 instr.propertyIndex = prop->index;
699 instr.vector.xp = vector.x();
700 instr.vector.yp = vector.y();
701 instr.vector.zp = vector.z();
702 instr.vector.wp = vector.w();
703 output->addInstruction(instr);
708 // generate single literal value assignment to a list property if required
709 if (type == qMetaTypeId<QList<qreal> >()) {
710 Instruction::StoreDoubleQList instr;
711 instr.propertyIndex = prop->index;
712 instr.value = v->value.asNumber();
713 output->addInstruction(instr);
715 } else if (type == qMetaTypeId<QList<int> >()) {
716 Instruction::StoreIntegerQList instr;
717 instr.propertyIndex = prop->index;
718 instr.value = int(v->value.asNumber());
719 output->addInstruction(instr);
721 } else if (type == qMetaTypeId<QList<bool> >()) {
722 Instruction::StoreBoolQList instr;
723 bool b = v->value.asBoolean();
724 instr.propertyIndex = prop->index;
726 output->addInstruction(instr);
728 } else if (type == qMetaTypeId<QList<QUrl> >()) {
729 Instruction::StoreUrlQList instr;
730 QString string = v->value.asString();
731 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
732 instr.propertyIndex = prop->index;
733 instr.value = output->indexForUrl(u);
734 output->addInstruction(instr);
736 } else if (type == qMetaTypeId<QList<QString> >()) {
737 Instruction::StoreStringQList instr;
738 instr.propertyIndex = prop->index;
739 instr.value = output->indexForString(v->value.asString());
740 output->addInstruction(instr);
744 // otherwise, generate custom type literal assignment
745 Instruction::AssignCustomType instr;
746 instr.propertyIndex = prop->index;
747 instr.primitive = output->indexForString(v->value.asString());
749 output->addInstruction(instr);
756 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
758 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
761 data->primitives.clear();
763 data->bytecode.resize(0);
767 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
768 with which the QDeclarativeCompiledData will be associated.
770 Returns true on success, false on failure. On failure, the compile errors
771 are available from errors().
773 If the environment variant QML_COMPILER_DUMP is set
774 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
775 on a successful compiler.
777 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
778 QDeclarativeTypeData *unit,
779 QDeclarativeCompiledData *out)
786 QDeclarativeScript::Object *root = unit->parser().tree();
789 this->engine = engine;
790 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
792 this->unitRoot = root;
796 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
797 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
799 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
800 QDeclarativeCompiledData::TypeReference ref;
802 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
803 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
806 ref.type = tref.type;
807 if (!ref.type->isCreatable()) {
808 QString err = ref.type->noCreationReason();
810 err = tr( "Element is not creatable.");
811 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
814 if (ref.type->containsRevisionedAttributes()) {
815 QDeclarativeError cacheError;
816 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
818 if (!ref.typePropertyCache)
819 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
820 ref.typePropertyCache->addref();
823 } else if (tref.typeData) {
824 ref.component = tref.typeData->compiledData();
826 ref.className = parserRef->name;
834 out->dumpInstructions();
837 Q_ASSERT(out->rootPropertyCache);
845 this->enginePrivate = 0;
847 this->cachedComponentTypeRef = -1;
848 this->cachedTranslationContextIndex = -1;
854 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
856 compileState = pool->New<ComponentCompileState>();
858 compileState->root = tree;
860 componentStats->componentStat.lineNumber = tree->location.start.line;
862 // Build global import scripts
863 QStringList importedScriptIndexes;
865 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
866 importedScriptIndexes.append(script.qualifier);
869 // We generate the importCache before we build the tree so that
870 // it can be used in the binding compiler. Given we "expect" the
871 // QML compilation to succeed, this isn't a waste.
872 output->importCache = new QDeclarativeTypeNameCache();
873 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
874 output->importCache->add(importedScriptIndexes.at(ii), ii);
875 unit->imports().populateCache(output->importCache, engine);
877 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
880 Instruction::Init init;
881 init.bindingsSize = compileState->totalBindingsCount;
882 init.parserStatusSize = compileState->parserStatusCount;
883 init.contextCache = genContextCache();
884 init.objectStackSize = compileState->objectDepth.maxDepth();
885 init.listStackSize = compileState->listDepth.maxDepth();
886 if (compileState->compiledBindingData.isEmpty())
887 init.compiledBinding = -1;
889 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
890 output->addInstruction(init);
892 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
893 Instruction::StoreImportedScript import;
894 import.value = output->scripts.count();
896 QDeclarativeScriptData *scriptData = script.script->scriptData();
897 scriptData->addref();
898 output->scripts << scriptData;
899 output->addInstruction(import);
902 if (!compileState->v8BindingProgram.isEmpty()) {
903 Instruction::InitV8Bindings bindings;
904 bindings.program = output->indexForString(compileState->v8BindingProgram);
905 bindings.programIndex = compileState->v8BindingProgramIndex;
906 bindings.line = compileState->v8BindingProgramLine;
907 output->addInstruction(bindings);
912 Instruction::SetDefault def;
913 output->addInstruction(def);
915 Instruction::Done done;
916 output->addInstruction(done);
918 Q_ASSERT(tree->metatype);
920 if (tree->metadata.isEmpty()) {
921 output->root = tree->metatype;
923 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
924 output->root = &output->rootData;
926 if (!tree->metadata.isEmpty())
927 enginePrivate->registerCompositeType(output);
930 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
932 for (int ii = 0; ii < list.count(); ++ii)
933 if (string == list.at(ii))
939 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
942 componentStats->componentStat.objects++;
944 Q_ASSERT (obj->type != -1);
945 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
946 obj->metatype = tr.metaObject();
949 obj->typeName = tr.type->qmlTypeName();
951 // This object is a "Component" element
952 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
953 COMPILE_CHECK(buildComponent(obj, ctxt));
958 typedef QDeclarativeInstruction I;
959 const I *init = ((const I *)tr.component->bytecode.constData());
960 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
962 // Adjust stack depths to include nested components
963 compileState->objectDepth.pushPop(init->init.objectStackSize);
964 compileState->listDepth.pushPop(init->init.listStackSize);
965 compileState->parserStatusCount += init->init.parserStatusSize;
966 compileState->totalBindingsCount += init->init.bindingsSize;
969 compileState->objectDepth.push();
971 // Object instantiations reset the binding context
972 BindingContext objCtxt(obj);
974 // Create the synthesized meta object, ignoring aliases
975 COMPILE_CHECK(checkDynamicMeta(obj));
976 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
977 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
979 // Find the native type and check for the QDeclarativeParserStatus interface
980 QDeclarativeType *type = toQmlType(obj);
982 obj->parserStatusCast = type->parserStatusCast();
983 if (obj->parserStatusCast != -1)
984 compileState->parserStatusCount++;
986 // Check if this is a custom parser type. Custom parser types allow
987 // assignments to non-existent properties. These assignments are then
988 // compiled by the type.
989 bool isCustomParser = output->types.at(obj->type).type &&
990 output->types.at(obj->type).type->customParser() != 0;
991 QList<QDeclarativeCustomParserProperty> customProps;
993 // Fetch the list of deferred properties
994 QStringList deferredList = deferredProperties(obj);
996 // Must do id property first. This is to ensure that the id given to any
997 // id reference created matches the order in which the objects are
999 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1000 if (prop->name() == id_string) {
1001 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1007 Property *defaultProperty = 0;
1008 Property *skipProperty = 0;
1009 if (obj->defaultProperty) {
1010 defaultProperty = obj->defaultProperty;
1012 Property *explicitProperty = 0;
1014 const QMetaObject *mo = obj->metatype;
1015 int idx = mo->indexOfClassInfo("DefaultProperty");
1017 QMetaClassInfo info = mo->classInfo(idx);
1018 const char *p = info.value();
1022 while (char c = p[plen++]) { ord |= c; };
1026 // Utf8 - unoptimal, but seldom hit
1027 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1028 QHashedStringRef r(*s);
1030 if (obj->propertiesHashField.test(r.hash())) {
1031 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1032 if (ep->name() == r) {
1033 explicitProperty = ep;
1039 if (!explicitProperty)
1040 defaultProperty->setName(r);
1043 QHashedCStringRef r(p, plen);
1045 if (obj->propertiesHashField.test(r.hash())) {
1046 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1047 if (ep->name() == r) {
1048 explicitProperty = ep;
1054 if (!explicitProperty) {
1055 // Set the default property name
1056 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1057 r.writeUtf16(buffer);
1058 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1064 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1066 skipProperty = explicitProperty; // We merge the values into defaultProperty
1068 // Find the correct insertion point
1069 Value *insertPos = 0;
1071 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1072 if (!(v->location.start < explicitProperty->values.first()->location.start))
1077 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1081 QDeclarativeCustomParser *cp = 0;
1083 cp = output->types.at(obj->type).type->customParser();
1085 // Build all explicit properties specified
1086 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1088 if (prop == skipProperty)
1090 if (prop->name() == id_string)
1093 bool canDefer = false;
1094 if (isCustomParser) {
1095 if (doesPropertyExist(prop, obj) &&
1096 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
1097 !isAttachedPropertyName(prop->name()))) {
1098 int ids = compileState->ids.count();
1099 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1100 canDefer = ids == compileState->ids.count();
1101 } else if (isSignalPropertyName(prop->name()) &&
1102 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
1103 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1105 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1108 if (isSignalPropertyName(prop->name())) {
1109 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1111 int ids = compileState->ids.count();
1112 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1113 canDefer = ids == compileState->ids.count();
1117 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1118 prop->isDeferred = true;
1122 // Build the default property
1123 if (defaultProperty) {
1124 Property *prop = defaultProperty;
1126 bool canDefer = false;
1127 if (isCustomParser) {
1128 if (doesPropertyExist(prop, obj)) {
1129 int ids = compileState->ids.count();
1130 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1131 canDefer = ids == compileState->ids.count();
1133 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1136 int ids = compileState->ids.count();
1137 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1138 canDefer = ids == compileState->ids.count();
1141 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1142 prop->isDeferred = true;
1145 // Compile custom parser parts
1146 if (isCustomParser && !customProps.isEmpty()) {
1148 cp->compiler = this;
1150 obj->custom = cp->compile(customProps);
1153 foreach (QDeclarativeError err, cp->errors()) {
1154 err.setUrl(output->url);
1159 compileState->objectDepth.pop();
1164 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1166 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1167 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1172 // Create the object
1173 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1174 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1176 Instruction::CreateSimpleObject create;
1177 create.create = output->types.at(obj->type).type->createFunction();
1178 create.typeSize = output->types.at(obj->type).type->createSize();
1179 create.type = obj->type;
1180 create.line = obj->location.start.line;
1181 create.column = obj->location.start.column;
1182 output->addInstruction(create);
1186 if (output->types.at(obj->type).type) {
1187 Instruction::CreateCppObject create;
1188 create.line = obj->location.start.line;
1189 create.column = obj->location.start.column;
1191 if (!obj->custom.isEmpty())
1192 create.data = output->indexForByteArray(obj->custom);
1193 create.type = obj->type;
1194 create.isRoot = (compileState->root == obj);
1195 output->addInstruction(create);
1197 Instruction::CreateQMLObject create;
1198 create.type = obj->type;
1199 create.isRoot = (compileState->root == obj);
1201 if (!obj->bindingBitmask.isEmpty()) {
1202 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1203 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1205 create.bindingBits = -1;
1207 output->addInstruction(create);
1209 Instruction::CompleteQMLObject complete;
1210 complete.line = obj->location.start.line;
1211 complete.column = obj->location.start.column;
1212 complete.isRoot = (compileState->root == obj);
1213 output->addInstruction(complete);
1217 // Setup the synthesized meta object if necessary
1218 if (!obj->metadata.isEmpty()) {
1219 Instruction::StoreMetaObject meta;
1220 meta.data = output->indexForByteArray(obj->metadata);
1221 meta.aliasData = output->indexForByteArray(obj->synthdata);
1222 meta.propertyCache = output->propertyCaches.count();
1224 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1225 Q_ASSERT(propertyCache);
1226 propertyCache->addref();
1228 // Add flag for alias properties
1229 if (!obj->synthdata.isEmpty()) {
1230 const QDeclarativeVMEMetaData *vmeMetaData =
1231 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1232 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1233 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1234 QDeclarativePropertyData *data = propertyCache->property(index);
1235 data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias);
1239 if (obj == unitRoot) {
1240 propertyCache->addref();
1241 output->rootPropertyCache = propertyCache;
1244 output->propertyCaches << propertyCache;
1245 output->addInstruction(meta);
1246 } else if (obj == unitRoot) {
1247 output->rootPropertyCache = tr.createPropertyCache(engine);
1248 output->rootPropertyCache->addref();
1251 // Set the object id
1252 if (!obj->id.isEmpty()) {
1253 Instruction::SetId id;
1254 id.value = output->indexForString(obj->id);
1255 id.index = obj->idIndex;
1256 output->addInstruction(id);
1260 if (tr.type && obj->parserStatusCast != -1) {
1261 Instruction::BeginObject begin;
1262 begin.castValue = obj->parserStatusCast;
1263 output->addInstruction(begin);
1269 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1271 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1272 Q_ASSERT(prop->scriptStringScope != -1);
1273 const QString &script = prop->values.first()->value.asScript();
1274 Instruction::StoreScriptString ss;
1275 ss.propertyIndex = prop->index;
1276 ss.value = output->indexForString(script);
1277 ss.scope = prop->scriptStringScope;
1278 // ss.bindingId = rewriteBinding(script, prop->name());
1279 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1280 ss.line = prop->location.start.line;
1281 ss.column = prop->location.start.column;
1282 output->addInstruction(ss);
1285 bool seenDefer = false;
1286 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1287 if (prop->isDeferred) {
1292 genValueProperty(prop, obj);
1295 Instruction::Defer defer;
1296 defer.deferCount = 0;
1297 int deferIdx = output->addInstruction(defer);
1298 int nextInstructionIndex = output->nextInstructionIndex();
1300 Instruction::DeferInit dinit;
1301 // XXX - these are now massive over allocations
1302 dinit.bindingsSize = compileState->totalBindingsCount;
1303 dinit.parserStatusSize = compileState->parserStatusCount;
1304 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1305 dinit.listStackSize = compileState->listDepth.maxDepth();
1306 output->addInstruction(dinit);
1308 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1309 if (!prop->isDeferred)
1311 genValueProperty(prop, obj);
1314 Instruction::Done done;
1315 output->addInstruction(done);
1317 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1320 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1322 QDeclarativeScript::Value *v = prop->values.first();
1324 if (v->type == Value::SignalObject) {
1326 genObject(v->object);
1328 Instruction::AssignSignalObject assign;
1329 assign.line = v->location.start.line;
1330 assign.signal = output->indexForString(prop->name().toString());
1331 output->addInstruction(assign);
1333 } else if (v->type == Value::SignalExpression) {
1335 Instruction::StoreSignal store;
1336 store.signalIndex = prop->index;
1337 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
1338 const QString &rewrite =
1339 rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString());
1340 store.value = output->indexForString(rewrite);
1341 store.context = v->signalExpressionContextStack;
1342 store.line = v->location.start.line;
1343 store.column = v->location.start.column;
1344 output->addInstruction(store);
1350 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1351 Instruction::FetchAttached fetch;
1352 fetch.id = prop->index;
1353 fetch.line = prop->location.start.line;
1354 output->addInstruction(fetch);
1356 genObjectBody(prop->value);
1358 Instruction::PopFetchedObject pop;
1359 output->addInstruction(pop);
1362 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1363 Instruction::FetchObject fetch;
1364 fetch.property = prop->index;
1365 fetch.line = prop->location.start.line;
1366 output->addInstruction(fetch);
1368 if (!prop->value->metadata.isEmpty()) {
1369 Instruction::StoreMetaObject meta;
1370 meta.data = output->indexForByteArray(prop->value->metadata);
1371 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1372 meta.propertyCache = -1;
1373 output->addInstruction(meta);
1376 genObjectBody(prop->value);
1378 Instruction::PopFetchedObject pop;
1379 output->addInstruction(pop);
1382 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1384 genValueTypeProperty(obj, prop);
1387 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1388 if (prop->isDeferred)
1391 genValueProperty(prop, obj);
1394 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1396 genValueTypeProperty(obj, prop);
1400 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1402 Instruction::FetchValueType fetch;
1403 fetch.property = prop->index;
1404 fetch.type = prop->type;
1405 fetch.bindingSkipList = 0;
1407 if (obj->type == -1 || output->types.at(obj->type).component) {
1408 // We only have to do this if this is a composite type. If it is a builtin
1409 // type it can't possibly already have bindings that need to be cleared.
1410 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1411 if (!vprop->values.isEmpty()) {
1412 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1413 fetch.bindingSkipList |= (1 << vprop->index);
1418 output->addInstruction(fetch);
1420 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1421 genPropertyAssignment(vprop, prop->value, prop);
1424 Instruction::PopValueType pop;
1425 pop.property = prop->index;
1426 pop.type = prop->type;
1427 pop.bindingSkipList = 0;
1428 output->addInstruction(pop);
1431 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1433 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1436 Instruction::CreateComponent create;
1437 create.line = root->location.start.line;
1438 create.column = root->location.start.column;
1439 create.endLine = root->location.end.line;
1440 create.isRoot = (compileState->root == obj);
1441 int createInstruction = output->addInstruction(create);
1442 int nextInstructionIndex = output->nextInstructionIndex();
1444 ComponentCompileState *oldCompileState = compileState;
1445 compileState = componentState(root);
1447 Instruction::Init init;
1448 init.bindingsSize = compileState->totalBindingsCount;
1449 init.parserStatusSize = compileState->parserStatusCount;
1450 init.contextCache = genContextCache();
1451 init.objectStackSize = compileState->objectDepth.maxDepth();
1452 init.listStackSize = compileState->listDepth.maxDepth();
1453 if (compileState->compiledBindingData.isEmpty())
1454 init.compiledBinding = -1;
1456 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1457 output->addInstruction(init);
1459 if (!compileState->v8BindingProgram.isEmpty()) {
1460 Instruction::InitV8Bindings bindings;
1461 bindings.program = output->indexForString(compileState->v8BindingProgram);
1462 bindings.programIndex = compileState->v8BindingProgramIndex;
1463 bindings.line = compileState->v8BindingProgramLine;
1464 output->addInstruction(bindings);
1469 Instruction::SetDefault def;
1470 output->addInstruction(def);
1472 Instruction::Done done;
1473 output->addInstruction(done);
1475 output->instruction(createInstruction)->createComponent.count =
1476 output->nextInstructionIndex() - nextInstructionIndex;
1478 compileState = oldCompileState;
1480 if (!obj->id.isEmpty()) {
1481 Instruction::SetId id;
1482 id.value = output->indexForString(obj->id);
1483 id.index = obj->idIndex;
1484 output->addInstruction(id);
1487 if (obj == unitRoot) {
1488 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1489 output->rootPropertyCache->addref();
1493 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1494 const BindingContext &ctxt)
1496 // The special "Component" element can only have the id property and a
1497 // default property, that actually defines the component's tree
1499 compileState->objectDepth.push();
1501 // Find, check and set the "id" property (if any)
1502 Property *idProp = 0;
1503 if (obj->properties.isMany() ||
1504 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1505 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1507 if (!obj->properties.isEmpty())
1508 idProp = obj->properties.first();
1511 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1512 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1513 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1515 QString idVal = idProp->values.first()->primitive();
1517 if (compileState->ids.value(idVal))
1518 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1524 // Check the Component tree is well formed
1525 if (obj->defaultProperty &&
1526 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1527 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1528 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1530 if (!obj->dynamicProperties.isEmpty())
1531 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1532 if (!obj->dynamicSignals.isEmpty())
1533 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1534 if (!obj->dynamicSlots.isEmpty())
1535 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1537 QDeclarativeScript::Object *root = 0;
1538 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1539 root = obj->defaultProperty->values.first()->object;
1542 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1544 // Build the component tree
1545 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1547 compileState->objectDepth.pop();
1552 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1553 const BindingContext &ctxt)
1555 ComponentCompileState *oldComponentCompileState = compileState;
1556 compileState = pool->New<ComponentCompileState>();
1557 compileState->root = obj;
1558 compileState->nested = true;
1560 if (componentStats) {
1561 ComponentStat oldComponentStat = componentStats->componentStat;
1563 componentStats->componentStat = ComponentStat();
1564 componentStats->componentStat.lineNumber = obj->location.start.line;
1567 COMPILE_CHECK(buildObject(obj, ctxt));
1569 COMPILE_CHECK(completeComponentBuild());
1571 componentStats->componentStat = oldComponentStat;
1574 COMPILE_CHECK(buildObject(obj, ctxt));
1576 COMPILE_CHECK(completeComponentBuild());
1579 compileState = oldComponentCompileState;
1585 // Build a sub-object. A sub-object is one that was not created directly by
1586 // QML - such as a grouped property object, or an attached object. Sub-object's
1587 // can't have an id, involve a custom parser, have attached properties etc.
1588 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1590 Q_ASSERT(obj->metatype);
1591 Q_ASSERT(!obj->defaultProperty);
1592 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1595 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1596 if (isSignalPropertyName(prop->name())) {
1597 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1599 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1606 int QDeclarativeCompiler::componentTypeRef()
1608 if (cachedComponentTypeRef == -1) {
1609 QDeclarativeType *t = QDeclarativeMetaType::qmlType(Component_import_string,1,0);
1610 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1611 if (output->types.at(ii).type == t) {
1612 cachedComponentTypeRef = ii;
1616 QDeclarativeCompiledData::TypeReference ref;
1617 ref.className = Component_string;
1619 output->types << ref;
1620 cachedComponentTypeRef = output->types.count() - 1;
1622 return cachedComponentTypeRef;
1625 int QDeclarativeCompiler::translationContextIndex()
1627 if (cachedTranslationContextIndex == -1) {
1628 // This code must match that in the qsTr() implementation
1629 QString path = output->url.toString();
1630 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1631 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1633 QByteArray contextUtf8 = context.toUtf8();
1634 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1636 return cachedTranslationContextIndex;
1639 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1640 const BindingContext &ctxt)
1642 Q_ASSERT(obj->metaObject());
1644 const QHashedStringRef &propName = prop->name();
1646 Q_ASSERT(propName.startsWith(on_string));
1647 QString name = propName.mid(2, -1).toString();
1649 // Note that the property name could start with any alpha or '_' or '$' character,
1650 // so we need to do the lower-casing of the first alpha character.
1651 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1652 if (name.at(firstAlphaIndex).isUpper()) {
1653 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1658 bool notInRevision = false;
1660 QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1664 if (notInRevision && 0 == property(obj, propName, 0)) {
1665 Q_ASSERT(obj->type != -1);
1666 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1667 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1669 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));
1671 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1675 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1677 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1681 if (prop->value || !prop->values.isOne())
1682 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1684 prop->index = sig->coreIndex;
1687 obj->addSignalProperty(prop);
1689 if (prop->values.first()->object) {
1690 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1691 prop->values.first()->type = Value::SignalObject;
1693 prop->values.first()->type = Value::SignalExpression;
1695 if (!prop->values.first()->value.isScript())
1696 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1698 QString script = prop->values.first()->value.asScript().trimmed();
1699 if (script.isEmpty())
1700 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1702 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1711 Returns true if (value) property \a prop exists on obj, false otherwise.
1713 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1714 QDeclarativeScript::Object *obj)
1716 if (prop->name().isEmpty())
1718 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1721 return property(obj, prop->name()) != 0;
1724 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1725 QDeclarativeScript::Object *obj,
1726 const BindingContext &ctxt)
1728 if (prop->isEmpty())
1729 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1731 const QMetaObject *metaObject = obj->metaObject();
1732 Q_ASSERT(metaObject);
1734 if (isAttachedPropertyName(prop->name())) {
1735 // Setup attached property data
1737 if (ctxt.isSubContext()) {
1738 // Attached properties cannot be used on sub-objects. Sub-objects
1739 // always exist in a binding sub-context, which is what we test
1741 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1744 QDeclarativeType *type = 0;
1745 QDeclarativeImportedNamespace *typeNamespace = 0;
1746 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1748 if (typeNamespace) {
1749 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1752 } else if (!type || !type->attachedPropertiesType()) {
1753 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1757 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1759 Q_ASSERT(type->attachedPropertiesFunction());
1760 prop->index = type->attachedPropertiesId();
1761 prop->value->metatype = type->attachedPropertiesType();
1763 // Setup regular property data
1764 bool notInRevision = false;
1765 QDeclarativePropertyData *d =
1766 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1768 if (d == 0 && notInRevision) {
1769 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1770 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1772 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));
1774 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1777 prop->index = d->coreIndex;
1779 } else if (prop->isDefault) {
1780 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1781 QDeclarativePropertyData defaultPropertyData;
1782 defaultPropertyData.load(p, engine);
1784 prop->setName(QLatin1String(p.name()));
1785 prop->core = defaultPropertyData;
1786 prop->index = prop->core.coreIndex;
1789 // We can't error here as the "id" property does not require a
1790 // successful index resolution
1791 if (prop->index != -1)
1792 prop->type = prop->core.propType;
1794 // Check if this is an alias
1795 if (prop->index != -1 &&
1797 prop->parent->type != -1 &&
1798 output->types.at(prop->parent->type).component) {
1800 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1801 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1802 prop->isAlias = true;
1805 if (prop->index != -1 && !prop->values.isEmpty())
1806 prop->parent->setBindingBit(prop->index);
1809 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1811 // The magic "id" behavior doesn't apply when "id" is resolved as a
1812 // default property or to sub-objects (which are always in binding
1814 COMPILE_CHECK(buildIdProperty(prop, obj));
1815 if (prop->type == QVariant::String &&
1816 prop->values.first()->value.isString())
1817 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1819 } else if (isAttachedPropertyName(prop->name())) {
1821 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1823 } else if (prop->index == -1) {
1825 if (prop->isDefault) {
1826 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1828 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1831 } else if (prop->value) {
1833 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1835 } else if (prop->core.isQList()) {
1837 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1839 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1841 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1845 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1852 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1853 QDeclarativeScript::Property *nsProp,
1854 QDeclarativeScript::Object *obj,
1855 const BindingContext &ctxt)
1858 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1860 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1862 if (!isAttachedPropertyName(prop->name()))
1863 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1865 // Setup attached property data
1867 QDeclarativeType *type = 0;
1868 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1870 if (!type || !type->attachedPropertiesType())
1871 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1874 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1876 Q_ASSERT(type->attachedPropertiesFunction());
1877 prop->index = type->index();
1878 prop->value->metatype = type->attachedPropertiesType();
1880 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1886 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1887 QDeclarativeScript::Object *obj)
1889 if (prop->core.isQList()) {
1890 genListProperty(prop, obj);
1892 genPropertyAssignment(prop, obj);
1896 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1897 QDeclarativeScript::Object *obj)
1899 int listType = enginePrivate->listType(prop->type);
1901 Instruction::FetchQList fetch;
1902 fetch.property = prop->index;
1903 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1904 fetch.type = listType;
1905 output->addInstruction(fetch);
1907 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1909 if (v->type == Value::CreatedObject) {
1911 genObject(v->object);
1912 if (listTypeIsInterface) {
1913 Instruction::AssignObjectList assign;
1914 assign.line = prop->location.start.line;
1915 output->addInstruction(assign);
1917 Instruction::StoreObjectQList store;
1918 output->addInstruction(store);
1921 } else if (v->type == Value::PropertyBinding) {
1923 genBindingAssignment(v, prop, obj);
1929 Instruction::PopQList pop;
1930 output->addInstruction(pop);
1933 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1934 QDeclarativeScript::Object *obj,
1935 QDeclarativeScript::Property *valueTypeProperty)
1937 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1939 Q_ASSERT(v->type == Value::CreatedObject ||
1940 v->type == Value::PropertyBinding ||
1941 v->type == Value::Literal);
1943 if (v->type == Value::CreatedObject) {
1945 genObject(v->object);
1947 if (QDeclarativeMetaType::isInterface(prop->type)) {
1949 Instruction::StoreInterface store;
1950 store.line = v->object->location.start.line;
1951 store.propertyIndex = prop->index;
1952 output->addInstruction(store);
1954 } else if (prop->type == QMetaType::QVariant) {
1956 if (prop->core.isVMEProperty()) {
1957 Instruction::StoreVarObject store;
1958 store.line = v->object->location.start.line;
1959 store.propertyIndex = prop->index;
1960 output->addInstruction(store);
1962 Instruction::StoreVariantObject store;
1963 store.line = v->object->location.start.line;
1964 store.propertyIndex = prop->index;
1965 output->addInstruction(store);
1971 Instruction::StoreObject store;
1972 store.line = v->object->location.start.line;
1973 store.propertyIndex = prop->index;
1974 output->addInstruction(store);
1977 } else if (v->type == Value::PropertyBinding) {
1979 genBindingAssignment(v, prop, obj, valueTypeProperty);
1981 } else if (v->type == Value::Literal) {
1983 genLiteralAssignment(prop, v);
1989 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1991 Q_ASSERT(v->type == Value::ValueSource ||
1992 v->type == Value::ValueInterceptor);
1994 if (v->type == Value::ValueSource) {
1995 genObject(v->object);
1997 Instruction::StoreValueSource store;
1998 if (valueTypeProperty) {
1999 store.property = genValueTypeData(prop, valueTypeProperty);
2002 store.property = prop->core;
2005 QDeclarativeType *valueType = toQmlType(v->object);
2006 store.castValue = valueType->propertyValueSourceCast();
2007 output->addInstruction(store);
2009 } else if (v->type == Value::ValueInterceptor) {
2010 genObject(v->object);
2012 Instruction::StoreValueInterceptor store;
2013 if (valueTypeProperty) {
2014 store.property = genValueTypeData(prop, valueTypeProperty);
2017 store.property = prop->core;
2020 QDeclarativeType *valueType = toQmlType(v->object);
2021 store.castValue = valueType->propertyValueInterceptorCast();
2022 output->addInstruction(store);
2028 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
2029 QDeclarativeScript::Object *obj)
2032 prop->values.isMany() ||
2033 prop->values.first()->object)
2034 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2036 QDeclarativeScript::Value *idValue = prop->values.first();
2037 QString val = idValue->primitive();
2039 COMPILE_CHECK(checkValidId(idValue, val));
2041 if (compileState->ids.value(val))
2042 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2044 prop->values.first()->type = Value::Id;
2052 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
2055 Q_ASSERT(!compileState->ids.value(id));
2056 Q_ASSERT(obj->id == id);
2057 obj->idIndex = compileState->ids.count();
2058 compileState->ids.append(obj);
2061 void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref)
2063 Q_ASSERT(ref->value && !ref->value->bindingReference);
2064 ref->value->bindingReference = ref;
2065 compileState->totalBindingsCount++;
2066 compileState->bindings.prepend(ref);
2069 void QDeclarativeCompiler::saveComponentState()
2071 Q_ASSERT(compileState->root);
2072 Q_ASSERT(compileState->root->componentCompileState == 0);
2074 compileState->root->componentCompileState = compileState;
2077 componentStats->savedComponentStats.append(componentStats->componentStat);
2080 QDeclarativeCompilerTypes::ComponentCompileState *
2081 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
2083 Q_ASSERT(obj->componentCompileState);
2084 return obj->componentCompileState;
2087 // Build attached property object. In this example,
2091 // GridView is an attached property object.
2092 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
2093 QDeclarativeScript::Object *obj,
2094 const BindingContext &ctxt)
2096 Q_ASSERT(prop->value);
2097 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2099 compileState->objectDepth.push();
2101 obj->addAttachedProperty(prop);
2103 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2105 compileState->objectDepth.pop();
2111 // Build "grouped" properties. In this example:
2113 // font.pointSize: 12
2114 // font.family: "Helvetica"
2116 // font is a nested property. pointSize and family are not.
2117 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
2118 QDeclarativeScript::Object *obj,
2119 const BindingContext &ctxt)
2121 Q_ASSERT(prop->type != 0);
2122 Q_ASSERT(prop->index != -1);
2124 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
2125 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2127 if (!prop->values.isEmpty()) {
2128 if (prop->values.first()->location < prop->value->location) {
2129 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2131 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2135 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2136 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2140 if (prop->isAlias) {
2141 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2142 vtProp->isAlias = true;
2146 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2147 prop->value, obj, ctxt.incr()));
2148 obj->addValueTypeProperty(prop);
2150 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2154 // Load the nested property's meta type
2155 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2156 if (!prop->value->metatype)
2157 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2159 if (!prop->values.isEmpty())
2160 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2162 obj->addGroupedProperty(prop);
2164 compileState->objectDepth.push();
2166 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2168 compileState->objectDepth.pop();
2174 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2175 QDeclarativeScript::Object *obj,
2176 QDeclarativeScript::Object *baseObj,
2177 const BindingContext &ctxt)
2179 compileState->objectDepth.push();
2181 if (obj->defaultProperty)
2182 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2183 obj->metatype = type->metaObject();
2185 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2187 QDeclarativePropertyData *d = property(obj, prop->name());
2189 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2191 prop->index = d->coreIndex;
2192 prop->type = d->propType;
2194 prop->isValueTypeSubProperty = true;
2197 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2199 if (prop->values.isMany()) {
2200 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2201 } else if (!prop->values.isEmpty()) {
2202 QDeclarativeScript::Value *value = prop->values.first();
2204 if (value->object) {
2205 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2206 } else if (value->value.isScript()) {
2207 // ### Check for writability
2209 //optimization for <Type>.<EnumValue> enum assignments
2210 bool isEnumAssignment = false;
2212 if (prop->core.isEnum())
2213 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2215 if (isEnumAssignment) {
2216 value->type = Value::Literal;
2218 JSBindingReference *reference = pool->New<JSBindingReference>();
2219 reference->expression = value->value;
2220 reference->property = prop;
2221 reference->value = value;
2222 reference->bindingContext = ctxt;
2223 reference->bindingContext.owner++;
2224 addBindingReference(reference);
2225 value->type = Value::PropertyBinding;
2228 COMPILE_CHECK(testLiteralAssignment(prop, value));
2229 value->type = Value::Literal;
2233 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2234 Q_ASSERT(v->object);
2236 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2239 obj->addValueProperty(prop);
2242 compileState->objectDepth.pop();
2247 // Build assignments to QML lists. QML lists are properties of type
2248 // QDeclarativeListProperty<T>. List properties can accept a list of
2249 // objects, or a single binding.
2250 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2251 QDeclarativeScript::Object *obj,
2252 const BindingContext &ctxt)
2254 Q_ASSERT(prop->core.isQList());
2256 compileState->listDepth.push();
2260 obj->addValueProperty(prop);
2262 int listType = enginePrivate->listType(t);
2263 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2265 bool assignedBinding = false;
2266 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2268 v->type = Value::CreatedObject;
2269 COMPILE_CHECK(buildObject(v->object, ctxt));
2271 // We check object coercian here. We check interface assignment
2273 if (!listTypeIsInterface) {
2274 if (!canCoerce(listType, v->object)) {
2275 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2279 } else if (v->value.isScript()) {
2280 if (assignedBinding)
2281 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2283 assignedBinding = true;
2284 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2285 v->type = Value::PropertyBinding;
2287 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2291 compileState->listDepth.pop();
2296 // Compiles an assignment to a QDeclarativeScriptString property
2297 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2298 QDeclarativeScript::Object *obj,
2299 const BindingContext &ctxt)
2301 if (prop->values.isMany())
2302 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2304 if (prop->values.first()->object)
2305 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2307 prop->scriptStringScope = ctxt.stack;
2308 obj->addScriptStringProperty(prop);
2313 // Compile regular property assignments of the form "property: <value>"
2314 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2315 QDeclarativeScript::Object *obj,
2316 const BindingContext &ctxt)
2318 obj->addValueProperty(prop);
2320 if (prop->values.isMany())
2321 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2323 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2326 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2330 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2335 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2336 Q_ASSERT(v->object);
2337 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2343 // Compile assigning a single object instance to a regular property
2344 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2345 QDeclarativeScript::Object *obj,
2346 QDeclarativeScript::Value *v,
2347 const BindingContext &ctxt)
2349 Q_ASSERT(prop->index != -1);
2350 Q_ASSERT(v->object->type != -1);
2352 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2353 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2355 if (QDeclarativeMetaType::isInterface(prop->type)) {
2357 // Assigning an object to an interface ptr property
2358 COMPILE_CHECK(buildObject(v->object, ctxt));
2360 v->type = Value::CreatedObject;
2362 } else if (prop->type == QMetaType::QVariant) {
2364 // Assigning an object to a QVariant
2365 COMPILE_CHECK(buildObject(v->object, ctxt));
2367 v->type = Value::CreatedObject;
2369 // Normally buildObject() will set this up, but we need the static
2370 // meta object earlier to test for assignability. It doesn't matter
2371 // that there may still be outstanding synthesized meta object changes
2372 // on this type, as they are not relevant for assignability testing
2373 v->object->metatype = output->types.at(v->object->type).metaObject();
2374 Q_ASSERT(v->object->metaObject());
2376 // We want to raw metaObject here as the raw metaobject is the
2377 // actual property type before we applied any extensions that might
2378 // effect the properties on the type, but don't effect assignability
2379 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2381 // Will be true if the assgned type inherits propertyMetaObject
2382 bool isAssignable = false;
2383 // Determine isAssignable value
2384 if (propertyMetaObject) {
2385 const QMetaObject *c = v->object->metatype;
2387 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2388 c = c->superClass();
2393 // Simple assignment
2394 COMPILE_CHECK(buildObject(v->object, ctxt));
2396 v->type = Value::CreatedObject;
2397 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2398 // Automatic "Component" insertion
2399 QDeclarativeScript::Object *root = v->object;
2400 QDeclarativeScript::Object *component = pool->New<Object>();
2401 component->type = componentTypeRef();
2402 component->typeName = QStringLiteral("Qt/Component");
2403 component->metatype = &QDeclarativeComponent::staticMetaObject;
2404 component->location = root->location;
2405 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2406 componentValue->object = root;
2407 component->getDefaultProperty()->addValue(componentValue);
2408 v->object = component;
2409 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2411 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2418 // Compile assigning a single object instance to a regular property using the "on" syntax.
2422 // NumberAnimation on x { }
2424 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2425 QDeclarativeScript::Object *obj,
2426 QDeclarativeScript::Object *baseObj,
2427 QDeclarativeScript::Value *v,
2428 const BindingContext &ctxt)
2430 Q_ASSERT(prop->index != -1);
2431 Q_ASSERT(v->object->type != -1);
2435 if (!prop->core.isWritable())
2436 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2439 // Normally buildObject() will set this up, but we need the static
2440 // meta object earlier to test for assignability. It doesn't matter
2441 // that there may still be outstanding synthesized meta object changes
2442 // on this type, as they are not relevant for assignability testing
2443 v->object->metatype = output->types.at(v->object->type).metaObject();
2444 Q_ASSERT(v->object->metaObject());
2446 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2447 bool isPropertyValue = false;
2448 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2449 bool isPropertyInterceptor = false;
2450 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2451 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2452 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2455 if (isPropertyValue || isPropertyInterceptor) {
2456 // Assign as a property value source
2457 COMPILE_CHECK(buildObject(v->object, ctxt));
2459 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2460 buildDynamicMeta(baseObj, ForceCreation);
2461 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2463 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2469 // Compile assigning a literal or binding to a regular property
2470 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2471 QDeclarativeScript::Object *obj,
2472 QDeclarativeScript::Value *v,
2473 const BindingContext &ctxt)
2475 Q_ASSERT(prop->index != -1);
2477 if (v->value.isScript()) {
2479 //optimization for <Type>.<EnumValue> enum assignments
2480 if (prop->core.isEnum()) {
2481 bool isEnumAssignment = false;
2482 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2483 if (isEnumAssignment) {
2484 v->type = Value::Literal;
2489 // Test for other binding optimizations
2490 if (!buildLiteralBinding(v, prop, ctxt))
2491 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2493 v->type = Value::PropertyBinding;
2497 COMPILE_CHECK(testLiteralAssignment(prop, v));
2499 v->type = Value::Literal;
2505 bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
2506 QDeclarativeScript::Object *obj,
2507 QDeclarativeScript::Value *v,
2510 *isAssignment = false;
2511 if (!prop->core.isEnum())
2514 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2516 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2517 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2519 QString string = v->value.asString();
2520 if (!string.at(0).isUpper())
2523 QStringList parts = string.split(QLatin1Char('.'));
2524 if (parts.count() != 2)
2527 QString typeName = parts.at(0);
2528 QDeclarativeType *type = 0;
2529 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2531 //handle enums on value types (where obj->typeName is empty)
2532 QString objTypeName = obj->typeName;
2533 if (objTypeName.isEmpty()) {
2534 QDeclarativeType *objType = toQmlType(obj);
2536 objTypeName = objType->qmlTypeName();
2542 QString enumValue = parts.at(1);
2546 if (objTypeName == type->qmlTypeName()) {
2547 // When these two match, we can short cut the search
2548 if (mprop.isFlagType()) {
2549 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2551 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2554 // Otherwise we have to search the whole type
2555 // This matches the logic in QV8TypeWrapper
2556 QByteArray enumName = enumValue.toUtf8();
2557 const QMetaObject *metaObject = type->baseMetaObject();
2559 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2560 QMetaEnum e = metaObject->enumerator(ii);
2561 value = e.keyToValue(enumName.constData(), &ok);
2568 v->type = Value::Literal;
2569 v->value = QDeclarativeScript::Variant((double)value);
2570 *isAssignment = true;
2575 struct StaticQtMetaObject : public QObject
2577 static const QMetaObject *get()
2578 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2581 // Similar logic to above, but not knowing target property.
2582 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2584 int dot = script.indexOf('.');
2586 const QByteArray &scope = script.left(dot);
2587 QDeclarativeType *type = 0;
2588 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2589 if (!type && scope != "Qt")
2591 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2592 const char *key = script.constData() + dot+1;
2593 int i = mo->enumeratorCount();
2596 int v = mo->enumerator(i).keyToValue(key, &ok);
2604 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2606 QDeclarativeType *qmltype = 0;
2607 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2611 return qmltype->metaObject();
2614 // similar to logic of completeComponentBuild, but also sticks data
2615 // into primitives at the end
2616 int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name)
2618 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2619 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2621 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2623 return output->indexForString(rewrite);
2626 QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name)
2628 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
2629 return rewriteSignalHandler(handler, name);
2632 // Ensures that the dynamic meta specification on obj is valid
2633 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2635 bool seenDefaultProperty = false;
2637 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2638 // Calculating the hash for the names is not a waste as we have to test
2639 // them against the illegalNames set anyway.
2640 QHashField propNames;
2641 QHashField methodNames;
2644 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2645 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2647 if (prop.isDefaultProperty) {
2648 if (seenDefaultProperty)
2649 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2650 seenDefaultProperty = true;
2653 if (propNames.testAndSet(prop.name.hash())) {
2654 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2655 p2 = obj->dynamicProperties.next(p2)) {
2656 if (p2->name == prop.name) {
2657 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2658 prop.nameLocation.column,
2659 tr("Duplicate property name"));
2664 if (prop.name.at(0).isUpper()) {
2665 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2666 prop.nameLocation.column,
2667 tr("Property names cannot begin with an upper case letter"));
2670 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2671 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2672 prop.nameLocation.column,
2673 tr("Illegal property name"));
2677 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2678 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2680 if (methodNames.testAndSet(currSig.name.hash())) {
2681 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2682 s2 = obj->dynamicSignals.next(s2)) {
2683 if (s2->name == currSig.name)
2684 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2688 if (currSig.name.at(0).isUpper())
2689 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2690 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2691 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2694 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2695 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2697 if (methodNames.testAndSet(currSlot.name.hash())) {
2698 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2699 s2 = obj->dynamicSignals.next(s2)) {
2700 if (s2->name == currSlot.name)
2701 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2703 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2704 s2 = obj->dynamicSlots.next(s2)) {
2705 if (s2->name == currSlot.name)
2706 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2710 if (currSlot.name.at(0).isUpper())
2711 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2712 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2713 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2719 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2721 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2722 p = obj->dynamicProperties.next(p)) {
2724 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2727 Property *property = 0;
2728 if (p->isDefaultProperty) {
2729 property = obj->getDefaultProperty();
2731 property = obj->getProperty(p->name);
2732 if (!property->values.isEmpty())
2733 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2737 property->isReadOnlyDeclaration = true;
2739 if (property->value)
2740 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2742 property->values.append(p->defaultValue->values);
2747 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2749 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2752 Q_ASSERT(obj->metatype);
2754 if (mode != ForceCreation &&
2755 obj->dynamicProperties.isEmpty() &&
2756 obj->dynamicSignals.isEmpty() &&
2757 obj->dynamicSlots.isEmpty())
2760 bool resolveAlias = (mode == ResolveAliases);
2762 const Object::DynamicProperty *defaultProperty = 0;
2764 int varPropCount = 0;
2765 int totalPropCount = 0;
2766 int firstPropertyVarIndex = 0;
2768 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2770 if (p->type == Object::DynamicProperty::Alias)
2772 if (p->type == Object::DynamicProperty::Var)
2775 if (p->isDefaultProperty &&
2776 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2777 defaultProperty = p;
2779 if (!resolveAlias) {
2780 // No point doing this for both the alias and non alias cases
2781 QDeclarativePropertyData *d = property(obj, p->name);
2782 if (d && d->isFinal())
2783 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2787 bool buildData = resolveAlias || aliasCount == 0;
2789 QByteArray dynamicData;
2791 typedef QDeclarativeVMEMetaData VMD;
2793 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2794 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2795 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2796 aliasCount * sizeof(VMD::AliasData), 0);
2799 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2801 QByteArray newClassName = obj->metatype->className();
2802 newClassName.append("_QML_");
2803 newClassName.append(QByteArray::number(uniqueClassId));
2805 if (compileState->root == obj && !compileState->nested) {
2806 QString path = output->url.path();
2807 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2808 if (lastSlash > -1) {
2809 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2810 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2811 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2815 QFastMetaBuilder builder;
2816 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2817 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2818 obj->dynamicSlots.count(),
2819 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2820 defaultProperty?1:0);
2823 Object::DynamicProperty::Type dtype;
2825 const char *cppType;
2826 } builtinTypes[] = {
2827 { Object::DynamicProperty::Var, 0, "QVariant" },
2828 { Object::DynamicProperty::Variant, 0, "QVariant" },
2829 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2830 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2831 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2832 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2833 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2834 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2835 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2836 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2837 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2839 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2840 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2842 // Reserve dynamic properties
2843 if (obj->dynamicProperties.count()) {
2844 typedef QDeclarativeVMEMetaData VMD;
2846 int effectivePropertyIndex = 0;
2847 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2849 // Reserve space for name
2850 p->nameRef = builder.newString(p->name.utf8length());
2852 int propertyType = 0;
2853 bool readonly = false;
2854 QFastMetaBuilder::StringRef typeRef;
2856 if (p->type == Object::DynamicProperty::Alias) {
2858 } else if (p->type < builtinTypeCount) {
2859 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2860 propertyType = builtinTypes[p->type].metaType;
2861 if (typeRefs[p->type].isEmpty())
2862 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2863 typeRef = typeRefs[p->type];
2864 if (p->type == Object::DynamicProperty::Variant)
2868 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2869 p->type == Object::DynamicProperty::Custom);
2871 // XXX don't double resolve this in the case of an alias run
2873 QByteArray customTypeName;
2874 QDeclarativeType *qmltype = 0;
2876 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2877 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2880 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2882 Q_ASSERT(tdata->isComplete());
2884 QDeclarativeCompiledData *data = tdata->compiledData();
2885 customTypeName = data->root->className();
2889 customTypeName = qmltype->typeName();
2892 if (p->type == Object::DynamicProperty::Custom) {
2893 customTypeName += '*';
2894 propertyType = QMetaType::QObjectStar;
2897 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2898 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2901 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2902 p->typeRef = builder.newString(customTypeName.length());
2903 typeRef = p->typeRef;
2906 if (p->type == Object::DynamicProperty::Var)
2913 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2914 vmd->propertyCount++;
2915 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2918 if (p->type < builtinTypeCount)
2919 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2920 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2921 effectivePropertyIndex);
2923 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2924 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2925 effectivePropertyIndex);
2927 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2928 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2930 effectivePropertyIndex++;
2934 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2936 vmd->varPropertyCount = varPropCount;
2937 firstPropertyVarIndex = effectivePropertyIndex;
2938 totalPropCount = varPropCount + effectivePropertyIndex;
2939 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2940 if (p->type == Object::DynamicProperty::Var) {
2941 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2943 vmd->propertyCount++;
2944 (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
2947 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2948 (QMetaType::Type)-1,
2949 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2950 effectivePropertyIndex);
2952 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2953 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2955 effectivePropertyIndex++;
2962 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2963 if (p->type == Object::DynamicProperty::Alias) {
2965 Q_ASSERT(buildData);
2966 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2967 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2970 // Even if we aren't resolving the alias, we need a fake signal so that the
2971 // metaobject remains consistent across the resolve and non-resolve alias runs
2972 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2973 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2974 effectivePropertyIndex++;
2981 // Reserve default property
2982 QFastMetaBuilder::StringRef defPropRef;
2983 if (defaultProperty) {
2984 defPropRef = builder.newString(strlen("DefaultProperty"));
2985 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2988 // Reserve dynamic signals
2989 int signalIndex = 0;
2990 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2992 int paramCount = s->parameterNames.count();
2994 int signatureSize = s->name.utf8length() + 2 /* paren */;
2996 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2997 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2999 s->signatureRef = builder.newString(signatureSize);
3000 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3003 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
3005 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
3009 // Reserve dynamic slots
3010 if (obj->dynamicSlots.count()) {
3012 // Allocate QVariant string
3013 if (typeRefs[0].isEmpty())
3014 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
3016 typedef QDeclarativeVMEMetaData VMD;
3018 int methodIndex = 0;
3019 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3020 int paramCount = s->parameterNames.count();
3022 int signatureSize = s->name.utf8length() + 2 /* paren */;
3024 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
3025 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3027 s->signatureRef = builder.newString(signatureSize);
3028 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3030 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
3034 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3035 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3036 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3037 for (int jj = 0; jj < paramCount; ++jj) {
3038 if (jj) funcScript.append(QLatin1Char(','));
3039 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3041 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3043 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3044 funcScript.length(),
3045 s->location.start.line };
3047 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
3050 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3052 md.bodyOffset = dynamicData.size();
3054 dynamicData.append((const char *)funcScript.constData(),
3055 (funcScript.length() * sizeof(QChar)));
3062 // Now allocate used builtin types
3063 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3064 if (!typeRefs[ii].isEmpty())
3065 typeRefs[ii].load(builtinTypes[ii].cppType);
3068 // Now allocate properties
3069 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3071 char *d = p->changedSignatureRef.data();
3072 p->name.writeUtf8(d);
3073 strcpy(d + p->name.utf8length(), "Changed()");
3075 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3078 p->nameRef.load(p->name);
3080 if (p->type >= builtinTypeCount) {
3081 Q_ASSERT(p->resolvedCustomTypeName);
3082 p->typeRef.load(*p->resolvedCustomTypeName);
3086 // Allocate default property if necessary
3087 if (defaultProperty)
3088 strcpy(defPropRef.data(), "DefaultProperty");
3090 // Now allocate signals
3091 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3093 char *d = s->signatureRef.data();
3094 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3095 s->name.writeUtf8(d); d += s->name.utf8length();
3098 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3099 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3100 strcpy(d, s->parameterTypes.at(jj).constData());
3101 d += s->parameterTypes.at(jj).length();
3102 s->parameterNames.at(jj).writeUtf8(d2);
3103 d2 += s->parameterNames.at(jj).utf8length();
3110 // Now allocate methods
3111 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3112 char *d = s->signatureRef.data();
3113 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3114 s->name.writeUtf8(d); d += s->name.utf8length();
3116 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3117 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3118 strcpy(d, "QVariant");
3119 d += strlen("QVariant");
3120 strcpy(d2, s->parameterNames.at(jj).constData());
3121 d2 += s->parameterNames.at(jj).length();
3128 // Now allocate class name
3129 classNameRef.load(newClassName);
3131 obj->metadata = builder.toData();
3132 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3134 if (mode == IgnoreAliases && aliasCount)
3135 compileState->aliasingObjects.append(obj);
3137 obj->synthdata = dynamicData;
3139 if (obj->synthCache) {
3140 obj->synthCache->release();
3141 obj->synthCache = 0;
3144 if (obj->type != -1) {
3145 QDeclarativePropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3146 QDeclarativePropertyCache *cache =
3147 superCache->copyAndAppend(engine, &obj->extObject,
3148 QDeclarativePropertyData::NoFlags,
3149 QDeclarativePropertyData::IsVMEFunction,
3150 QDeclarativePropertyData::IsVMESignal);
3152 // now we modify the flags appropriately for var properties.
3153 int propertyOffset = obj->extObject.propertyOffset();
3154 QDeclarativePropertyData *currPropData = 0;
3155 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3156 currPropData = cache->property(pvi + propertyOffset);
3157 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty);
3160 obj->synthCache = cache;
3166 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3169 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3171 QChar ch = val.at(0);
3172 if (ch.isLetter() && !ch.isLower())
3173 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3175 QChar u(QLatin1Char('_'));
3176 if (!ch.isLetter() && ch != u)
3177 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3179 for (int ii = 1; ii < val.count(); ++ii) {
3181 if (!ch.isLetterOrNumber() && ch != u)
3182 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3185 if (enginePrivate->v8engine()->illegalNames().contains(val))
3186 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3191 #include <private/qdeclarativejsparser_p.h>
3193 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3195 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3197 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3198 return QStringList() << name;
3199 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3200 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3202 QStringList rv = astNodeToStringList(expr->base);
3205 rv.append(expr->name.toString());
3208 return QStringList();
3211 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3213 QDeclarativeScript::Object *obj,
3214 int propIndex, int aliasIndex,
3215 Object::DynamicProperty &prop)
3217 if (!prop.defaultValue)
3218 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3220 if (!prop.defaultValue->values.isOne() ||
3221 prop.defaultValue->values.first()->object ||
3222 !prop.defaultValue->values.first()->value.isScript())
3223 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3225 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3227 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3229 QStringList alias = astNodeToStringList(node);
3231 if (alias.count() < 1 || alias.count() > 3)
3232 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3234 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3236 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3238 QByteArray typeName;
3243 bool writable = false;
3244 bool resettable = false;
3245 if (alias.count() == 2 || alias.count() == 3) {
3246 propIdx = indexOfProperty(idObject, alias.at(1));
3248 if (-1 == propIdx) {
3249 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3250 } else if (propIdx > 0xFFFF) {
3251 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3254 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3255 if (!aliasProperty.isScriptable())
3256 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3258 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3259 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3261 if (aliasProperty.type() < QVariant::UserType ||
3262 aliasProperty.type() == QVariant::LastType /* for QVariant */ )
3263 type = aliasProperty.type();
3265 if (alias.count() == 3) {
3266 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3268 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3270 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3272 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3273 if (valueTypeIndex == -1)
3274 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3275 Q_ASSERT(valueTypeIndex <= 0xFF);
3277 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3278 propIdx |= (valueTypeIndex << 16);
3280 // update the property type
3281 type = aliasProperty.type();
3282 if (type >= (int)QVariant::UserType)
3286 if (aliasProperty.isEnumType())
3287 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3289 typeName = aliasProperty.typeName();
3291 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3293 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3295 typeName = ref.type->typeName();
3297 typeName = ref.component->root->className();
3302 if (typeName.endsWith('*'))
3303 flags |= QML_ALIAS_FLAG_PTR;
3305 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3307 typedef QDeclarativeVMEMetaData VMD;
3308 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3309 *(vmd->aliasData() + aliasIndex) = aliasData;
3311 prop.nameRef = builder.newString(prop.name.utf8length());
3312 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3313 prop.typeRef = builder.newString(typeName.length());
3315 int propertyFlags = 0;
3317 propertyFlags |= QFastMetaBuilder::Writable;
3319 propertyFlags |= QFastMetaBuilder::Resettable;
3321 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3322 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3328 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3329 QDeclarativeScript::Property *prop,
3330 const BindingContext &ctxt)
3332 Q_ASSERT(prop->index != -1);
3333 Q_ASSERT(prop->parent);
3334 Q_ASSERT(prop->parent->metaObject());
3336 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3337 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3339 JSBindingReference *reference = pool->New<JSBindingReference>();
3340 reference->expression = value->value;
3341 reference->property = prop;
3342 reference->value = value;
3343 reference->bindingContext = ctxt;
3344 addBindingReference(reference);
3349 bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v,
3350 QDeclarativeScript::Property *prop,
3351 const QDeclarativeCompilerTypes::BindingContext &)
3353 Q_ASSERT(v->value.isScript());
3355 if (!prop->core.isWritable())
3358 AST::Node *binding = v->value.asAST();
3360 if (prop->type == QVariant::String) {
3361 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3362 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3363 if (i->name == qsTrId_string) {
3364 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3365 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3367 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3368 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3369 (!arg2 || !arg2->next)) {
3374 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3375 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3377 TrBindingReference *reference = pool->New<TrBindingReference>();
3378 reference->dataType = BindingReference::TrId;
3379 reference->text = text;
3381 v->bindingReference = reference;
3385 } else if (i->name == qsTr_string) {
3387 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3388 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3389 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3391 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3392 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3393 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3394 (!arg3 || !arg3->next)) {
3400 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3401 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3402 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3404 TrBindingReference *reference = pool->New<TrBindingReference>();
3405 reference->dataType = BindingReference::Tr;
3406 reference->text = text;
3407 reference->comment = comment;
3409 v->bindingReference = reference;
3422 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3423 QDeclarativeScript::Property *prop,
3424 QDeclarativeScript::Object *obj,
3425 QDeclarativeScript::Property *valueTypeProperty)
3428 Q_ASSERT(binding->bindingReference);
3430 const BindingReference &ref = *binding->bindingReference;
3431 if (ref.dataType == BindingReference::TrId) {
3432 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3434 Instruction::StoreTrIdString store;
3435 store.propertyIndex = prop->core.coreIndex;
3436 store.text = output->indexForByteArray(tr.text.toUtf8());
3438 output->addInstruction(store);
3439 } else if (ref.dataType == BindingReference::Tr) {
3440 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3442 Instruction::StoreTrString store;
3443 store.propertyIndex = prop->core.coreIndex;
3444 store.context = translationContextIndex();
3445 store.text = output->indexForByteArray(tr.text.toUtf8());
3446 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3448 output->addInstruction(store);
3449 } else if (ref.dataType == BindingReference::V4) {
3450 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3452 Instruction::StoreV4Binding store;
3453 store.value = js.compiledIndex;
3454 store.context = js.bindingContext.stack;
3455 store.owner = js.bindingContext.owner;
3456 if (valueTypeProperty) {
3457 store.property = (valueTypeProperty->index & 0xFFFF) |
3458 ((valueTypeProperty->type & 0xFF)) << 16 |
3459 ((prop->index & 0xFF) << 24);
3460 store.isRoot = (compileState->root == valueTypeProperty->parent);
3462 store.property = prop->index;
3463 store.isRoot = (compileState->root == obj);
3465 store.line = binding->location.start.line;
3466 store.column = binding->location.start.column;
3467 output->addInstruction(store);
3468 } else if (ref.dataType == BindingReference::V8) {
3469 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3471 Instruction::StoreV8Binding store;
3472 store.value = js.compiledIndex;
3473 store.context = js.bindingContext.stack;
3474 store.owner = js.bindingContext.owner;
3475 if (valueTypeProperty) {
3476 store.isRoot = (compileState->root == valueTypeProperty->parent);
3478 store.isRoot = (compileState->root == obj);
3480 store.line = binding->location.start.line;
3481 store.column = binding->location.start.column;
3483 Q_ASSERT(js.bindingContext.owner == 0 ||
3484 (js.bindingContext.owner != 0 && valueTypeProperty));
3485 if (js.bindingContext.owner) {
3486 store.property = genValueTypeData(prop, valueTypeProperty);
3488 store.property = prop->core;
3491 output->addInstruction(store);
3492 } else if (ref.dataType == BindingReference::QtScript) {
3493 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3495 QDeclarativeInstruction store;
3496 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3497 store.assignBinding.context = js.bindingContext.stack;
3498 store.assignBinding.owner = js.bindingContext.owner;
3499 store.assignBinding.line = binding->location.start.line;
3500 store.assignBinding.column = binding->location.start.column;
3502 if (valueTypeProperty) {
3503 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3505 store.assignBinding.isRoot = (compileState->root == obj);
3508 Q_ASSERT(js.bindingContext.owner == 0 ||
3509 (js.bindingContext.owner != 0 && valueTypeProperty));
3510 if (js.bindingContext.owner) {
3511 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3513 store.assignBinding.property = prop->core;
3515 output->addInstructionHelper(
3516 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3517 : QDeclarativeInstruction::StoreBindingOnAlias
3520 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3524 int QDeclarativeCompiler::genContextCache()
3526 if (compileState->ids.count() == 0)
3529 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3530 cache->reserve(compileState->ids.count());
3531 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3532 cache->add(o->id, o->idIndex);
3534 output->contextCaches.append(cache);
3535 return output->contextCaches.count() - 1;
3538 QDeclarativePropertyData
3539 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3540 QDeclarativeScript::Property *prop)
3542 typedef QDeclarativePropertyPrivate QDPP;
3543 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3544 enginePrivate->valueTypes[prop->type]->metaObject(),
3545 valueTypeProp->index, engine);
3548 bool QDeclarativeCompiler::completeComponentBuild()
3551 componentStats->componentStat.ids = compileState->ids.count();
3553 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3554 aliasObject = compileState->aliasingObjects.next(aliasObject))
3555 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3557 QV4Compiler::Expression expr(unit->imports());
3558 expr.component = compileState->root;
3559 expr.ids = &compileState->ids;
3560 expr.importCache = output->importCache;
3562 QV4Compiler bindingCompiler;
3564 QList<JSBindingReference*> sharedBindings;
3566 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3568 JSBindingReference &binding = *b;
3570 // ### We don't currently optimize for bindings on alias's - because
3571 // of the solution to QTBUG-13719
3572 if (!binding.property->isAlias) {
3573 expr.context = binding.bindingContext.object;
3574 expr.property = binding.property;
3575 expr.expression = binding.expression;
3577 int index = bindingCompiler.compile(expr, enginePrivate);
3579 binding.dataType = BindingReference::V4;
3580 binding.compiledIndex = index;
3582 componentStats->componentStat.optimizedBindings.append(b->value->location);
3587 // Pre-rewrite the expression
3588 QString expression = binding.expression.asScript();
3590 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3591 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3592 bool isSharable = false;
3593 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3595 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3596 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3597 binding.dataType = BindingReference::V8;
3598 sharedBindings.append(b);
3600 binding.dataType = BindingReference::QtScript;
3604 componentStats->componentStat.scriptBindings.append(b->value->location);
3607 if (!sharedBindings.isEmpty()) {
3609 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3611 return lhs->value->location.start.line < rhs->value->location.start.line;
3615 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3617 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3618 int lineNumber = startLineNumber;
3620 QString functionArray(QLatin1String("["));
3621 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3622 JSBindingReference *reference = sharedBindings.at(ii);
3623 QDeclarativeScript::Value *value = reference->value;
3624 const QString &expression = reference->rewrittenExpression;
3626 if (ii != 0) functionArray += QLatin1String(",");
3628 while (lineNumber < value->location.start.line) {
3630 functionArray += QLatin1String("\n");
3633 functionArray += expression;
3634 lineNumber += expression.count(QLatin1Char('\n'));
3635 reference->compiledIndex = ii;
3637 functionArray += QLatin1String("]");
3639 compileState->v8BindingProgram = functionArray;
3640 compileState->v8BindingProgramLine = startLineNumber;
3641 compileState->v8BindingProgramIndex = output->v8bindings.count();
3642 output->v8bindings.append(v8::Persistent<v8::Array>());
3645 if (bindingCompiler.isValid())
3646 compileState->compiledBindingData = bindingCompiler.program();
3648 // Check pop()'s matched push()'s
3649 Q_ASSERT(compileState->objectDepth.depth() == 0);
3650 Q_ASSERT(compileState->listDepth.depth() == 0);
3652 saveComponentState();
3657 void QDeclarativeCompiler::dumpStats()
3659 Q_ASSERT(componentStats);
3660 qWarning().nospace() << "QML Document: " << output->url.toString();
3661 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3662 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3663 qWarning().nospace() << " Component Line " << stat.lineNumber;
3664 qWarning().nospace() << " Total Objects: " << stat.objects;
3665 qWarning().nospace() << " IDs Used: " << stat.ids;
3666 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3670 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3671 if (0 == (ii % 10)) {
3672 if (ii) output.append("\n");
3677 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3679 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3680 output.append(") ");
3682 if (!output.isEmpty())
3683 qWarning().nospace() << output.constData();
3686 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3689 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3690 if (0 == (ii % 10)) {
3691 if (ii) output.append("\n");
3696 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3698 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3699 output.append(") ");
3701 if (!output.isEmpty())
3702 qWarning().nospace() << output.constData();
3708 Returns true if from can be assigned to a (QObject) property of type
3711 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3713 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3714 const QMetaObject *fromMo = from->metaObject();
3717 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3719 fromMo = fromMo->superClass();
3725 Returns the element name, as written in the QML file, for o.
3727 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3730 if (o->type != -1) {
3731 return output->types.at(o->type).className;
3737 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3740 const QMetaObject *mo = from->metatype;
3741 QDeclarativeType *type = 0;
3742 while (!type && mo) {
3743 type = QDeclarativeMetaType::qmlType(mo);
3744 mo = mo->superClass();
3749 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3751 const QMetaObject *mo = obj->metatype;
3753 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3755 return QStringList();
3757 QMetaClassInfo classInfo = mo->classInfo(idx);
3758 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3762 QDeclarativePropertyData *
3763 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3765 QDeclarativePropertyCache *cache = 0;
3767 if (object->synthCache)
3768 cache = object->synthCache;
3769 else if (object->type != -1)
3770 cache = output->types[object->type].createPropertyCache(engine);
3772 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3774 return cache->property(index);
3777 QDeclarativePropertyData *
3778 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3780 if (notInRevision) *notInRevision = false;
3782 QDeclarativePropertyCache *cache = 0;
3784 if (object->synthCache)
3785 cache = object->synthCache;
3786 else if (object->type != -1)
3787 cache = output->types[object->type].createPropertyCache(engine);
3789 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3791 QDeclarativePropertyData *d = cache->property(name);
3793 // Find the first property
3794 while (d && d->isFunction())
3795 d = cache->overrideData(d);
3797 if (d && !cache->isAllowedInRevision(d)) {
3798 if (notInRevision) *notInRevision = true;
3805 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3806 QDeclarativePropertyData *
3807 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3809 if (notInRevision) *notInRevision = false;
3811 QDeclarativePropertyCache *cache = 0;
3813 if (object->synthCache)
3814 cache = object->synthCache;
3815 else if (object->type != -1)
3816 cache = output->types[object->type].createPropertyCache(engine);
3818 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3821 QDeclarativePropertyData *d = cache->property(name);
3822 if (notInRevision) *notInRevision = false;
3824 while (d && !(d->isFunction()))
3825 d = cache->overrideData(d);
3827 if (d && !cache->isAllowedInRevision(d)) {
3828 if (notInRevision) *notInRevision = true;
3834 if (name.endsWith(Changed_string)) {
3835 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3837 d = property(object, propName, notInRevision);
3839 return cache->method(d->notifyIndex);
3845 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3846 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3847 bool *notInRevision)
3849 QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision);
3850 return d?d->coreIndex:-1;
3853 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3854 bool *notInRevision)
3856 return indexOfProperty(object, QStringRef(&name), notInRevision);
3859 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3860 bool *notInRevision)
3862 QDeclarativePropertyData *d = property(object, name, notInRevision);
3863 return d?d->coreIndex:-1;