1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 // We generate the importCache before we build the tree so that
863 // it can be used in the binding compiler. Given we "expect" the
864 // QML compilation to succeed, this isn't a waste.
865 output->importCache = new QDeclarativeTypeNameCache();
866 foreach (const QString &ns, unit->namespaces()) {
867 output->importCache->add(ns);
871 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
872 QString qualifier = script.qualifier;
873 QString enclosingNamespace;
875 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
876 if (lastDotIndex != -1) {
877 enclosingNamespace = qualifier.left(lastDotIndex);
878 qualifier = qualifier.mid(lastDotIndex+1);
881 output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
884 unit->imports().populateCache(output->importCache, engine);
886 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
889 Instruction::Init init;
890 init.bindingsSize = compileState->totalBindingsCount;
891 init.parserStatusSize = compileState->parserStatusCount;
892 init.contextCache = genContextCache();
893 init.objectStackSize = compileState->objectDepth.maxDepth();
894 init.listStackSize = compileState->listDepth.maxDepth();
895 if (compileState->compiledBindingData.isEmpty())
896 init.compiledBinding = -1;
898 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
899 output->addInstruction(init);
901 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
902 Instruction::StoreImportedScript import;
903 import.value = output->scripts.count();
905 QDeclarativeScriptData *scriptData = script.script->scriptData();
906 scriptData->addref();
907 output->scripts << scriptData;
908 output->addInstruction(import);
911 if (!compileState->v8BindingProgram.isEmpty()) {
912 Instruction::InitV8Bindings bindings;
913 bindings.program = output->indexForString(compileState->v8BindingProgram);
914 bindings.programIndex = compileState->v8BindingProgramIndex;
915 bindings.line = compileState->v8BindingProgramLine;
916 output->addInstruction(bindings);
921 Instruction::SetDefault def;
922 output->addInstruction(def);
924 Instruction::Done done;
925 output->addInstruction(done);
927 Q_ASSERT(tree->metatype);
929 if (tree->metadata.isEmpty()) {
930 output->root = tree->metatype;
932 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
933 output->root = &output->rootData;
935 if (!tree->metadata.isEmpty())
936 enginePrivate->registerCompositeType(output);
939 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
941 for (int ii = 0; ii < list.count(); ++ii)
942 if (string == list.at(ii))
948 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
951 componentStats->componentStat.objects++;
953 Q_ASSERT (obj->type != -1);
954 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
955 obj->metatype = tr.metaObject();
958 obj->typeName = tr.type->qmlTypeName();
960 // This object is a "Component" element
961 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
962 COMPILE_CHECK(buildComponent(obj, ctxt));
967 typedef QDeclarativeInstruction I;
968 const I *init = ((const I *)tr.component->bytecode.constData());
969 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
971 // Adjust stack depths to include nested components
972 compileState->objectDepth.pushPop(init->init.objectStackSize);
973 compileState->listDepth.pushPop(init->init.listStackSize);
974 compileState->parserStatusCount += init->init.parserStatusSize;
975 compileState->totalBindingsCount += init->init.bindingsSize;
978 compileState->objectDepth.push();
980 // Object instantiations reset the binding context
981 BindingContext objCtxt(obj);
983 // Create the synthesized meta object, ignoring aliases
984 COMPILE_CHECK(checkDynamicMeta(obj));
985 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
986 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
988 // Find the native type and check for the QDeclarativeParserStatus interface
989 QDeclarativeType *type = toQmlType(obj);
991 obj->parserStatusCast = type->parserStatusCast();
992 if (obj->parserStatusCast != -1)
993 compileState->parserStatusCount++;
995 // Check if this is a custom parser type. Custom parser types allow
996 // assignments to non-existent properties. These assignments are then
997 // compiled by the type.
998 bool isCustomParser = output->types.at(obj->type).type &&
999 output->types.at(obj->type).type->customParser() != 0;
1000 QList<QDeclarativeCustomParserProperty> customProps;
1002 // Fetch the list of deferred properties
1003 QStringList deferredList = deferredProperties(obj);
1005 // Must do id property first. This is to ensure that the id given to any
1006 // id reference created matches the order in which the objects are
1008 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1009 if (prop->name() == id_string) {
1010 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1016 Property *defaultProperty = 0;
1017 Property *skipProperty = 0;
1018 if (obj->defaultProperty) {
1019 defaultProperty = obj->defaultProperty;
1021 Property *explicitProperty = 0;
1023 const QMetaObject *mo = obj->metatype;
1024 int idx = mo->indexOfClassInfo("DefaultProperty");
1026 QMetaClassInfo info = mo->classInfo(idx);
1027 const char *p = info.value();
1031 while (char c = p[plen++]) { ord |= c; };
1035 // Utf8 - unoptimal, but seldom hit
1036 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1037 QHashedStringRef r(*s);
1039 if (obj->propertiesHashField.test(r.hash())) {
1040 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1041 if (ep->name() == r) {
1042 explicitProperty = ep;
1048 if (!explicitProperty)
1049 defaultProperty->setName(r);
1052 QHashedCStringRef r(p, plen);
1054 if (obj->propertiesHashField.test(r.hash())) {
1055 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1056 if (ep->name() == r) {
1057 explicitProperty = ep;
1063 if (!explicitProperty) {
1064 // Set the default property name
1065 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1066 r.writeUtf16(buffer);
1067 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1073 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1075 skipProperty = explicitProperty; // We merge the values into defaultProperty
1077 // Find the correct insertion point
1078 Value *insertPos = 0;
1080 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1081 if (!(v->location.start < explicitProperty->values.first()->location.start))
1086 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1090 QDeclarativeCustomParser *cp = 0;
1092 cp = output->types.at(obj->type).type->customParser();
1094 // Build all explicit properties specified
1095 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1097 if (prop == skipProperty)
1099 if (prop->name() == id_string)
1102 bool canDefer = false;
1103 if (isCustomParser) {
1104 if (doesPropertyExist(prop, obj) &&
1105 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
1106 !isAttachedPropertyName(prop->name()))) {
1107 int ids = compileState->ids.count();
1108 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1109 canDefer = ids == compileState->ids.count();
1110 } else if (isSignalPropertyName(prop->name()) &&
1111 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
1112 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1114 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1117 if (isSignalPropertyName(prop->name())) {
1118 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1120 int ids = compileState->ids.count();
1121 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1122 canDefer = ids == compileState->ids.count();
1126 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1127 prop->isDeferred = true;
1131 // Build the default property
1132 if (defaultProperty) {
1133 Property *prop = defaultProperty;
1135 bool canDefer = false;
1136 if (isCustomParser) {
1137 if (doesPropertyExist(prop, obj)) {
1138 int ids = compileState->ids.count();
1139 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1140 canDefer = ids == compileState->ids.count();
1142 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1145 int ids = compileState->ids.count();
1146 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1147 canDefer = ids == compileState->ids.count();
1150 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1151 prop->isDeferred = true;
1154 // Compile custom parser parts
1155 if (isCustomParser && !customProps.isEmpty()) {
1157 cp->compiler = this;
1159 obj->custom = cp->compile(customProps);
1162 foreach (QDeclarativeError err, cp->errors()) {
1163 err.setUrl(output->url);
1168 compileState->objectDepth.pop();
1173 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1175 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1176 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1181 // Create the object
1182 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1183 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1185 Instruction::CreateSimpleObject create;
1186 create.create = output->types.at(obj->type).type->createFunction();
1187 create.typeSize = output->types.at(obj->type).type->createSize();
1188 create.type = obj->type;
1189 create.line = obj->location.start.line;
1190 create.column = obj->location.start.column;
1191 output->addInstruction(create);
1195 if (output->types.at(obj->type).type) {
1196 Instruction::CreateCppObject create;
1197 create.line = obj->location.start.line;
1198 create.column = obj->location.start.column;
1200 if (!obj->custom.isEmpty())
1201 create.data = output->indexForByteArray(obj->custom);
1202 create.type = obj->type;
1203 create.isRoot = (compileState->root == obj);
1204 output->addInstruction(create);
1206 Instruction::CreateQMLObject create;
1207 create.type = obj->type;
1208 create.isRoot = (compileState->root == obj);
1210 if (!obj->bindingBitmask.isEmpty()) {
1211 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1212 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1214 create.bindingBits = -1;
1216 output->addInstruction(create);
1218 Instruction::CompleteQMLObject complete;
1219 complete.line = obj->location.start.line;
1220 complete.column = obj->location.start.column;
1221 complete.isRoot = (compileState->root == obj);
1222 output->addInstruction(complete);
1226 // Setup the synthesized meta object if necessary
1227 if (!obj->metadata.isEmpty()) {
1228 Instruction::StoreMetaObject meta;
1229 meta.data = output->indexForByteArray(obj->metadata);
1230 meta.aliasData = output->indexForByteArray(obj->synthdata);
1231 meta.propertyCache = output->propertyCaches.count();
1233 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1234 Q_ASSERT(propertyCache);
1235 propertyCache->addref();
1237 // Add flag for alias properties
1238 if (!obj->synthdata.isEmpty()) {
1239 const QDeclarativeVMEMetaData *vmeMetaData =
1240 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1241 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1242 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1243 QDeclarativePropertyData *data = propertyCache->property(index);
1244 data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias);
1248 if (obj == unitRoot) {
1249 propertyCache->addref();
1250 output->rootPropertyCache = propertyCache;
1253 output->propertyCaches << propertyCache;
1254 output->addInstruction(meta);
1255 } else if (obj == unitRoot) {
1256 output->rootPropertyCache = tr.createPropertyCache(engine);
1257 output->rootPropertyCache->addref();
1260 // Set the object id
1261 if (!obj->id.isEmpty()) {
1262 Instruction::SetId id;
1263 id.value = output->indexForString(obj->id);
1264 id.index = obj->idIndex;
1265 output->addInstruction(id);
1269 if (tr.type && obj->parserStatusCast != -1) {
1270 Instruction::BeginObject begin;
1271 begin.castValue = obj->parserStatusCast;
1272 output->addInstruction(begin);
1278 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1280 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1281 Q_ASSERT(prop->scriptStringScope != -1);
1282 const QString &script = prop->values.first()->value.asScript();
1283 Instruction::StoreScriptString ss;
1284 ss.propertyIndex = prop->index;
1285 ss.value = output->indexForString(script);
1286 ss.scope = prop->scriptStringScope;
1287 // ss.bindingId = rewriteBinding(script, prop->name());
1288 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1289 ss.line = prop->location.start.line;
1290 ss.column = prop->location.start.column;
1291 output->addInstruction(ss);
1294 bool seenDefer = false;
1295 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1296 if (prop->isDeferred) {
1301 genValueProperty(prop, obj);
1304 Instruction::Defer defer;
1305 defer.deferCount = 0;
1306 int deferIdx = output->addInstruction(defer);
1307 int nextInstructionIndex = output->nextInstructionIndex();
1309 Instruction::DeferInit dinit;
1310 // XXX - these are now massive over allocations
1311 dinit.bindingsSize = compileState->totalBindingsCount;
1312 dinit.parserStatusSize = compileState->parserStatusCount;
1313 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1314 dinit.listStackSize = compileState->listDepth.maxDepth();
1315 output->addInstruction(dinit);
1317 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1318 if (!prop->isDeferred)
1320 genValueProperty(prop, obj);
1323 Instruction::Done done;
1324 output->addInstruction(done);
1326 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1329 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1331 QDeclarativeScript::Value *v = prop->values.first();
1333 if (v->type == Value::SignalObject) {
1335 genObject(v->object);
1337 Instruction::AssignSignalObject assign;
1338 assign.line = v->location.start.line;
1339 assign.signal = output->indexForString(prop->name().toString());
1340 output->addInstruction(assign);
1342 } else if (v->type == Value::SignalExpression) {
1344 Instruction::StoreSignal store;
1345 store.signalIndex = prop->index;
1346 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
1347 const QString &rewrite =
1348 rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString());
1349 store.value = output->indexForString(rewrite);
1350 store.context = v->signalExpressionContextStack;
1351 store.line = v->location.start.line;
1352 store.column = v->location.start.column;
1353 output->addInstruction(store);
1359 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1360 Instruction::FetchAttached fetch;
1361 fetch.id = prop->index;
1362 fetch.line = prop->location.start.line;
1363 output->addInstruction(fetch);
1365 genObjectBody(prop->value);
1367 Instruction::PopFetchedObject pop;
1368 output->addInstruction(pop);
1371 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1372 Instruction::FetchObject fetch;
1373 fetch.property = prop->index;
1374 fetch.line = prop->location.start.line;
1375 output->addInstruction(fetch);
1377 if (!prop->value->metadata.isEmpty()) {
1378 Instruction::StoreMetaObject meta;
1379 meta.data = output->indexForByteArray(prop->value->metadata);
1380 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1381 meta.propertyCache = -1;
1382 output->addInstruction(meta);
1385 genObjectBody(prop->value);
1387 Instruction::PopFetchedObject pop;
1388 output->addInstruction(pop);
1391 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1393 genValueTypeProperty(obj, prop);
1396 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1397 if (prop->isDeferred)
1400 genValueProperty(prop, obj);
1403 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1405 genValueTypeProperty(obj, prop);
1409 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1411 Instruction::FetchValueType fetch;
1412 fetch.property = prop->index;
1413 fetch.type = prop->type;
1414 fetch.bindingSkipList = 0;
1416 if (obj->type == -1 || output->types.at(obj->type).component) {
1417 // We only have to do this if this is a composite type. If it is a builtin
1418 // type it can't possibly already have bindings that need to be cleared.
1419 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1420 if (!vprop->values.isEmpty()) {
1421 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1422 fetch.bindingSkipList |= (1 << vprop->index);
1427 output->addInstruction(fetch);
1429 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1430 genPropertyAssignment(vprop, prop->value, prop);
1433 Instruction::PopValueType pop;
1434 pop.property = prop->index;
1435 pop.type = prop->type;
1436 pop.bindingSkipList = 0;
1437 output->addInstruction(pop);
1440 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1442 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1445 Instruction::CreateComponent create;
1446 create.line = root->location.start.line;
1447 create.column = root->location.start.column;
1448 create.endLine = root->location.end.line;
1449 create.isRoot = (compileState->root == obj);
1450 int createInstruction = output->addInstruction(create);
1451 int nextInstructionIndex = output->nextInstructionIndex();
1453 ComponentCompileState *oldCompileState = compileState;
1454 compileState = componentState(root);
1456 Instruction::Init init;
1457 init.bindingsSize = compileState->totalBindingsCount;
1458 init.parserStatusSize = compileState->parserStatusCount;
1459 init.contextCache = genContextCache();
1460 init.objectStackSize = compileState->objectDepth.maxDepth();
1461 init.listStackSize = compileState->listDepth.maxDepth();
1462 if (compileState->compiledBindingData.isEmpty())
1463 init.compiledBinding = -1;
1465 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1466 output->addInstruction(init);
1468 if (!compileState->v8BindingProgram.isEmpty()) {
1469 Instruction::InitV8Bindings bindings;
1470 bindings.program = output->indexForString(compileState->v8BindingProgram);
1471 bindings.programIndex = compileState->v8BindingProgramIndex;
1472 bindings.line = compileState->v8BindingProgramLine;
1473 output->addInstruction(bindings);
1478 Instruction::SetDefault def;
1479 output->addInstruction(def);
1481 Instruction::Done done;
1482 output->addInstruction(done);
1484 output->instruction(createInstruction)->createComponent.count =
1485 output->nextInstructionIndex() - nextInstructionIndex;
1487 compileState = oldCompileState;
1489 if (!obj->id.isEmpty()) {
1490 Instruction::SetId id;
1491 id.value = output->indexForString(obj->id);
1492 id.index = obj->idIndex;
1493 output->addInstruction(id);
1496 if (obj == unitRoot) {
1497 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1498 output->rootPropertyCache->addref();
1502 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1503 const BindingContext &ctxt)
1505 // The special "Component" element can only have the id property and a
1506 // default property, that actually defines the component's tree
1508 compileState->objectDepth.push();
1510 // Find, check and set the "id" property (if any)
1511 Property *idProp = 0;
1512 if (obj->properties.isMany() ||
1513 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1514 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1516 if (!obj->properties.isEmpty())
1517 idProp = obj->properties.first();
1520 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1521 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1522 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1524 QString idVal = idProp->values.first()->primitive();
1526 if (compileState->ids.value(idVal))
1527 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1533 // Check the Component tree is well formed
1534 if (obj->defaultProperty &&
1535 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1536 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1537 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1539 if (!obj->dynamicProperties.isEmpty())
1540 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1541 if (!obj->dynamicSignals.isEmpty())
1542 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1543 if (!obj->dynamicSlots.isEmpty())
1544 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1546 QDeclarativeScript::Object *root = 0;
1547 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1548 root = obj->defaultProperty->values.first()->object;
1551 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1553 // Build the component tree
1554 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1556 compileState->objectDepth.pop();
1561 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1562 const BindingContext &ctxt)
1564 ComponentCompileState *oldComponentCompileState = compileState;
1565 compileState = pool->New<ComponentCompileState>();
1566 compileState->root = obj;
1567 compileState->nested = true;
1569 if (componentStats) {
1570 ComponentStat oldComponentStat = componentStats->componentStat;
1572 componentStats->componentStat = ComponentStat();
1573 componentStats->componentStat.lineNumber = obj->location.start.line;
1576 COMPILE_CHECK(buildObject(obj, ctxt));
1578 COMPILE_CHECK(completeComponentBuild());
1580 componentStats->componentStat = oldComponentStat;
1583 COMPILE_CHECK(buildObject(obj, ctxt));
1585 COMPILE_CHECK(completeComponentBuild());
1588 compileState = oldComponentCompileState;
1594 // Build a sub-object. A sub-object is one that was not created directly by
1595 // QML - such as a grouped property object, or an attached object. Sub-object's
1596 // can't have an id, involve a custom parser, have attached properties etc.
1597 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1599 Q_ASSERT(obj->metatype);
1600 Q_ASSERT(!obj->defaultProperty);
1601 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1604 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1605 if (isSignalPropertyName(prop->name())) {
1606 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1608 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1615 int QDeclarativeCompiler::componentTypeRef()
1617 if (cachedComponentTypeRef == -1) {
1618 QDeclarativeType *t = QDeclarativeMetaType::qmlType(Component_import_string,1,0);
1619 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1620 if (output->types.at(ii).type == t) {
1621 cachedComponentTypeRef = ii;
1625 QDeclarativeCompiledData::TypeReference ref;
1626 ref.className = Component_string;
1628 output->types << ref;
1629 cachedComponentTypeRef = output->types.count() - 1;
1631 return cachedComponentTypeRef;
1634 int QDeclarativeCompiler::translationContextIndex()
1636 if (cachedTranslationContextIndex == -1) {
1637 // This code must match that in the qsTr() implementation
1638 QString path = output->url.toString();
1639 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1640 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1642 QByteArray contextUtf8 = context.toUtf8();
1643 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1645 return cachedTranslationContextIndex;
1648 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1649 const BindingContext &ctxt)
1651 Q_ASSERT(obj->metaObject());
1653 const QHashedStringRef &propName = prop->name();
1655 Q_ASSERT(propName.startsWith(on_string));
1656 QString name = propName.mid(2, -1).toString();
1658 // Note that the property name could start with any alpha or '_' or '$' character,
1659 // so we need to do the lower-casing of the first alpha character.
1660 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1661 if (name.at(firstAlphaIndex).isUpper()) {
1662 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1667 bool notInRevision = false;
1669 QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1673 if (notInRevision && 0 == property(obj, propName, 0)) {
1674 Q_ASSERT(obj->type != -1);
1675 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1676 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1678 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));
1680 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1684 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1686 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1690 if (prop->value || !prop->values.isOne())
1691 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1693 prop->index = sig->coreIndex;
1696 obj->addSignalProperty(prop);
1698 if (prop->values.first()->object) {
1699 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1700 prop->values.first()->type = Value::SignalObject;
1702 prop->values.first()->type = Value::SignalExpression;
1704 if (!prop->values.first()->value.isScript())
1705 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1707 QString script = prop->values.first()->value.asScript().trimmed();
1708 if (script.isEmpty())
1709 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1711 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1720 Returns true if (value) property \a prop exists on obj, false otherwise.
1722 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1723 QDeclarativeScript::Object *obj)
1725 if (prop->name().isEmpty())
1727 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1730 return property(obj, prop->name()) != 0;
1733 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1734 QDeclarativeScript::Object *obj,
1735 const BindingContext &ctxt)
1737 if (prop->isEmpty())
1738 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1740 const QMetaObject *metaObject = obj->metaObject();
1741 Q_ASSERT(metaObject);
1743 if (isAttachedPropertyName(prop->name())) {
1744 // Setup attached property data
1746 if (ctxt.isSubContext()) {
1747 // Attached properties cannot be used on sub-objects. Sub-objects
1748 // always exist in a binding sub-context, which is what we test
1750 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1753 QDeclarativeType *type = 0;
1754 QDeclarativeImportedNamespace *typeNamespace = 0;
1755 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1757 if (typeNamespace) {
1758 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1761 } else if (!type || !type->attachedPropertiesType()) {
1762 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1766 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1768 Q_ASSERT(type->attachedPropertiesFunction());
1769 prop->index = type->attachedPropertiesId();
1770 prop->value->metatype = type->attachedPropertiesType();
1772 // Setup regular property data
1773 bool notInRevision = false;
1774 QDeclarativePropertyData *d =
1775 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1777 if (d == 0 && notInRevision) {
1778 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1779 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1781 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));
1783 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1786 prop->index = d->coreIndex;
1788 } else if (prop->isDefault) {
1789 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1790 QDeclarativePropertyData defaultPropertyData;
1791 defaultPropertyData.load(p, engine);
1793 prop->setName(QLatin1String(p.name()));
1794 prop->core = defaultPropertyData;
1795 prop->index = prop->core.coreIndex;
1798 // We can't error here as the "id" property does not require a
1799 // successful index resolution
1800 if (prop->index != -1)
1801 prop->type = prop->core.propType;
1803 // Check if this is an alias
1804 if (prop->index != -1 &&
1806 prop->parent->type != -1 &&
1807 output->types.at(prop->parent->type).component) {
1809 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1810 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1811 prop->isAlias = true;
1814 if (prop->index != -1 && !prop->values.isEmpty())
1815 prop->parent->setBindingBit(prop->index);
1818 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1820 // The magic "id" behavior doesn't apply when "id" is resolved as a
1821 // default property or to sub-objects (which are always in binding
1823 COMPILE_CHECK(buildIdProperty(prop, obj));
1824 if (prop->type == QVariant::String &&
1825 prop->values.first()->value.isString())
1826 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1828 } else if (isAttachedPropertyName(prop->name())) {
1830 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1832 } else if (prop->index == -1) {
1834 if (prop->isDefault) {
1835 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1837 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1840 } else if (prop->value) {
1842 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1844 } else if (prop->core.isQList()) {
1846 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1848 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1850 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1854 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1861 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1862 QDeclarativeScript::Property *nsProp,
1863 QDeclarativeScript::Object *obj,
1864 const BindingContext &ctxt)
1867 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1869 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1871 if (!isAttachedPropertyName(prop->name()))
1872 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1874 // Setup attached property data
1876 QDeclarativeType *type = 0;
1877 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1879 if (!type || !type->attachedPropertiesType())
1880 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1883 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1885 Q_ASSERT(type->attachedPropertiesFunction());
1886 prop->index = type->index();
1887 prop->value->metatype = type->attachedPropertiesType();
1889 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1895 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1896 QDeclarativeScript::Object *obj)
1898 if (prop->core.isQList()) {
1899 genListProperty(prop, obj);
1901 genPropertyAssignment(prop, obj);
1905 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1906 QDeclarativeScript::Object *obj)
1908 int listType = enginePrivate->listType(prop->type);
1910 Instruction::FetchQList fetch;
1911 fetch.property = prop->index;
1912 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1913 fetch.type = listType;
1914 output->addInstruction(fetch);
1916 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1918 if (v->type == Value::CreatedObject) {
1920 genObject(v->object);
1921 if (listTypeIsInterface) {
1922 Instruction::AssignObjectList assign;
1923 assign.line = prop->location.start.line;
1924 output->addInstruction(assign);
1926 Instruction::StoreObjectQList store;
1927 output->addInstruction(store);
1930 } else if (v->type == Value::PropertyBinding) {
1932 genBindingAssignment(v, prop, obj);
1938 Instruction::PopQList pop;
1939 output->addInstruction(pop);
1942 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1943 QDeclarativeScript::Object *obj,
1944 QDeclarativeScript::Property *valueTypeProperty)
1946 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1948 Q_ASSERT(v->type == Value::CreatedObject ||
1949 v->type == Value::PropertyBinding ||
1950 v->type == Value::Literal);
1952 if (v->type == Value::CreatedObject) {
1954 genObject(v->object);
1956 if (QDeclarativeMetaType::isInterface(prop->type)) {
1958 Instruction::StoreInterface store;
1959 store.line = v->object->location.start.line;
1960 store.propertyIndex = prop->index;
1961 output->addInstruction(store);
1963 } else if (prop->type == QMetaType::QVariant) {
1965 if (prop->core.isVMEProperty()) {
1966 Instruction::StoreVarObject store;
1967 store.line = v->object->location.start.line;
1968 store.propertyIndex = prop->index;
1969 output->addInstruction(store);
1971 Instruction::StoreVariantObject store;
1972 store.line = v->object->location.start.line;
1973 store.propertyIndex = prop->index;
1974 output->addInstruction(store);
1980 Instruction::StoreObject store;
1981 store.line = v->object->location.start.line;
1982 store.propertyIndex = prop->index;
1983 output->addInstruction(store);
1986 } else if (v->type == Value::PropertyBinding) {
1988 genBindingAssignment(v, prop, obj, valueTypeProperty);
1990 } else if (v->type == Value::Literal) {
1992 genLiteralAssignment(prop, v);
1998 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2000 Q_ASSERT(v->type == Value::ValueSource ||
2001 v->type == Value::ValueInterceptor);
2003 if (v->type == Value::ValueSource) {
2004 genObject(v->object);
2006 Instruction::StoreValueSource store;
2007 if (valueTypeProperty) {
2008 store.property = genValueTypeData(prop, valueTypeProperty);
2011 store.property = prop->core;
2014 QDeclarativeType *valueType = toQmlType(v->object);
2015 store.castValue = valueType->propertyValueSourceCast();
2016 output->addInstruction(store);
2018 } else if (v->type == Value::ValueInterceptor) {
2019 genObject(v->object);
2021 Instruction::StoreValueInterceptor store;
2022 if (valueTypeProperty) {
2023 store.property = genValueTypeData(prop, valueTypeProperty);
2026 store.property = prop->core;
2029 QDeclarativeType *valueType = toQmlType(v->object);
2030 store.castValue = valueType->propertyValueInterceptorCast();
2031 output->addInstruction(store);
2037 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
2038 QDeclarativeScript::Object *obj)
2041 prop->values.isMany() ||
2042 prop->values.first()->object)
2043 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2045 QDeclarativeScript::Value *idValue = prop->values.first();
2046 QString val = idValue->primitive();
2048 COMPILE_CHECK(checkValidId(idValue, val));
2050 if (compileState->ids.value(val))
2051 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2053 prop->values.first()->type = Value::Id;
2061 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
2064 Q_ASSERT(!compileState->ids.value(id));
2065 Q_ASSERT(obj->id == id);
2066 obj->idIndex = compileState->ids.count();
2067 compileState->ids.append(obj);
2070 void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref)
2072 Q_ASSERT(ref->value && !ref->value->bindingReference);
2073 ref->value->bindingReference = ref;
2074 compileState->totalBindingsCount++;
2075 compileState->bindings.prepend(ref);
2078 void QDeclarativeCompiler::saveComponentState()
2080 Q_ASSERT(compileState->root);
2081 Q_ASSERT(compileState->root->componentCompileState == 0);
2083 compileState->root->componentCompileState = compileState;
2086 componentStats->savedComponentStats.append(componentStats->componentStat);
2089 QDeclarativeCompilerTypes::ComponentCompileState *
2090 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
2092 Q_ASSERT(obj->componentCompileState);
2093 return obj->componentCompileState;
2096 // Build attached property object. In this example,
2100 // GridView is an attached property object.
2101 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
2102 QDeclarativeScript::Object *obj,
2103 const BindingContext &ctxt)
2105 Q_ASSERT(prop->value);
2106 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2108 compileState->objectDepth.push();
2110 obj->addAttachedProperty(prop);
2112 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2114 compileState->objectDepth.pop();
2120 // Build "grouped" properties. In this example:
2122 // font.pointSize: 12
2123 // font.family: "Helvetica"
2125 // font is a nested property. pointSize and family are not.
2126 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
2127 QDeclarativeScript::Object *obj,
2128 const BindingContext &ctxt)
2130 Q_ASSERT(prop->type != 0);
2131 Q_ASSERT(prop->index != -1);
2133 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
2134 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2136 if (!prop->values.isEmpty()) {
2137 if (prop->values.first()->location < prop->value->location) {
2138 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2140 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2144 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2145 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2149 if (prop->isAlias) {
2150 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2151 vtProp->isAlias = true;
2155 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2156 prop->value, obj, ctxt.incr()));
2157 obj->addValueTypeProperty(prop);
2159 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2163 // Load the nested property's meta type
2164 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2165 if (!prop->value->metatype)
2166 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2168 if (!prop->values.isEmpty())
2169 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2171 obj->addGroupedProperty(prop);
2173 compileState->objectDepth.push();
2175 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2177 compileState->objectDepth.pop();
2183 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2184 QDeclarativeScript::Object *obj,
2185 QDeclarativeScript::Object *baseObj,
2186 const BindingContext &ctxt)
2188 compileState->objectDepth.push();
2190 if (obj->defaultProperty)
2191 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2192 obj->metatype = type->metaObject();
2194 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2196 QDeclarativePropertyData *d = property(obj, prop->name());
2198 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2200 prop->index = d->coreIndex;
2201 prop->type = d->propType;
2203 prop->isValueTypeSubProperty = true;
2206 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2208 if (prop->values.isMany()) {
2209 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2210 } else if (!prop->values.isEmpty()) {
2211 QDeclarativeScript::Value *value = prop->values.first();
2213 if (value->object) {
2214 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2215 } else if (value->value.isScript()) {
2216 // ### Check for writability
2218 //optimization for <Type>.<EnumValue> enum assignments
2219 bool isEnumAssignment = false;
2221 if (prop->core.isEnum())
2222 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2224 if (isEnumAssignment) {
2225 value->type = Value::Literal;
2227 JSBindingReference *reference = pool->New<JSBindingReference>();
2228 reference->expression = value->value;
2229 reference->property = prop;
2230 reference->value = value;
2231 reference->bindingContext = ctxt;
2232 reference->bindingContext.owner++;
2233 addBindingReference(reference);
2234 value->type = Value::PropertyBinding;
2237 COMPILE_CHECK(testLiteralAssignment(prop, value));
2238 value->type = Value::Literal;
2242 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2243 Q_ASSERT(v->object);
2245 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2248 obj->addValueProperty(prop);
2251 compileState->objectDepth.pop();
2256 // Build assignments to QML lists. QML lists are properties of type
2257 // QDeclarativeListProperty<T>. List properties can accept a list of
2258 // objects, or a single binding.
2259 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2260 QDeclarativeScript::Object *obj,
2261 const BindingContext &ctxt)
2263 Q_ASSERT(prop->core.isQList());
2265 compileState->listDepth.push();
2269 obj->addValueProperty(prop);
2271 int listType = enginePrivate->listType(t);
2272 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2274 bool assignedBinding = false;
2275 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2277 v->type = Value::CreatedObject;
2278 COMPILE_CHECK(buildObject(v->object, ctxt));
2280 // We check object coercian here. We check interface assignment
2282 if (!listTypeIsInterface) {
2283 if (!canCoerce(listType, v->object)) {
2284 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2288 } else if (v->value.isScript()) {
2289 if (assignedBinding)
2290 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2292 assignedBinding = true;
2293 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2294 v->type = Value::PropertyBinding;
2296 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2300 compileState->listDepth.pop();
2305 // Compiles an assignment to a QDeclarativeScriptString property
2306 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2307 QDeclarativeScript::Object *obj,
2308 const BindingContext &ctxt)
2310 if (prop->values.isMany())
2311 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2313 if (prop->values.first()->object)
2314 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2316 prop->scriptStringScope = ctxt.stack;
2317 obj->addScriptStringProperty(prop);
2322 // Compile regular property assignments of the form "property: <value>"
2323 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2324 QDeclarativeScript::Object *obj,
2325 const BindingContext &ctxt)
2327 obj->addValueProperty(prop);
2329 if (prop->values.isMany())
2330 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2332 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2335 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2339 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2344 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2345 Q_ASSERT(v->object);
2346 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2352 // Compile assigning a single object instance to a regular property
2353 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2354 QDeclarativeScript::Object *obj,
2355 QDeclarativeScript::Value *v,
2356 const BindingContext &ctxt)
2358 Q_ASSERT(prop->index != -1);
2359 Q_ASSERT(v->object->type != -1);
2361 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2362 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2364 if (QDeclarativeMetaType::isInterface(prop->type)) {
2366 // Assigning an object to an interface ptr property
2367 COMPILE_CHECK(buildObject(v->object, ctxt));
2369 v->type = Value::CreatedObject;
2371 } else if (prop->type == QMetaType::QVariant) {
2373 // Assigning an object to a QVariant
2374 COMPILE_CHECK(buildObject(v->object, ctxt));
2376 v->type = Value::CreatedObject;
2378 // Normally buildObject() will set this up, but we need the static
2379 // meta object earlier to test for assignability. It doesn't matter
2380 // that there may still be outstanding synthesized meta object changes
2381 // on this type, as they are not relevant for assignability testing
2382 v->object->metatype = output->types.at(v->object->type).metaObject();
2383 Q_ASSERT(v->object->metaObject());
2385 // We want to raw metaObject here as the raw metaobject is the
2386 // actual property type before we applied any extensions that might
2387 // effect the properties on the type, but don't effect assignability
2388 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2390 // Will be true if the assgned type inherits propertyMetaObject
2391 bool isAssignable = false;
2392 // Determine isAssignable value
2393 if (propertyMetaObject) {
2394 const QMetaObject *c = v->object->metatype;
2396 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2397 c = c->superClass();
2402 // Simple assignment
2403 COMPILE_CHECK(buildObject(v->object, ctxt));
2405 v->type = Value::CreatedObject;
2406 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2407 // Automatic "Component" insertion
2408 QDeclarativeScript::Object *root = v->object;
2409 QDeclarativeScript::Object *component = pool->New<Object>();
2410 component->type = componentTypeRef();
2411 component->typeName = QStringLiteral("Qt/Component");
2412 component->metatype = &QDeclarativeComponent::staticMetaObject;
2413 component->location = root->location;
2414 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2415 componentValue->object = root;
2416 component->getDefaultProperty()->addValue(componentValue);
2417 v->object = component;
2418 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2420 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2427 // Compile assigning a single object instance to a regular property using the "on" syntax.
2431 // NumberAnimation on x { }
2433 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2434 QDeclarativeScript::Object *obj,
2435 QDeclarativeScript::Object *baseObj,
2436 QDeclarativeScript::Value *v,
2437 const BindingContext &ctxt)
2439 Q_ASSERT(prop->index != -1);
2440 Q_ASSERT(v->object->type != -1);
2444 if (!prop->core.isWritable())
2445 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2448 // Normally buildObject() will set this up, but we need the static
2449 // meta object earlier to test for assignability. It doesn't matter
2450 // that there may still be outstanding synthesized meta object changes
2451 // on this type, as they are not relevant for assignability testing
2452 v->object->metatype = output->types.at(v->object->type).metaObject();
2453 Q_ASSERT(v->object->metaObject());
2455 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2456 bool isPropertyValue = false;
2457 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2458 bool isPropertyInterceptor = false;
2459 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2460 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2461 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2464 if (isPropertyValue || isPropertyInterceptor) {
2465 // Assign as a property value source
2466 COMPILE_CHECK(buildObject(v->object, ctxt));
2468 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2469 buildDynamicMeta(baseObj, ForceCreation);
2470 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2472 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2478 // Compile assigning a literal or binding to a regular property
2479 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2480 QDeclarativeScript::Object *obj,
2481 QDeclarativeScript::Value *v,
2482 const BindingContext &ctxt)
2484 Q_ASSERT(prop->index != -1);
2486 if (v->value.isScript()) {
2488 //optimization for <Type>.<EnumValue> enum assignments
2489 if (prop->core.isEnum()) {
2490 bool isEnumAssignment = false;
2491 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2492 if (isEnumAssignment) {
2493 v->type = Value::Literal;
2498 // Test for other binding optimizations
2499 if (!buildLiteralBinding(v, prop, ctxt))
2500 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2502 v->type = Value::PropertyBinding;
2506 COMPILE_CHECK(testLiteralAssignment(prop, v));
2508 v->type = Value::Literal;
2514 bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
2515 QDeclarativeScript::Object *obj,
2516 QDeclarativeScript::Value *v,
2519 *isAssignment = false;
2520 if (!prop->core.isEnum())
2523 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2525 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2526 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2528 QString string = v->value.asString();
2529 if (!string.at(0).isUpper())
2532 QStringList parts = string.split(QLatin1Char('.'));
2533 if (parts.count() != 2)
2536 QString typeName = parts.at(0);
2537 QDeclarativeType *type = 0;
2538 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2540 //handle enums on value types (where obj->typeName is empty)
2541 QString objTypeName = obj->typeName;
2542 if (objTypeName.isEmpty()) {
2543 QDeclarativeType *objType = toQmlType(obj);
2545 objTypeName = objType->qmlTypeName();
2551 QString enumValue = parts.at(1);
2555 if (objTypeName == type->qmlTypeName()) {
2556 // When these two match, we can short cut the search
2557 if (mprop.isFlagType()) {
2558 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2560 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2563 // Otherwise we have to search the whole type
2564 // This matches the logic in QV8TypeWrapper
2565 QByteArray enumName = enumValue.toUtf8();
2566 const QMetaObject *metaObject = type->baseMetaObject();
2568 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2569 QMetaEnum e = metaObject->enumerator(ii);
2570 value = e.keyToValue(enumName.constData(), &ok);
2577 v->type = Value::Literal;
2578 v->value = QDeclarativeScript::Variant((double)value);
2579 *isAssignment = true;
2584 struct StaticQtMetaObject : public QObject
2586 static const QMetaObject *get()
2587 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2590 // Similar logic to above, but not knowing target property.
2591 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2593 int dot = script.indexOf('.');
2595 const QByteArray &scope = script.left(dot);
2596 QDeclarativeType *type = 0;
2597 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2598 if (!type && scope != "Qt")
2600 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2601 const char *key = script.constData() + dot+1;
2602 int i = mo->enumeratorCount();
2605 int v = mo->enumerator(i).keyToValue(key, &ok);
2613 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2615 QDeclarativeType *qmltype = 0;
2616 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2620 return qmltype->metaObject();
2623 // similar to logic of completeComponentBuild, but also sticks data
2624 // into primitives at the end
2625 int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name)
2627 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2628 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2630 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2632 return output->indexForString(rewrite);
2635 QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name)
2637 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
2638 return rewriteSignalHandler(handler, name);
2641 // Ensures that the dynamic meta specification on obj is valid
2642 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2644 bool seenDefaultProperty = false;
2646 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2647 // Calculating the hash for the names is not a waste as we have to test
2648 // them against the illegalNames set anyway.
2649 QHashField propNames;
2650 QHashField methodNames;
2653 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2654 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2656 if (prop.isDefaultProperty) {
2657 if (seenDefaultProperty)
2658 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2659 seenDefaultProperty = true;
2662 if (propNames.testAndSet(prop.name.hash())) {
2663 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2664 p2 = obj->dynamicProperties.next(p2)) {
2665 if (p2->name == prop.name) {
2666 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2667 prop.nameLocation.column,
2668 tr("Duplicate property name"));
2673 if (prop.name.at(0).isUpper()) {
2674 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2675 prop.nameLocation.column,
2676 tr("Property names cannot begin with an upper case letter"));
2679 if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2680 COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2681 prop.nameLocation.column,
2682 tr("Illegal property name"));
2686 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2687 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2689 if (methodNames.testAndSet(currSig.name.hash())) {
2690 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2691 s2 = obj->dynamicSignals.next(s2)) {
2692 if (s2->name == currSig.name)
2693 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2697 if (currSig.name.at(0).isUpper())
2698 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2699 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2700 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2703 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2704 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2706 if (methodNames.testAndSet(currSlot.name.hash())) {
2707 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2708 s2 = obj->dynamicSignals.next(s2)) {
2709 if (s2->name == currSlot.name)
2710 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2712 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2713 s2 = obj->dynamicSlots.next(s2)) {
2714 if (s2->name == currSlot.name)
2715 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2719 if (currSlot.name.at(0).isUpper())
2720 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2721 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2722 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2728 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2730 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2731 p = obj->dynamicProperties.next(p)) {
2733 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2736 Property *property = 0;
2737 if (p->isDefaultProperty) {
2738 property = obj->getDefaultProperty();
2740 property = obj->getProperty(p->name);
2741 if (!property->values.isEmpty())
2742 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2746 property->isReadOnlyDeclaration = true;
2748 if (property->value)
2749 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2751 property->values.append(p->defaultValue->values);
2756 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2758 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2761 Q_ASSERT(obj->metatype);
2763 if (mode != ForceCreation &&
2764 obj->dynamicProperties.isEmpty() &&
2765 obj->dynamicSignals.isEmpty() &&
2766 obj->dynamicSlots.isEmpty())
2769 bool resolveAlias = (mode == ResolveAliases);
2771 const Object::DynamicProperty *defaultProperty = 0;
2773 int varPropCount = 0;
2774 int totalPropCount = 0;
2775 int firstPropertyVarIndex = 0;
2777 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2779 if (p->type == Object::DynamicProperty::Alias)
2781 if (p->type == Object::DynamicProperty::Var)
2784 if (p->isDefaultProperty &&
2785 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2786 defaultProperty = p;
2788 if (!resolveAlias) {
2789 // No point doing this for both the alias and non alias cases
2790 QDeclarativePropertyData *d = property(obj, p->name);
2791 if (d && d->isFinal())
2792 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2796 bool buildData = resolveAlias || aliasCount == 0;
2798 QByteArray dynamicData;
2800 typedef QDeclarativeVMEMetaData VMD;
2802 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2803 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2804 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2805 aliasCount * sizeof(VMD::AliasData), 0);
2808 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2810 QByteArray newClassName = obj->metatype->className();
2811 newClassName.append("_QML_");
2812 newClassName.append(QByteArray::number(uniqueClassId));
2814 if (compileState->root == obj && !compileState->nested) {
2815 QString path = output->url.path();
2816 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2817 if (lastSlash > -1) {
2818 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2819 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2820 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2824 QFastMetaBuilder builder;
2825 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2826 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2827 obj->dynamicSlots.count(),
2828 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2829 defaultProperty?1:0);
2832 Object::DynamicProperty::Type dtype;
2834 const char *cppType;
2835 } builtinTypes[] = {
2836 { Object::DynamicProperty::Var, 0, "QVariant" },
2837 { Object::DynamicProperty::Variant, 0, "QVariant" },
2838 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2839 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2840 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2841 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2842 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2843 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2844 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2845 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2846 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2848 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2849 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2851 // Reserve dynamic properties
2852 if (obj->dynamicProperties.count()) {
2853 typedef QDeclarativeVMEMetaData VMD;
2855 int effectivePropertyIndex = 0;
2856 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2858 // Reserve space for name
2859 p->nameRef = builder.newString(p->name.utf8length());
2861 int propertyType = 0;
2862 bool readonly = false;
2863 QFastMetaBuilder::StringRef typeRef;
2865 if (p->type == Object::DynamicProperty::Alias) {
2867 } else if (p->type < builtinTypeCount) {
2868 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2869 propertyType = builtinTypes[p->type].metaType;
2870 if (typeRefs[p->type].isEmpty())
2871 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2872 typeRef = typeRefs[p->type];
2873 if (p->type == Object::DynamicProperty::Variant)
2877 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2878 p->type == Object::DynamicProperty::Custom);
2880 // XXX don't double resolve this in the case of an alias run
2882 QByteArray customTypeName;
2883 QDeclarativeType *qmltype = 0;
2885 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2886 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2889 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2891 Q_ASSERT(tdata->isComplete());
2893 QDeclarativeCompiledData *data = tdata->compiledData();
2894 customTypeName = data->root->className();
2898 customTypeName = qmltype->typeName();
2901 if (p->type == Object::DynamicProperty::Custom) {
2902 customTypeName += '*';
2903 propertyType = QMetaType::QObjectStar;
2906 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2907 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2910 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2911 p->typeRef = builder.newString(customTypeName.length());
2912 typeRef = p->typeRef;
2915 if (p->type == Object::DynamicProperty::Var)
2922 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2923 vmd->propertyCount++;
2924 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2927 if (p->type < builtinTypeCount)
2928 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2929 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2930 effectivePropertyIndex);
2932 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2933 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2934 effectivePropertyIndex);
2936 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2937 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2939 effectivePropertyIndex++;
2943 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2945 vmd->varPropertyCount = varPropCount;
2946 firstPropertyVarIndex = effectivePropertyIndex;
2947 totalPropCount = varPropCount + effectivePropertyIndex;
2948 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2949 if (p->type == Object::DynamicProperty::Var) {
2950 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2952 vmd->propertyCount++;
2953 (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
2956 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2957 (QMetaType::Type)-1,
2958 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2959 effectivePropertyIndex);
2961 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2962 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2964 effectivePropertyIndex++;
2971 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2972 if (p->type == Object::DynamicProperty::Alias) {
2974 Q_ASSERT(buildData);
2975 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2976 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2979 // Even if we aren't resolving the alias, we need a fake signal so that the
2980 // metaobject remains consistent across the resolve and non-resolve alias runs
2981 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2982 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2983 effectivePropertyIndex++;
2990 // Reserve default property
2991 QFastMetaBuilder::StringRef defPropRef;
2992 if (defaultProperty) {
2993 defPropRef = builder.newString(strlen("DefaultProperty"));
2994 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2997 // Reserve dynamic signals
2998 int signalIndex = 0;
2999 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3001 int paramCount = s->parameterNames.count();
3003 int signatureSize = s->name.utf8length() + 2 /* paren */;
3005 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
3006 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
3008 s->signatureRef = builder.newString(signatureSize);
3009 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3012 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
3014 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
3018 // Reserve dynamic slots
3019 if (obj->dynamicSlots.count()) {
3021 // Allocate QVariant string
3022 if (typeRefs[0].isEmpty())
3023 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
3025 typedef QDeclarativeVMEMetaData VMD;
3027 int methodIndex = 0;
3028 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3029 int paramCount = s->parameterNames.count();
3031 int signatureSize = s->name.utf8length() + 2 /* paren */;
3033 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
3034 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3036 s->signatureRef = builder.newString(signatureSize);
3037 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3039 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
3043 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3044 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3045 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3046 for (int jj = 0; jj < paramCount; ++jj) {
3047 if (jj) funcScript.append(QLatin1Char(','));
3048 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3050 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3052 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3053 funcScript.length(),
3054 s->location.start.line };
3056 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
3059 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3061 md.bodyOffset = dynamicData.size();
3063 dynamicData.append((const char *)funcScript.constData(),
3064 (funcScript.length() * sizeof(QChar)));
3071 // Now allocate used builtin types
3072 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3073 if (!typeRefs[ii].isEmpty())
3074 typeRefs[ii].load(builtinTypes[ii].cppType);
3077 // Now allocate properties
3078 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3080 char *d = p->changedSignatureRef.data();
3081 p->name.writeUtf8(d);
3082 strcpy(d + p->name.utf8length(), "Changed()");
3084 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3087 p->nameRef.load(p->name);
3089 if (p->type >= builtinTypeCount) {
3090 Q_ASSERT(p->resolvedCustomTypeName);
3091 p->typeRef.load(*p->resolvedCustomTypeName);
3095 // Allocate default property if necessary
3096 if (defaultProperty)
3097 strcpy(defPropRef.data(), "DefaultProperty");
3099 // Now allocate signals
3100 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3102 char *d = s->signatureRef.data();
3103 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3104 s->name.writeUtf8(d); d += s->name.utf8length();
3107 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3108 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3109 strcpy(d, s->parameterTypes.at(jj).constData());
3110 d += s->parameterTypes.at(jj).length();
3111 s->parameterNames.at(jj).writeUtf8(d2);
3112 d2 += s->parameterNames.at(jj).utf8length();
3119 // Now allocate methods
3120 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3121 char *d = s->signatureRef.data();
3122 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3123 s->name.writeUtf8(d); d += s->name.utf8length();
3125 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3126 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3127 strcpy(d, "QVariant");
3128 d += strlen("QVariant");
3129 strcpy(d2, s->parameterNames.at(jj).constData());
3130 d2 += s->parameterNames.at(jj).length();
3137 // Now allocate class name
3138 classNameRef.load(newClassName);
3140 obj->metadata = builder.toData();
3141 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3143 if (mode == IgnoreAliases && aliasCount)
3144 compileState->aliasingObjects.append(obj);
3146 obj->synthdata = dynamicData;
3148 if (obj->synthCache) {
3149 obj->synthCache->release();
3150 obj->synthCache = 0;
3153 if (obj->type != -1) {
3154 QDeclarativePropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3155 QDeclarativePropertyCache *cache =
3156 superCache->copyAndAppend(engine, &obj->extObject,
3157 QDeclarativePropertyData::NoFlags,
3158 QDeclarativePropertyData::IsVMEFunction,
3159 QDeclarativePropertyData::IsVMESignal);
3161 // now we modify the flags appropriately for var properties.
3162 int propertyOffset = obj->extObject.propertyOffset();
3163 QDeclarativePropertyData *currPropData = 0;
3164 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3165 currPropData = cache->property(pvi + propertyOffset);
3166 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty);
3169 obj->synthCache = cache;
3175 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3178 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3180 QChar ch = val.at(0);
3181 if (ch.isLetter() && !ch.isLower())
3182 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3184 QChar u(QLatin1Char('_'));
3185 if (!ch.isLetter() && ch != u)
3186 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3188 for (int ii = 1; ii < val.count(); ++ii) {
3190 if (!ch.isLetterOrNumber() && ch != u)
3191 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3194 if (enginePrivate->v8engine()->illegalNames().contains(val))
3195 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3200 #include <private/qdeclarativejsparser_p.h>
3202 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3204 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3206 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3207 return QStringList() << name;
3208 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3209 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3211 QStringList rv = astNodeToStringList(expr->base);
3214 rv.append(expr->name.toString());
3217 return QStringList();
3220 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3222 QDeclarativeScript::Object *obj,
3223 int propIndex, int aliasIndex,
3224 Object::DynamicProperty &prop)
3226 if (!prop.defaultValue)
3227 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3229 if (!prop.defaultValue->values.isOne() ||
3230 prop.defaultValue->values.first()->object ||
3231 !prop.defaultValue->values.first()->value.isScript())
3232 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3234 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3236 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3238 QStringList alias = astNodeToStringList(node);
3240 if (alias.count() < 1 || alias.count() > 3)
3241 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3243 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3245 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3247 QByteArray typeName;
3252 bool writable = false;
3253 bool resettable = false;
3254 if (alias.count() == 2 || alias.count() == 3) {
3255 propIdx = indexOfProperty(idObject, alias.at(1));
3257 if (-1 == propIdx) {
3258 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3259 } else if (propIdx > 0xFFFF) {
3260 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3263 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3264 if (!aliasProperty.isScriptable())
3265 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3267 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3268 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3270 if (aliasProperty.type() < QVariant::UserType ||
3271 aliasProperty.type() == QVariant::LastType /* for QVariant */ )
3272 type = aliasProperty.type();
3274 if (alias.count() == 3) {
3275 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3277 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3279 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3281 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3282 if (valueTypeIndex == -1)
3283 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3284 Q_ASSERT(valueTypeIndex <= 0xFF);
3286 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3287 propIdx |= (valueTypeIndex << 16);
3289 // update the property type
3290 type = aliasProperty.type();
3291 if (type >= (int)QVariant::UserType)
3295 if (aliasProperty.isEnumType())
3296 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3298 typeName = aliasProperty.typeName();
3300 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3302 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3304 typeName = ref.type->typeName();
3306 typeName = ref.component->root->className();
3311 if (typeName.endsWith('*'))
3312 flags |= QML_ALIAS_FLAG_PTR;
3314 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3316 typedef QDeclarativeVMEMetaData VMD;
3317 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3318 *(vmd->aliasData() + aliasIndex) = aliasData;
3320 prop.nameRef = builder.newString(prop.name.utf8length());
3321 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3322 prop.typeRef = builder.newString(typeName.length());
3324 int propertyFlags = 0;
3326 propertyFlags |= QFastMetaBuilder::Writable;
3328 propertyFlags |= QFastMetaBuilder::Resettable;
3330 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3331 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3337 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3338 QDeclarativeScript::Property *prop,
3339 const BindingContext &ctxt)
3341 Q_ASSERT(prop->index != -1);
3342 Q_ASSERT(prop->parent);
3343 Q_ASSERT(prop->parent->metaObject());
3345 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3346 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3348 JSBindingReference *reference = pool->New<JSBindingReference>();
3349 reference->expression = value->value;
3350 reference->property = prop;
3351 reference->value = value;
3352 reference->bindingContext = ctxt;
3353 addBindingReference(reference);
3358 bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v,
3359 QDeclarativeScript::Property *prop,
3360 const QDeclarativeCompilerTypes::BindingContext &)
3362 Q_ASSERT(v->value.isScript());
3364 if (!prop->core.isWritable())
3367 AST::Node *binding = v->value.asAST();
3369 if (prop->type == QVariant::String) {
3370 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3371 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3372 if (i->name == qsTrId_string) {
3373 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3374 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3376 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3377 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3378 (!arg2 || !arg2->next)) {
3383 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3384 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3386 TrBindingReference *reference = pool->New<TrBindingReference>();
3387 reference->dataType = BindingReference::TrId;
3388 reference->text = text;
3390 v->bindingReference = reference;
3394 } else if (i->name == qsTr_string) {
3396 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3397 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3398 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3400 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3401 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3402 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3403 (!arg3 || !arg3->next)) {
3409 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3410 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3411 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3413 TrBindingReference *reference = pool->New<TrBindingReference>();
3414 reference->dataType = BindingReference::Tr;
3415 reference->text = text;
3416 reference->comment = comment;
3418 v->bindingReference = reference;
3431 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3432 QDeclarativeScript::Property *prop,
3433 QDeclarativeScript::Object *obj,
3434 QDeclarativeScript::Property *valueTypeProperty)
3437 Q_ASSERT(binding->bindingReference);
3439 const BindingReference &ref = *binding->bindingReference;
3440 if (ref.dataType == BindingReference::TrId) {
3441 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3443 Instruction::StoreTrIdString store;
3444 store.propertyIndex = prop->core.coreIndex;
3445 store.text = output->indexForByteArray(tr.text.toUtf8());
3447 output->addInstruction(store);
3448 } else if (ref.dataType == BindingReference::Tr) {
3449 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3451 Instruction::StoreTrString store;
3452 store.propertyIndex = prop->core.coreIndex;
3453 store.context = translationContextIndex();
3454 store.text = output->indexForByteArray(tr.text.toUtf8());
3455 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3457 output->addInstruction(store);
3458 } else if (ref.dataType == BindingReference::V4) {
3459 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3461 Instruction::StoreV4Binding store;
3462 store.value = js.compiledIndex;
3463 store.context = js.bindingContext.stack;
3464 store.owner = js.bindingContext.owner;
3465 if (valueTypeProperty) {
3466 store.property = (valueTypeProperty->index & 0xFFFF) |
3467 ((valueTypeProperty->type & 0xFF)) << 16 |
3468 ((prop->index & 0xFF) << 24);
3469 store.isRoot = (compileState->root == valueTypeProperty->parent);
3471 store.property = prop->index;
3472 store.isRoot = (compileState->root == obj);
3474 store.line = binding->location.start.line;
3475 store.column = binding->location.start.column;
3476 output->addInstruction(store);
3477 } else if (ref.dataType == BindingReference::V8) {
3478 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3480 Instruction::StoreV8Binding store;
3481 store.value = js.compiledIndex;
3482 store.context = js.bindingContext.stack;
3483 store.owner = js.bindingContext.owner;
3484 if (valueTypeProperty) {
3485 store.isRoot = (compileState->root == valueTypeProperty->parent);
3487 store.isRoot = (compileState->root == obj);
3489 store.line = binding->location.start.line;
3490 store.column = binding->location.start.column;
3492 Q_ASSERT(js.bindingContext.owner == 0 ||
3493 (js.bindingContext.owner != 0 && valueTypeProperty));
3494 if (js.bindingContext.owner) {
3495 store.property = genValueTypeData(prop, valueTypeProperty);
3497 store.property = prop->core;
3500 output->addInstruction(store);
3501 } else if (ref.dataType == BindingReference::QtScript) {
3502 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3504 QDeclarativeInstruction store;
3505 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3506 store.assignBinding.context = js.bindingContext.stack;
3507 store.assignBinding.owner = js.bindingContext.owner;
3508 store.assignBinding.line = binding->location.start.line;
3509 store.assignBinding.column = binding->location.start.column;
3511 if (valueTypeProperty) {
3512 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3514 store.assignBinding.isRoot = (compileState->root == obj);
3517 Q_ASSERT(js.bindingContext.owner == 0 ||
3518 (js.bindingContext.owner != 0 && valueTypeProperty));
3519 if (js.bindingContext.owner) {
3520 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3522 store.assignBinding.property = prop->core;
3524 output->addInstructionHelper(
3525 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3526 : QDeclarativeInstruction::StoreBindingOnAlias
3529 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3533 int QDeclarativeCompiler::genContextCache()
3535 if (compileState->ids.count() == 0)
3538 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3539 cache->reserve(compileState->ids.count());
3540 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3541 cache->add(o->id, o->idIndex);
3543 output->contextCaches.append(cache);
3544 return output->contextCaches.count() - 1;
3547 QDeclarativePropertyData
3548 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3549 QDeclarativeScript::Property *prop)
3551 typedef QDeclarativePropertyPrivate QDPP;
3552 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3553 enginePrivate->valueTypes[prop->type]->metaObject(),
3554 valueTypeProp->index, engine);
3557 bool QDeclarativeCompiler::completeComponentBuild()
3560 componentStats->componentStat.ids = compileState->ids.count();
3562 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3563 aliasObject = compileState->aliasingObjects.next(aliasObject))
3564 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3566 QV4Compiler::Expression expr(unit->imports());
3567 expr.component = compileState->root;
3568 expr.ids = &compileState->ids;
3569 expr.importCache = output->importCache;
3571 QV4Compiler bindingCompiler;
3573 QList<JSBindingReference*> sharedBindings;
3575 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3577 JSBindingReference &binding = *b;
3579 // ### We don't currently optimize for bindings on alias's - because
3580 // of the solution to QTBUG-13719
3581 if (!binding.property->isAlias) {
3582 expr.context = binding.bindingContext.object;
3583 expr.property = binding.property;
3584 expr.expression = binding.expression;
3586 int index = bindingCompiler.compile(expr, enginePrivate);
3588 binding.dataType = BindingReference::V4;
3589 binding.compiledIndex = index;
3591 componentStats->componentStat.optimizedBindings.append(b->value->location);
3596 // Pre-rewrite the expression
3597 QString expression = binding.expression.asScript();
3599 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3600 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3601 bool isSharable = false;
3602 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3604 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3605 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3606 binding.dataType = BindingReference::V8;
3607 sharedBindings.append(b);
3609 binding.dataType = BindingReference::QtScript;
3613 componentStats->componentStat.scriptBindings.append(b->value->location);
3616 if (!sharedBindings.isEmpty()) {
3618 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3620 return lhs->value->location.start.line < rhs->value->location.start.line;
3624 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3626 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3627 int lineNumber = startLineNumber;
3629 QString functionArray(QLatin1String("["));
3630 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3631 JSBindingReference *reference = sharedBindings.at(ii);
3632 QDeclarativeScript::Value *value = reference->value;
3633 const QString &expression = reference->rewrittenExpression;
3635 if (ii != 0) functionArray += QLatin1String(",");
3637 while (lineNumber < value->location.start.line) {
3639 functionArray += QLatin1String("\n");
3642 functionArray += expression;
3643 lineNumber += expression.count(QLatin1Char('\n'));
3644 reference->compiledIndex = ii;
3646 functionArray += QLatin1String("]");
3648 compileState->v8BindingProgram = functionArray;
3649 compileState->v8BindingProgramLine = startLineNumber;
3650 compileState->v8BindingProgramIndex = output->v8bindings.count();
3651 output->v8bindings.append(v8::Persistent<v8::Array>());
3654 if (bindingCompiler.isValid())
3655 compileState->compiledBindingData = bindingCompiler.program();
3657 // Check pop()'s matched push()'s
3658 Q_ASSERT(compileState->objectDepth.depth() == 0);
3659 Q_ASSERT(compileState->listDepth.depth() == 0);
3661 saveComponentState();
3666 void QDeclarativeCompiler::dumpStats()
3668 Q_ASSERT(componentStats);
3669 qWarning().nospace() << "QML Document: " << output->url.toString();
3670 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3671 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3672 qWarning().nospace() << " Component Line " << stat.lineNumber;
3673 qWarning().nospace() << " Total Objects: " << stat.objects;
3674 qWarning().nospace() << " IDs Used: " << stat.ids;
3675 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3679 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3680 if (0 == (ii % 10)) {
3681 if (ii) output.append("\n");
3686 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3688 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3689 output.append(") ");
3691 if (!output.isEmpty())
3692 qWarning().nospace() << output.constData();
3695 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3698 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3699 if (0 == (ii % 10)) {
3700 if (ii) output.append("\n");
3705 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3707 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3708 output.append(") ");
3710 if (!output.isEmpty())
3711 qWarning().nospace() << output.constData();
3717 Returns true if from can be assigned to a (QObject) property of type
3720 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3722 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3723 const QMetaObject *fromMo = from->metaObject();
3726 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3728 fromMo = fromMo->superClass();
3734 Returns the element name, as written in the QML file, for o.
3736 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3739 if (o->type != -1) {
3740 return output->types.at(o->type).className;
3746 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3749 const QMetaObject *mo = from->metatype;
3750 QDeclarativeType *type = 0;
3751 while (!type && mo) {
3752 type = QDeclarativeMetaType::qmlType(mo);
3753 mo = mo->superClass();
3758 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3760 const QMetaObject *mo = obj->metatype;
3762 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3764 return QStringList();
3766 QMetaClassInfo classInfo = mo->classInfo(idx);
3767 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3771 QDeclarativePropertyData *
3772 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3774 QDeclarativePropertyCache *cache = 0;
3776 if (object->synthCache)
3777 cache = object->synthCache;
3778 else if (object->type != -1)
3779 cache = output->types[object->type].createPropertyCache(engine);
3781 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3783 return cache->property(index);
3786 QDeclarativePropertyData *
3787 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3789 if (notInRevision) *notInRevision = false;
3791 QDeclarativePropertyCache *cache = 0;
3793 if (object->synthCache)
3794 cache = object->synthCache;
3795 else if (object->type != -1)
3796 cache = output->types[object->type].createPropertyCache(engine);
3798 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3800 QDeclarativePropertyData *d = cache->property(name);
3802 // Find the first property
3803 while (d && d->isFunction())
3804 d = cache->overrideData(d);
3806 if (d && !cache->isAllowedInRevision(d)) {
3807 if (notInRevision) *notInRevision = true;
3814 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3815 QDeclarativePropertyData *
3816 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3818 if (notInRevision) *notInRevision = false;
3820 QDeclarativePropertyCache *cache = 0;
3822 if (object->synthCache)
3823 cache = object->synthCache;
3824 else if (object->type != -1)
3825 cache = output->types[object->type].createPropertyCache(engine);
3827 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3830 QDeclarativePropertyData *d = cache->property(name);
3831 if (notInRevision) *notInRevision = false;
3833 while (d && !(d->isFunction()))
3834 d = cache->overrideData(d);
3836 if (d && !cache->isAllowedInRevision(d)) {
3837 if (notInRevision) *notInRevision = true;
3843 if (name.endsWith(Changed_string)) {
3844 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3846 d = property(object, propName, notInRevision);
3848 return cache->method(d->notifyIndex);
3854 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3855 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3856 bool *notInRevision)
3858 QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision);
3859 return d?d->coreIndex:-1;
3862 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3863 bool *notInRevision)
3865 return indexOfProperty(object, QStringRef(&name), notInRevision);
3868 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3869 bool *notInRevision)
3871 QDeclarativePropertyData *d = property(object, name, notInRevision);
3872 return d?d->coreIndex:-1;