1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "private/qdeclarativeparser_p.h"
45 #include "private/qdeclarativescriptparser_p.h"
46 #include "qdeclarativepropertyvaluesource.h"
47 #include "qdeclarativecomponent.h"
48 #include "private/qmetaobjectbuilder_p.h"
49 #include "private/qdeclarativestringconverters_p.h"
50 #include "private/qdeclarativeengine_p.h"
51 #include "qdeclarativeengine.h"
52 #include "qdeclarativecontext.h"
53 #include "private/qdeclarativemetatype_p.h"
54 #include "private/qdeclarativecustomparser_p_p.h"
55 #include "private/qdeclarativecontext_p.h"
56 #include "private/qdeclarativecomponent_p.h"
57 #include "parser/qdeclarativejsast_p.h"
58 #include "private/qdeclarativevmemetaobject_p.h"
59 #include "private/qdeclarativeexpression_p.h"
60 #include "private/qdeclarativeproperty_p.h"
61 #include "private/qdeclarativerewrite_p.h"
62 #include "qdeclarativescriptstring.h"
63 #include "private/qdeclarativeglobal_p.h"
64 #include "private/qdeclarativescriptparser_p.h"
65 #include "private/qdeclarativebinding_p.h"
66 #include "private/qdeclarativev4compiler_p.h"
74 #include <QtCore/qdebug.h>
75 #include <QtCore/qdatetime.h>
79 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
80 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
82 using namespace QDeclarativeParser;
83 using namespace QDeclarativeCompilerTypes;
85 static QString id_string(QLatin1String("id"));
86 static QString on_string(QLatin1String("on"));
87 static QString Changed_string(QLatin1String("Changed"));
88 static QString Component_string(QLatin1String("Component"));
91 Instantiate a new QDeclarativeCompiler.
93 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
94 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), componentStats(0)
96 if (compilerStatDump())
97 componentStats = pool->New<ComponentStats>();
101 Returns true if the last call to compile() caused errors.
105 bool QDeclarativeCompiler::isError() const
107 return !exceptions.isEmpty();
111 Return the list of errors from the last call to compile(), or an empty list
112 if there were no errors.
114 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
120 Returns true if \a name refers to an attached property, false otherwise.
122 Attached property names are those that start with a capital letter.
124 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
126 return isAttachedPropertyName(QStringRef(&name));
129 bool QDeclarativeCompiler::isAttachedPropertyName(const QStringRef &name)
131 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
135 Returns true if \a name refers to a signal property, false otherwise.
137 Signal property names are those that start with "on", followed by a first
138 character which is either a capital letter or one or more underscores followed
139 by a capital letter, which is then followed by other allowed characters.
141 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
142 character codes in property names, for simplicity and performance reasons
143 QML only supports letters, numbers and underscores.
145 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
147 return isSignalPropertyName(QStringRef(&name));
150 bool QDeclarativeCompiler::isSignalPropertyName(const QStringRef &name)
152 if (name.length() < 3) return false;
153 if (!name.startsWith(on_string)) return false;
154 int ns = name.size();
155 for (int i = 2; i < ns; ++i) {
156 QChar curr = name.at(i);
157 if (curr == QLatin1Char('_')) continue;
158 if (curr >= QLatin1Char('A') && curr <= QLatin1Char('Z')) return true;
161 return false; // consists solely of underscores - invalid.
165 \macro COMPILE_EXCEPTION
167 Inserts an error into the QDeclarativeCompiler error list, and returns false
170 \a token is used to source the error line and column, and \a desc is the
171 error itself. \a desc can be an expression that can be piped into QDebug.
176 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
179 #define COMPILE_EXCEPTION(token, desc) \
181 QString exceptionDescription; \
182 QDeclarativeError error; \
183 error.setUrl(output->url); \
184 error.setLine((token)->location.start.line); \
185 error.setColumn((token)->location.start.column); \
186 error.setDescription(desc.trimmed()); \
187 exceptions << error; \
194 Returns false if \a is false, otherwise does nothing.
196 #define COMPILE_CHECK(a) \
198 if (!a) return false; \
202 Returns true if literal \a v can be assigned to property \a prop, otherwise
205 This test corresponds to action taken by genLiteralAssignment(). Any change
206 made here, must have a corresponding action in genLiteralAssigment().
208 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
209 QDeclarativeParser::Value *v)
211 const QDeclarativeParser::Variant &value = v->value;
213 if (!prop.isWritable())
214 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
216 if (prop.isEnumType()) {
218 if (prop.isFlagType()) {
219 enumValue = prop.enumerator().keysToValue(value.asString().toUtf8().constData());
221 enumValue = prop.enumerator().keyToValue(value.asString().toUtf8().constData());
223 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
226 int type = prop.userType();
230 case QVariant::String:
231 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
233 case QVariant::ByteArray:
234 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
237 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
241 bool ok = v->value.isNumber();
243 double n = v->value.asNumber();
244 if (double(uint(n)) != n)
247 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
252 bool ok = v->value.isNumber();
254 double n = v->value.asNumber();
255 if (double(int(n)) != n)
258 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
261 case QMetaType::Float:
262 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
264 case QVariant::Double:
265 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
267 case QVariant::Color:
270 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
271 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
274 #ifndef QT_NO_DATESTRING
278 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
279 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
285 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
286 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
289 case QVariant::DateTime:
292 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
293 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
296 #endif // QT_NO_DATESTRING
297 case QVariant::Point:
298 case QVariant::PointF:
301 QPointF point = QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
302 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
306 case QVariant::SizeF:
309 QSizeF size = QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
310 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
314 case QVariant::RectF:
317 QRectF rect = QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
318 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
323 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
326 case QVariant::Vector3D:
329 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
330 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
333 case QVariant::Vector4D:
336 QDeclarativeStringConverters::vector4DFromString(string, &ok);
337 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
342 int t = prop.userType();
343 QDeclarativeMetaType::StringConverter converter =
344 QDeclarativeMetaType::customStringConverter(t);
346 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
354 Generate a store instruction for assigning literal \a v to property \a prop.
356 Any literal assignment that is approved in testLiteralAssignment() must have
357 a corresponding action in this method.
359 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
360 QDeclarativeParser::Value *v)
362 QDeclarativeInstruction instr;
363 if (prop.isEnumType()) {
365 if (v->value.isNumber()) {
367 value = (int)v->value.asNumber();
370 if (prop.isFlagType()) {
371 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
373 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
376 instr.setType(QDeclarativeInstruction::StoreInteger);
377 instr.storeInteger.propertyIndex = prop.propertyIndex();
378 instr.storeInteger.value = value;
379 output->addInstruction(instr);
383 int type = prop.userType();
387 if (v->value.isNumber()) {
388 double n = v->value.asNumber();
389 if (double(int(n)) == n) {
390 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
391 instr.storeInteger.propertyIndex = prop.propertyIndex();
392 instr.storeInteger.value = int(n);
394 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
395 instr.storeDouble.propertyIndex = prop.propertyIndex();
396 instr.storeDouble.value = n;
398 } else if(v->value.isBoolean()) {
399 instr.setType(QDeclarativeInstruction::StoreVariantBool);
400 instr.storeBool.propertyIndex = prop.propertyIndex();
401 instr.storeBool.value = v->value.asBoolean();
403 instr.setType(QDeclarativeInstruction::StoreVariant);
404 instr.storeString.propertyIndex = prop.propertyIndex();
405 instr.storeString.value = output->indexForString(v->value.asString());
409 case QVariant::String:
411 instr.setType(QDeclarativeInstruction::StoreString);
412 instr.storeString.propertyIndex = prop.propertyIndex();
413 instr.storeString.value = output->indexForString(v->value.asString());
416 case QVariant::ByteArray:
418 instr.setType(QDeclarativeInstruction::StoreByteArray);
419 instr.storeByteArray.propertyIndex = prop.propertyIndex();
420 instr.storeByteArray.value = output->indexForByteArray(v->value.asString().toLatin1());
425 instr.setType(QDeclarativeInstruction::StoreUrl);
426 QString string = v->value.asString();
427 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
428 instr.storeUrl.propertyIndex = prop.propertyIndex();
429 instr.storeUrl.value = output->indexForUrl(u);
434 instr.setType(QDeclarativeInstruction::StoreInteger);
435 instr.storeInteger.propertyIndex = prop.propertyIndex();
436 instr.storeInteger.value = uint(v->value.asNumber());
441 instr.setType(QDeclarativeInstruction::StoreInteger);
442 instr.storeInteger.propertyIndex = prop.propertyIndex();
443 instr.storeInteger.value = int(v->value.asNumber());
446 case QMetaType::Float:
448 instr.setType(QDeclarativeInstruction::StoreFloat);
449 instr.storeFloat.propertyIndex = prop.propertyIndex();
450 instr.storeFloat.value = float(v->value.asNumber());
453 case QVariant::Double:
455 instr.setType(QDeclarativeInstruction::StoreDouble);
456 instr.storeDouble.propertyIndex = prop.propertyIndex();
457 instr.storeDouble.value = v->value.asNumber();
460 case QVariant::Color:
462 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
463 instr.setType(QDeclarativeInstruction::StoreColor);
464 instr.storeColor.propertyIndex = prop.propertyIndex();
465 instr.storeColor.value = c.rgba();
468 #ifndef QT_NO_DATESTRING
471 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
472 instr.setType(QDeclarativeInstruction::StoreDate);
473 instr.storeDate.propertyIndex = prop.propertyIndex();
474 instr.storeDate.value = d.toJulianDay();
479 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
480 instr.setType(QDeclarativeInstruction::StoreTime);
481 instr.storeTime.propertyIndex = prop.propertyIndex();
482 Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime));
483 ::memcpy(&instr.storeTime.time, &time, sizeof(QTime));
486 case QVariant::DateTime:
488 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
489 QTime time = dateTime.time();
490 instr.setType(QDeclarativeInstruction::StoreDateTime);
491 instr.storeDateTime.propertyIndex = prop.propertyIndex();
492 instr.storeDateTime.date = dateTime.date().toJulianDay();
493 Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime));
494 ::memcpy(&instr.storeDateTime.time, &time, sizeof(QTime));
497 #endif // QT_NO_DATESTRING
498 case QVariant::Point:
501 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
502 instr.setType(QDeclarativeInstruction::StorePoint);
503 instr.storePoint.propertyIndex = prop.propertyIndex();
504 instr.storePoint.point.xp = point.x();
505 instr.storePoint.point.yp = point.y();
508 case QVariant::PointF:
511 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
512 instr.setType(QDeclarativeInstruction::StorePointF);
513 instr.storePointF.propertyIndex = prop.propertyIndex();
514 instr.storePointF.point.xp = point.x();
515 instr.storePointF.point.yp = point.y();
521 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
522 instr.setType(QDeclarativeInstruction::StoreSize);
523 instr.storeSize.propertyIndex = prop.propertyIndex();
524 instr.storeSize.size.wd = size.width();
525 instr.storeSize.size.ht = size.height();
528 case QVariant::SizeF:
531 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
532 instr.setType(QDeclarativeInstruction::StoreSizeF);
533 instr.storeSizeF.propertyIndex = prop.propertyIndex();
534 instr.storeSizeF.size.wd = size.width();
535 instr.storeSizeF.size.ht = size.height();
541 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
542 instr.setType(QDeclarativeInstruction::StoreRect);
543 instr.storeRect.propertyIndex = prop.propertyIndex();
544 instr.storeRect.rect.x1 = rect.left();
545 instr.storeRect.rect.y1 = rect.top();
546 instr.storeRect.rect.x2 = rect.right();
547 instr.storeRect.rect.y2 = rect.bottom();
550 case QVariant::RectF:
553 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
554 instr.setType(QDeclarativeInstruction::StoreRectF);
555 instr.storeRectF.propertyIndex = prop.propertyIndex();
556 instr.storeRectF.rect.xp = rect.left();
557 instr.storeRectF.rect.yp = rect.top();
558 instr.storeRectF.rect.w = rect.width();
559 instr.storeRectF.rect.h = rect.height();
564 bool b = v->value.asBoolean();
565 instr.setType(QDeclarativeInstruction::StoreBool);
566 instr.storeBool.propertyIndex = prop.propertyIndex();
567 instr.storeBool.value = b;
570 case QVariant::Vector3D:
573 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
574 instr.setType(QDeclarativeInstruction::StoreVector3D);
575 instr.storeVector3D.propertyIndex = prop.propertyIndex();
576 instr.storeVector3D.vector.xp = vector.x();
577 instr.storeVector3D.vector.yp = vector.y();
578 instr.storeVector3D.vector.zp = vector.z();
581 case QVariant::Vector4D:
584 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(string, &ok);
585 instr.setType(QDeclarativeInstruction::StoreVector4D);
586 instr.storeVector4D.propertyIndex = prop.propertyIndex();
587 instr.storeVector4D.vector.xp = vector.x();
588 instr.storeVector4D.vector.yp = vector.y();
589 instr.storeVector4D.vector.zp = vector.z();
590 instr.storeVector4D.vector.wp = vector.w();
595 int t = prop.userType();
596 instr.setType(QDeclarativeInstruction::AssignCustomType);
597 instr.assignCustomType.propertyIndex = prop.propertyIndex();
598 instr.assignCustomType.primitive = output->indexForString(v->value.asString());
599 instr.assignCustomType.type = t;
603 output->addInstruction(instr);
607 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
609 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
612 data->primitives.clear();
614 data->bytecode.clear();
618 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
619 with which the QDeclarativeCompiledData will be associated.
621 Returns true on success, false on failure. On failure, the compile errors
622 are available from errors().
624 If the environment variant QML_COMPILER_DUMP is set
625 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
626 on a successful compiler.
628 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
629 QDeclarativeTypeData *unit,
630 QDeclarativeCompiledData *out)
640 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
641 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
643 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
644 QDeclarativeCompiledData::TypeReference ref;
646 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
647 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
650 ref.type = tref.type;
651 if (!ref.type->isCreatable()) {
652 QString err = ref.type->noCreationReason();
654 err = tr( "Element is not creatable.");
655 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
658 if (ref.type->containsRevisionedAttributes()) {
659 QDeclarativeError cacheError;
660 ref.typePropertyCache =
661 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
663 if (!ref.typePropertyCache) {
664 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
666 ref.typePropertyCache->addref();
669 } else if (tref.typeData) {
670 ref.component = tref.typeData->compiledData();
672 ref.className = parserRef->name;
676 QDeclarativeParser::Object *root = unit->parser().tree();
679 this->engine = engine;
680 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
682 this->unitRoot = root;
687 out->dumpInstructions();
690 Q_ASSERT(out->rootPropertyCache);
698 this->enginePrivate = 0;
705 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
707 compileState = pool->New<ComponentCompileState>();
709 compileState->root = tree;
711 componentStats->componentStat.lineNumber = tree->location.start.line;
713 // Build global import scripts
714 QStringList importedScriptIndexes;
716 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
717 importedScriptIndexes.append(script.qualifier);
719 QDeclarativeInstruction import;
720 import.setType(QDeclarativeInstruction::StoreImportedScript);
721 import.storeScript.value = output->scripts.count();
723 QDeclarativeScriptData *scriptData = script.script->scriptData();
724 scriptData->addref();
725 output->scripts << scriptData;
726 output->addInstruction(import);
729 // We generate the importCache before we build the tree so that
730 // it can be used in the binding compiler. Given we "expect" the
731 // QML compilation to succeed, this isn't a waste.
732 output->importCache = new QDeclarativeTypeNameCache(engine);
733 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
734 output->importCache->add(importedScriptIndexes.at(ii), ii);
735 unit->imports().populateCache(output->importCache, engine);
737 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
740 QDeclarativeInstruction init;
741 init.setType(QDeclarativeInstruction::Init);
742 init.init.bindingsSize = compileState->bindings.count();
743 init.init.parserStatusSize = compileState->parserStatusCount;
744 init.init.contextCache = genContextCache();
745 if (compileState->compiledBindingData.isEmpty())
746 init.init.compiledBinding = -1;
748 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
749 output->addInstruction(init);
751 if (!compileState->v8BindingProgram.isEmpty()) {
752 QDeclarativeInstruction bindings;
753 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
754 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
755 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
756 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
757 output->addInstruction(bindings);
762 QDeclarativeInstruction def;
763 def.setType(QDeclarativeInstruction::SetDefault);
764 output->addInstruction(def);
766 QDeclarativeInstruction done;
767 done.setType(QDeclarativeInstruction::Done);
768 output->addInstruction(done);
770 Q_ASSERT(tree->metatype);
772 if (tree->metadata.isEmpty()) {
773 output->root = tree->metatype;
775 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
776 output->root = &output->rootData;
778 if (!tree->metadata.isEmpty())
779 enginePrivate->registerCompositeType(output);
782 static bool QStringList_contains(const QStringList &list, const QStringRef &string)
784 for (int ii = 0; ii < list.count(); ++ii)
785 if (list.at(ii) == string)
791 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
794 componentStats->componentStat.objects++;
796 Q_ASSERT (obj->type != -1);
797 const QDeclarativeCompiledData::TypeReference &tr =
798 output->types.at(obj->type);
799 obj->metatype = tr.metaObject();
802 obj->typeName = tr.type->qmlTypeName();
804 // This object is a "Component" element
805 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
806 COMPILE_CHECK(buildComponent(obj, ctxt));
810 // Object instantiations reset the binding context
811 BindingContext objCtxt(obj);
813 // Create the synthesized meta object, ignoring aliases
814 COMPILE_CHECK(checkDynamicMeta(obj));
815 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
816 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
818 // Find the native type and check for the QDeclarativeParserStatus interface
819 QDeclarativeType *type = toQmlType(obj);
821 obj->parserStatusCast = type->parserStatusCast();
822 if (obj->parserStatusCast != -1)
823 compileState->parserStatusCount++;
825 // Check if this is a custom parser type. Custom parser types allow
826 // assignments to non-existent properties. These assignments are then
827 // compiled by the type.
828 bool isCustomParser = output->types.at(obj->type).type &&
829 output->types.at(obj->type).type->customParser() != 0;
830 QList<QDeclarativeCustomParserProperty> customProps;
832 // Fetch the list of deferred properties
833 QStringList deferredList = deferredProperties(obj);
835 // Must do id property first. This is to ensure that the id given to any
836 // id reference created matches the order in which the objects are
838 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
839 if (prop->name() == id_string) {
840 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
846 Property *defaultProperty = 0;
847 Property *skipProperty = 0;
848 if (obj->defaultProperty) {
849 defaultProperty = obj->defaultProperty;
851 const QMetaObject *metaObject = obj->metaObject();
852 Q_ASSERT(metaObject);
853 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
855 Property *explicitProperty = obj->getProperty(QString::fromUtf8(p.name()), false);
856 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
858 skipProperty = explicitProperty; // We merge the values into defaultProperty
860 // Find the correct insertion point
861 Value *insertPos = 0;
863 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
864 if (!(v->location.start < explicitProperty->values.first()->location.start))
869 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
875 QDeclarativeCustomParser *cp = 0;
877 cp = output->types.at(obj->type).type->customParser();
879 // Build all explicit properties specified
880 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
882 if (prop == skipProperty)
884 if (prop->name() == id_string)
887 bool canDefer = false;
888 if (isCustomParser) {
889 if (doesPropertyExist(prop, obj) &&
890 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
891 !isAttachedPropertyName(prop->name()))) {
892 int ids = compileState->ids.count();
893 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
894 canDefer = ids == compileState->ids.count();
895 } else if (isSignalPropertyName(prop->name()) &&
896 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
897 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
899 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
902 if (isSignalPropertyName(prop->name())) {
903 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
905 int ids = compileState->ids.count();
906 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
907 canDefer = ids == compileState->ids.count();
911 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
912 prop->isDeferred = true;
916 // Build the default property
917 if (defaultProperty) {
918 Property *prop = defaultProperty;
920 bool canDefer = false;
921 if (isCustomParser) {
922 if (doesPropertyExist(prop, obj)) {
923 int ids = compileState->ids.count();
924 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
925 canDefer = ids == compileState->ids.count();
927 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
930 int ids = compileState->ids.count();
931 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
932 canDefer = ids == compileState->ids.count();
935 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
936 prop->isDeferred = true;
939 // Compile custom parser parts
940 if (isCustomParser && !customProps.isEmpty()) {
944 obj->custom = cp->compile(customProps);
947 foreach (QDeclarativeError err, cp->errors()) {
948 err.setUrl(output->url);
956 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
958 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
959 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
965 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
966 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
968 QDeclarativeInstruction create;
969 create.setType(QDeclarativeInstruction::CreateSimpleObject);
970 create.createSimple.create = output->types.at(obj->type).type->createFunction();
971 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
972 create.createSimple.type = obj->type;
973 create.createSimple.line = obj->location.start.line;
974 create.createSimple.column = obj->location.start.column;
975 output->addInstruction(create);
979 QDeclarativeInstruction create;
980 create.setType(QDeclarativeInstruction::CreateObject);
981 create.create.line = obj->location.start.line;
982 create.create.column = obj->location.start.column;
983 create.create.data = -1;
984 if (!obj->custom.isEmpty())
985 create.create.data = output->indexForByteArray(obj->custom);
986 create.create.type = obj->type;
987 if (!output->types.at(create.create.type).type &&
988 !obj->bindingBitmask.isEmpty()) {
989 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
990 create.create.bindingBits =
991 output->indexForByteArray(obj->bindingBitmask);
993 create.create.bindingBits = -1;
995 output->addInstruction(create);
999 // Setup the synthesized meta object if necessary
1000 if (!obj->metadata.isEmpty()) {
1001 QDeclarativeInstruction meta;
1002 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1003 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1004 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1005 meta.storeMeta.propertyCache = output->propertyCaches.count();
1007 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1008 Q_ASSERT(propertyCache);
1009 propertyCache->addref();
1011 // Add flag for alias properties
1012 if (!obj->synthdata.isEmpty()) {
1013 const QDeclarativeVMEMetaData *vmeMetaData =
1014 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1015 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1016 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1017 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1018 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1022 if (obj == unitRoot) {
1023 propertyCache->addref();
1024 output->rootPropertyCache = propertyCache;
1027 output->propertyCaches << propertyCache;
1028 output->addInstruction(meta);
1029 } else if (obj == unitRoot) {
1030 output->rootPropertyCache = tr.createPropertyCache(engine);
1031 output->rootPropertyCache->addref();
1034 // Set the object id
1035 if (!obj->id.isEmpty()) {
1036 QDeclarativeInstruction id;
1037 id.setType(QDeclarativeInstruction::SetId);
1038 id.setId.value = output->indexForString(obj->id);
1039 id.setId.index = obj->idIndex;
1040 output->addInstruction(id);
1044 if (tr.type && obj->parserStatusCast != -1) {
1045 QDeclarativeInstruction begin;
1046 begin.setType(QDeclarativeInstruction::BeginObject);
1047 begin.begin.castValue = obj->parserStatusCast;
1048 output->addInstruction(begin);
1054 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1056 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1057 Q_ASSERT(prop->scriptStringScope != -1);
1058 const QString &script = prop->values.first()->value.asScript();
1059 QDeclarativeInstruction ss;
1060 ss.setType(QDeclarativeInstruction::StoreScriptString);
1061 ss.storeScriptString.propertyIndex = prop->index;
1062 ss.storeScriptString.value = output->indexForString(script);
1063 ss.storeScriptString.scope = prop->scriptStringScope;
1064 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1065 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1066 ss.storeScriptString.line = prop->location.start.line;
1067 output->addInstruction(ss);
1070 bool seenDefer = false;
1071 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1072 if (prop->isDeferred) {
1077 genValueProperty(prop, obj);
1080 QDeclarativeInstruction defer;
1081 defer.setType(QDeclarativeInstruction::Defer);
1082 defer.defer.deferCount = 0;
1083 int deferIdx = output->addInstruction(defer);
1084 int nextInstructionIndex = output->nextInstructionIndex();
1086 QDeclarativeInstruction init;
1087 init.setType(QDeclarativeInstruction::Init);
1088 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1089 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1090 init.init.contextCache = -1;
1091 init.init.compiledBinding = -1;
1092 output->addInstruction(init);
1094 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1095 if (!prop->isDeferred)
1097 genValueProperty(prop, obj);
1100 QDeclarativeInstruction done;
1101 done.setType(QDeclarativeInstruction::Done);
1102 output->addInstruction(done);
1104 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1107 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1109 QDeclarativeParser::Value *v = prop->values.first();
1111 if (v->type == Value::SignalObject) {
1113 genObject(v->object);
1115 QDeclarativeInstruction assign;
1116 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1117 assign.assignSignalObject.line = v->location.start.line;
1118 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1119 output->addInstruction(assign);
1121 } else if (v->type == Value::SignalExpression) {
1123 QDeclarativeInstruction store;
1124 store.setType(QDeclarativeInstruction::StoreSignal);
1125 store.storeSignal.signalIndex = prop->index;
1126 store.storeSignal.value =
1127 output->indexForString(v->value.asScript().trimmed());
1128 store.storeSignal.context = v->signalExpressionContextStack;
1129 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1130 store.storeSignal.line = v->location.start.line;
1131 output->addInstruction(store);
1137 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1138 QDeclarativeInstruction fetch;
1139 fetch.setType(QDeclarativeInstruction::FetchAttached);
1140 fetch.fetchAttached.id = prop->index;
1141 fetch.fetchAttached.line = prop->location.start.line;
1142 output->addInstruction(fetch);
1144 genObjectBody(prop->value);
1146 QDeclarativeInstruction pop;
1147 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1148 output->addInstruction(pop);
1151 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1152 QDeclarativeInstruction fetch;
1153 fetch.setType(QDeclarativeInstruction::FetchObject);
1154 fetch.fetch.property = prop->index;
1155 fetch.fetch.line = prop->location.start.line;
1156 output->addInstruction(fetch);
1158 if (!prop->value->metadata.isEmpty()) {
1159 QDeclarativeInstruction meta;
1160 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1161 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1162 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1163 meta.storeMeta.propertyCache = -1;
1164 output->addInstruction(meta);
1167 genObjectBody(prop->value);
1169 QDeclarativeInstruction pop;
1170 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1171 output->addInstruction(pop);
1174 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1176 genValueTypeProperty(obj, prop);
1179 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1180 if (prop->isDeferred)
1183 genValueProperty(prop, obj);
1186 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1188 genValueTypeProperty(obj, prop);
1192 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1194 QDeclarativeInstruction fetch;
1195 fetch.setType(QDeclarativeInstruction::FetchValueType);
1196 fetch.fetchValue.property = prop->index;
1197 fetch.fetchValue.type = prop->type;
1198 fetch.fetchValue.bindingSkipList = 0;
1200 if (obj->type == -1 || output->types.at(obj->type).component) {
1201 // We only have to do this if this is a composite type. If it is a builtin
1202 // type it can't possibly already have bindings that need to be cleared.
1203 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1204 if (!vprop->values.isEmpty()) {
1205 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1206 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1211 output->addInstruction(fetch);
1213 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1214 genPropertyAssignment(vprop, prop->value, prop);
1217 QDeclarativeInstruction pop;
1218 pop.setType(QDeclarativeInstruction::PopValueType);
1219 pop.fetchValue.property = prop->index;
1220 pop.fetchValue.type = prop->type;
1221 pop.fetchValue.bindingSkipList = 0;
1222 output->addInstruction(pop);
1225 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1227 QDeclarativeParser::Object *root = obj->defaultProperty->values.first()->object;
1230 QDeclarativeInstruction create;
1231 create.setType(QDeclarativeInstruction::CreateComponent);
1232 create.createComponent.line = root->location.start.line;
1233 create.createComponent.column = root->location.start.column;
1234 create.createComponent.endLine = root->location.end.line;
1235 int createInstruction = output->addInstruction(create);
1236 int nextInstructionIndex = output->nextInstructionIndex();
1238 ComponentCompileState *oldCompileState = compileState;
1239 compileState = componentState(root);
1241 QDeclarativeInstruction init;
1242 init.setType(QDeclarativeInstruction::Init);
1243 init.init.bindingsSize = compileState->bindings.count();
1244 init.init.parserStatusSize = compileState->parserStatusCount;
1245 init.init.contextCache = genContextCache();
1246 if (compileState->compiledBindingData.isEmpty())
1247 init.init.compiledBinding = -1;
1249 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1250 output->addInstruction(init);
1252 if (!compileState->v8BindingProgram.isEmpty()) {
1253 QDeclarativeInstruction bindings;
1254 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1255 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1256 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1257 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1258 output->addInstruction(bindings);
1263 QDeclarativeInstruction def;
1264 def.setType(QDeclarativeInstruction::SetDefault);
1265 output->addInstruction(def);
1267 QDeclarativeInstruction done;
1268 done.setType(QDeclarativeInstruction::Done);
1269 output->addInstruction(done);
1271 output->instruction(createInstruction)->createComponent.count =
1272 output->nextInstructionIndex() - nextInstructionIndex;
1274 compileState = oldCompileState;
1276 if (!obj->id.isEmpty()) {
1277 QDeclarativeInstruction id;
1278 id.setType(QDeclarativeInstruction::SetId);
1279 id.setId.value = output->indexForString(obj->id);
1280 id.setId.index = obj->idIndex;
1281 output->addInstruction(id);
1284 if (obj == unitRoot) {
1285 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1286 output->rootPropertyCache->addref();
1290 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1291 const BindingContext &ctxt)
1293 // The special "Component" element can only have the id property and a
1294 // default property, that actually defines the component's tree
1296 // Find, check and set the "id" property (if any)
1297 Property *idProp = 0;
1298 if (obj->properties.isMany() ||
1299 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1300 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1302 if (!obj->properties.isEmpty())
1303 idProp = obj->properties.first();
1306 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1307 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1308 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1310 QString idVal = idProp->values.first()->primitive();
1312 if (compileState->ids.value(idVal))
1313 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1319 // Check the Component tree is well formed
1320 if (obj->defaultProperty &&
1321 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1322 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1323 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1325 if (!obj->dynamicProperties.isEmpty())
1326 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1327 if (!obj->dynamicSignals.isEmpty())
1328 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1329 if (!obj->dynamicSlots.isEmpty())
1330 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1332 QDeclarativeParser::Object *root = 0;
1333 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1334 root = obj->defaultProperty->values.first()->object;
1337 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1339 // Build the component tree
1340 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1345 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1346 const BindingContext &ctxt)
1348 ComponentCompileState *oldComponentCompileState = compileState;
1349 compileState = pool->New<ComponentCompileState>();
1350 compileState->root = obj;
1351 compileState->nested = true;
1353 if (componentStats) {
1354 ComponentStat oldComponentStat = componentStats->componentStat;
1356 componentStats->componentStat = ComponentStat();
1357 componentStats->componentStat.lineNumber = obj->location.start.line;
1360 COMPILE_CHECK(buildObject(obj, ctxt));
1362 COMPILE_CHECK(completeComponentBuild());
1364 componentStats->componentStat = oldComponentStat;
1367 COMPILE_CHECK(buildObject(obj, ctxt));
1369 COMPILE_CHECK(completeComponentBuild());
1372 compileState = oldComponentCompileState;
1378 // Build a sub-object. A sub-object is one that was not created directly by
1379 // QML - such as a grouped property object, or an attached object. Sub-object's
1380 // can't have an id, involve a custom parser, have attached properties etc.
1381 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1383 Q_ASSERT(obj->metatype);
1384 Q_ASSERT(!obj->defaultProperty);
1385 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1388 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1389 if (isSignalPropertyName(prop->name())) {
1390 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1392 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1399 int QDeclarativeCompiler::componentTypeRef()
1401 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1402 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1403 if (output->types.at(ii).type == t)
1406 QDeclarativeCompiledData::TypeReference ref;
1407 ref.className = Component_string;
1409 output->types << ref;
1410 return output->types.count() - 1;
1413 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1414 const BindingContext &ctxt)
1416 Q_ASSERT(obj->metaObject());
1418 QString name = prop->name().toString();
1419 Q_ASSERT(name.startsWith(on_string));
1422 // Note that the property name could start with any alpha or '_' or '$' character,
1423 // so we need to do the lower-casing of the first alpha character.
1424 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1425 if (name.at(firstAlphaIndex) >= QLatin1Char('A') && name.at(firstAlphaIndex) <= QLatin1Char('Z')) {
1426 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1431 bool notInRevision = false;
1432 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1436 if (notInRevision && -1 == indexOfProperty(obj, prop->name(), 0)) {
1437 Q_ASSERT(obj->type != -1);
1438 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1439 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1441 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1443 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1447 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1449 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1453 if (prop->value || !prop->values.isOne())
1454 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1456 prop->index = sigIdx;
1457 obj->addSignalProperty(prop);
1459 if (prop->values.first()->object) {
1460 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1461 prop->values.first()->type = Value::SignalObject;
1463 prop->values.first()->type = Value::SignalExpression;
1465 if (!prop->values.first()->value.isScript())
1466 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1468 QString script = prop->values.first()->value.asScript().trimmed();
1469 if (script.isEmpty())
1470 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1472 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1481 Returns true if (value) property \a prop exists on obj, false otherwise.
1483 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1484 QDeclarativeParser::Object *obj)
1486 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1489 const QMetaObject *mo = obj->metaObject();
1491 if (prop->isDefault) {
1492 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1493 return p.name() != 0;
1495 int idx = indexOfProperty(obj, prop->name());
1496 return idx != -1 && mo->property(idx).isScriptable();
1503 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1504 QDeclarativeParser::Object *obj,
1505 const BindingContext &ctxt)
1507 if (prop->isEmpty())
1508 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1510 const QMetaObject *metaObject = obj->metaObject();
1511 Q_ASSERT(metaObject);
1513 if (isAttachedPropertyName(prop->name())) {
1514 // Setup attached property data
1516 if (ctxt.isSubContext()) {
1517 // Attached properties cannot be used on sub-objects. Sub-objects
1518 // always exist in a binding sub-context, which is what we test
1520 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1523 QDeclarativeType *type = 0;
1524 QDeclarativeImportedNamespace *typeNamespace = 0;
1525 unit->imports().resolveType(prop->name().toUtf8(), &type, 0, 0, 0, &typeNamespace);
1527 if (typeNamespace) {
1528 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1531 } else if (!type || !type->attachedPropertiesType()) {
1532 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1536 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1538 Q_ASSERT(type->attachedPropertiesFunction());
1539 prop->index = type->attachedPropertiesId();
1540 prop->value->metatype = type->attachedPropertiesType();
1542 // Setup regular property data
1545 if (prop->isDefault) {
1546 p = QDeclarativeMetaType::defaultProperty(metaObject);
1549 prop->index = p.propertyIndex();
1550 prop->setName(QString::fromLatin1(p.name()));
1554 bool notInRevision = false;
1555 prop->index = indexOfProperty(obj, prop->name(), ¬InRevision);
1556 if (prop->index == -1 && notInRevision) {
1557 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1558 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1560 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1562 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1566 if (prop->index != -1) {
1567 p = metaObject->property(prop->index);
1570 if (!p.isScriptable()) {
1572 p = QMetaProperty();
1577 // We can't error here as the "id" property does not require a
1578 // successful index resolution
1580 prop->type = p.userType();
1582 // Check if this is an alias
1583 if (prop->index != -1 &&
1585 prop->parent->type != -1 &&
1586 output->types.at(prop->parent->type).component) {
1588 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1589 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1590 prop->isAlias = true;
1593 if (prop->index != -1 && !prop->values.isEmpty())
1594 prop->parent->setBindingBit(prop->index);
1597 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1599 // The magic "id" behavior doesn't apply when "id" is resolved as a
1600 // default property or to sub-objects (which are always in binding
1602 COMPILE_CHECK(buildIdProperty(prop, obj));
1603 if (prop->type == QVariant::String &&
1604 prop->values.first()->value.isString())
1605 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1607 } else if (isAttachedPropertyName(prop->name())) {
1609 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1611 } else if (prop->index == -1) {
1613 if (prop->isDefault) {
1614 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1616 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1619 } else if (prop->value) {
1621 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1623 } else if (enginePrivate->isList(prop->type)) {
1625 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1627 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1629 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1633 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1640 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1641 QDeclarativeParser::Property *nsProp,
1642 QDeclarativeParser::Object *obj,
1643 const BindingContext &ctxt)
1646 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1648 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1650 if (!isAttachedPropertyName(prop->name()))
1651 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1653 // Setup attached property data
1655 QDeclarativeType *type = 0;
1656 unit->imports().resolveType(ns, prop->name().toUtf8(), &type, 0, 0, 0);
1658 if (!type || !type->attachedPropertiesType())
1659 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1662 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1664 Q_ASSERT(type->attachedPropertiesFunction());
1665 prop->index = type->index();
1666 prop->value->metatype = type->attachedPropertiesType();
1668 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1674 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1675 QDeclarativeParser::Object *obj)
1677 if (enginePrivate->isList(prop->type)) {
1678 genListProperty(prop, obj);
1680 genPropertyAssignment(prop, obj);
1684 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1685 QDeclarativeParser::Object *obj)
1687 int listType = enginePrivate->listType(prop->type);
1689 QDeclarativeInstruction fetch;
1690 fetch.setType(QDeclarativeInstruction::FetchQList);
1691 fetch.fetchQmlList.property = prop->index;
1692 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1693 fetch.fetchQmlList.type = listType;
1694 output->addInstruction(fetch);
1696 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1698 if (v->type == Value::CreatedObject) {
1700 genObject(v->object);
1701 if (listTypeIsInterface) {
1702 QDeclarativeInstruction assign;
1703 assign.setType(QDeclarativeInstruction::AssignObjectList);
1704 assign.assignObjectList.line = prop->location.start.line;
1705 output->addInstruction(assign);
1707 QDeclarativeInstruction store;
1708 store.setType(QDeclarativeInstruction::StoreObjectQList);
1709 output->addInstruction(store);
1712 } else if (v->type == Value::PropertyBinding) {
1714 genBindingAssignment(v, prop, obj);
1720 QDeclarativeInstruction pop;
1721 pop.setType(QDeclarativeInstruction::PopQList);
1722 output->addInstruction(pop);
1725 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1726 QDeclarativeParser::Object *obj,
1727 QDeclarativeParser::Property *valueTypeProperty)
1729 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1731 Q_ASSERT(v->type == Value::CreatedObject ||
1732 v->type == Value::PropertyBinding ||
1733 v->type == Value::Literal);
1735 if (v->type == Value::CreatedObject) {
1737 genObject(v->object);
1739 if (QDeclarativeMetaType::isInterface(prop->type)) {
1741 QDeclarativeInstruction store;
1742 store.setType(QDeclarativeInstruction::StoreInterface);
1743 store.storeObject.line = v->object->location.start.line;
1744 store.storeObject.propertyIndex = prop->index;
1745 output->addInstruction(store);
1747 } else if (prop->type == -1) {
1749 QDeclarativeInstruction store;
1750 store.setType(QDeclarativeInstruction::StoreVariantObject);
1751 store.storeObject.line = v->object->location.start.line;
1752 store.storeObject.propertyIndex = prop->index;
1753 output->addInstruction(store);
1757 QDeclarativeInstruction store;
1758 store.setType(QDeclarativeInstruction::StoreObject);
1759 store.storeObject.line = v->object->location.start.line;
1760 store.storeObject.propertyIndex = prop->index;
1761 output->addInstruction(store);
1764 } else if (v->type == Value::PropertyBinding) {
1766 genBindingAssignment(v, prop, obj, valueTypeProperty);
1768 } else if (v->type == Value::Literal) {
1770 QMetaProperty mp = obj->metaObject()->property(prop->index);
1771 genLiteralAssignment(mp, v);
1777 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1779 Q_ASSERT(v->type == Value::ValueSource ||
1780 v->type == Value::ValueInterceptor);
1782 if (v->type == Value::ValueSource) {
1783 genObject(v->object);
1785 QDeclarativeInstruction store;
1786 store.setType(QDeclarativeInstruction::StoreValueSource);
1787 if (valueTypeProperty) {
1788 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1789 store.assignValueSource.owner = 1;
1791 store.assignValueSource.property = genPropertyData(prop);
1792 store.assignValueSource.owner = 0;
1794 QDeclarativeType *valueType = toQmlType(v->object);
1795 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1796 output->addInstruction(store);
1798 } else if (v->type == Value::ValueInterceptor) {
1799 genObject(v->object);
1801 QDeclarativeInstruction store;
1802 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1803 if (valueTypeProperty) {
1804 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1805 store.assignValueInterceptor.owner = 1;
1807 store.assignValueInterceptor.property = genPropertyData(prop);
1808 store.assignValueInterceptor.owner = 0;
1810 QDeclarativeType *valueType = toQmlType(v->object);
1811 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1812 output->addInstruction(store);
1818 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1819 QDeclarativeParser::Object *obj)
1822 prop->values.isMany() ||
1823 prop->values.first()->object)
1824 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1826 QDeclarativeParser::Value *idValue = prop->values.first();
1827 QString val = idValue->primitive();
1829 COMPILE_CHECK(checkValidId(idValue, val));
1831 if (compileState->ids.value(val))
1832 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1834 prop->values.first()->type = Value::Id;
1842 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1844 Q_ASSERT(!compileState->ids.value(id));
1845 Q_ASSERT(obj->id == id);
1846 obj->idIndex = compileState->ids.count();
1847 compileState->ids.append(obj);
1850 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1852 Q_ASSERT(ref->value && !ref->value->bindingReference);
1853 ref->value->bindingReference = ref;
1854 compileState->bindings.prepend(ref);
1857 void QDeclarativeCompiler::saveComponentState()
1859 Q_ASSERT(compileState->root);
1860 Q_ASSERT(compileState->root->componentCompileState == 0);
1862 compileState->root->componentCompileState = compileState;
1865 componentStats->savedComponentStats.append(componentStats->componentStat);
1868 QDeclarativeCompilerTypes::ComponentCompileState *
1869 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1871 Q_ASSERT(obj->componentCompileState);
1872 return obj->componentCompileState;
1875 // Build attached property object. In this example,
1879 // GridView is an attached property object.
1880 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1881 QDeclarativeParser::Object *obj,
1882 const BindingContext &ctxt)
1884 Q_ASSERT(prop->value);
1885 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1887 obj->addAttachedProperty(prop);
1889 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1895 // Build "grouped" properties. In this example:
1897 // font.pointSize: 12
1898 // font.family: "Helvetica"
1900 // font is a nested property. pointSize and family are not.
1901 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1902 QDeclarativeParser::Object *obj,
1903 const BindingContext &ctxt)
1905 Q_ASSERT(prop->type != 0);
1906 Q_ASSERT(prop->index != -1);
1908 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1909 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1911 if (!prop->values.isEmpty()) {
1912 if (prop->values.first()->location < prop->value->location) {
1913 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1915 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1919 if (!obj->metaObject()->property(prop->index).isWritable()) {
1920 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1924 if (prop->isAlias) {
1925 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1926 vtProp->isAlias = true;
1930 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1931 prop->value, obj, ctxt.incr()));
1932 obj->addValueTypeProperty(prop);
1934 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1938 // Load the nested property's meta type
1939 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1940 if (!prop->value->metatype)
1941 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1943 if (!prop->values.isEmpty())
1944 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1946 obj->addGroupedProperty(prop);
1948 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1954 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1955 QDeclarativeParser::Object *obj,
1956 QDeclarativeParser::Object *baseObj,
1957 const BindingContext &ctxt)
1959 if (obj->defaultProperty)
1960 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1961 obj->metatype = type->metaObject();
1963 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1964 int idx = type->metaObject()->indexOfProperty(prop->name().toUtf8().constData());
1966 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1967 QMetaProperty p = type->metaObject()->property(idx);
1968 if (!p.isScriptable())
1969 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1971 prop->type = p.userType();
1972 prop->isValueTypeSubProperty = true;
1975 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1977 if (prop->values.isMany()) {
1978 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1979 } else if (!prop->values.isEmpty()) {
1980 QDeclarativeParser::Value *value = prop->values.first();
1982 if (value->object) {
1983 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1984 } else if (value->value.isScript()) {
1985 // ### Check for writability
1987 //optimization for <Type>.<EnumValue> enum assignments
1988 bool isEnumAssignment = false;
1989 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1990 if (isEnumAssignment) {
1991 value->type = Value::Literal;
1993 BindingReference *reference = pool->New<BindingReference>();
1994 reference->expression = value->value;
1995 reference->property = prop;
1996 reference->value = value;
1997 reference->bindingContext = ctxt;
1998 reference->bindingContext.owner++;
1999 addBindingReference(reference);
2000 value->type = Value::PropertyBinding;
2003 COMPILE_CHECK(testLiteralAssignment(p, value));
2004 value->type = Value::Literal;
2008 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2009 Q_ASSERT(v->object);
2011 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2014 obj->addValueProperty(prop);
2020 // Build assignments to QML lists. QML lists are properties of type
2021 // QDeclarativeListProperty<T>. List properties can accept a list of
2022 // objects, or a single binding.
2023 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2024 QDeclarativeParser::Object *obj,
2025 const BindingContext &ctxt)
2027 Q_ASSERT(enginePrivate->isList(prop->type));
2031 obj->addValueProperty(prop);
2033 int listType = enginePrivate->listType(t);
2034 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2036 bool assignedBinding = false;
2037 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2039 v->type = Value::CreatedObject;
2040 COMPILE_CHECK(buildObject(v->object, ctxt));
2042 // We check object coercian here. We check interface assignment
2044 if (!listTypeIsInterface) {
2045 if (!canCoerce(listType, v->object)) {
2046 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2050 } else if (v->value.isScript()) {
2051 if (assignedBinding)
2052 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2054 assignedBinding = true;
2055 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2056 v->type = Value::PropertyBinding;
2058 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2065 // Compiles an assignment to a QDeclarativeScriptString property
2066 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2067 QDeclarativeParser::Object *obj,
2068 const BindingContext &ctxt)
2070 if (prop->values.isMany())
2071 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2073 if (prop->values.first()->object)
2074 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2076 prop->scriptStringScope = ctxt.stack;
2077 obj->addScriptStringProperty(prop);
2082 // Compile regular property assignments of the form "property: <value>"
2083 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2084 QDeclarativeParser::Object *obj,
2085 const BindingContext &ctxt)
2087 obj->addValueProperty(prop);
2089 if (prop->values.isMany())
2090 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2092 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2095 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2099 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2104 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2105 Q_ASSERT(v->object);
2106 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2112 // Compile assigning a single object instance to a regular property
2113 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2114 QDeclarativeParser::Object *obj,
2115 QDeclarativeParser::Value *v,
2116 const BindingContext &ctxt)
2118 Q_ASSERT(prop->index != -1);
2119 Q_ASSERT(v->object->type != -1);
2121 if (!obj->metaObject()->property(prop->index).isWritable())
2122 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2124 if (QDeclarativeMetaType::isInterface(prop->type)) {
2126 // Assigning an object to an interface ptr property
2127 COMPILE_CHECK(buildObject(v->object, ctxt));
2129 v->type = Value::CreatedObject;
2131 } else if (prop->type == -1) {
2133 // Assigning an object to a QVariant
2134 COMPILE_CHECK(buildObject(v->object, ctxt));
2136 v->type = Value::CreatedObject;
2138 // Normally buildObject() will set this up, but we need the static
2139 // meta object earlier to test for assignability. It doesn't matter
2140 // that there may still be outstanding synthesized meta object changes
2141 // on this type, as they are not relevant for assignability testing
2142 v->object->metatype = output->types.at(v->object->type).metaObject();
2143 Q_ASSERT(v->object->metaObject());
2145 // We want to raw metaObject here as the raw metaobject is the
2146 // actual property type before we applied any extensions that might
2147 // effect the properties on the type, but don't effect assignability
2148 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2150 // Will be true if the assgned type inherits propertyMetaObject
2151 bool isAssignable = false;
2152 // Determine isAssignable value
2153 if (propertyMetaObject) {
2154 const QMetaObject *c = v->object->metatype;
2156 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2157 c = c->superClass();
2162 // Simple assignment
2163 COMPILE_CHECK(buildObject(v->object, ctxt));
2165 v->type = Value::CreatedObject;
2166 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2167 // Automatic "Component" insertion
2168 QDeclarativeParser::Object *root = v->object;
2169 QDeclarativeParser::Object *component = pool->New<Object>();
2170 component->type = componentTypeRef();
2171 component->typeName = "Qt/Component";
2172 component->metatype = &QDeclarativeComponent::staticMetaObject;
2173 component->location = root->location;
2174 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2175 componentValue->object = root;
2176 component->getDefaultProperty()->addValue(componentValue);
2177 v->object = component;
2178 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2180 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2187 // Compile assigning a single object instance to a regular property using the "on" syntax.
2191 // NumberAnimation on x { }
2193 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2194 QDeclarativeParser::Object *obj,
2195 QDeclarativeParser::Object *baseObj,
2196 QDeclarativeParser::Value *v,
2197 const BindingContext &ctxt)
2199 Q_ASSERT(prop->index != -1);
2200 Q_ASSERT(v->object->type != -1);
2202 if (!obj->metaObject()->property(prop->index).isWritable())
2203 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2206 // Normally buildObject() will set this up, but we need the static
2207 // meta object earlier to test for assignability. It doesn't matter
2208 // that there may still be outstanding synthesized meta object changes
2209 // on this type, as they are not relevant for assignability testing
2210 v->object->metatype = output->types.at(v->object->type).metaObject();
2211 Q_ASSERT(v->object->metaObject());
2213 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2214 bool isPropertyValue = false;
2215 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2216 bool isPropertyInterceptor = false;
2217 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2218 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2219 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2222 if (isPropertyValue || isPropertyInterceptor) {
2223 // Assign as a property value source
2224 COMPILE_CHECK(buildObject(v->object, ctxt));
2226 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2227 buildDynamicMeta(baseObj, ForceCreation);
2228 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2230 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2236 // Compile assigning a literal or binding to a regular property
2237 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2238 QDeclarativeParser::Object *obj,
2239 QDeclarativeParser::Value *v,
2240 const BindingContext &ctxt)
2242 Q_ASSERT(prop->index != -1);
2244 if (v->value.isScript()) {
2246 //optimization for <Type>.<EnumValue> enum assignments
2247 bool isEnumAssignment = false;
2248 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2249 if (isEnumAssignment) {
2250 v->type = Value::Literal;
2254 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2256 v->type = Value::PropertyBinding;
2260 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2262 v->type = Value::Literal;
2268 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2269 QDeclarativeParser::Object *obj,
2270 QDeclarativeParser::Value *v,
2273 *isAssignment = false;
2274 if (!prop.isEnumType())
2277 if (!prop.isWritable())
2278 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2280 QString string = v->value.asString();
2281 if (!string.at(0).isUpper())
2284 QStringList parts = string.split(QLatin1Char('.'));
2285 if (parts.count() != 2)
2288 QString typeName = parts.at(0);
2289 QDeclarativeType *type = 0;
2290 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2292 //handle enums on value types (where obj->typeName is empty)
2293 QByteArray objTypeName = obj->typeName;
2294 if (objTypeName.isEmpty()) {
2295 QDeclarativeType *objType = toQmlType(obj);
2297 objTypeName = objType->qmlTypeName();
2303 QString enumValue = parts.at(1);
2306 if (objTypeName == type->qmlTypeName()) {
2307 // When these two match, we can short cut the search
2308 if (prop.isFlagType()) {
2309 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2311 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2314 // Otherwise we have to search the whole type
2315 // This matches the logic in QV8TypeWrapper
2316 QByteArray enumName = enumValue.toUtf8();
2317 const QMetaObject *metaObject = type->baseMetaObject();
2318 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2319 QMetaEnum e = metaObject->enumerator(ii);
2320 value = e.keyToValue(enumName.constData());
2327 v->type = Value::Literal;
2328 v->value = QDeclarativeParser::Variant((double)value);
2329 *isAssignment = true;
2334 struct StaticQtMetaObject : public QObject
2336 static const QMetaObject *get()
2337 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2340 // Similar logic to above, but not knowing target property.
2341 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2343 int dot = script.indexOf('.');
2345 const QByteArray &scope = script.left(dot);
2346 QDeclarativeType *type = 0;
2347 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2348 if (!type && scope != "Qt")
2350 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2351 const char *key = script.constData() + dot+1;
2352 int i = mo->enumeratorCount();
2354 int v = mo->enumerator(i).keyToValue(key);
2362 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2364 QDeclarativeType *qmltype = 0;
2365 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2369 return qmltype->metaObject();
2372 // similar to logic of completeComponentBuild, but also sticks data
2373 // into primitives at the end
2374 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2376 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2377 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2379 QString rewrite = rewriteBinding(expression, 0, 0);
2381 return output->indexForString(rewrite);
2384 // Ensures that the dynamic meta specification on obj is valid
2385 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2387 QSet<QByteArray> propNames;
2388 QSet<QByteArray> methodNames;
2389 bool seenDefaultProperty = false;
2392 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2393 const QDeclarativeParser::Object::DynamicProperty &prop =
2394 obj->dynamicProperties.at(ii);
2396 if (prop.isDefaultProperty) {
2397 if (seenDefaultProperty)
2398 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2399 seenDefaultProperty = true;
2402 if (propNames.contains(prop.name))
2403 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2405 QString propName = QString::fromUtf8(prop.name);
2406 if (propName.at(0).isUpper())
2407 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2409 if (enginePrivate->v8engine()->illegalNames().contains(propName))
2410 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2412 propNames.insert(prop.name);
2415 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2416 const QDeclarativeParser::Object::DynamicSignal &currSig = obj->dynamicSignals.at(ii);
2417 QByteArray name = currSig.name;
2418 if (methodNames.contains(name))
2419 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2420 QString nameStr = QString::fromUtf8(name);
2421 if (nameStr.at(0).isUpper())
2422 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2423 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2424 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2425 methodNames.insert(name);
2427 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2428 const QDeclarativeParser::Object::DynamicSlot &currSlot = obj->dynamicSlots.at(ii);
2429 QByteArray name = currSlot.name;
2430 if (methodNames.contains(name))
2431 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2432 QString nameStr = QString::fromUtf8(name);
2433 if (nameStr.at(0).isUpper())
2434 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2435 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2436 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2437 methodNames.insert(name);
2443 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2445 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2446 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2448 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2451 Property *property = 0;
2452 if (p.isDefaultProperty) {
2453 property = obj->getDefaultProperty();
2455 property = obj->getProperty(p.name);
2456 if (!property->values.isEmpty())
2457 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2460 if (property->value)
2461 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2463 property->values.append(p.defaultValue->values);
2468 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2470 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2473 Q_ASSERT(obj->metatype);
2475 if (mode != ForceCreation &&
2476 obj->dynamicProperties.isEmpty() &&
2477 obj->dynamicSignals.isEmpty() &&
2478 obj->dynamicSlots.isEmpty())
2481 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2483 QByteArray newClassName = obj->metatype->className();
2484 newClassName.append("_QML_");
2485 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2486 newClassName.append(QByteArray::number(idx));
2487 if (compileState->root == obj && !compileState->nested) {
2488 QString path = output->url.path();
2489 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2490 if (lastSlash > -1) {
2491 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2492 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2493 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2497 QMetaObjectBuilder builder;
2498 builder.setClassName(newClassName);
2499 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2501 bool hasAlias = false;
2502 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2503 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2505 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2506 if (-1 != propIdx) {
2507 QMetaProperty prop = obj->metaObject()->property(propIdx);
2509 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2512 if (p.isDefaultProperty &&
2513 (p.type != Object::DynamicProperty::Alias ||
2514 mode == ResolveAliases))
2515 builder.addClassInfo("DefaultProperty", p.name);
2518 int propertyType = 0;
2519 bool readonly = false;
2521 case Object::DynamicProperty::Alias:
2525 case Object::DynamicProperty::CustomList:
2526 case Object::DynamicProperty::Custom:
2528 QByteArray customTypeName;
2529 QDeclarativeType *qmltype = 0;
2531 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2532 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2535 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2537 Q_ASSERT(tdata->isComplete());
2539 QDeclarativeCompiledData *data = tdata->compiledData();
2540 customTypeName = data->root->className();
2544 customTypeName = qmltype->typeName();
2547 if (p.type == Object::DynamicProperty::Custom) {
2548 type = customTypeName + '*';
2549 propertyType = QMetaType::QObjectStar;
2552 type = "QDeclarativeListProperty<";
2553 type.append(customTypeName);
2555 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2559 case Object::DynamicProperty::Variant:
2563 case Object::DynamicProperty::Int:
2564 propertyType = QVariant::Int;
2567 case Object::DynamicProperty::Bool:
2568 propertyType = QVariant::Bool;
2571 case Object::DynamicProperty::Real:
2572 propertyType = QVariant::Double;
2575 case Object::DynamicProperty::String:
2576 propertyType = QVariant::String;
2579 case Object::DynamicProperty::Url:
2580 propertyType = QVariant::Url;
2583 case Object::DynamicProperty::Color:
2584 propertyType = QVariant::Color;
2587 case Object::DynamicProperty::Time:
2588 propertyType = QVariant::Time;
2591 case Object::DynamicProperty::Date:
2592 propertyType = QVariant::Date;
2595 case Object::DynamicProperty::DateTime:
2596 propertyType = QVariant::DateTime;
2601 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2602 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2603 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2605 builder.addSignal(p.name + "Changed()");
2606 QMetaPropertyBuilder propBuilder =
2607 builder.addProperty(p.name, type, builder.methodCount() - 1);
2608 propBuilder.setWritable(!readonly);
2611 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2612 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2614 if (p.type == Object::DynamicProperty::Alias) {
2615 if (mode == ResolveAliases) {
2616 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2617 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2619 // Need a fake signal so that the metaobject remains consistent across
2620 // the resolve and non-resolve alias runs
2621 builder.addSignal(p.name + "Changed()");
2626 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2627 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2628 QByteArray sig(s.name + '(');
2629 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2630 if (jj) sig.append(',');
2631 sig.append(s.parameterTypes.at(jj));
2634 QMetaMethodBuilder b = builder.addSignal(sig);
2635 b.setParameterNames(s.parameterNames);
2636 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2639 QStringList funcScripts;
2641 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2642 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2643 QByteArray sig(s.name + '(');
2644 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2646 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2649 funcScript.append(QLatin1Char(','));
2651 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2652 sig.append("QVariant");
2655 funcScript.append(QLatin1Char(')'));
2656 funcScript.append(s.body);
2657 funcScript.append(QLatin1Char(')'));
2658 funcScripts << funcScript;
2660 QMetaMethodBuilder b = builder.addSlot(sig);
2661 b.setReturnType("QVariant");
2662 b.setParameterNames(s.parameterNames);
2664 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2665 QDeclarativeVMEMetaData::MethodData methodData =
2666 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2668 dynamicData.append((char *)&methodData, sizeof(methodData));
2671 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2672 const QString &funcScript = funcScripts.at(ii);
2673 QDeclarativeVMEMetaData::MethodData *data =
2674 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2676 data->bodyOffset = dynamicData.size();
2678 dynamicData.append((const char *)funcScript.constData(),
2679 (funcScript.length() * sizeof(QChar)));
2682 obj->metadata = builder.toRelocatableData();
2683 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2685 if (mode == IgnoreAliases && hasAlias)
2686 compileState->aliasingObjects.append(obj);
2688 obj->synthdata = dynamicData;
2690 if (obj->synthCache) {
2691 obj->synthCache->release();
2692 obj->synthCache = 0;
2695 if (obj->type != -1) {
2696 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2697 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2698 QDeclarativePropertyCache::Data::IsVMEFunction,
2699 QDeclarativePropertyCache::Data::IsVMESignal);
2700 obj->synthCache = cache;
2706 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2709 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2711 if (val.at(0).isLetter() && !val.at(0).isLower())
2712 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2714 QChar u(QLatin1Char('_'));
2715 for (int ii = 0; ii < val.count(); ++ii) {
2717 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2718 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2719 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2720 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2725 if (enginePrivate->v8engine()->illegalNames().contains(val))
2726 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2731 #include <qdeclarativejsparser_p.h>
2733 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2735 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2737 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2738 return QStringList() << name;
2739 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2740 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2742 QStringList rv = astNodeToStringList(expr->base);
2745 rv.append(expr->name.toString());
2748 return QStringList();
2751 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2753 QDeclarativeParser::Object *obj,
2754 const Object::DynamicProperty &prop)
2756 if (!prop.defaultValue)
2757 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2759 if (!prop.defaultValue->values.isOne() ||
2760 prop.defaultValue->values.first()->object ||
2761 !prop.defaultValue->values.first()->value.isScript())
2762 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2764 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2766 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2768 QStringList alias = astNodeToStringList(node);
2770 if (alias.count() < 1 || alias.count() > 3)
2771 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2773 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2775 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2777 QByteArray typeName;
2781 bool writable = false;
2782 bool resettable = false;
2783 if (alias.count() == 2 || alias.count() == 3) {
2784 propIdx = indexOfProperty(idObject, alias.at(1));
2786 if (-1 == propIdx) {
2787 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2788 } else if (propIdx > 0xFFFF) {
2789 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2792 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2793 if (!aliasProperty.isScriptable())
2794 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2796 writable = aliasProperty.isWritable();
2797 resettable = aliasProperty.isResettable();
2799 if (alias.count() == 3) {
2800 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2802 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2804 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2806 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2807 if (valueTypeIndex == -1)
2808 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2809 Q_ASSERT(valueTypeIndex <= 0xFF);
2811 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2812 propIdx |= (valueTypeIndex << 16);
2815 if (aliasProperty.isEnumType())
2816 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2818 typeName = aliasProperty.typeName();
2820 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2822 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2824 typeName = ref.type->typeName();
2826 typeName = ref.component->root->className();
2831 if (typeName.endsWith('*'))
2832 flags |= QML_ALIAS_FLAG_PTR;
2834 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2835 data.append((const char *)&propIdx, sizeof(propIdx));
2836 data.append((const char *)&flags, sizeof(flags));
2838 builder.addSignal(prop.name + "Changed()");
2839 QMetaPropertyBuilder propBuilder =
2840 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2841 propBuilder.setWritable(writable);
2842 propBuilder.setResettable(resettable);
2846 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2847 QDeclarativeParser::Property *prop,
2848 const BindingContext &ctxt)
2850 Q_ASSERT(prop->index != -1);
2851 Q_ASSERT(prop->parent);
2852 Q_ASSERT(prop->parent->metaObject());
2854 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2855 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2856 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2858 BindingReference *reference = pool->New<BindingReference>();
2859 reference->expression = value->value;
2860 reference->property = prop;
2861 reference->value = value;
2862 reference->bindingContext = ctxt;
2863 addBindingReference(reference);
2868 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2869 QDeclarativeParser::Property *prop,
2870 QDeclarativeParser::Object *obj,
2871 QDeclarativeParser::Property *valueTypeProperty)
2874 Q_ASSERT(binding->bindingReference);
2876 const BindingReference &ref = *binding->bindingReference;
2877 if (ref.dataType == BindingReference::V4) {
2878 QDeclarativeInstruction store;
2879 store.setType(QDeclarativeInstruction::StoreV4Binding);
2880 store.assignBinding.value = ref.compiledIndex;
2881 store.assignBinding.context = ref.bindingContext.stack;
2882 store.assignBinding.owner = ref.bindingContext.owner;
2883 if (valueTypeProperty)
2884 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2885 ((valueTypeProperty->type & 0xFF)) << 16 |
2886 ((prop->index & 0xFF) << 24);
2888 store.assignBinding.property = prop->index;
2889 store.assignBinding.line = binding->location.start.line;
2890 output->addInstruction(store);
2891 } else if (ref.dataType == BindingReference::V8) {
2892 QDeclarativeInstruction store;
2893 store.setType(QDeclarativeInstruction::StoreV8Binding);
2894 store.assignBinding.value = ref.compiledIndex;
2895 store.assignBinding.context = ref.bindingContext.stack;
2896 store.assignBinding.owner = ref.bindingContext.owner;
2897 store.assignBinding.line = binding->location.start.line;
2899 Q_ASSERT(ref.bindingContext.owner == 0 ||
2900 (ref.bindingContext.owner != 0 && valueTypeProperty));
2901 if (ref.bindingContext.owner) {
2902 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2904 store.assignBinding.property = genPropertyData(prop);
2907 output->addInstruction(store);
2909 QDeclarativeInstruction store;
2911 store.setType(QDeclarativeInstruction::StoreBinding);
2913 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2914 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2915 store.assignBinding.context = ref.bindingContext.stack;
2916 store.assignBinding.owner = ref.bindingContext.owner;
2917 store.assignBinding.line = binding->location.start.line;
2919 Q_ASSERT(ref.bindingContext.owner == 0 ||
2920 (ref.bindingContext.owner != 0 && valueTypeProperty));
2921 if (ref.bindingContext.owner) {
2922 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2924 store.assignBinding.property = genPropertyData(prop);
2926 output->addInstruction(store);
2930 int QDeclarativeCompiler::genContextCache()
2932 if (compileState->ids.count() == 0)
2935 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2936 cache->reserve(compileState->ids.count());
2937 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
2938 cache->add(o->id, o->idIndex);
2940 output->contextCaches.append(cache);
2941 return output->contextCaches.count() - 1;
2944 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2945 QDeclarativeParser::Property *prop)
2947 typedef QDeclarativePropertyPrivate QDPP;
2948 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
2949 enginePrivate->valueTypes[prop->type]->metaObject(),
2950 valueTypeProp->index, engine);
2952 return output->indexForByteArray(data);
2955 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2957 typedef QDeclarativePropertyPrivate QDPP;
2958 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
2960 return output->indexForByteArray(data);
2963 bool QDeclarativeCompiler::completeComponentBuild()
2966 componentStats->componentStat.ids = compileState->ids.count();
2968 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
2969 aliasObject = compileState->aliasingObjects.next(aliasObject))
2970 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2972 QDeclarativeV4Compiler::Expression expr(unit->imports());
2973 expr.component = compileState->root;
2974 expr.ids = &compileState->ids;
2975 expr.importCache = output->importCache;
2977 QDeclarativeV4Compiler bindingCompiler;
2979 QList<BindingReference*> sharedBindings;
2981 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
2983 BindingReference &binding = *b;
2985 // ### We don't currently optimize for bindings on alias's - because
2986 // of the solution to QTBUG-13719
2987 if (!binding.property->isAlias) {
2988 expr.context = binding.bindingContext.object;
2989 expr.property = binding.property;
2990 expr.expression = binding.expression;
2992 int index = bindingCompiler.compile(expr, enginePrivate);
2994 binding.dataType = BindingReference::V4;
2995 binding.compiledIndex = index;
2997 componentStats->componentStat.optimizedBindings.append(b->value->location);
3002 // Pre-rewrite the expression
3003 QString expression = binding.expression.asScript();
3005 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3006 rewriteBinding.setName(QLatin1Char('$')+binding.property->name());
3007 bool isSharable = false;
3008 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3010 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3011 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3012 binding.dataType = BindingReference::V8;
3013 sharedBindings.append(b);
3015 binding.dataType = BindingReference::QtScript;
3019 componentStats->componentStat.scriptBindings.append(b->value->location);
3022 if (!sharedBindings.isEmpty()) {
3024 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3026 return lhs->value->location.start.line < rhs->value->location.start.line;
3030 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3032 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3033 int lineNumber = startLineNumber;
3035 QString functionArray(QLatin1String("["));
3036 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3037 BindingReference *reference = sharedBindings.at(ii);
3038 QDeclarativeParser::Value *value = reference->value;
3039 const QString &expression = reference->rewrittenExpression;
3041 if (ii != 0) functionArray += QLatin1String(",");
3043 while (lineNumber < value->location.start.line) {
3045 functionArray += QLatin1String("\n");
3048 functionArray += expression;
3049 reference->compiledIndex = ii;
3051 functionArray += QLatin1String("]");
3053 compileState->v8BindingProgram = functionArray;
3054 compileState->v8BindingProgramLine = startLineNumber;
3055 compileState->v8BindingProgramIndex = output->v8bindings.count();
3056 output->v8bindings.append(v8::Persistent<v8::Array>());
3059 if (bindingCompiler.isValid())
3060 compileState->compiledBindingData = bindingCompiler.program();
3062 saveComponentState();
3067 void QDeclarativeCompiler::dumpStats()
3069 Q_ASSERT(componentStats);
3070 qWarning().nospace() << "QML Document: " << output->url.toString();
3071 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3072 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3073 qWarning().nospace() << " Component Line " << stat.lineNumber;
3074 qWarning().nospace() << " Total Objects: " << stat.objects;
3075 qWarning().nospace() << " IDs Used: " << stat.ids;
3076 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3080 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3081 if (0 == (ii % 10)) {
3082 if (ii) output.append("\n");
3087 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3089 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3090 output.append(") ");
3092 if (!output.isEmpty())
3093 qWarning().nospace() << output.constData();
3096 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3099 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3100 if (0 == (ii % 10)) {
3101 if (ii) output.append("\n");
3106 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3108 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3109 output.append(") ");
3111 if (!output.isEmpty())
3112 qWarning().nospace() << output.constData();
3118 Returns true if from can be assigned to a (QObject) property of type
3121 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3123 const QMetaObject *toMo =
3124 enginePrivate->rawMetaObjectForType(to);
3125 const QMetaObject *fromMo = from->metaObject();
3128 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3130 fromMo = fromMo->superClass();
3136 Returns the element name, as written in the QML file, for o.
3138 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3141 if (o->type != -1) {
3142 return output->types.at(o->type).className;
3148 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3151 const QMetaObject *mo = from->metatype;
3152 QDeclarativeType *type = 0;
3153 while (!type && mo) {
3154 type = QDeclarativeMetaType::qmlType(mo);
3155 mo = mo->superClass();
3160 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3162 const QMetaObject *mo = obj->metatype;
3164 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3166 return QStringList();
3168 QMetaClassInfo classInfo = mo->classInfo(idx);
3169 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3173 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3174 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3175 bool *notInRevision)
3177 if (notInRevision) *notInRevision = false;
3179 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3180 QDeclarativePropertyCache *cache =
3181 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3183 QDeclarativePropertyCache::Data *d = cache->property(name);
3184 if (notInRevision) *notInRevision = false;
3186 while (d && !(d->isFunction()))
3187 d = cache->overrideData(d);
3189 if (d && !cache->isAllowedInRevision(d)) {
3190 if (notInRevision) *notInRevision = true;
3193 return d->coreIndex;
3196 if (name.endsWith(Changed_string)) {
3197 QString propName = name.mid(0, name.length() - 7);
3199 int propIndex = indexOfProperty(object, QStringRef(&propName), notInRevision);
3200 if (propIndex != -1) {
3201 d = cache->property(propIndex);
3202 return d->notifyIndex;
3208 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name.toUtf8()).methodIndex();
3213 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3214 bool *notInRevision)
3216 return indexOfProperty(object, QStringRef(&name), notInRevision);
3219 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QStringRef &name,
3220 bool *notInRevision)
3222 if (notInRevision) *notInRevision = false;
3224 QDeclarativePropertyCache *cache = 0;
3226 if (object->synthCache)
3227 cache = object->synthCache;
3228 else if (object->type != -1)
3229 cache = output->types[object->type].createPropertyCache(engine);
3231 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3233 QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
3235 // Find the first property
3236 while (d && d->isFunction())
3237 d = cache->overrideData(d);
3239 if (d && !cache->isAllowedInRevision(d)) {
3240 if (notInRevision) *notInRevision = true;
3243 return d?d->coreIndex:-1;